mirror of
https://github.com/Xevion/paperless-mobile.git
synced 2025-12-06 03:15:48 -06:00
feat: add accessibility setting and conditionally disable animations
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
* Neue Einstellung um Animationen zu deaktivieren
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
* Add setting to disable animations
|
||||||
89
lib/accessibility/accessibility_utils.dart
Normal file
89
lib/accessibility/accessibility_utils.dart
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:flutter_animate/flutter_animate.dart';
|
||||||
|
import 'package:hive/hive.dart';
|
||||||
|
import 'package:paperless_mobile/core/database/hive/hive_config.dart';
|
||||||
|
import 'package:paperless_mobile/core/database/hive/hive_extensions.dart';
|
||||||
|
import 'package:paperless_mobile/features/settings/view/widgets/global_settings_builder.dart';
|
||||||
|
import 'package:paperless_mobile/routing/navigation_keys.dart';
|
||||||
|
|
||||||
|
extension AccessibilityAwareAnimationDurationExtension on Duration {
|
||||||
|
Duration accessible() {
|
||||||
|
bool shouldDisableAnimations = WidgetsBinding.instance.disableAnimations ||
|
||||||
|
Hive.globalSettingsBox.getValue()!.disableAnimations;
|
||||||
|
// print(shouldDisableAnimations);
|
||||||
|
if (shouldDisableAnimations) {
|
||||||
|
return 0.seconds;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension AccessibleHero on Hero {
|
||||||
|
Widget accessible() {
|
||||||
|
return GlobalSettingsBuilder(
|
||||||
|
builder: (context, settings) {
|
||||||
|
return HeroMode(
|
||||||
|
enabled: WidgetsBinding.instance.disableAnimations ||
|
||||||
|
!settings.disableAnimations,
|
||||||
|
child: this,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
// bool shouldDisableAnimations = WidgetsBinding.instance.disableAnimations ||
|
||||||
|
// Hive.globalSettingsBox.getValue()!.disableAnimations;
|
||||||
|
// return _AccessibilityAwareObserverWidget(
|
||||||
|
// accessibilityAwareBuilder: (context, accessibilityFeatures) {
|
||||||
|
// return HeroMode(
|
||||||
|
// enabled: !accessibilityFeatures.disableAnimations,
|
||||||
|
// child: this,
|
||||||
|
// );
|
||||||
|
// },
|
||||||
|
// );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AccessibilityAwareObserverWidget extends StatefulWidget {
|
||||||
|
final Widget Function(
|
||||||
|
BuildContext context,
|
||||||
|
AccessibilityFeatures accessibilityFeatures,
|
||||||
|
) accessibilityAwareBuilder;
|
||||||
|
const _AccessibilityAwareObserverWidget({
|
||||||
|
super.key,
|
||||||
|
required this.accessibilityAwareBuilder,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<_AccessibilityAwareObserverWidget> createState() =>
|
||||||
|
_AccessibilityAwareObserverWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AccessibilityAwareObserverWidgetState
|
||||||
|
extends State<_AccessibilityAwareObserverWidget>
|
||||||
|
with WidgetsBindingObserver {
|
||||||
|
late final AccessibilityFeatures _accessibilityFeatures;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_accessibilityFeatures = WidgetsBinding.instance.accessibilityFeatures;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didChangeAccessibilityFeatures() {
|
||||||
|
super.didChangeAccessibilityFeatures();
|
||||||
|
setState(() {
|
||||||
|
_accessibilityFeatures = WidgetsBinding.instance.accessibilityFeatures;
|
||||||
|
});
|
||||||
|
print("Accessibility features changed");
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return widget.accessibilityAwareBuilder(
|
||||||
|
context,
|
||||||
|
_accessibilityFeatures,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
58
lib/accessibility/accessible_page.dart
Normal file
58
lib/accessibility/accessible_page.dart
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:hive/hive.dart';
|
||||||
|
import 'package:paperless_mobile/core/database/hive/hive_config.dart';
|
||||||
|
import 'package:paperless_mobile/core/database/hive/hive_extensions.dart';
|
||||||
|
|
||||||
|
Page<T> accessiblePlatformPage<T>({
|
||||||
|
required Widget child,
|
||||||
|
String? name,
|
||||||
|
Object? arguments,
|
||||||
|
String? restorationId,
|
||||||
|
LocalKey? key,
|
||||||
|
bool allowSnapshotting = true,
|
||||||
|
bool fullscreenDialog = false,
|
||||||
|
bool maintainState = true,
|
||||||
|
String? title,
|
||||||
|
}) {
|
||||||
|
final shouldDisableAnimations = WidgetsBinding.instance.disableAnimations ||
|
||||||
|
Hive.globalSettingsBox.getValue()!.disableAnimations;
|
||||||
|
if (shouldDisableAnimations) {
|
||||||
|
return NoTransitionPage(
|
||||||
|
key: key,
|
||||||
|
name: name,
|
||||||
|
arguments: arguments,
|
||||||
|
restorationId: restorationId,
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
return MaterialPage(
|
||||||
|
child: child,
|
||||||
|
name: name,
|
||||||
|
restorationId: restorationId,
|
||||||
|
arguments: arguments,
|
||||||
|
allowSnapshotting: allowSnapshotting,
|
||||||
|
fullscreenDialog: fullscreenDialog,
|
||||||
|
key: key,
|
||||||
|
maintainState: maintainState,
|
||||||
|
);
|
||||||
|
} else if (Platform.isIOS) {
|
||||||
|
return CupertinoPage(
|
||||||
|
child: child,
|
||||||
|
allowSnapshotting: allowSnapshotting,
|
||||||
|
arguments: arguments,
|
||||||
|
fullscreenDialog: fullscreenDialog,
|
||||||
|
key: key,
|
||||||
|
maintainState: maintainState,
|
||||||
|
name: name,
|
||||||
|
restorationId: restorationId,
|
||||||
|
title: title,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
throw UnsupportedError("The current platform is not supported.");
|
||||||
|
}
|
||||||
@@ -35,6 +35,9 @@ class GlobalSettings with HiveObjectMixin {
|
|||||||
@HiveField(8, defaultValue: false)
|
@HiveField(8, defaultValue: false)
|
||||||
bool skipDocumentPreprarationOnUpload;
|
bool skipDocumentPreprarationOnUpload;
|
||||||
|
|
||||||
|
@HiveField(9, defaultValue: false)
|
||||||
|
bool disableAnimations;
|
||||||
|
|
||||||
GlobalSettings({
|
GlobalSettings({
|
||||||
required this.preferredLocaleSubtag,
|
required this.preferredLocaleSubtag,
|
||||||
this.preferredThemeMode = ThemeMode.system,
|
this.preferredThemeMode = ThemeMode.system,
|
||||||
@@ -45,5 +48,6 @@ class GlobalSettings with HiveObjectMixin {
|
|||||||
this.defaultShareType = FileDownloadType.alwaysAsk,
|
this.defaultShareType = FileDownloadType.alwaysAsk,
|
||||||
this.enforceSinglePagePdfUpload = false,
|
this.enforceSinglePagePdfUpload = false,
|
||||||
this.skipDocumentPreprarationOnUpload = false,
|
this.skipDocumentPreprarationOnUpload = false,
|
||||||
|
this.disableAnimations = false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
20
lib/core/notifier/go_router_refresh_stream.dart
Normal file
20
lib/core/notifier/go_router_refresh_stream.dart
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
|
class GoRouterRefreshStream extends ChangeNotifier {
|
||||||
|
GoRouterRefreshStream(Stream<dynamic> stream) {
|
||||||
|
notifyListeners();
|
||||||
|
_subscription = stream.asBroadcastStream().listen(
|
||||||
|
(dynamic _) => notifyListeners(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final StreamSubscription<dynamic> _subscription;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_subscription.cancel();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_animate/flutter_animate.dart';
|
||||||
|
import 'package:paperless_mobile/accessibility/accessibility_utils.dart';
|
||||||
import 'package:paperless_mobile/core/extensions/flutter_extensions.dart';
|
import 'package:paperless_mobile/core/extensions/flutter_extensions.dart';
|
||||||
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
||||||
|
|
||||||
@@ -24,7 +26,7 @@ class HintCard extends StatelessWidget {
|
|||||||
crossFadeState:
|
crossFadeState:
|
||||||
show ? CrossFadeState.showFirst : CrossFadeState.showSecond,
|
show ? CrossFadeState.showFirst : CrossFadeState.showSecond,
|
||||||
secondChild: const SizedBox.shrink(),
|
secondChild: const SizedBox.shrink(),
|
||||||
duration: const Duration(milliseconds: 500),
|
duration: 500.milliseconds.accessible(),
|
||||||
firstChild: Card(
|
firstChild: Card(
|
||||||
elevation: elevation,
|
elevation: elevation,
|
||||||
child: Column(
|
child: Column(
|
||||||
|
|||||||
@@ -164,7 +164,10 @@ class AppDrawer extends StatelessWidget {
|
|||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
return child
|
return child
|
||||||
.animate(onPlay: (c) => c.repeat(reverse: true))
|
.animate(
|
||||||
|
onPlay: (c) => c.repeat(reverse: true),
|
||||||
|
autoPlay: !MediaQuery.disableAnimationsOf(context),
|
||||||
|
)
|
||||||
.fade(duration: 1.seconds, begin: 1, end: 0.3);
|
.fade(duration: 1.seconds, begin: 1, end: 0.3);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ class ChangelogDialog extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const _versionNumbers = {
|
const _versionNumbers = {
|
||||||
|
"58": "3.1.4",
|
||||||
"57": "3.1.3",
|
"57": "3.1.3",
|
||||||
"56": "3.1.2",
|
"56": "3.1.2",
|
||||||
"55": "3.1.1",
|
"55": "3.1.1",
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import 'package:go_router/go_router.dart';
|
|||||||
import 'package:intl/date_symbol_data_local.dart';
|
import 'package:intl/date_symbol_data_local.dart';
|
||||||
import 'package:open_filex/open_filex.dart';
|
import 'package:open_filex/open_filex.dart';
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
|
import 'package:paperless_mobile/accessibility/accessibility_utils.dart';
|
||||||
import 'package:paperless_mobile/core/bloc/connectivity_cubit.dart';
|
import 'package:paperless_mobile/core/bloc/connectivity_cubit.dart';
|
||||||
import 'package:paperless_mobile/core/database/tables/local_user_account.dart';
|
import 'package:paperless_mobile/core/database/tables/local_user_account.dart';
|
||||||
import 'package:paperless_mobile/core/extensions/flutter_extensions.dart';
|
import 'package:paperless_mobile/core/extensions/flutter_extensions.dart';
|
||||||
@@ -60,6 +61,8 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final disableAnimations = MediaQuery.disableAnimationsOf(context);
|
||||||
|
debugPrint(disableAnimations.toString());
|
||||||
final hasMultiUserSupport =
|
final hasMultiUserSupport =
|
||||||
context.watch<LocalUserAccount>().hasMultiUserSupport;
|
context.watch<LocalUserAccount>().hasMultiUserSupport;
|
||||||
final tabLength = 4 + (hasMultiUserSupport && false ? 1 : 0);
|
final tabLength = 4 + (hasMultiUserSupport && false ? 1 : 0);
|
||||||
@@ -150,7 +153,7 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
).accessible();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -50,8 +50,8 @@ class _DocumentEditPageState extends State<DocumentEditPage>
|
|||||||
late final Animation<double> _animation;
|
late final Animation<double> _animation;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void didChangeDependencies() {
|
||||||
super.initState();
|
super.didChangeDependencies();
|
||||||
_animationController = AnimationController(
|
_animationController = AnimationController(
|
||||||
duration: const Duration(milliseconds: 150),
|
duration: const Duration(milliseconds: 150),
|
||||||
vsync: this,
|
vsync: this,
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import 'dart:math' as math;
|
|||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:paperless_mobile/accessibility/accessibility_utils.dart';
|
||||||
import 'package:paperless_mobile/core/extensions/document_extensions.dart';
|
import 'package:paperless_mobile/core/extensions/document_extensions.dart';
|
||||||
import 'package:paperless_mobile/core/extensions/flutter_extensions.dart';
|
import 'package:paperless_mobile/core/extensions/flutter_extensions.dart';
|
||||||
import 'package:paperless_mobile/features/document_search/cubit/document_search_cubit.dart';
|
import 'package:paperless_mobile/features/document_search/cubit/document_search_cubit.dart';
|
||||||
@@ -67,7 +68,7 @@ class _DocumentSearchPageState extends State<DocumentSearchPage> {
|
|||||||
context.read<DocumentSearchCubit>().search(query);
|
context.read<DocumentSearchCubit>().search(query);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
).accessible(),
|
||||||
actions: [
|
actions: [
|
||||||
IconButton(
|
IconButton(
|
||||||
color: theme.colorScheme.onSurfaceVariant,
|
color: theme.colorScheme.onSurfaceVariant,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'package:cached_network_image/cached_network_image.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
|
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
|
import 'package:paperless_mobile/accessibility/accessibility_utils.dart';
|
||||||
import 'package:paperless_mobile/helpers/connectivity_aware_action_wrapper.dart';
|
import 'package:paperless_mobile/helpers/connectivity_aware_action_wrapper.dart';
|
||||||
import 'package:paperless_mobile/routing/routes/documents_route.dart';
|
import 'package:paperless_mobile/routing/routes/documents_route.dart';
|
||||||
import 'package:paperless_mobile/routing/routes/shells/authenticated_route.dart';
|
import 'package:paperless_mobile/routing/routes/shells/authenticated_route.dart';
|
||||||
@@ -46,7 +47,7 @@ class DocumentPreview extends StatelessWidget {
|
|||||||
return Hero(
|
return Hero(
|
||||||
tag: "thumb_$documentId",
|
tag: "thumb_$documentId",
|
||||||
child: _buildPreview(context),
|
child: _buildPreview(context),
|
||||||
);
|
).accessible();
|
||||||
}
|
}
|
||||||
return _buildPreview(context);
|
return _buildPreview(context);
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/scheduler.dart';
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
|
import 'package:paperless_mobile/accessibility/accessibility_utils.dart';
|
||||||
import 'package:paperless_mobile/core/extensions/flutter_extensions.dart';
|
import 'package:paperless_mobile/core/extensions/flutter_extensions.dart';
|
||||||
import 'package:paperless_mobile/routing/routes/saved_views_route.dart';
|
import 'package:paperless_mobile/routing/routes/saved_views_route.dart';
|
||||||
import 'package:paperless_mobile/routing/routes/shells/authenticated_route.dart';
|
import 'package:paperless_mobile/routing/routes/shells/authenticated_route.dart';
|
||||||
@@ -38,7 +40,7 @@ class _SavedViewChipState extends State<SavedViewChip>
|
|||||||
super.initState();
|
super.initState();
|
||||||
_animationController = AnimationController(
|
_animationController = AnimationController(
|
||||||
vsync: this,
|
vsync: this,
|
||||||
duration: const Duration(milliseconds: 200),
|
duration: const Duration(milliseconds: 200).accessible(),
|
||||||
);
|
);
|
||||||
_animation = _animationController.drive(Tween(begin: 0, end: 1));
|
_animation = _animationController.drive(Tween(begin: 0, end: 1));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
import 'package:paperless_mobile/core/widgets/shimmer_placeholder.dart';
|
import 'package:paperless_mobile/accessibility/accessibility_utils.dart';
|
||||||
import 'package:paperless_mobile/core/extensions/flutter_extensions.dart';
|
import 'package:paperless_mobile/core/extensions/flutter_extensions.dart';
|
||||||
|
import 'package:paperless_mobile/core/widgets/shimmer_placeholder.dart';
|
||||||
import 'package:paperless_mobile/features/documents/view/widgets/saved_views/saved_view_chip.dart';
|
import 'package:paperless_mobile/features/documents/view/widgets/saved_views/saved_view_chip.dart';
|
||||||
import 'package:paperless_mobile/features/saved_view/cubit/saved_view_cubit.dart';
|
import 'package:paperless_mobile/features/saved_view/cubit/saved_view_cubit.dart';
|
||||||
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
||||||
@@ -41,7 +42,7 @@ class _SavedViewsWidgetState extends State<SavedViewsWidget>
|
|||||||
super.initState();
|
super.initState();
|
||||||
_animationController = AnimationController(
|
_animationController = AnimationController(
|
||||||
vsync: this,
|
vsync: this,
|
||||||
duration: const Duration(milliseconds: 200),
|
duration: const Duration(milliseconds: 200).accessible(),
|
||||||
);
|
);
|
||||||
_animation = _animationController.drive(Tween(begin: 0, end: 0.5));
|
_animation = _animationController.drive(Tween(begin: 0, end: 0.5));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import 'package:paperless_mobile/features/settings/view/widgets/clear_storage_se
|
|||||||
import 'package:paperless_mobile/features/settings/view/widgets/color_scheme_option_setting.dart';
|
import 'package:paperless_mobile/features/settings/view/widgets/color_scheme_option_setting.dart';
|
||||||
import 'package:paperless_mobile/features/settings/view/widgets/default_download_file_type_setting.dart';
|
import 'package:paperless_mobile/features/settings/view/widgets/default_download_file_type_setting.dart';
|
||||||
import 'package:paperless_mobile/features/settings/view/widgets/default_share_file_type_setting.dart';
|
import 'package:paperless_mobile/features/settings/view/widgets/default_share_file_type_setting.dart';
|
||||||
|
import 'package:paperless_mobile/features/settings/view/widgets/disable_animations_setting.dart';
|
||||||
import 'package:paperless_mobile/features/settings/view/widgets/enforce_pdf_upload_setting.dart';
|
import 'package:paperless_mobile/features/settings/view/widgets/enforce_pdf_upload_setting.dart';
|
||||||
import 'package:paperless_mobile/features/settings/view/widgets/language_selection_setting.dart';
|
import 'package:paperless_mobile/features/settings/view/widgets/language_selection_setting.dart';
|
||||||
import 'package:paperless_mobile/features/settings/view/widgets/skip_document_prepraration_on_share_setting.dart';
|
import 'package:paperless_mobile/features/settings/view/widgets/skip_document_prepraration_on_share_setting.dart';
|
||||||
@@ -39,6 +40,8 @@ class SettingsPage extends StatelessWidget {
|
|||||||
const SkipDocumentPreprationOnShareSetting(),
|
const SkipDocumentPreprationOnShareSetting(),
|
||||||
_buildSectionHeader(context, S.of(context)!.storage),
|
_buildSectionHeader(context, S.of(context)!.storage),
|
||||||
const ClearCacheSetting(),
|
const ClearCacheSetting(),
|
||||||
|
_buildSectionHeader(context, 'Accessibility'),
|
||||||
|
const DisableAnimationsSetting(),
|
||||||
_buildSectionHeader(context, S.of(context)!.misc),
|
_buildSectionHeader(context, S.of(context)!.misc),
|
||||||
const AppLogsTile(),
|
const AppLogsTile(),
|
||||||
const ChangelogsTile(),
|
const ChangelogsTile(),
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:paperless_mobile/features/settings/view/widgets/global_settings_builder.dart';
|
||||||
|
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
||||||
|
|
||||||
|
class DisableAnimationsSetting extends StatelessWidget {
|
||||||
|
const DisableAnimationsSetting({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return GlobalSettingsBuilder(builder: (context, settings) {
|
||||||
|
return SwitchListTile(
|
||||||
|
value: settings.disableAnimations,
|
||||||
|
title: Text('Disable animations'),
|
||||||
|
subtitle: Text('Disables page transitions and most animations.'
|
||||||
|
' Temporary workaround until system accessibility settings can be used.'),
|
||||||
|
onChanged: (val) async {
|
||||||
|
settings.disableAnimations = val;
|
||||||
|
settings.save();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,6 +19,7 @@ import 'package:local_auth/local_auth.dart';
|
|||||||
import 'package:logger/logger.dart' as l;
|
import 'package:logger/logger.dart' as l;
|
||||||
import 'package:package_info_plus/package_info_plus.dart';
|
import 'package:package_info_plus/package_info_plus.dart';
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
|
import 'package:paperless_mobile/accessibility/accessible_page.dart';
|
||||||
import 'package:paperless_mobile/constants.dart';
|
import 'package:paperless_mobile/constants.dart';
|
||||||
import 'package:paperless_mobile/core/bloc/connectivity_cubit.dart';
|
import 'package:paperless_mobile/core/bloc/connectivity_cubit.dart';
|
||||||
import 'package:paperless_mobile/core/database/hive/hive_config.dart';
|
import 'package:paperless_mobile/core/database/hive/hive_config.dart';
|
||||||
@@ -29,6 +30,7 @@ import 'package:paperless_mobile/core/exception/server_message_exception.dart';
|
|||||||
import 'package:paperless_mobile/core/factory/paperless_api_factory.dart';
|
import 'package:paperless_mobile/core/factory/paperless_api_factory.dart';
|
||||||
import 'package:paperless_mobile/core/factory/paperless_api_factory_impl.dart';
|
import 'package:paperless_mobile/core/factory/paperless_api_factory_impl.dart';
|
||||||
import 'package:paperless_mobile/core/interceptor/language_header.interceptor.dart';
|
import 'package:paperless_mobile/core/interceptor/language_header.interceptor.dart';
|
||||||
|
import 'package:paperless_mobile/core/notifier/go_router_refresh_stream.dart';
|
||||||
import 'package:paperless_mobile/features/logging/data/formatted_printer.dart';
|
import 'package:paperless_mobile/features/logging/data/formatted_printer.dart';
|
||||||
import 'package:paperless_mobile/features/logging/data/logger.dart';
|
import 'package:paperless_mobile/features/logging/data/logger.dart';
|
||||||
import 'package:paperless_mobile/features/logging/data/mirrored_file_output.dart';
|
import 'package:paperless_mobile/features/logging/data/mirrored_file_output.dart';
|
||||||
@@ -249,7 +251,7 @@ void main() async {
|
|||||||
_ => null
|
_ => null
|
||||||
};
|
};
|
||||||
logger.fe(
|
logger.fe(
|
||||||
"An unexpected error occurred${message != null ? "- $message" : ""}",
|
"An unexpected error occurred ${message != null ? "- $message" : ""}",
|
||||||
error: message == null ? error : null,
|
error: message == null ? error : null,
|
||||||
methodName: "main",
|
methodName: "main",
|
||||||
stackTrace: stackTrace,
|
stackTrace: stackTrace,
|
||||||
@@ -301,47 +303,50 @@ class _GoRouterShellState extends State<GoRouterShell> {
|
|||||||
initialLocation: "/login",
|
initialLocation: "/login",
|
||||||
routes: [
|
routes: [
|
||||||
ShellRoute(
|
ShellRoute(
|
||||||
builder: (context, state, child) {
|
pageBuilder: (context, state, child) {
|
||||||
return Provider.value(
|
return accessiblePlatformPage(
|
||||||
value: widget.apiFactory,
|
child: Provider.value(
|
||||||
child: BlocListener<AuthenticationCubit, AuthenticationState>(
|
value: widget.apiFactory,
|
||||||
listener: (context, state) {
|
child: BlocListener<AuthenticationCubit, AuthenticationState>(
|
||||||
switch (state) {
|
listener: (context, state) {
|
||||||
case UnauthenticatedState(
|
switch (state) {
|
||||||
redirectToAccountSelection: var shouldRedirect
|
case UnauthenticatedState(
|
||||||
):
|
redirectToAccountSelection: var shouldRedirect
|
||||||
if (shouldRedirect) {
|
):
|
||||||
const LoginToExistingAccountRoute().go(context);
|
if (shouldRedirect) {
|
||||||
} else {
|
const LoginToExistingAccountRoute().go(context);
|
||||||
const LoginRoute().go(context);
|
} else {
|
||||||
}
|
const LoginRoute().go(context);
|
||||||
break;
|
}
|
||||||
case RestoringSessionState():
|
break;
|
||||||
const RestoringSessionRoute().go(context);
|
case RestoringSessionState():
|
||||||
break;
|
const RestoringSessionRoute().go(context);
|
||||||
case VerifyIdentityState(userId: var userId):
|
break;
|
||||||
VerifyIdentityRoute(userId: userId).go(context);
|
case VerifyIdentityState(userId: var userId):
|
||||||
break;
|
VerifyIdentityRoute(userId: userId).go(context);
|
||||||
case SwitchingAccountsState():
|
break;
|
||||||
const SwitchingAccountsRoute().push(context);
|
case SwitchingAccountsState():
|
||||||
break;
|
const SwitchingAccountsRoute().push(context);
|
||||||
case AuthenticatedState():
|
break;
|
||||||
const LandingRoute().go(context);
|
case AuthenticatedState():
|
||||||
break;
|
const LandingRoute().go(context);
|
||||||
case AuthenticatingState state:
|
break;
|
||||||
AuthenticatingRoute(state.currentStage.name).push(context);
|
case AuthenticatingState state:
|
||||||
break;
|
AuthenticatingRoute(state.currentStage.name)
|
||||||
case LoggingOutState():
|
.push(context);
|
||||||
const LoggingOutRoute().go(context);
|
break;
|
||||||
break;
|
case LoggingOutState():
|
||||||
case AuthenticationErrorState():
|
const LoggingOutRoute().go(context);
|
||||||
if (context.canPop()) {
|
break;
|
||||||
context.pop();
|
case AuthenticationErrorState():
|
||||||
}
|
if (context.canPop()) {
|
||||||
break;
|
context.pop();
|
||||||
}
|
}
|
||||||
},
|
break;
|
||||||
child: child,
|
}
|
||||||
|
},
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import 'package:flutter/widgets.dart';
|
|||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:hive_flutter/adapters.dart';
|
import 'package:hive_flutter/adapters.dart';
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
|
import 'package:paperless_mobile/accessibility/accessible_page.dart';
|
||||||
import 'package:paperless_mobile/core/database/hive/hive_config.dart';
|
import 'package:paperless_mobile/core/database/hive/hive_config.dart';
|
||||||
import 'package:paperless_mobile/core/database/tables/global_settings.dart';
|
import 'package:paperless_mobile/core/database/tables/global_settings.dart';
|
||||||
import 'package:paperless_mobile/core/database/tables/local_user_account.dart';
|
import 'package:paperless_mobile/core/database/tables/local_user_account.dart';
|
||||||
@@ -141,32 +142,39 @@ class AuthenticatedRoute extends ShellRouteData {
|
|||||||
const AuthenticatedRoute();
|
const AuthenticatedRoute();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget builder(
|
Page<void> pageBuilder(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
GoRouterState state,
|
GoRouterState state,
|
||||||
Widget navigator,
|
Widget navigator,
|
||||||
) {
|
) {
|
||||||
final currentUserId = Hive.box<GlobalSettings>(HiveBoxes.globalSettings)
|
return accessiblePlatformPage(
|
||||||
.getValue()!
|
child: Builder(
|
||||||
.loggedInUserId;
|
builder: (context) {
|
||||||
if (currentUserId == null) {
|
final currentUserId =
|
||||||
return const SizedBox.shrink();
|
Hive.box<GlobalSettings>(HiveBoxes.globalSettings)
|
||||||
}
|
.getValue()!
|
||||||
final authenticatedUser =
|
.loggedInUserId;
|
||||||
Hive.box<LocalUserAccount>(HiveBoxes.localUserAccount).get(
|
if (currentUserId == null) {
|
||||||
currentUserId,
|
return const SizedBox.shrink();
|
||||||
)!;
|
}
|
||||||
final apiFactory = context.read<PaperlessApiFactory>();
|
final authenticatedUser =
|
||||||
return HomeShellWidget(
|
Hive.box<LocalUserAccount>(HiveBoxes.localUserAccount).get(
|
||||||
localUserId: authenticatedUser.id,
|
currentUserId,
|
||||||
paperlessApiVersion: authenticatedUser.apiVersion,
|
)!;
|
||||||
paperlessProviderFactory: apiFactory,
|
final apiFactory = context.read<PaperlessApiFactory>();
|
||||||
child: ChangeNotifierProvider(
|
return HomeShellWidget(
|
||||||
create: (context) => ConsumptionChangeNotifier()
|
localUserId: authenticatedUser.id,
|
||||||
..loadFromConsumptionDirectory(userId: currentUserId),
|
paperlessApiVersion: authenticatedUser.apiVersion,
|
||||||
child: EventListenerShell(
|
paperlessProviderFactory: apiFactory,
|
||||||
child: navigator,
|
child: ChangeNotifierProvider(
|
||||||
),
|
create: (context) => ConsumptionChangeNotifier()
|
||||||
|
..loadFromConsumptionDirectory(userId: currentUserId),
|
||||||
|
child: EventListenerShell(
|
||||||
|
child: navigator,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class AnimatedTouchBubblePart extends StatefulWidget {
|
class AnimatedTouchBubblePart extends StatefulWidget {
|
||||||
const AnimatedTouchBubblePart({super.key,
|
const AnimatedTouchBubblePart({
|
||||||
|
super.key,
|
||||||
required this.dragging,
|
required this.dragging,
|
||||||
required this.size,
|
required this.size,
|
||||||
});
|
});
|
||||||
@@ -22,6 +23,7 @@ class _AnimatedTouchBubblePartState extends State<AnimatedTouchBubblePart>
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void didChangeDependencies() {
|
void didChangeDependencies() {
|
||||||
|
super.didChangeDependencies();
|
||||||
_controller = AnimationController(
|
_controller = AnimationController(
|
||||||
duration: const Duration(milliseconds: 1000),
|
duration: const Duration(milliseconds: 1000),
|
||||||
vsync: this,
|
vsync: this,
|
||||||
@@ -40,7 +42,6 @@ class _AnimatedTouchBubblePartState extends State<AnimatedTouchBubblePart>
|
|||||||
);
|
);
|
||||||
|
|
||||||
_controller.repeat();
|
_controller.repeat();
|
||||||
super.didChangeDependencies();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
|
|||||||
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
||||||
# Read more about iOS versioning at
|
# Read more about iOS versioning at
|
||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||||
version: 3.1.3+57
|
version: 3.1.4+58
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=3.0.0 <4.0.0"
|
sdk: ">=3.0.0 <4.0.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user