mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
Implement cover plugin 1868 (#1897)
* implement_cover_plugin_#1868 * code cleanup * fix: CI issue fix * fix: cover plugin implementation finalized * fix: localization fixes * fix: added add cover button * chore: optimize the cover plugin code * feat: auto hide the add button and cover buttons when leaving --------- Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
This commit is contained in:
@ -0,0 +1,376 @@
|
||||
import 'dart:io';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/plugins/cover/cover_node_widget.dart';
|
||||
import 'package:appflowy/startup/startup.dart';
|
||||
import 'package:appflowy/util/file_picker/file_picker_service.dart';
|
||||
import 'package:appflowy/workspace/application/settings/settings_location_cubit.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:appflowy_editor_plugins/appflowy_editor_plugins.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:file_picker/file_picker.dart' show FileType;
|
||||
import 'package:flowy_infra/size.dart';
|
||||
import 'package:flowy_infra/theme_extension.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/text.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
const String kLocalImagesKey = 'local_images';
|
||||
|
||||
List<String> get builtInAssetImages => [
|
||||
"assets/images/app_flowy_abstract_cover_1.jpg",
|
||||
"assets/images/app_flowy_abstract_cover_2.jpg"
|
||||
];
|
||||
|
||||
class ChangeCoverPopover extends StatefulWidget {
|
||||
final EditorState editorState;
|
||||
final Node node;
|
||||
final Function(
|
||||
CoverSelectionType selectionType,
|
||||
String selection,
|
||||
) onCoverChanged;
|
||||
|
||||
const ChangeCoverPopover({
|
||||
super.key,
|
||||
required this.editorState,
|
||||
required this.onCoverChanged,
|
||||
required this.node,
|
||||
});
|
||||
|
||||
@override
|
||||
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> {
|
||||
late Future<List<String>>? fileImages;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
fileImages = _getPreviouslyPickedImagePaths();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(15),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
FlowyText.semibold(LocaleKeys.document_plugins_cover_colors.tr()),
|
||||
const SizedBox(height: 10),
|
||||
_buildColorPickerList(),
|
||||
const SizedBox(height: 10),
|
||||
FlowyText.semibold(LocaleKeys.document_plugins_cover_images.tr()),
|
||||
const SizedBox(height: 10),
|
||||
_buildFileImagePicker(),
|
||||
const SizedBox(height: 10),
|
||||
FlowyText.semibold(LocaleKeys.document_plugins_cover_abstract.tr()),
|
||||
const SizedBox(height: 10),
|
||||
_buildAbstractImagePicker(),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAbstractImagePicker() {
|
||||
return GridView.builder(
|
||||
shrinkWrap: true,
|
||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 3,
|
||||
childAspectRatio: 1 / 0.65,
|
||||
crossAxisSpacing: 7,
|
||||
mainAxisSpacing: 7),
|
||||
itemCount: builtInAssetImages.length,
|
||||
itemBuilder: (BuildContext ctx, index) {
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
widget.onCoverChanged(
|
||||
CoverSelectionType.asset,
|
||||
builtInAssetImages[index],
|
||||
);
|
||||
},
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage(builtInAssetImages[index]),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
borderRadius: Corners.s8Border,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildColorPickerList() {
|
||||
return CoverColorPicker(
|
||||
pickerBackgroundColor:
|
||||
widget.editorState.editorStyle.selectionMenuBackgroundColor ??
|
||||
Colors.white,
|
||||
pickerItemHoverColor:
|
||||
widget.editorState.editorStyle.selectionMenuItemSelectedColor ??
|
||||
Colors.blue.withOpacity(0.3),
|
||||
selectedBackgroundColorHex:
|
||||
widget.node.attributes[kCoverSelectionTypeAttribute] ==
|
||||
CoverSelectionType.color.toString()
|
||||
? widget.node.attributes[kCoverSelectionAttribute]
|
||||
: "ffffff",
|
||||
backgroundColorOptions:
|
||||
_generateBackgroundColorOptions(widget.editorState),
|
||||
onSubmittedbackgroundColorHex: (color) {
|
||||
widget.onCoverChanged(CoverSelectionType.color, color);
|
||||
setState(() {});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildFileImagePicker() {
|
||||
return FutureBuilder<List<String>>(
|
||||
future: _getPreviouslyPickedImagePaths(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
List<String> images = snapshot.data!;
|
||||
return GridView.builder(
|
||||
shrinkWrap: true,
|
||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 3,
|
||||
childAspectRatio: 1 / 0.65,
|
||||
crossAxisSpacing: 7,
|
||||
mainAxisSpacing: 7,
|
||||
),
|
||||
itemCount: images.length + 1,
|
||||
itemBuilder: (BuildContext ctx, index) {
|
||||
if (index == 0) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.primary
|
||||
.withOpacity(0.15),
|
||||
border: Border.all(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
borderRadius: Corners.s8Border,
|
||||
),
|
||||
child: FlowyIconButton(
|
||||
iconPadding: EdgeInsets.zero,
|
||||
icon: Icon(
|
||||
Icons.add,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
width: 20,
|
||||
onPressed: () {
|
||||
_pickImages();
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
widget.onCoverChanged(
|
||||
CoverSelectionType.file,
|
||||
images[index - 1],
|
||||
);
|
||||
},
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: FileImage(File(images[index - 1])),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
borderRadius: Corners.s8Border,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
} else {
|
||||
return Container();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
List<ColorOption> _generateBackgroundColorOptions(EditorState editorState) {
|
||||
return FlowyTint.values
|
||||
.map((t) => ColorOption(
|
||||
colorHex: t.color(context).toHex(),
|
||||
name: t.tintName(AppFlowyEditorLocalizations.current),
|
||||
))
|
||||
.toList();
|
||||
}
|
||||
|
||||
Future<List<String>> _getPreviouslyPickedImagePaths() async {
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
final imageNames = prefs.getStringList(kLocalImagesKey) ?? [];
|
||||
final removeNames = [];
|
||||
for (final name in imageNames) {
|
||||
if (!File(name).existsSync()) {
|
||||
removeNames.add(name);
|
||||
}
|
||||
}
|
||||
imageNames.removeWhere((element) => removeNames.contains(element));
|
||||
prefs.setStringList(kLocalImagesKey, imageNames);
|
||||
return imageNames;
|
||||
}
|
||||
|
||||
Future<void> _pickImages() async {
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
List<String> imageNames = prefs.getStringList(kLocalImagesKey) ?? [];
|
||||
FilePickerResult? result = await getIt<FilePickerService>().pickFiles(
|
||||
dialogTitle: LocaleKeys.document_plugins_cover_addLocalImage.tr(),
|
||||
allowMultiple: false,
|
||||
type: FileType.image,
|
||||
allowedExtensions: ['jpg', 'png', 'jpeg'],
|
||||
);
|
||||
if (result != null && result.files.isNotEmpty) {
|
||||
final path = result.files.first.path;
|
||||
if (path != null) {
|
||||
final directory = await _coverPath();
|
||||
final newPath = await File(path).copy(
|
||||
'$directory/${path.split('/').last}',
|
||||
);
|
||||
imageNames.add(newPath.path);
|
||||
}
|
||||
}
|
||||
await prefs.setStringList(kLocalImagesKey, imageNames);
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
Future<String> _coverPath() async {
|
||||
final directory = await getIt<SettingsLocationCubit>().fetchLocation();
|
||||
return Directory('$directory/covers')
|
||||
.create(recursive: true)
|
||||
.then((value) => value.path);
|
||||
}
|
||||
}
|
||||
|
||||
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: ListView.builder(
|
||||
controller: scrollController,
|
||||
shrinkWrap: true,
|
||||
itemCount: widget.backgroundColorOptions.length,
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemBuilder: (context, index) {
|
||||
return _buildColorItems(
|
||||
widget.backgroundColorOptions,
|
||||
widget.selectedBackgroundColorHex,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
scrollController.dispose();
|
||||
}
|
||||
|
||||
Widget _buildColorItem(ColorOption option, bool isChecked) {
|
||||
return InkWell(
|
||||
customBorder: const RoundedRectangleBorder(
|
||||
borderRadius: Corners.s6Border,
|
||||
),
|
||||
hoverColor: widget.pickerItemHoverColor,
|
||||
onTap: () {
|
||||
widget.onSubmittedbackgroundColorHex(option.colorHex);
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(right: 10.0),
|
||||
child: SizedBox.square(
|
||||
dimension: 25,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: isChecked
|
||||
? Colors.transparent
|
||||
: Color(int.tryParse(option.colorHex) ?? 0xFFFFFFFF),
|
||||
border: isChecked
|
||||
? Border.all(
|
||||
color: Color(int.tryParse(option.colorHex) ?? 0xFFFFFF))
|
||||
: null,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: isChecked
|
||||
? SizedBox.square(
|
||||
dimension: 25,
|
||||
child: Container(
|
||||
margin: const EdgeInsets.all(4),
|
||||
decoration: BoxDecoration(
|
||||
color:
|
||||
Color(int.tryParse(option.colorHex) ?? 0xFFFFFFFF),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
),
|
||||
)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildColorItems(List<ColorOption> options, String? selectedColor) {
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: options
|
||||
.map((e) => _buildColorItem(e, e.colorHex == selectedColor))
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
extension on Color {
|
||||
String toHex() {
|
||||
return '0x${value.toRadixString(16)}';
|
||||
}
|
||||
}
|
@ -0,0 +1,302 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/plugins/cover/change_cover_popover.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra/image.dart';
|
||||
import 'package:flowy_infra/size.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/button.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
|
||||
import 'package:flowy_infra_ui/widget/rounded_button.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
const String kCoverType = 'cover';
|
||||
const String kCoverSelectionTypeAttribute = 'cover_selection_type';
|
||||
const String kCoverSelectionAttribute = 'cover_selection';
|
||||
|
||||
enum CoverSelectionType {
|
||||
initial,
|
||||
|
||||
color,
|
||||
file,
|
||||
asset;
|
||||
|
||||
static CoverSelectionType fromString(String? value) {
|
||||
if (value == null) {
|
||||
return CoverSelectionType.initial;
|
||||
}
|
||||
return CoverSelectionType.values.firstWhere(
|
||||
(e) => e.toString() == value,
|
||||
orElse: () => CoverSelectionType.initial,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class CoverNodeWidgetBuilder implements NodeWidgetBuilder {
|
||||
@override
|
||||
Widget build(NodeWidgetContext<Node> context) {
|
||||
return _CoverImageNodeWidget(
|
||||
key: context.node.key,
|
||||
node: context.node,
|
||||
editorState: context.editorState,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
NodeValidator<Node> get nodeValidator => (node) {
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
class _CoverImageNodeWidget extends StatefulWidget {
|
||||
const _CoverImageNodeWidget({
|
||||
Key? key,
|
||||
required this.node,
|
||||
required this.editorState,
|
||||
}) : super(key: key);
|
||||
|
||||
final Node node;
|
||||
final EditorState editorState;
|
||||
|
||||
@override
|
||||
State<_CoverImageNodeWidget> createState() => _CoverImageNodeWidgetState();
|
||||
}
|
||||
|
||||
class _CoverImageNodeWidgetState extends State<_CoverImageNodeWidget> {
|
||||
CoverSelectionType get selectionType => CoverSelectionType.fromString(
|
||||
widget.node.attributes[kCoverSelectionTypeAttribute],
|
||||
);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (selectionType == CoverSelectionType.initial) {
|
||||
return _AddCoverButton(
|
||||
onTap: () {
|
||||
_insertCover(CoverSelectionType.asset, builtInAssetImages.first);
|
||||
},
|
||||
);
|
||||
} else {
|
||||
return _CoverImage(
|
||||
editorState: widget.editorState,
|
||||
node: widget.node,
|
||||
onCoverChanged: (type, value) {
|
||||
_insertCover(type, value);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _insertCover(CoverSelectionType type, dynamic cover) async {
|
||||
final transaction = widget.editorState.transaction;
|
||||
transaction.updateNode(widget.node, {
|
||||
kCoverSelectionTypeAttribute: type.toString(),
|
||||
kCoverSelectionAttribute: cover,
|
||||
});
|
||||
return widget.editorState.apply(transaction);
|
||||
}
|
||||
}
|
||||
|
||||
class _AddCoverButton extends StatefulWidget {
|
||||
const _AddCoverButton({
|
||||
required this.onTap,
|
||||
});
|
||||
|
||||
final VoidCallback onTap;
|
||||
|
||||
@override
|
||||
State<_AddCoverButton> createState() => _AddCoverButtonState();
|
||||
}
|
||||
|
||||
class _AddCoverButtonState extends State<_AddCoverButton> {
|
||||
bool isHidden = true;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MouseRegion(
|
||||
onEnter: (event) {
|
||||
setHidden(false);
|
||||
},
|
||||
onExit: (event) {
|
||||
setHidden(true);
|
||||
},
|
||||
child: Container(
|
||||
height: 50.0,
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.only(top: 20, bottom: 5),
|
||||
// color: Colors.red,
|
||||
child: isHidden
|
||||
? const SizedBox()
|
||||
: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
// Add Cover Button.
|
||||
FlowyButton(
|
||||
leftIconSize: const Size.square(18),
|
||||
onTap: widget.onTap,
|
||||
useIntrinsicWidth: true,
|
||||
leftIcon: svgWidget(
|
||||
'editor/image',
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
text: FlowyText.regular(
|
||||
LocaleKeys.document_plugins_cover_addCover.tr(),
|
||||
),
|
||||
)
|
||||
// Add Icon Button.
|
||||
// ...
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void setHidden(bool value) {
|
||||
if (isHidden == value) return;
|
||||
setState(() {
|
||||
isHidden = value;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class _CoverImage extends StatefulWidget {
|
||||
const _CoverImage({
|
||||
required this.editorState,
|
||||
required this.node,
|
||||
required this.onCoverChanged,
|
||||
});
|
||||
|
||||
final Node node;
|
||||
final EditorState editorState;
|
||||
final Function(
|
||||
CoverSelectionType selectionType,
|
||||
dynamic selection,
|
||||
) onCoverChanged;
|
||||
|
||||
@override
|
||||
State<_CoverImage> createState() => _CoverImageState();
|
||||
}
|
||||
|
||||
class _CoverImageState extends State<_CoverImage> {
|
||||
final popoverController = PopoverController();
|
||||
|
||||
CoverSelectionType get selectionType => CoverSelectionType.fromString(
|
||||
widget.node.attributes[kCoverSelectionTypeAttribute],
|
||||
);
|
||||
Color get color =>
|
||||
Color(int.tryParse(widget.node.attributes[kCoverSelectionAttribute]) ??
|
||||
0xFFFFFFFF);
|
||||
|
||||
bool isOverlayButtonsHidden = true;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(
|
||||
children: [
|
||||
_buildCoverImage(context),
|
||||
_buildCoverOverlayButtons(context),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCoverOverlayButtons(BuildContext context) {
|
||||
return Positioned(
|
||||
bottom: 22,
|
||||
right: 12,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
AppFlowyPopover(
|
||||
offset: const Offset(-125, 10),
|
||||
controller: popoverController,
|
||||
direction: PopoverDirection.bottomWithCenterAligned,
|
||||
constraints: BoxConstraints.loose(const Size(380, 450)),
|
||||
margin: EdgeInsets.zero,
|
||||
child: RoundedTextButton(
|
||||
onPressed: () {
|
||||
popoverController.show();
|
||||
},
|
||||
hoverColor: Theme.of(context).colorScheme.surface,
|
||||
textColor: Theme.of(context).colorScheme.onSurface,
|
||||
fillColor: Theme.of(context).colorScheme.surface.withOpacity(0.8),
|
||||
width: 120,
|
||||
height: 28,
|
||||
title: LocaleKeys.document_plugins_cover_changeCover.tr(),
|
||||
),
|
||||
popupBuilder: (BuildContext popoverContext) {
|
||||
return ChangeCoverPopover(
|
||||
node: widget.node,
|
||||
editorState: widget.editorState,
|
||||
onCoverChanged: widget.onCoverChanged,
|
||||
);
|
||||
},
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
FlowyIconButton(
|
||||
fillColor: Theme.of(context).colorScheme.surface.withOpacity(0.8),
|
||||
hoverColor: Theme.of(context).colorScheme.surface,
|
||||
iconPadding: const EdgeInsets.all(5),
|
||||
width: 28,
|
||||
icon: svgWidget(
|
||||
'editor/delete',
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
onPressed: () {
|
||||
widget.onCoverChanged(CoverSelectionType.initial, null);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCoverImage(BuildContext context) {
|
||||
final screenSize = MediaQuery.of(context).size;
|
||||
const height = 200.0;
|
||||
final Widget coverImage;
|
||||
switch (selectionType) {
|
||||
case CoverSelectionType.file:
|
||||
coverImage = Image.file(
|
||||
File(widget.node.attributes[kCoverSelectionAttribute]),
|
||||
fit: BoxFit.cover,
|
||||
);
|
||||
break;
|
||||
case CoverSelectionType.asset:
|
||||
coverImage = Image.asset(
|
||||
widget.node.attributes[kCoverSelectionAttribute],
|
||||
fit: BoxFit.cover,
|
||||
);
|
||||
break;
|
||||
case CoverSelectionType.color:
|
||||
coverImage = Container(
|
||||
decoration: BoxDecoration(
|
||||
color: color,
|
||||
borderRadius: Corners.s6Border,
|
||||
),
|
||||
alignment: Alignment.center,
|
||||
);
|
||||
break;
|
||||
case CoverSelectionType.initial:
|
||||
coverImage = const SizedBox(); // just an empty sizebox
|
||||
break;
|
||||
}
|
||||
return UnconstrainedBox(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.only(bottom: 10),
|
||||
height: height,
|
||||
width: screenSize.width,
|
||||
child: coverImage,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void setOverlayButtonsHidden(bool value) {
|
||||
if (isOverlayButtonsHidden == value) return;
|
||||
setState(() {
|
||||
isOverlayButtonsHidden = value;
|
||||
});
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user