Преглед на файлове

feat: select cover image on upload (#3488)

Mathias Mogensen преди 1 година
родител
ревизия
048434024b

+ 97 - 86
frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/header/cover_editor.dart

@@ -41,36 +41,6 @@ class ChangeCoverPopover extends StatefulWidget {
   State<ChangeCoverPopover> createState() => _ChangeCoverPopoverState();
 }
 
-class ColorOption {
-  final String colorHex;
-
-  final String name;
-  const ColorOption({
-    required this.colorHex,
-    required this.name,
-  });
-}
-
-class CoverColorPicker extends StatefulWidget {
-  final String? selectedBackgroundColorHex;
-
-  final Color pickerBackgroundColor;
-  final Color pickerItemHoverColor;
-  final void Function(String color) onSubmittedBackgroundColorHex;
-  final List<ColorOption> backgroundColorOptions;
-  const CoverColorPicker({
-    super.key,
-    this.selectedBackgroundColorHex,
-    required this.pickerBackgroundColor,
-    required this.backgroundColorOptions,
-    required this.pickerItemHoverColor,
-    required this.onSubmittedBackgroundColorHex,
-  });
-
-  @override
-  State<CoverColorPicker> createState() => _CoverColorPickerState();
-}
-
 class _ChangeCoverPopoverState extends State<ChangeCoverPopover> {
   bool isAddingImage = false;
 
@@ -81,7 +51,15 @@ class _ChangeCoverPopoverState extends State<ChangeCoverPopover> {
         editorState: widget.editorState,
         node: widget.node,
       )..add(const ChangeCoverPopoverEvent.fetchPickedImagePaths()),
-      child: BlocBuilder<ChangeCoverPopoverBloc, ChangeCoverPopoverState>(
+      child: BlocConsumer<ChangeCoverPopoverBloc, ChangeCoverPopoverState>(
+        listener: (context, state) {
+          if (state is Loaded && state.selectLatestImage) {
+            widget.onCoverChanged(
+              CoverType.file,
+              state.imageNames.last,
+            );
+          }
+        },
         builder: (context, state) {
           return Padding(
             padding: const EdgeInsets.all(12),
@@ -91,14 +69,15 @@ class _ChangeCoverPopoverState extends State<ChangeCoverPopover> {
                       onBackPressed: () => setState(() {
                         isAddingImage = false;
                       }),
-                      onFileSubmit: (List<String> path) {
+                      onFileSubmit: (_) {
                         context.read<ChangeCoverPopoverBloc>().add(
                               const ChangeCoverPopoverEvent
-                                  .fetchPickedImagePaths(),
+                                  .fetchPickedImagePaths(
+                                selectLatestImage: true,
+                              ),
                             );
-                        setState(() {
-                          isAddingImage = false;
-                        });
+
+                        setState(() => isAddingImage = false);
                       },
                     )
                   : _buildCoverSelection(),
@@ -294,7 +273,8 @@ class _ChangeCoverPopoverState extends State<ChangeCoverPopover> {
             },
           );
         }
-        return Container();
+
+        return const SizedBox.shrink();
       },
     );
   }
@@ -314,6 +294,7 @@ class _ChangeCoverPopoverState extends State<ChangeCoverPopover> {
 @visibleForTesting
 class NewCustomCoverButton extends StatelessWidget {
   final VoidCallback onPressed;
+
   const NewCustomCoverButton({super.key, required this.onPressed});
 
   @override
@@ -337,6 +318,85 @@ class NewCustomCoverButton extends StatelessWidget {
   }
 }
 
+class ColorOption {
+  final String colorHex;
+
+  final String name;
+  const ColorOption({
+    required this.colorHex,
+    required this.name,
+  });
+}
+
+class CoverColorPicker extends StatefulWidget {
+  final String? selectedBackgroundColorHex;
+
+  final Color pickerBackgroundColor;
+  final Color pickerItemHoverColor;
+  final void Function(String color) onSubmittedBackgroundColorHex;
+  final List<ColorOption> backgroundColorOptions;
+  const CoverColorPicker({
+    super.key,
+    this.selectedBackgroundColorHex,
+    required this.pickerBackgroundColor,
+    required this.backgroundColorOptions,
+    required this.pickerItemHoverColor,
+    required this.onSubmittedBackgroundColorHex,
+  });
+
+  @override
+  State<CoverColorPicker> createState() => _CoverColorPickerState();
+}
+
+class _CoverColorPickerState extends State<CoverColorPicker> {
+  final scrollController = ScrollController();
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      height: 30,
+      alignment: Alignment.center,
+      child: ScrollConfiguration(
+        behavior: ScrollConfiguration.of(context).copyWith(
+          dragDevices: {
+            PointerDeviceKind.touch,
+            PointerDeviceKind.mouse,
+          },
+          platform: TargetPlatform.windows,
+        ),
+        child: SingleChildScrollView(
+          child: _buildColorItems(
+            widget.backgroundColorOptions,
+            widget.selectedBackgroundColorHex,
+          ),
+        ),
+      ),
+    );
+  }
+
+  @override
+  void dispose() {
+    super.dispose();
+    scrollController.dispose();
+  }
+
+  Widget _buildColorItems(List<ColorOption> options, String? selectedColor) {
+    return Row(
+      crossAxisAlignment: CrossAxisAlignment.start,
+      children: options
+          .map(
+            (e) => ColorItem(
+              option: e,
+              isChecked: e.colorHex == selectedColor,
+              hoverColor: widget.pickerItemHoverColor,
+              onTap: widget.onSubmittedBackgroundColorHex,
+            ),
+          )
+          .toList(),
+    );
+  }
+}
+
 class DeleteImageAlertDialog extends StatelessWidget {
   const DeleteImageAlertDialog({
     Key? key,
@@ -458,55 +518,6 @@ class _ImageGridItemState extends State<ImageGridItem> {
   }
 }
 
-class _CoverColorPickerState extends State<CoverColorPicker> {
-  final scrollController = ScrollController();
-
-  @override
-  Widget build(BuildContext context) {
-    return Container(
-      height: 30,
-      alignment: Alignment.center,
-      child: ScrollConfiguration(
-        behavior: ScrollConfiguration.of(context).copyWith(
-          dragDevices: {
-            PointerDeviceKind.touch,
-            PointerDeviceKind.mouse,
-          },
-          platform: TargetPlatform.windows,
-        ),
-        child: SingleChildScrollView(
-          child: _buildColorItems(
-            widget.backgroundColorOptions,
-            widget.selectedBackgroundColorHex,
-          ),
-        ),
-      ),
-    );
-  }
-
-  @override
-  void dispose() {
-    super.dispose();
-    scrollController.dispose();
-  }
-
-  Widget _buildColorItems(List<ColorOption> options, String? selectedColor) {
-    return Row(
-      crossAxisAlignment: CrossAxisAlignment.start,
-      children: options
-          .map(
-            (e) => ColorItem(
-              option: e,
-              isChecked: e.colorHex == selectedColor,
-              hoverColor: widget.pickerItemHoverColor,
-              onTap: widget.onSubmittedBackgroundColorHex,
-            ),
-          )
-          .toList(),
-    );
-  }
-}
-
 @visibleForTesting
 class ColorItem extends StatelessWidget {
   final ColorOption option;

+ 19 - 7
frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/header/cover_editor_bloc.dart

@@ -16,18 +16,28 @@ class ChangeCoverPopoverBloc
   final Node node;
   late final SharedPreferences _prefs;
   final _initCompleter = Completer<void>();
-  ChangeCoverPopoverBloc({required this.editorState, required this.node})
-      : super(const ChangeCoverPopoverState.initial()) {
+
+  ChangeCoverPopoverBloc({
+    required this.editorState,
+    required this.node,
+  }) : super(const ChangeCoverPopoverState.initial()) {
     SharedPreferences.getInstance().then((prefs) {
       _prefs = prefs;
       _initCompleter.complete();
     });
+
     on<ChangeCoverPopoverEvent>((event, emit) async {
       await event.map(
         fetchPickedImagePaths:
             (FetchPickedImagePaths fetchPickedImagePaths) async {
           final imageNames = await _getPreviouslyPickedImagePaths();
-          emit(ChangeCoverPopoverState.loaded(imageNames));
+
+          emit(
+            ChangeCoverPopoverState.loaded(
+              imageNames,
+              selectLatestImage: fetchPickedImagePaths.selectLatestImage,
+            ),
+          );
         },
         deleteImage: (DeleteImage deleteImage) async {
           final currentState = state;
@@ -100,8 +110,9 @@ class ChangeCoverPopoverBloc
 
 @freezed
 class ChangeCoverPopoverEvent with _$ChangeCoverPopoverEvent {
-  const factory ChangeCoverPopoverEvent.fetchPickedImagePaths() =
-      FetchPickedImagePaths;
+  const factory ChangeCoverPopoverEvent.fetchPickedImagePaths({
+    @Default(false) bool selectLatestImage,
+  }) = FetchPickedImagePaths;
 
   const factory ChangeCoverPopoverEvent.deleteImage(String path) = DeleteImage;
   const factory ChangeCoverPopoverEvent.clearAllImages() = ClearAllImages;
@@ -112,6 +123,7 @@ class ChangeCoverPopoverState with _$ChangeCoverPopoverState {
   const factory ChangeCoverPopoverState.initial() = Initial;
   const factory ChangeCoverPopoverState.loading() = Loading;
   const factory ChangeCoverPopoverState.loaded(
-    List<String> imageNames,
-  ) = Loaded;
+    List<String> imageNames, {
+    @Default(false) selectLatestImage,
+  }) = Loaded;
 }