From 378c4a6cbb8391794e1107c422e49aa676c5ba59 Mon Sep 17 00:00:00 2001 From: Matthias Nehlsen Date: Tue, 4 Jun 2024 18:09:13 +0200 Subject: [PATCH] feat: improve toolbar behavior --- lib/blocs/journal/entry_state.dart | 2 + lib/blocs/journal/entry_state.freezed.dart | 229 ++++++++++++++---- .../journal/state/entry_controller.dart | 7 + .../journal/state/entry_controller.g.dart | 2 +- .../journal/editor/editor_toolbar.dart | 7 +- lib/widgets/journal/editor/editor_widget.dart | 9 +- .../journal/entry_details/save_button.dart | 1 - lib/widgets/journal/entry_image_widget.dart | 1 + pubspec.yaml | 2 +- .../journal/state/entry_controller_test.dart | 14 ++ 10 files changed, 213 insertions(+), 61 deletions(-) diff --git a/lib/blocs/journal/entry_state.dart b/lib/blocs/journal/entry_state.dart index 0f23dc401..cd9fb876f 100644 --- a/lib/blocs/journal/entry_state.dart +++ b/lib/blocs/journal/entry_state.dart @@ -12,6 +12,7 @@ class EntryState with _$EntryState { required JournalEntity? entry, required bool showMap, required bool isFocused, + required bool shouldShowEditorToolBar, GlobalKey? formKey, }) = _EntryStateSaved; @@ -20,6 +21,7 @@ class EntryState with _$EntryState { required JournalEntity? entry, required bool showMap, required bool isFocused, + required bool shouldShowEditorToolBar, GlobalKey? formKey, }) = EntryStateDirty; } diff --git a/lib/blocs/journal/entry_state.freezed.dart b/lib/blocs/journal/entry_state.freezed.dart index 982f78ff8..c672f6d23 100644 --- a/lib/blocs/journal/entry_state.freezed.dart +++ b/lib/blocs/journal/entry_state.freezed.dart @@ -20,35 +20,66 @@ mixin _$EntryState { JournalEntity? get entry => throw _privateConstructorUsedError; bool get showMap => throw _privateConstructorUsedError; bool get isFocused => throw _privateConstructorUsedError; + bool get shouldShowEditorToolBar => throw _privateConstructorUsedError; GlobalKey? get formKey => throw _privateConstructorUsedError; @optionalTypeArgs TResult when({ - required TResult Function(String entryId, JournalEntity? entry, - bool showMap, bool isFocused, GlobalKey? formKey) + required TResult Function( + String entryId, + JournalEntity? entry, + bool showMap, + bool isFocused, + bool shouldShowEditorToolBar, + GlobalKey? formKey) saved, - required TResult Function(String entryId, JournalEntity? entry, - bool showMap, bool isFocused, GlobalKey? formKey) + required TResult Function( + String entryId, + JournalEntity? entry, + bool showMap, + bool isFocused, + bool shouldShowEditorToolBar, + GlobalKey? formKey) dirty, }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult? whenOrNull({ - TResult? Function(String entryId, JournalEntity? entry, bool showMap, - bool isFocused, GlobalKey? formKey)? + TResult? Function( + String entryId, + JournalEntity? entry, + bool showMap, + bool isFocused, + bool shouldShowEditorToolBar, + GlobalKey? formKey)? saved, - TResult? Function(String entryId, JournalEntity? entry, bool showMap, - bool isFocused, GlobalKey? formKey)? + TResult? Function( + String entryId, + JournalEntity? entry, + bool showMap, + bool isFocused, + bool shouldShowEditorToolBar, + GlobalKey? formKey)? dirty, }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult maybeWhen({ - TResult Function(String entryId, JournalEntity? entry, bool showMap, - bool isFocused, GlobalKey? formKey)? + TResult Function( + String entryId, + JournalEntity? entry, + bool showMap, + bool isFocused, + bool shouldShowEditorToolBar, + GlobalKey? formKey)? saved, - TResult Function(String entryId, JournalEntity? entry, bool showMap, - bool isFocused, GlobalKey? formKey)? + TResult Function( + String entryId, + JournalEntity? entry, + bool showMap, + bool isFocused, + bool shouldShowEditorToolBar, + GlobalKey? formKey)? dirty, required TResult orElse(), }) => @@ -89,6 +120,7 @@ abstract class $EntryStateCopyWith<$Res> { JournalEntity? entry, bool showMap, bool isFocused, + bool shouldShowEditorToolBar, GlobalKey? formKey}); $JournalEntityCopyWith<$Res>? get entry; @@ -111,6 +143,7 @@ class _$EntryStateCopyWithImpl<$Res, $Val extends EntryState> Object? entry = freezed, Object? showMap = null, Object? isFocused = null, + Object? shouldShowEditorToolBar = null, Object? formKey = freezed, }) { return _then(_value.copyWith( @@ -130,6 +163,10 @@ class _$EntryStateCopyWithImpl<$Res, $Val extends EntryState> ? _value.isFocused : isFocused // ignore: cast_nullable_to_non_nullable as bool, + shouldShowEditorToolBar: null == shouldShowEditorToolBar + ? _value.shouldShowEditorToolBar + : shouldShowEditorToolBar // ignore: cast_nullable_to_non_nullable + as bool, formKey: freezed == formKey ? _value.formKey : formKey // ignore: cast_nullable_to_non_nullable @@ -163,6 +200,7 @@ abstract class _$$EntryStateSavedImplCopyWith<$Res> JournalEntity? entry, bool showMap, bool isFocused, + bool shouldShowEditorToolBar, GlobalKey? formKey}); @override @@ -184,6 +222,7 @@ class __$$EntryStateSavedImplCopyWithImpl<$Res> Object? entry = freezed, Object? showMap = null, Object? isFocused = null, + Object? shouldShowEditorToolBar = null, Object? formKey = freezed, }) { return _then(_$EntryStateSavedImpl( @@ -203,6 +242,10 @@ class __$$EntryStateSavedImplCopyWithImpl<$Res> ? _value.isFocused : isFocused // ignore: cast_nullable_to_non_nullable as bool, + shouldShowEditorToolBar: null == shouldShowEditorToolBar + ? _value.shouldShowEditorToolBar + : shouldShowEditorToolBar // ignore: cast_nullable_to_non_nullable + as bool, formKey: freezed == formKey ? _value.formKey : formKey // ignore: cast_nullable_to_non_nullable @@ -219,6 +262,7 @@ class _$EntryStateSavedImpl implements _EntryStateSaved { required this.entry, required this.showMap, required this.isFocused, + required this.shouldShowEditorToolBar, this.formKey}); @override @@ -230,11 +274,13 @@ class _$EntryStateSavedImpl implements _EntryStateSaved { @override final bool isFocused; @override + final bool shouldShowEditorToolBar; + @override final GlobalKey? formKey; @override String toString() { - return 'EntryState.saved(entryId: $entryId, entry: $entry, showMap: $showMap, isFocused: $isFocused, formKey: $formKey)'; + return 'EntryState.saved(entryId: $entryId, entry: $entry, showMap: $showMap, isFocused: $isFocused, shouldShowEditorToolBar: $shouldShowEditorToolBar, formKey: $formKey)'; } @override @@ -247,12 +293,15 @@ class _$EntryStateSavedImpl implements _EntryStateSaved { (identical(other.showMap, showMap) || other.showMap == showMap) && (identical(other.isFocused, isFocused) || other.isFocused == isFocused) && + (identical( + other.shouldShowEditorToolBar, shouldShowEditorToolBar) || + other.shouldShowEditorToolBar == shouldShowEditorToolBar) && (identical(other.formKey, formKey) || other.formKey == formKey)); } @override - int get hashCode => - Object.hash(runtimeType, entryId, entry, showMap, isFocused, formKey); + int get hashCode => Object.hash(runtimeType, entryId, entry, showMap, + isFocused, shouldShowEditorToolBar, formKey); @JsonKey(ignore: true) @override @@ -264,42 +313,75 @@ class _$EntryStateSavedImpl implements _EntryStateSaved { @override @optionalTypeArgs TResult when({ - required TResult Function(String entryId, JournalEntity? entry, - bool showMap, bool isFocused, GlobalKey? formKey) + required TResult Function( + String entryId, + JournalEntity? entry, + bool showMap, + bool isFocused, + bool shouldShowEditorToolBar, + GlobalKey? formKey) saved, - required TResult Function(String entryId, JournalEntity? entry, - bool showMap, bool isFocused, GlobalKey? formKey) + required TResult Function( + String entryId, + JournalEntity? entry, + bool showMap, + bool isFocused, + bool shouldShowEditorToolBar, + GlobalKey? formKey) dirty, }) { - return saved(entryId, entry, showMap, isFocused, formKey); + return saved( + entryId, entry, showMap, isFocused, shouldShowEditorToolBar, formKey); } @override @optionalTypeArgs TResult? whenOrNull({ - TResult? Function(String entryId, JournalEntity? entry, bool showMap, - bool isFocused, GlobalKey? formKey)? + TResult? Function( + String entryId, + JournalEntity? entry, + bool showMap, + bool isFocused, + bool shouldShowEditorToolBar, + GlobalKey? formKey)? saved, - TResult? Function(String entryId, JournalEntity? entry, bool showMap, - bool isFocused, GlobalKey? formKey)? + TResult? Function( + String entryId, + JournalEntity? entry, + bool showMap, + bool isFocused, + bool shouldShowEditorToolBar, + GlobalKey? formKey)? dirty, }) { - return saved?.call(entryId, entry, showMap, isFocused, formKey); + return saved?.call( + entryId, entry, showMap, isFocused, shouldShowEditorToolBar, formKey); } @override @optionalTypeArgs TResult maybeWhen({ - TResult Function(String entryId, JournalEntity? entry, bool showMap, - bool isFocused, GlobalKey? formKey)? + TResult Function( + String entryId, + JournalEntity? entry, + bool showMap, + bool isFocused, + bool shouldShowEditorToolBar, + GlobalKey? formKey)? saved, - TResult Function(String entryId, JournalEntity? entry, bool showMap, - bool isFocused, GlobalKey? formKey)? + TResult Function( + String entryId, + JournalEntity? entry, + bool showMap, + bool isFocused, + bool shouldShowEditorToolBar, + GlobalKey? formKey)? dirty, required TResult orElse(), }) { if (saved != null) { - return saved(entryId, entry, showMap, isFocused, formKey); + return saved( + entryId, entry, showMap, isFocused, shouldShowEditorToolBar, formKey); } return orElse(); } @@ -342,6 +424,7 @@ abstract class _EntryStateSaved implements EntryState { required final JournalEntity? entry, required final bool showMap, required final bool isFocused, + required final bool shouldShowEditorToolBar, final GlobalKey? formKey}) = _$EntryStateSavedImpl; @override @@ -353,6 +436,8 @@ abstract class _EntryStateSaved implements EntryState { @override bool get isFocused; @override + bool get shouldShowEditorToolBar; + @override GlobalKey? get formKey; @override @JsonKey(ignore: true) @@ -373,6 +458,7 @@ abstract class _$$EntryStateDirtyImplCopyWith<$Res> JournalEntity? entry, bool showMap, bool isFocused, + bool shouldShowEditorToolBar, GlobalKey? formKey}); @override @@ -394,6 +480,7 @@ class __$$EntryStateDirtyImplCopyWithImpl<$Res> Object? entry = freezed, Object? showMap = null, Object? isFocused = null, + Object? shouldShowEditorToolBar = null, Object? formKey = freezed, }) { return _then(_$EntryStateDirtyImpl( @@ -413,6 +500,10 @@ class __$$EntryStateDirtyImplCopyWithImpl<$Res> ? _value.isFocused : isFocused // ignore: cast_nullable_to_non_nullable as bool, + shouldShowEditorToolBar: null == shouldShowEditorToolBar + ? _value.shouldShowEditorToolBar + : shouldShowEditorToolBar // ignore: cast_nullable_to_non_nullable + as bool, formKey: freezed == formKey ? _value.formKey : formKey // ignore: cast_nullable_to_non_nullable @@ -429,6 +520,7 @@ class _$EntryStateDirtyImpl implements EntryStateDirty { required this.entry, required this.showMap, required this.isFocused, + required this.shouldShowEditorToolBar, this.formKey}); @override @@ -440,11 +532,13 @@ class _$EntryStateDirtyImpl implements EntryStateDirty { @override final bool isFocused; @override + final bool shouldShowEditorToolBar; + @override final GlobalKey? formKey; @override String toString() { - return 'EntryState.dirty(entryId: $entryId, entry: $entry, showMap: $showMap, isFocused: $isFocused, formKey: $formKey)'; + return 'EntryState.dirty(entryId: $entryId, entry: $entry, showMap: $showMap, isFocused: $isFocused, shouldShowEditorToolBar: $shouldShowEditorToolBar, formKey: $formKey)'; } @override @@ -457,12 +551,15 @@ class _$EntryStateDirtyImpl implements EntryStateDirty { (identical(other.showMap, showMap) || other.showMap == showMap) && (identical(other.isFocused, isFocused) || other.isFocused == isFocused) && + (identical( + other.shouldShowEditorToolBar, shouldShowEditorToolBar) || + other.shouldShowEditorToolBar == shouldShowEditorToolBar) && (identical(other.formKey, formKey) || other.formKey == formKey)); } @override - int get hashCode => - Object.hash(runtimeType, entryId, entry, showMap, isFocused, formKey); + int get hashCode => Object.hash(runtimeType, entryId, entry, showMap, + isFocused, shouldShowEditorToolBar, formKey); @JsonKey(ignore: true) @override @@ -474,42 +571,75 @@ class _$EntryStateDirtyImpl implements EntryStateDirty { @override @optionalTypeArgs TResult when({ - required TResult Function(String entryId, JournalEntity? entry, - bool showMap, bool isFocused, GlobalKey? formKey) + required TResult Function( + String entryId, + JournalEntity? entry, + bool showMap, + bool isFocused, + bool shouldShowEditorToolBar, + GlobalKey? formKey) saved, - required TResult Function(String entryId, JournalEntity? entry, - bool showMap, bool isFocused, GlobalKey? formKey) + required TResult Function( + String entryId, + JournalEntity? entry, + bool showMap, + bool isFocused, + bool shouldShowEditorToolBar, + GlobalKey? formKey) dirty, }) { - return dirty(entryId, entry, showMap, isFocused, formKey); + return dirty( + entryId, entry, showMap, isFocused, shouldShowEditorToolBar, formKey); } @override @optionalTypeArgs TResult? whenOrNull({ - TResult? Function(String entryId, JournalEntity? entry, bool showMap, - bool isFocused, GlobalKey? formKey)? + TResult? Function( + String entryId, + JournalEntity? entry, + bool showMap, + bool isFocused, + bool shouldShowEditorToolBar, + GlobalKey? formKey)? saved, - TResult? Function(String entryId, JournalEntity? entry, bool showMap, - bool isFocused, GlobalKey? formKey)? + TResult? Function( + String entryId, + JournalEntity? entry, + bool showMap, + bool isFocused, + bool shouldShowEditorToolBar, + GlobalKey? formKey)? dirty, }) { - return dirty?.call(entryId, entry, showMap, isFocused, formKey); + return dirty?.call( + entryId, entry, showMap, isFocused, shouldShowEditorToolBar, formKey); } @override @optionalTypeArgs TResult maybeWhen({ - TResult Function(String entryId, JournalEntity? entry, bool showMap, - bool isFocused, GlobalKey? formKey)? + TResult Function( + String entryId, + JournalEntity? entry, + bool showMap, + bool isFocused, + bool shouldShowEditorToolBar, + GlobalKey? formKey)? saved, - TResult Function(String entryId, JournalEntity? entry, bool showMap, - bool isFocused, GlobalKey? formKey)? + TResult Function( + String entryId, + JournalEntity? entry, + bool showMap, + bool isFocused, + bool shouldShowEditorToolBar, + GlobalKey? formKey)? dirty, required TResult orElse(), }) { if (dirty != null) { - return dirty(entryId, entry, showMap, isFocused, formKey); + return dirty( + entryId, entry, showMap, isFocused, shouldShowEditorToolBar, formKey); } return orElse(); } @@ -552,6 +682,7 @@ abstract class EntryStateDirty implements EntryState { required final JournalEntity? entry, required final bool showMap, required final bool isFocused, + required final bool shouldShowEditorToolBar, final GlobalKey? formKey}) = _$EntryStateDirtyImpl; @override @@ -563,6 +694,8 @@ abstract class EntryStateDirty implements EntryState { @override bool get isFocused; @override + bool get shouldShowEditorToolBar; + @override GlobalKey? get formKey; @override @JsonKey(ignore: true) diff --git a/lib/features/journal/state/entry_controller.dart b/lib/features/journal/state/entry_controller.dart index adf7345ff..01509339a 100644 --- a/lib/features/journal/state/entry_controller.dart +++ b/lib/features/journal/state/entry_controller.dart @@ -30,6 +30,9 @@ class EntryController extends _$EntryController { focusNode.addListener(() { _isFocused = focusNode.hasFocus; + if (_isFocused) { + _shouldShowEditorToolBar = true; + } emitState(); if (isDesktop) { @@ -68,6 +71,7 @@ class EntryController extends _$EntryController { bool _dirty = false; bool _isFocused = false; + bool _shouldShowEditorToolBar = false; final PersistenceLogic _persistenceLogic = getIt(); StreamSubscription<({DatabaseType type, String id})>? _updateSubscription; @@ -120,6 +124,7 @@ class EntryController extends _$EntryController { entry: entry, showMap: false, isFocused: false, + shouldShowEditorToolBar: false, formKey: formKey, ); } @@ -275,6 +280,7 @@ class EntryController extends _$EntryController { entry: entry, showMap: state.value?.showMap ?? false, isFocused: _isFocused, + shouldShowEditorToolBar: _shouldShowEditorToolBar, formKey: formKey, ), ); @@ -285,6 +291,7 @@ class EntryController extends _$EntryController { entry: entry, showMap: state.value?.showMap ?? false, isFocused: _isFocused, + shouldShowEditorToolBar: _shouldShowEditorToolBar, formKey: formKey, ), ); diff --git a/lib/features/journal/state/entry_controller.g.dart b/lib/features/journal/state/entry_controller.g.dart index 248354959..1d706d736 100644 --- a/lib/features/journal/state/entry_controller.g.dart +++ b/lib/features/journal/state/entry_controller.g.dart @@ -6,7 +6,7 @@ part of 'entry_controller.dart'; // RiverpodGenerator // ************************************************************************** -String _$entryControllerHash() => r'13fc1f36eadf674646ad646825d984210a775721'; +String _$entryControllerHash() => r'5d783ad17f1134a347f4b77fc195e0e30ff9f492'; /// Copied from Dart SDK class _SystemHash { diff --git a/lib/widgets/journal/editor/editor_toolbar.dart b/lib/widgets/journal/editor/editor_toolbar.dart index ec7f4369f..1b215450e 100644 --- a/lib/widgets/journal/editor/editor_toolbar.dart +++ b/lib/widgets/journal/editor/editor_toolbar.dart @@ -12,7 +12,7 @@ class ToolbarWidget extends StatelessWidget { @override Widget build(BuildContext context) { - const duration = Duration(milliseconds: 200); + const duration = Duration(milliseconds: 400); const curve = Curves.easeInOutQuint; const height = 60.0; @@ -44,10 +44,7 @@ class ToolbarWidget extends StatelessWidget { curve: curve, begin: 0, end: 1, - ) - .fadeIn( - duration: duration, - curve: curve, + alignment: Alignment.topCenter, ) .custom( duration: duration, diff --git a/lib/widgets/journal/editor/editor_widget.dart b/lib/widgets/journal/editor/editor_widget.dart index f913a8462..28962283e 100644 --- a/lib/widgets/journal/editor/editor_widget.dart +++ b/lib/widgets/journal/editor/editor_widget.dart @@ -41,12 +41,14 @@ class EditorWidget extends ConsumerWidget { final focusNode = notifier.focusNode; final isFocused = entryState.value?.isFocused ?? false; + final shouldShowEditorToolBar = + entryState.value?.shouldShowEditorToolBar ?? false; if (isFocused && isMobile) { Future.microtask(() { Scrollable.ensureVisible( context, - duration: const Duration(milliseconds: 200), + duration: const Duration(milliseconds: 400), curve: Curves.easeInOutQuint, ); }); @@ -67,10 +69,7 @@ class EditorWidget extends ConsumerWidget { child: Column( mainAxisSize: MainAxisSize.min, children: [ - if (isFocused) - ToolbarWidget( - controller: controller, - ), + if (shouldShowEditorToolBar) ToolbarWidget(controller: controller), Flexible( child: QuillEditor( scrollController: ScrollController(), diff --git a/lib/widgets/journal/entry_details/save_button.dart b/lib/widgets/journal/entry_details/save_button.dart index 6d1d8a641..3ffb79591 100644 --- a/lib/widgets/journal/entry_details/save_button.dart +++ b/lib/widgets/journal/entry_details/save_button.dart @@ -28,7 +28,6 @@ class SaveButton extends ConsumerWidget { } return TextButton( onPressed: () { - //context.read().save(); ref.read(provider.notifier).save(); FocusManager.instance.primaryFocus?.unfocus(); }, diff --git a/lib/widgets/journal/entry_image_widget.dart b/lib/widgets/journal/entry_image_widget.dart index d66b44652..85e6bc2aa 100644 --- a/lib/widgets/journal/entry_image_widget.dart +++ b/lib/widgets/journal/entry_image_widget.dart @@ -43,6 +43,7 @@ class EntryImageWidget extends ConsumerWidget { ), child: Image.file( file, + width: MediaQuery.of(context).size.width, fit: BoxFit.contain, ), ), diff --git a/pubspec.yaml b/pubspec.yaml index 420b91b46..220cb8de6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: lotti description: Achieve your goals and keep your data private with Lotti. publish_to: 'none' -version: 0.9.475+2550 +version: 0.9.475+2552 msix_config: display_name: LottiApp diff --git a/test/features/journal/state/entry_controller_test.dart b/test/features/journal/state/entry_controller_test.dart index eb6a769fb..2fe3eaabf 100644 --- a/test/features/journal/state/entry_controller_test.dart +++ b/test/features/journal/state/entry_controller_test.dart @@ -124,6 +124,7 @@ void main() { entry: testTextEntry, showMap: false, isFocused: false, + shouldShowEditorToolBar: false, ), ), ); @@ -143,6 +144,7 @@ void main() { entry: testTextEntry, showMap: false, isFocused: false, + shouldShowEditorToolBar: false, ), ), ); @@ -157,6 +159,7 @@ void main() { entry: testTextEntry, showMap: true, isFocused: false, + shouldShowEditorToolBar: false, ), ), ); @@ -171,6 +174,7 @@ void main() { entry: testTextEntry, showMap: false, isFocused: false, + shouldShowEditorToolBar: false, ), ), ); @@ -190,6 +194,7 @@ void main() { entry: testTextEntryNoGeo, showMap: false, isFocused: false, + shouldShowEditorToolBar: false, ), ), ); @@ -204,6 +209,7 @@ void main() { entry: testTextEntryNoGeo, showMap: false, isFocused: false, + shouldShowEditorToolBar: false, ), ), ); @@ -223,6 +229,7 @@ void main() { entry: testTextEntry, showMap: false, isFocused: false, + shouldShowEditorToolBar: false, ), ), ); @@ -237,6 +244,7 @@ void main() { entry: testTextEntry, showMap: false, isFocused: false, + shouldShowEditorToolBar: false, ), ), ); @@ -275,6 +283,7 @@ void main() { entry: testTextEntry, showMap: false, isFocused: false, + shouldShowEditorToolBar: false, ), ), ); @@ -355,6 +364,7 @@ void main() { entry: testTextEntry, showMap: false, isFocused: false, + shouldShowEditorToolBar: false, ), ), ); @@ -369,6 +379,7 @@ void main() { entry: testTextEntry, showMap: false, isFocused: false, + shouldShowEditorToolBar: false, ), ), ); @@ -397,6 +408,7 @@ void main() { entry: testTextEntry, showMap: false, isFocused: false, + shouldShowEditorToolBar: false, ), ), ); @@ -418,6 +430,7 @@ void main() { entry: testTextEntry, showMap: false, isFocused: false, + shouldShowEditorToolBar: false, ), ), ); @@ -450,6 +463,7 @@ void main() { entry: testTextEntry, showMap: false, isFocused: false, + shouldShowEditorToolBar: false, ), ), );