mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
* feat: #1832 Support to import data from Markdown or Text to Document page * feat: #1832 Support to import data from Markdown or Text to Document page
This commit is contained in:
parent
592b918175
commit
2f803959e7
@ -44,7 +44,8 @@
|
|||||||
"small": "small",
|
"small": "small",
|
||||||
"medium": "medium",
|
"medium": "medium",
|
||||||
"large": "large",
|
"large": "large",
|
||||||
"fontSize": "Font Size"
|
"fontSize": "Font Size",
|
||||||
|
"import": "Import"
|
||||||
},
|
},
|
||||||
"disclosureAction": {
|
"disclosureAction": {
|
||||||
"rename": "Rename",
|
"rename": "Rename",
|
||||||
|
@ -6,4 +6,31 @@ class FilePicker implements FilePickerService {
|
|||||||
Future<String?> getDirectoryPath({String? title}) {
|
Future<String?> getDirectoryPath({String? title}) {
|
||||||
return fp.FilePicker.platform.getDirectoryPath();
|
return fp.FilePicker.platform.getDirectoryPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<FilePickerResult?> pickFiles(
|
||||||
|
{String? dialogTitle,
|
||||||
|
String? initialDirectory,
|
||||||
|
fp.FileType type = fp.FileType.any,
|
||||||
|
List<String>? allowedExtensions,
|
||||||
|
Function(fp.FilePickerStatus p1)? onFileLoading,
|
||||||
|
bool allowCompression = true,
|
||||||
|
bool allowMultiple = false,
|
||||||
|
bool withData = false,
|
||||||
|
bool withReadStream = false,
|
||||||
|
bool lockParentWindow = false}) async {
|
||||||
|
final result = await fp.FilePicker.platform.pickFiles(
|
||||||
|
dialogTitle: dialogTitle,
|
||||||
|
initialDirectory: initialDirectory,
|
||||||
|
type: type,
|
||||||
|
allowedExtensions: allowedExtensions,
|
||||||
|
onFileLoading: onFileLoading,
|
||||||
|
allowCompression: allowCompression,
|
||||||
|
allowMultiple: allowMultiple,
|
||||||
|
withData: withData,
|
||||||
|
withReadStream: withReadStream,
|
||||||
|
lockParentWindow: lockParentWindow,
|
||||||
|
);
|
||||||
|
return FilePickerResult(result?.files ?? []);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,4 +13,18 @@ abstract class FilePickerService {
|
|||||||
String? title,
|
String? title,
|
||||||
}) async =>
|
}) async =>
|
||||||
throw UnimplementedError('getDirectoryPath() has not been implemented.');
|
throw UnimplementedError('getDirectoryPath() has not been implemented.');
|
||||||
|
|
||||||
|
Future<FilePickerResult?> pickFiles({
|
||||||
|
String? dialogTitle,
|
||||||
|
String? initialDirectory,
|
||||||
|
FileType type = FileType.any,
|
||||||
|
List<String>? allowedExtensions,
|
||||||
|
Function(FilePickerStatus)? onFileLoading,
|
||||||
|
bool allowCompression = true,
|
||||||
|
bool allowMultiple = false,
|
||||||
|
bool withData = false,
|
||||||
|
bool withReadStream = false,
|
||||||
|
bool lockParentWindow = false,
|
||||||
|
}) async =>
|
||||||
|
throw UnimplementedError('pickFiles() has not been implemented.');
|
||||||
}
|
}
|
||||||
|
@ -102,6 +102,7 @@ class AppBloc extends Bloc<AppEvent, AppState> {
|
|||||||
dataFormatType: value.pluginBuilder.dataFormatType,
|
dataFormatType: value.pluginBuilder.dataFormatType,
|
||||||
pluginType: value.pluginBuilder.pluginType,
|
pluginType: value.pluginBuilder.pluginType,
|
||||||
layoutType: value.pluginBuilder.layoutType!,
|
layoutType: value.pluginBuilder.layoutType!,
|
||||||
|
initialData: value.initialData,
|
||||||
);
|
);
|
||||||
result.fold(
|
result.fold(
|
||||||
(view) => emit(state.copyWith(
|
(view) => emit(state.copyWith(
|
||||||
@ -140,6 +141,10 @@ class AppEvent with _$AppEvent {
|
|||||||
String name,
|
String name,
|
||||||
PluginBuilder pluginBuilder, {
|
PluginBuilder pluginBuilder, {
|
||||||
String? desc,
|
String? desc,
|
||||||
|
|
||||||
|
/// The initial data should be the JSON of the doucment
|
||||||
|
/// For example: {"document":{"type":"editor","children":[]}}
|
||||||
|
String? initialData,
|
||||||
}) = CreateView;
|
}) = CreateView;
|
||||||
const factory AppEvent.loadViews() = LoadApp;
|
const factory AppEvent.loadViews() = LoadApp;
|
||||||
const factory AppEvent.delete() = DeleteApp;
|
const factory AppEvent.delete() = DeleteApp;
|
||||||
|
@ -35,7 +35,9 @@ class AppService {
|
|||||||
..desc = desc ?? ""
|
..desc = desc ?? ""
|
||||||
..dataFormat = dataFormatType
|
..dataFormat = dataFormatType
|
||||||
..layout = layoutType
|
..layout = layoutType
|
||||||
..initialData = utf8.encode(initialData ?? "");
|
..initialData = utf8.encode(
|
||||||
|
initialData ?? "",
|
||||||
|
);
|
||||||
|
|
||||||
return FolderEventCreateView(payload).send();
|
return FolderEventCreateView(payload).send();
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,22 @@
|
|||||||
|
import 'package:app_flowy/plugins/document/document.dart';
|
||||||
import 'package:app_flowy/startup/plugin/plugin.dart';
|
import 'package:app_flowy/startup/plugin/plugin.dart';
|
||||||
|
import 'package:app_flowy/startup/startup.dart';
|
||||||
|
import 'package:app_flowy/workspace/presentation/home/menu/app/header/import/import_panel.dart';
|
||||||
import 'package:app_flowy/workspace/presentation/widgets/pop_up_action.dart';
|
import 'package:app_flowy/workspace/presentation/widgets/pop_up_action.dart';
|
||||||
|
import 'package:appflowy_editor/appflowy_editor.dart' show Document;
|
||||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||||
import 'package:flowy_infra/image.dart';
|
import 'package:flowy_infra/image.dart';
|
||||||
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
|
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
import 'package:app_flowy/generated/locale_keys.g.dart';
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
|
||||||
class AddButton extends StatelessWidget {
|
class AddButton extends StatelessWidget {
|
||||||
final Function(PluginBuilder) onSelected;
|
final Function(
|
||||||
|
PluginBuilder,
|
||||||
|
Document? document,
|
||||||
|
) onSelected;
|
||||||
|
|
||||||
const AddButton({
|
const AddButton({
|
||||||
Key? key,
|
Key? key,
|
||||||
@ -17,6 +26,8 @@ class AddButton extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final List<PopoverAction> actions = [];
|
final List<PopoverAction> actions = [];
|
||||||
|
|
||||||
|
// Plugins
|
||||||
actions.addAll(
|
actions.addAll(
|
||||||
pluginBuilders()
|
pluginBuilders()
|
||||||
.map((pluginBuilder) =>
|
.map((pluginBuilder) =>
|
||||||
@ -24,6 +35,16 @@ class AddButton extends StatelessWidget {
|
|||||||
.toList(),
|
.toList(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Import
|
||||||
|
actions.addAll(
|
||||||
|
getIt<PluginSandbox>()
|
||||||
|
.builders
|
||||||
|
.whereType<DocumentPluginBuilder>()
|
||||||
|
.map((pluginBuilder) =>
|
||||||
|
ImportActionWrapper(pluginBuilder: pluginBuilder))
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
|
|
||||||
return PopoverActionList<PopoverAction>(
|
return PopoverActionList<PopoverAction>(
|
||||||
direction: PopoverDirection.bottomWithLeftAligned,
|
direction: PopoverDirection.bottomWithLeftAligned,
|
||||||
actions: actions,
|
actions: actions,
|
||||||
@ -39,9 +60,16 @@ class AddButton extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
onSelected: (action, controller) {
|
onSelected: (action, controller) {
|
||||||
if (action is AddButtonActionWrapper) {
|
if (action is AddButtonActionWrapper) {
|
||||||
onSelected(action.pluginBuilder);
|
onSelected(action.pluginBuilder, null);
|
||||||
|
}
|
||||||
|
if (action is ImportActionWrapper) {
|
||||||
|
showImportPanel(context, (document) {
|
||||||
|
if (document == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
onSelected(action.pluginBuilder, document);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
controller.close();
|
controller.close();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -60,3 +88,20 @@ class AddButtonActionWrapper extends ActionCell {
|
|||||||
@override
|
@override
|
||||||
String get name => pluginBuilder.menuName;
|
String get name => pluginBuilder.menuName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ImportActionWrapper extends ActionCell {
|
||||||
|
final DocumentPluginBuilder pluginBuilder;
|
||||||
|
|
||||||
|
ImportActionWrapper({
|
||||||
|
required this.pluginBuilder,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget? leftIcon(Color iconColor) => svgWidget(
|
||||||
|
'editor/import',
|
||||||
|
color: iconColor,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get name => LocaleKeys.moreAction_import.tr();
|
||||||
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:app_flowy/workspace/presentation/widgets/dialogs.dart';
|
import 'package:app_flowy/workspace/presentation/widgets/dialogs.dart';
|
||||||
import 'package:app_flowy/workspace/presentation/widgets/pop_up_action.dart';
|
import 'package:app_flowy/workspace/presentation/widgets/pop_up_action.dart';
|
||||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||||
@ -104,11 +106,13 @@ class MenuAppHeader extends StatelessWidget {
|
|||||||
message: LocaleKeys.menuAppHeader_addPageTooltip.tr(),
|
message: LocaleKeys.menuAppHeader_addPageTooltip.tr(),
|
||||||
textStyle: AFThemeExtension.of(context).caption.textColor(Colors.white),
|
textStyle: AFThemeExtension.of(context).caption.textColor(Colors.white),
|
||||||
child: AddButton(
|
child: AddButton(
|
||||||
onSelected: (pluginBuilder) {
|
onSelected: (pluginBuilder, document) {
|
||||||
context.read<AppBloc>().add(
|
context.read<AppBloc>().add(
|
||||||
AppEvent.createView(
|
AppEvent.createView(
|
||||||
LocaleKeys.menuAppHeader_defaultNewPageName.tr(),
|
LocaleKeys.menuAppHeader_defaultNewPageName.tr(),
|
||||||
pluginBuilder,
|
pluginBuilder,
|
||||||
|
initialData:
|
||||||
|
document != null ? jsonEncode(document.toJson()) : '',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -0,0 +1,144 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:app_flowy/startup/startup.dart';
|
||||||
|
import 'package:app_flowy/util/file_picker/file_picker_service.dart';
|
||||||
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||||
|
import 'package:file_picker/file_picker.dart';
|
||||||
|
import 'package:flowy_infra/image.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/container.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:app_flowy/generated/locale_keys.g.dart';
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
|
||||||
|
typedef ImportCallback = void Function(Document? document);
|
||||||
|
|
||||||
|
Future<void> showImportPanel(
|
||||||
|
BuildContext context,
|
||||||
|
ImportCallback callback,
|
||||||
|
) async {
|
||||||
|
await showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: FlowyText.semibold(
|
||||||
|
LocaleKeys.moreAction_import.tr(),
|
||||||
|
fontSize: 20,
|
||||||
|
),
|
||||||
|
content: _ImportPanel(importCallback: callback),
|
||||||
|
contentPadding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 10.0,
|
||||||
|
horizontal: 20.0,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum _ImportType {
|
||||||
|
markdownOrText;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
switch (this) {
|
||||||
|
case _ImportType.markdownOrText:
|
||||||
|
return 'Text & Markdown';
|
||||||
|
default:
|
||||||
|
assert(false, 'Unsupported Type ${this}');
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget? get icon {
|
||||||
|
switch (this) {
|
||||||
|
case _ImportType.markdownOrText:
|
||||||
|
return svgWidget('editor/documents');
|
||||||
|
default:
|
||||||
|
assert(false, 'Unsupported Type ${this}');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> get allowedExtensions {
|
||||||
|
switch (this) {
|
||||||
|
case _ImportType.markdownOrText:
|
||||||
|
return ['md', 'txt'];
|
||||||
|
default:
|
||||||
|
assert(false, 'Unsupported Type ${this}');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ImportPanel extends StatefulWidget {
|
||||||
|
const _ImportPanel({
|
||||||
|
required this.importCallback,
|
||||||
|
});
|
||||||
|
|
||||||
|
final ImportCallback importCallback;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<_ImportPanel> createState() => _ImportPanelState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ImportPanelState extends State<_ImportPanel> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final width = MediaQuery.of(context).size.width * 0.7;
|
||||||
|
final height = width * 0.5;
|
||||||
|
return FlowyContainer(
|
||||||
|
Theme.of(context).colorScheme.surface,
|
||||||
|
height: height,
|
||||||
|
width: width,
|
||||||
|
child: GridView.count(
|
||||||
|
childAspectRatio: 1 / .2,
|
||||||
|
crossAxisCount: 2,
|
||||||
|
children: _ImportType.values.map(
|
||||||
|
(e) {
|
||||||
|
return Card(
|
||||||
|
child: FlowyButton(
|
||||||
|
leftIcon: e.icon,
|
||||||
|
leftIconSize: const Size.square(20),
|
||||||
|
text: FlowyText.medium(
|
||||||
|
e.toString(),
|
||||||
|
fontSize: 15,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
onTap: () async {
|
||||||
|
await _importFile(e);
|
||||||
|
if (mounted) {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
).toList(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _importFile(_ImportType importType) async {
|
||||||
|
final result = await getIt<FilePickerService>().pickFiles(
|
||||||
|
allowMultiple: false,
|
||||||
|
type: FileType.custom,
|
||||||
|
allowedExtensions: importType.allowedExtensions,
|
||||||
|
);
|
||||||
|
if (result == null || result.files.isEmpty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final path = result.files.single.path!;
|
||||||
|
final plainText = await File(path).readAsString();
|
||||||
|
|
||||||
|
switch (importType) {
|
||||||
|
case _ImportType.markdownOrText:
|
||||||
|
final document = markdownToDocument(plainText);
|
||||||
|
widget.importCallback(document);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(false, 'Unsupported Type $importType');
|
||||||
|
widget.importCallback(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -156,8 +156,8 @@ class EditorState {
|
|||||||
_applyRules(ruleCount);
|
_applyRules(ruleCount);
|
||||||
if (withUpdateCursor) {
|
if (withUpdateCursor) {
|
||||||
await updateCursorSelection(transaction.afterSelection);
|
await updateCursorSelection(transaction.afterSelection);
|
||||||
completer.complete();
|
|
||||||
}
|
}
|
||||||
|
completer.complete();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (options.recordUndo) {
|
if (options.recordUndo) {
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:intl/message_lookup_by_library.dart';
|
import 'package:intl/message_lookup_by_library.dart';
|
||||||
import 'package:intl/src/intl_helpers.dart';
|
import 'package:intl/src/intl_helpers.dart';
|
||||||
@ -41,28 +40,28 @@ import 'messages_zh-TW.dart' as messages_zh_tw;
|
|||||||
|
|
||||||
typedef Future<dynamic> LibraryLoader();
|
typedef Future<dynamic> LibraryLoader();
|
||||||
Map<String, LibraryLoader> _deferredLibraries = {
|
Map<String, LibraryLoader> _deferredLibraries = {
|
||||||
'bn_BN': () => new SynchronousFuture(null),
|
'bn_BN': () => new Future.value(null),
|
||||||
'ca': () => new SynchronousFuture(null),
|
'ca': () => new Future.value(null),
|
||||||
'cs_CZ': () => new SynchronousFuture(null),
|
'cs_CZ': () => new Future.value(null),
|
||||||
'de_DE': () => new SynchronousFuture(null),
|
'de_DE': () => new Future.value(null),
|
||||||
'en': () => new SynchronousFuture(null),
|
'en': () => new Future.value(null),
|
||||||
'es_VE': () => new SynchronousFuture(null),
|
'es_VE': () => new Future.value(null),
|
||||||
'fr_CA': () => new SynchronousFuture(null),
|
'fr_CA': () => new Future.value(null),
|
||||||
'fr_FR': () => new SynchronousFuture(null),
|
'fr_FR': () => new Future.value(null),
|
||||||
'hi_IN': () => new SynchronousFuture(null),
|
'hi_IN': () => new Future.value(null),
|
||||||
'hu_HU': () => new SynchronousFuture(null),
|
'hu_HU': () => new Future.value(null),
|
||||||
'id_ID': () => new SynchronousFuture(null),
|
'id_ID': () => new Future.value(null),
|
||||||
'it_IT': () => new SynchronousFuture(null),
|
'it_IT': () => new Future.value(null),
|
||||||
'ja_JP': () => new SynchronousFuture(null),
|
'ja_JP': () => new Future.value(null),
|
||||||
'ml_IN': () => new SynchronousFuture(null),
|
'ml_IN': () => new Future.value(null),
|
||||||
'nl_NL': () => new SynchronousFuture(null),
|
'nl_NL': () => new Future.value(null),
|
||||||
'pl_PL': () => new SynchronousFuture(null),
|
'pl_PL': () => new Future.value(null),
|
||||||
'pt_BR': () => new SynchronousFuture(null),
|
'pt_BR': () => new Future.value(null),
|
||||||
'pt_PT': () => new SynchronousFuture(null),
|
'pt_PT': () => new Future.value(null),
|
||||||
'ru_RU': () => new SynchronousFuture(null),
|
'ru_RU': () => new Future.value(null),
|
||||||
'tr_TR': () => new SynchronousFuture(null),
|
'tr_TR': () => new Future.value(null),
|
||||||
'zh_CN': () => new SynchronousFuture(null),
|
'zh_CN': () => new Future.value(null),
|
||||||
'zh_TW': () => new SynchronousFuture(null),
|
'zh_TW': () => new Future.value(null),
|
||||||
};
|
};
|
||||||
|
|
||||||
MessageLookupByLibrary? _findExact(String localeName) {
|
MessageLookupByLibrary? _findExact(String localeName) {
|
||||||
@ -117,18 +116,18 @@ MessageLookupByLibrary? _findExact(String localeName) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// User programs should call this before using [localeName] for messages.
|
/// User programs should call this before using [localeName] for messages.
|
||||||
Future<bool> initializeMessages(String localeName) {
|
Future<bool> initializeMessages(String localeName) async {
|
||||||
var availableLocale = Intl.verifiedLocale(
|
var availableLocale = Intl.verifiedLocale(
|
||||||
localeName, (locale) => _deferredLibraries[locale] != null,
|
localeName, (locale) => _deferredLibraries[locale] != null,
|
||||||
onFailure: (_) => null);
|
onFailure: (_) => null);
|
||||||
if (availableLocale == null) {
|
if (availableLocale == null) {
|
||||||
return new SynchronousFuture(false);
|
return new Future.value(false);
|
||||||
}
|
}
|
||||||
var lib = _deferredLibraries[availableLocale];
|
var lib = _deferredLibraries[availableLocale];
|
||||||
lib == null ? new SynchronousFuture(false) : lib();
|
await (lib == null ? new Future.value(false) : lib());
|
||||||
initializeInternalMessageLookup(() => new CompositeMessageLookup());
|
initializeInternalMessageLookup(() => new CompositeMessageLookup());
|
||||||
messageLookup.addLocale(availableLocale, _findGeneratedMessagesFor);
|
messageLookup.addLocale(availableLocale, _findGeneratedMessagesFor);
|
||||||
return new SynchronousFuture(true);
|
return new Future.value(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _messagesExistFor(String locale) {
|
bool _messagesExistFor(String locale) {
|
||||||
|
@ -21,6 +21,7 @@ class FlowyButton extends StatelessWidget {
|
|||||||
final bool useIntrinsicWidth;
|
final bool useIntrinsicWidth;
|
||||||
final bool disable;
|
final bool disable;
|
||||||
final double disableOpacity;
|
final double disableOpacity;
|
||||||
|
final Size? leftIconSize;
|
||||||
|
|
||||||
const FlowyButton({
|
const FlowyButton({
|
||||||
Key? key,
|
Key? key,
|
||||||
@ -37,6 +38,7 @@ class FlowyButton extends StatelessWidget {
|
|||||||
this.useIntrinsicWidth = false,
|
this.useIntrinsicWidth = false,
|
||||||
this.disable = false,
|
this.disable = false,
|
||||||
this.disableOpacity = 0.5,
|
this.disableOpacity = 0.5,
|
||||||
|
this.leftIconSize = const Size.square(16),
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -65,7 +67,11 @@ class FlowyButton extends StatelessWidget {
|
|||||||
|
|
||||||
if (leftIcon != null) {
|
if (leftIcon != null) {
|
||||||
children.add(
|
children.add(
|
||||||
SizedBox.fromSize(size: const Size.square(16), child: leftIcon!));
|
SizedBox.fromSize(
|
||||||
|
size: leftIconSize,
|
||||||
|
child: leftIcon!,
|
||||||
|
),
|
||||||
|
);
|
||||||
children.add(const HSpace(6));
|
children.add(const HSpace(6));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user