Files
inventree-app/lib/main.dart
T
Reza Fouladian ca655f36fe Add intent wedge scanner, MDM support for Android (#863)
Add Android intent wedge scanner support with auto configuration for supported Zebra and Datalogic devices.
Intent wedge scans can be done without pressing the scan button first.

Adds the ability for an MDM server to push settings on Android.
2026-08-16 13:59:20 +10:00

235 lines
7.0 KiB
Dart

import "dart:async";
import "dart:io";
import "package:flutter/foundation.dart";
import "package:flutter/material.dart";
import "package:flutter/services.dart";
import "package:adaptive_theme/adaptive_theme.dart";
import "package:flutter_localizations/flutter_localizations.dart";
import "package:flutter_localized_locales/flutter_localized_locales.dart";
import "package:inventree/barcode/barcode.dart";
import "package:inventree/barcode/wedge_detect.dart";
import "package:one_context/one_context.dart";
import "package:package_info_plus/package_info_plus.dart";
import "package:sentry_flutter/sentry_flutter.dart";
import "package:inventree/dsn.dart";
import "package:inventree/managed_config.dart";
import "package:inventree/preferences.dart";
import "package:inventree/inventree/sentry.dart";
import "package:inventree/l10n/supported_locales.dart";
import "package:inventree/l10n/collected/app_localizations.dart";
import "package:inventree/settings/release.dart";
import "package:inventree/user_profile.dart";
import "package:inventree/widget/home.dart";
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
AdaptiveThemeMode? savedThemeMode = await AdaptiveTheme.getThemeMode();
await runZonedGuarded<Future<void>>(
() async {
PackageInfo info = await PackageInfo.fromPlatform();
String pkg = info.packageName;
String version = info.version;
String build = info.buildNumber;
String release = "${pkg}@${version}:${build}";
if (SENTRY_DSN_KEY.isNotEmpty) {
await Sentry.init((options) {
options.dsn = SENTRY_DSN_KEY;
options.release = release;
options.environment = isInDebugMode() ? "debug" : "release";
options.diagnosticLevel = SentryLevel.debug;
options.attachStacktrace = true;
});
}
// Pass any flutter errors off to the Sentry reporting context!
FlutterError.onError = (FlutterErrorDetails details) async {
// Ensure that the error gets reported to sentry!
await sentryReportError(
"FlutterError.onError",
details.exception,
details.stack,
context: {
"context": details.context.toString(),
"summary": details.summary.toString(),
"library": details.library ?? "null",
},
);
};
// Get any config provided by the MDM server
await initManagedConfiguration();
final AdaptiveThemeMode? managedThemeMode =
await getPendingManagedThemeMode();
if (managedThemeMode != null) savedThemeMode = managedThemeMode;
final int orientation =
await InvenTreeSettingsManager().getValue(
INV_SCREEN_ORIENTATION,
SCREEN_ORIENTATION_SYSTEM,
)
as int;
List<DeviceOrientation> orientations = [];
switch (orientation) {
case SCREEN_ORIENTATION_PORTRAIT:
orientations.add(DeviceOrientation.portraitUp);
case SCREEN_ORIENTATION_LANDSCAPE:
orientations.add(DeviceOrientation.landscapeLeft);
default:
orientations.add(DeviceOrientation.portraitUp);
orientations.add(DeviceOrientation.landscapeLeft);
orientations.add(DeviceOrientation.landscapeRight);
}
SystemChrome.setPreferredOrientations(orientations).then((_) {
runApp(InvenTreeApp(savedThemeMode));
});
},
(Object error, StackTrace stackTrace) async {
sentryReportError("main.runZonedGuarded", error, stackTrace);
},
);
}
class InvenTreeApp extends StatefulWidget {
// This widget is the root of your application.
const InvenTreeApp(this.savedThemeMode);
final AdaptiveThemeMode? savedThemeMode;
@override
InvenTreeAppState createState() => InvenTreeAppState(savedThemeMode);
static InvenTreeAppState? of(BuildContext context) =>
context.findAncestorStateOfType<InvenTreeAppState>();
}
class InvenTreeAppState extends State<StatefulWidget> {
InvenTreeAppState(this.savedThemeMode) : super();
// Custom _locale (default = null; use system default)
Locale? _locale;
final AdaptiveThemeMode? savedThemeMode;
@override
void initState() {
super.initState();
// Run some async init tasks
runInitTasks();
WidgetsBinding.instance.addPostFrameCallback((_) {
applyPendingThemeMode();
});
}
Future<void> applyPendingThemeMode() async {
final AdaptiveThemeMode? mode = await getPendingManagedThemeMode();
if (mode == null) return;
final BuildContext? ctx = OneContext().context;
if (ctx == null) return;
final manager = AdaptiveTheme.maybeOf(ctx);
if (manager == null) return;
manager.setThemeMode(mode);
await clearPendingManagedThemeMode();
}
// Run app init routines in the background
Future<void> runInitTasks() async {
// Set the app locale (language)
Locale? locale = await InvenTreeSettingsManager().getSelectedLocale();
setLocale(locale);
await initWedgeScannerDefault();
if (!kIsWeb && Platform.isAndroid) {
initGlobalIntentListener();
}
// First-run only: seed a demo server profile if none are configured
await UserProfileDBManager().seedDemoProfileIfNeeded();
// Display release notes if this is a new version
final String version =
await InvenTreeSettingsManager().getValue("recentVersion", "")
as String;
final PackageInfo info = await PackageInfo.fromPlatform();
if (version != info.version) {
// Save latest version to the settings database
await InvenTreeSettingsManager().setValue("recentVersion", info.version);
// Load release notes from external file
String notes = await rootBundle.loadString("assets/release_notes.md");
// Show the release notes
OneContext().push(
MaterialPageRoute(builder: (context) => ReleaseNotesWidget(notes)),
);
}
}
// Update the app locale
void setLocale(Locale? locale) {
setState(() {
_locale = locale;
});
}
Locale? get locale => _locale;
@override
Widget build(BuildContext context) {
return AdaptiveTheme(
light: ThemeData(
brightness: Brightness.light,
colorSchemeSeed: Colors.lightBlueAccent,
useMaterial3: true,
),
dark: ThemeData(
brightness: Brightness.dark,
colorSchemeSeed: Colors.blue,
useMaterial3: true,
),
initial: savedThemeMode ?? AdaptiveThemeMode.system,
builder: (light, dark) => MaterialApp(
theme: light,
darkTheme: dark,
debugShowCheckedModeBanner: false,
builder: OneContext().builder,
navigatorKey: OneContext().key,
onGenerateTitle: (BuildContext context) => "InvenTree",
home: InvenTreeHomePage(),
localizationsDelegates: [
I18N.delegate,
LocaleNamesLocalizationsDelegate(),
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: supported_locales,
locale: _locale,
),
);
}
}