nc-photos/app/lib/widget/my_app.dart

619 lines
21 KiB
Dart
Raw Normal View History

import 'package:dynamic_color/dynamic_color.dart';
import 'package:flutter/gestures.dart';
2021-04-10 06:28:12 +02:00
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
2021-04-10 06:28:12 +02:00
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:kiwi/kiwi.dart';
2021-04-10 06:28:12 +02:00
import 'package:logging/logging.dart';
import 'package:nc_photos/controller/account_controller.dart';
import 'package:nc_photos/controller/pref_controller.dart';
import 'package:nc_photos/di_container.dart';
2023-07-17 09:35:45 +02:00
import 'package:nc_photos/entity/pref.dart';
2021-04-17 11:04:46 +02:00
import 'package:nc_photos/event/event.dart';
2021-06-23 10:15:25 +02:00
import 'package:nc_photos/language_util.dart' as language_util;
import 'package:nc_photos/legacy/connect.dart' as legacy;
import 'package:nc_photos/legacy/sign_in.dart' as legacy;
import 'package:nc_photos/navigation_manager.dart';
import 'package:nc_photos/session_storage.dart';
2021-04-10 06:28:12 +02:00
import 'package:nc_photos/snack_bar_manager.dart';
2023-06-06 15:39:58 +02:00
import 'package:nc_photos/stream_util.dart';
2021-04-10 06:28:12 +02:00
import 'package:nc_photos/theme.dart';
2021-06-29 11:44:35 +02:00
import 'package:nc_photos/widget/album_dir_picker.dart';
2021-07-01 13:32:22 +02:00
import 'package:nc_photos/widget/album_importer.dart';
import 'package:nc_photos/widget/album_share_outlier_browser.dart';
2021-07-31 19:02:41 +02:00
import 'package:nc_photos/widget/archive_browser.dart';
2022-07-17 21:35:35 +02:00
import 'package:nc_photos/widget/changelog.dart';
import 'package:nc_photos/widget/collection_browser.dart';
import 'package:nc_photos/widget/collection_picker.dart';
2021-04-10 06:28:12 +02:00
import 'package:nc_photos/widget/connect.dart';
2022-05-06 11:16:56 +02:00
import 'package:nc_photos/widget/enhanced_photo_browser.dart';
2021-04-10 06:28:12 +02:00
import 'package:nc_photos/widget/home.dart';
2022-07-12 22:11:27 +02:00
import 'package:nc_photos/widget/image_editor.dart';
import 'package:nc_photos/widget/image_enhancer.dart';
2022-05-06 11:16:56 +02:00
import 'package:nc_photos/widget/local_file_viewer.dart';
import 'package:nc_photos/widget/people_browser.dart';
2022-08-28 17:35:29 +02:00
import 'package:nc_photos/widget/places_browser.dart';
import 'package:nc_photos/widget/result_viewer.dart';
2021-04-10 06:28:12 +02:00
import 'package:nc_photos/widget/root_picker.dart';
import 'package:nc_photos/widget/settings.dart';
2023-06-10 12:44:02 +02:00
import 'package:nc_photos/widget/settings/account_settings.dart';
2023-06-06 15:39:58 +02:00
import 'package:nc_photos/widget/settings/language_settings.dart';
2021-04-10 06:28:12 +02:00
import 'package:nc_photos/widget/setup.dart';
import 'package:nc_photos/widget/share_folder_picker.dart';
2021-10-06 22:32:36 +02:00
import 'package:nc_photos/widget/shared_file_viewer.dart';
import 'package:nc_photos/widget/sharing_browser.dart';
2021-04-10 06:28:12 +02:00
import 'package:nc_photos/widget/sign_in.dart';
2021-09-14 23:00:24 +02:00
import 'package:nc_photos/widget/slideshow_viewer.dart';
2021-04-10 06:28:12 +02:00
import 'package:nc_photos/widget/splash.dart';
2021-08-01 22:46:16 +02:00
import 'package:nc_photos/widget/trashbin_browser.dart';
import 'package:nc_photos/widget/trashbin_viewer.dart';
2021-04-10 06:28:12 +02:00
import 'package:nc_photos/widget/viewer.dart';
2022-12-16 16:01:04 +01:00
import 'package:np_codegen/np_codegen.dart';
part 'my_app.g.dart';
2021-04-10 06:28:12 +02:00
class MyApp extends StatelessWidget {
const MyApp({super.key});
2021-09-15 08:58:06 +02:00
2021-04-17 11:04:46 +02:00
@override
Widget build(BuildContext context) {
final DiContainer _c = KiwiContainer().resolve<DiContainer>();
return MultiRepositoryProvider(
providers: [
RepositoryProvider(
create: (_) => AccountController(),
),
RepositoryProvider(
create: (_) => PrefController(_c),
),
],
child: const _WrappedApp(),
);
}
static RouteObserver get routeObserver => _routeObserver;
static BuildContext get globalContext => _globalContext;
static final _routeObserver = RouteObserver<PageRoute>();
static late BuildContext _globalContext;
2021-04-17 11:04:46 +02:00
}
class _WrappedApp extends StatefulWidget {
const _WrappedApp();
@override
State<StatefulWidget> createState() => _WrappedAppState();
}
2022-12-16 16:01:04 +01:00
@npLog
class _WrappedAppState extends State<_WrappedApp>
implements SnackBarHandler, NavigationHandler {
2021-04-17 11:04:46 +02:00
@override
void initState() {
super.initState();
2021-04-10 06:28:12 +02:00
SnackBarManager().registerHandler(this);
NavigationManager().setHandler(this);
2021-04-17 11:04:46 +02:00
_themeChangedListener =
AppEventListener<ThemeChangedEvent>(_onThemeChangedEvent)..begin();
2021-04-10 06:28:12 +02:00
}
@override
Widget build(BuildContext context) {
final ThemeMode themeMode;
2021-10-27 22:40:54 +02:00
if (Pref().isFollowSystemThemeOr(false)) {
themeMode = ThemeMode.system;
} else {
themeMode =
2021-10-27 22:40:54 +02:00
Pref().isDarkThemeOr(false) ? ThemeMode.dark : ThemeMode.light;
}
2023-06-06 15:39:58 +02:00
final prefController = context.read<PrefController>();
return ValueStreamBuilder<language_util.AppLanguage>(
stream: prefController.language,
builder: (context, snapshot) => DynamicColorBuilder(
builder: (lightDynamic, darkDynamic) {
if (lightDynamic != null) {
SessionStorage().isSupportDynamicColor = true;
}
return MaterialApp(
onGenerateTitle: (context) =>
AppLocalizations.of(context)!.appTitle,
theme: buildLightTheme(lightDynamic),
darkTheme: buildDarkTheme(darkDynamic),
themeMode: themeMode,
initialRoute: Splash.routeName,
onGenerateRoute: _onGenerateRoute,
navigatorObservers: <NavigatorObserver>[MyApp.routeObserver],
navigatorKey: _navigatorKey,
scaffoldMessengerKey: _scaffoldMessengerKey,
locale: snapshot.requireData.locale,
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: const <Locale>[
// the order here doesn't matter, except for the first one, which must
// be en
Locale("en"),
Locale("el"),
Locale("es"),
Locale("fr"),
Locale("ru"),
Locale("de"),
Locale("cs"),
Locale("fi"),
Locale("pl"),
Locale("pt"),
Locale.fromSubtags(languageCode: "zh", scriptCode: "Hans"),
Locale.fromSubtags(languageCode: "zh", scriptCode: "Hant"),
Locale("it"),
Locale("nl"),
],
builder: (context, child) {
MyApp._globalContext = context;
return child!;
},
debugShowCheckedModeBanner: false,
scrollBehavior: const _MyScrollBehavior(),
);
2023-06-06 15:39:58 +02:00
},
),
2021-04-10 06:28:12 +02:00
);
}
2021-04-17 11:04:46 +02:00
@override
void dispose() {
super.dispose();
SnackBarManager().unregisterHandler(this);
NavigationManager().unsetHandler(this);
2021-04-17 11:04:46 +02:00
_themeChangedListener.end();
}
2021-04-10 06:28:12 +02:00
@override
showSnackBar(SnackBar snackBar) =>
_scaffoldMessengerKey.currentState?.showSnackBar(snackBar);
@override
getNavigator() => _navigatorKey.currentState;
Map<String, Route Function()> _getRouter() => {
Setup.routeName: () => MaterialPageRoute(
builder: (context) => const Setup(),
),
SignIn.routeName: () => MaterialPageRoute(
builder: (context) => const SignIn(),
),
Splash.routeName: () => MaterialPageRoute(
builder: (context) => const Splash(),
),
legacy.SignIn.routeName: () => MaterialPageRoute(
builder: (context) => const legacy.SignIn(),
),
CollectionPicker.routeName: CollectionPicker.buildRoute,
2023-06-06 15:39:58 +02:00
LanguageSettings.routeName: LanguageSettings.buildRoute,
2023-07-03 19:23:42 +02:00
PeopleBrowser.routeName: PeopleBrowser.buildRoute,
2021-04-10 06:28:12 +02:00
};
2021-07-23 22:05:57 +02:00
Route<dynamic>? _onGenerateRoute(RouteSettings settings) {
2021-04-10 06:28:12 +02:00
_log.info("[_onGenerateRoute] Route: ${settings.name}");
2021-07-23 22:05:57 +02:00
Route<dynamic>? route;
2021-04-10 06:28:12 +02:00
route ??= _handleBasicRoute(settings);
route ??= _handleViewerRoute(settings);
route ??= _handleConnectRoute(settings);
route ??= _handleConnectLegacyRoute(settings);
2021-04-10 06:28:12 +02:00
route ??= _handleHomeRoute(settings);
route ??= _handleRootPickerRoute(settings);
route ??= _handleSettingsRoute(settings);
2021-07-31 19:02:41 +02:00
route ??= _handleArchiveBrowserRoute(settings);
2021-06-29 11:44:35 +02:00
route ??= _handleAlbumDirPickerRoute(settings);
2021-07-01 13:32:22 +02:00
route ??= _handleAlbumImporterRoute(settings);
2021-08-01 22:46:16 +02:00
route ??= _handleTrashbinBrowserRoute(settings);
route ??= _handleTrashbinViewerRoute(settings);
2021-09-14 23:00:24 +02:00
route ??= _handleSlideshowViewerRoute(settings);
2021-10-06 22:32:36 +02:00
route ??= _handleSharingBrowserRoute(settings);
route ??= _handleSharedFileViewerRoute(settings);
route ??= _handleAlbumShareOutlierBrowserRoute(settings);
route ??= _handleShareFolderPickerRoute(settings);
2022-05-06 11:16:56 +02:00
route ??= _handleEnhancedPhotoBrowserRoute(settings);
route ??= _handleLocalFileViewerRoute(settings);
route ??= _handleEnhancementSettingsRoute(settings);
2022-07-12 22:11:27 +02:00
route ??= _handleImageEditorRoute(settings);
2022-07-17 21:35:35 +02:00
route ??= _handleChangelogRoute(settings);
2022-08-28 17:35:29 +02:00
route ??= _handlePlacesBrowserRoute(settings);
route ??= _handleResultViewerRoute(settings);
route ??= _handleImageEnhancerRoute(settings);
route ??= _handleCollectionBrowserRoute(settings);
route ??= _handleAccountSettingsRoute(settings);
2021-04-10 06:28:12 +02:00
return route;
}
2021-04-17 11:04:46 +02:00
void _onThemeChangedEvent(ThemeChangedEvent ev) {
setState(() {});
}
2021-07-23 22:05:57 +02:00
Route<dynamic>? _handleBasicRoute(RouteSettings settings) {
2021-04-10 06:28:12 +02:00
for (final e in _getRouter().entries) {
if (e.key == settings.name) {
return e.value();
2021-04-10 06:28:12 +02:00
}
}
return null;
}
2021-07-23 22:05:57 +02:00
Route<dynamic>? _handleViewerRoute(RouteSettings settings) {
2021-04-10 06:28:12 +02:00
try {
if (settings.name == Viewer.routeName && settings.arguments != null) {
2021-07-23 22:05:57 +02:00
final args = settings.arguments as ViewerArguments;
return Viewer.buildRoute(args);
2021-04-10 06:28:12 +02:00
}
} catch (e) {
_log.severe("[_handleViewerRoute] Failed while handling route", e);
}
return null;
}
2021-07-23 22:05:57 +02:00
Route<dynamic>? _handleConnectRoute(RouteSettings settings) {
2021-04-10 06:28:12 +02:00
try {
if (settings.name == Connect.routeName && settings.arguments != null) {
2021-07-23 22:05:57 +02:00
final args = settings.arguments as ConnectArguments;
return Connect.buildRoute(args);
2021-04-10 06:28:12 +02:00
}
} catch (e) {
_log.severe("[_handleConnectRoute] Failed while handling route", e);
}
return null;
}
Route<dynamic>? _handleConnectLegacyRoute(RouteSettings settings) {
try {
if (settings.name == legacy.Connect.routeName &&
settings.arguments != null) {
final args = settings.arguments as legacy.ConnectArguments;
return legacy.Connect.buildRoute(args);
}
} catch (e) {
_log.severe("[_handleConnectLegacyRoute] Failed while handling route", e);
}
return null;
}
2021-07-23 22:05:57 +02:00
Route<dynamic>? _handleHomeRoute(RouteSettings settings) {
2021-04-10 06:28:12 +02:00
try {
if (settings.name == Home.routeName && settings.arguments != null) {
2021-07-23 22:05:57 +02:00
final args = settings.arguments as HomeArguments;
// move this elsewhere later
context.read<AccountController>().setCurrentAccount(args.account);
2021-07-23 22:05:57 +02:00
return Home.buildRoute(args);
2021-04-10 06:28:12 +02:00
}
} catch (e) {
_log.severe("[_handleHomeRoute] Failed while handling route", e);
}
return null;
}
2021-07-23 22:05:57 +02:00
Route<dynamic>? _handleRootPickerRoute(RouteSettings settings) {
2021-04-10 06:28:12 +02:00
try {
if (settings.name == RootPicker.routeName && settings.arguments != null) {
2021-07-23 22:05:57 +02:00
final args = settings.arguments as RootPickerArguments;
return RootPicker.buildRoute(args);
2021-04-10 06:28:12 +02:00
}
} catch (e) {
_log.severe("[_handleRootPickerRoute] Failed while handling route", e);
}
return null;
}
2021-07-23 22:05:57 +02:00
Route<dynamic>? _handleSettingsRoute(RouteSettings settings) {
2021-04-10 06:28:12 +02:00
try {
if (settings.name == Settings.routeName && settings.arguments != null) {
2021-07-23 22:05:57 +02:00
final args = settings.arguments as SettingsArguments;
return Settings.buildRoute(args);
2021-04-10 06:28:12 +02:00
}
} catch (e) {
_log.severe("[_handleSettingsRoute] Failed while handling route", e);
}
return null;
}
2021-07-31 19:02:41 +02:00
Route<dynamic>? _handleArchiveBrowserRoute(RouteSettings settings) {
2021-05-28 21:44:09 +02:00
try {
2021-07-31 19:02:41 +02:00
if (settings.name == ArchiveBrowser.routeName &&
2021-05-28 21:44:09 +02:00
settings.arguments != null) {
2021-07-31 19:02:41 +02:00
final args = settings.arguments as ArchiveBrowserArguments;
return ArchiveBrowser.buildRoute(args);
2021-05-28 21:44:09 +02:00
}
} catch (e) {
2021-07-31 19:02:41 +02:00
_log.severe(
"[_handleArchiveBrowserRoute] Failed while handling route", e);
2021-05-28 21:44:09 +02:00
}
return null;
}
2021-07-23 22:05:57 +02:00
Route<dynamic>? _handleAlbumDirPickerRoute(RouteSettings settings) {
2021-06-29 11:44:35 +02:00
try {
if (settings.name == AlbumDirPicker.routeName &&
settings.arguments != null) {
2021-07-23 22:05:57 +02:00
final args = settings.arguments as AlbumDirPickerArguments;
return AlbumDirPicker.buildRoute(args);
2021-06-29 11:44:35 +02:00
}
} catch (e) {
_log.severe(
"[_handleAlbumDirPickerRoute] Failed while handling route", e);
}
return null;
}
2021-07-23 22:05:57 +02:00
Route<dynamic>? _handleAlbumImporterRoute(RouteSettings settings) {
2021-07-01 13:32:22 +02:00
try {
if (settings.name == AlbumImporter.routeName &&
settings.arguments != null) {
2021-07-23 22:05:57 +02:00
final args = settings.arguments as AlbumImporterArguments;
return AlbumImporter.buildRoute(args);
2021-07-01 13:32:22 +02:00
}
} catch (e) {
_log.severe("[_handleAlbumImporterRoute] Failed while handling route", e);
}
return null;
}
2021-08-01 22:46:16 +02:00
Route<dynamic>? _handleTrashbinBrowserRoute(RouteSettings settings) {
try {
if (settings.name == TrashbinBrowser.routeName &&
settings.arguments != null) {
final args = settings.arguments as TrashbinBrowserArguments;
return TrashbinBrowser.buildRoute(args);
}
} catch (e) {
_log.severe(
"[_handleTrashbinBrowserRoute] Failed while handling route", e);
}
return null;
}
Route<dynamic>? _handleTrashbinViewerRoute(RouteSettings settings) {
try {
if (settings.name == TrashbinViewer.routeName &&
settings.arguments != null) {
final args = settings.arguments as TrashbinViewerArguments;
return TrashbinViewer.buildRoute(args);
}
} catch (e) {
_log.severe(
"[_handleTrashbinViewerRoute] Failed while handling route", e);
}
return null;
}
2021-09-14 23:00:24 +02:00
Route<dynamic>? _handleSlideshowViewerRoute(RouteSettings settings) {
try {
if (settings.name == SlideshowViewer.routeName &&
settings.arguments != null) {
final args = settings.arguments as SlideshowViewerArguments;
return SlideshowViewer.buildRoute(args);
}
} catch (e) {
_log.severe(
"[_handleSlideshowViewerRoute] Failed while handling route", e);
}
return null;
}
2021-10-06 22:32:36 +02:00
Route<dynamic>? _handleSharingBrowserRoute(RouteSettings settings) {
try {
if (settings.name == SharingBrowser.routeName &&
settings.arguments != null) {
final args = settings.arguments as SharingBrowserArguments;
return SharingBrowser.buildRoute(args);
}
} catch (e) {
_log.severe(
"[_handleSharingBrowserRoute] Failed while handling route", e);
}
return null;
}
Route<dynamic>? _handleSharedFileViewerRoute(RouteSettings settings) {
try {
if (settings.name == SharedFileViewer.routeName &&
settings.arguments != null) {
final args = settings.arguments as SharedFileViewerArguments;
return SharedFileViewer.buildRoute(args);
}
} catch (e) {
_log.severe(
"[_handleSharedFileViewerRoute] Failed while handling route", e);
}
return null;
}
Route<dynamic>? _handleAlbumShareOutlierBrowserRoute(RouteSettings settings) {
try {
if (settings.name == AlbumShareOutlierBrowser.routeName &&
settings.arguments != null) {
final args = settings.arguments as AlbumShareOutlierBrowserArguments;
return AlbumShareOutlierBrowser.buildRoute(args);
}
} catch (e) {
_log.severe(
"[_handleAlbumShareOutlierBrowserRoute] Failed while handling route",
e);
}
return null;
}
Route<dynamic>? _handleShareFolderPickerRoute(RouteSettings settings) {
try {
if (settings.name == ShareFolderPicker.routeName &&
settings.arguments != null) {
final args = settings.arguments as ShareFolderPickerArguments;
return ShareFolderPicker.buildRoute(args);
}
} catch (e) {
_log.severe(
"[_handleShareFolderPickerRoute] Failed while handling route", e);
}
return null;
}
2022-05-06 11:16:56 +02:00
Route<dynamic>? _handleEnhancedPhotoBrowserRoute(RouteSettings settings) {
try {
if (settings.name == EnhancedPhotoBrowser.routeName &&
settings.arguments != null) {
final args = settings.arguments as EnhancedPhotoBrowserArguments;
return EnhancedPhotoBrowser.buildRoute(args);
} else if (settings.name
?.startsWith("${EnhancedPhotoBrowser.routeName}?") ==
true) {
final queries = Uri.parse(settings.name!).queryParameters;
final args = EnhancedPhotoBrowserArguments(queries["filename"]);
return EnhancedPhotoBrowser.buildRoute(args);
2022-05-06 11:16:56 +02:00
}
} catch (e) {
_log.severe(
"[_handleEnhancedPhotoBrowserRoute] Failed while handling route", e);
}
return null;
}
Route<dynamic>? _handleLocalFileViewerRoute(RouteSettings settings) {
try {
if (settings.name == LocalFileViewer.routeName &&
settings.arguments != null) {
final args = settings.arguments as LocalFileViewerArguments;
return LocalFileViewer.buildRoute(args);
}
} catch (e) {
_log.severe(
"[_handleLocalFileViewerRoute] Failed while handling route", e);
}
return null;
}
Route<dynamic>? _handleEnhancementSettingsRoute(RouteSettings settings) {
try {
if (settings.name == EnhancementSettings.routeName) {
return EnhancementSettings.buildRoute();
}
} catch (e) {
_log.severe(
"[_handleEnhancementSettingsRoute] Failed while handling route", e);
}
return null;
}
2022-07-12 22:11:27 +02:00
Route<dynamic>? _handleImageEditorRoute(RouteSettings settings) {
try {
if (settings.name == ImageEditor.routeName &&
settings.arguments != null) {
final args = settings.arguments as ImageEditorArguments;
return ImageEditor.buildRoute(args);
}
} catch (e) {
_log.severe("[_handleImageEditorRoute] Failed while handling route", e);
}
return null;
}
2022-07-17 21:35:35 +02:00
Route<dynamic>? _handleChangelogRoute(RouteSettings settings) {
try {
if (settings.name == Changelog.routeName) {
if (settings.arguments != null) {
final args = settings.arguments as ChangelogArguments;
return Changelog.buildRoute(args);
} else {
return MaterialPageRoute(builder: (_) => const Changelog());
}
}
} catch (e) {
_log.severe("[_handleChangelogRoute] Failed while handling route", e);
}
return null;
}
2022-08-28 17:35:29 +02:00
Route<dynamic>? _handlePlacesBrowserRoute(RouteSettings settings) {
try {
if (settings.name == PlacesBrowser.routeName &&
settings.arguments != null) {
final args = settings.arguments as PlacesBrowserArguments;
return PlacesBrowser.buildRoute(args);
}
} catch (e) {
_log.severe("[_handlePlacesBrowserRoute] Failed while handling route", e);
}
return null;
}
Route<dynamic>? _handleResultViewerRoute(RouteSettings settings) {
try {
if (settings.name == ResultViewer.routeName &&
settings.arguments != null) {
final args = settings.arguments as ResultViewerArguments;
return ResultViewer.buildRoute(args);
} else if (settings.name?.startsWith("${ResultViewer.routeName}?") ==
true) {
final queries = Uri.parse(settings.name!).queryParameters;
final args = ResultViewerArguments(queries["url"]!);
return ResultViewer.buildRoute(args);
}
} catch (e, stackTrace) {
_log.severe("[_handleResultViewerRoute] Failed while handling route", e,
stackTrace);
}
return null;
}
Route<dynamic>? _handleImageEnhancerRoute(RouteSettings settings) {
try {
if (settings.name == ImageEnhancer.routeName &&
settings.arguments != null) {
final args = settings.arguments as ImageEnhancerArguments;
return ImageEnhancer.buildRoute(args);
}
} catch (e) {
_log.severe("[_handleImageEnhancerRoute] Failed while handling route", e);
}
return null;
}
Route<dynamic>? _handleCollectionBrowserRoute(RouteSettings settings) {
try {
if (settings.name == CollectionBrowser.routeName &&
settings.arguments != null) {
final args = settings.arguments as CollectionBrowserArguments;
return CollectionBrowser.buildRoute(args);
}
} catch (e) {
_log.severe(
"[_handleCollectionBrowserRoute] Failed while handling route", e);
}
return null;
}
Route<dynamic>? _handleAccountSettingsRoute(RouteSettings settings) {
try {
if (settings.name == AccountSettings.routeName) {
final args = settings.arguments as AccountSettingsArguments?;
return AccountSettings.buildRoute(args);
}
} catch (e) {
_log.severe(
"[_handleAccountSettingsRoute] Failed while handling route", e);
}
return null;
}
2021-04-10 06:28:12 +02:00
final _scaffoldMessengerKey = GlobalKey<ScaffoldMessengerState>();
final _navigatorKey = GlobalKey<NavigatorState>();
2021-04-10 06:28:12 +02:00
2021-07-23 22:05:57 +02:00
late AppEventListener<ThemeChangedEvent> _themeChangedListener;
2021-04-10 06:28:12 +02:00
}
class _MyScrollBehavior extends MaterialScrollBehavior {
const _MyScrollBehavior();
@override
get dragDevices => {
2021-10-06 23:17:19 +02:00
PointerDeviceKind.touch,
PointerDeviceKind.stylus,
PointerDeviceKind.invertedStylus,
PointerDeviceKind.mouse,
};
}