feat: added font choosing for android
This commit is contained in:
parent
5e20c582e6
commit
27b4992817
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
WYSIWYG editor for Android and JavaFX with a rich set of supported formatting options.
|
WYSIWYG editor for Android and JavaFX with a rich set of supported formatting options.
|
||||||
|
|
||||||
Based on https://github.com/dankito/RichTextEditor, but but for Flutter.
|
Based on https://github.com/dankito/RichTextEditor, but for Flutter.
|
||||||
|
|
||||||
## ✨ Features
|
## ✨ Features
|
||||||
- [x] Bold, Italic, Underline, Strike through, Subscript, Superscript
|
- [x] Bold, Italic, Underline, Strike through, Subscript, Superscript
|
||||||
|
@ -427,6 +427,13 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.1.1"
|
version: "5.1.1"
|
||||||
|
xml2json:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: xml2json
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "5.2.0"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=2.13.0 <3.0.0"
|
dart: ">=2.13.0 <3.0.0"
|
||||||
flutter: ">=2.0.0"
|
flutter: ">=2.0.0"
|
||||||
|
21
lib/src/models/alias.dart
Normal file
21
lib/src/models/alias.dart
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
class Alias {
|
||||||
|
String? name;
|
||||||
|
String? to;
|
||||||
|
String? weight;
|
||||||
|
|
||||||
|
Alias({this.name, this.to, this.weight});
|
||||||
|
|
||||||
|
Alias.fromJson(Map<String, dynamic> json) {
|
||||||
|
name = json['name'];
|
||||||
|
to = json['to'];
|
||||||
|
weight = json['weight'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||||
|
data['name'] = this.name;
|
||||||
|
data['to'] = this.to;
|
||||||
|
data['weight'] = this.weight;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
27
lib/src/models/config.dart
Normal file
27
lib/src/models/config.dart
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import 'package:rich_editor/src/models/alias.dart';
|
||||||
|
|
||||||
|
import 'family.dart';
|
||||||
|
|
||||||
|
class Config {
|
||||||
|
String? version;
|
||||||
|
List<Family>? families;
|
||||||
|
List<Alias>? aliases;
|
||||||
|
|
||||||
|
Config({this.version, this.families, this.aliases});
|
||||||
|
|
||||||
|
Config.fromJson(Map<String, dynamic> json) {
|
||||||
|
version = json['version'];
|
||||||
|
if (json['family'] != null) {
|
||||||
|
families = <Family>[];
|
||||||
|
json['family'].forEach((v) {
|
||||||
|
families!.add(new Family.fromJson(v));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (json['alias'] != null) {
|
||||||
|
aliases = <Alias>[];
|
||||||
|
json['alias'].forEach((v) {
|
||||||
|
aliases!.add(new Alias.fromJson(v));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,13 +3,28 @@ import 'package:rich_editor/src/models/enum.dart';
|
|||||||
import 'command_state.dart';
|
import 'command_state.dart';
|
||||||
|
|
||||||
class EditorState {
|
class EditorState {
|
||||||
bool didHtmlChange;
|
bool? didHtmlChange;
|
||||||
String html;
|
String? html;
|
||||||
Map<CommandName, CommandState> commandStates;
|
Map<CommandName, CommandState>? commandStates;
|
||||||
|
|
||||||
EditorState({
|
EditorState({
|
||||||
this.didHtmlChange = false,
|
this.didHtmlChange = false,
|
||||||
this.html = '',
|
this.html = '',
|
||||||
this.commandStates = const <CommandName, CommandState>{},
|
this.commandStates = const <CommandName, CommandState>{},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
EditorState.fromJson(Map<String, dynamic> json) {
|
||||||
|
didHtmlChange = json['didHtmlChange'];
|
||||||
|
html = json['html'];
|
||||||
|
commandStates = json['commandStates'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||||
|
data['didHtmlChange'] = this.didHtmlChange;
|
||||||
|
data['html'] = this.html;
|
||||||
|
data['commandStates'] = this.commandStates;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
36
lib/src/models/family.dart
Normal file
36
lib/src/models/family.dart
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import 'font.dart';
|
||||||
|
|
||||||
|
class Family {
|
||||||
|
String? name;
|
||||||
|
List<Font>? fonts;
|
||||||
|
String? lang;
|
||||||
|
String? variant;
|
||||||
|
|
||||||
|
Family({this.name, this.fonts, this.lang, this.variant});
|
||||||
|
|
||||||
|
Family.fromJson(Map<String, dynamic> json) {
|
||||||
|
name = json['name'];
|
||||||
|
if (json['font'] != null) {
|
||||||
|
fonts = <Font>[];
|
||||||
|
if(json['font'] is List) {
|
||||||
|
json['font'].forEach((v) {
|
||||||
|
fonts!.add(new Font.fromJson(v));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
lang = json['lang'];
|
||||||
|
variant = json['variant'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||||
|
data['name'] = this.name;
|
||||||
|
if (this.fonts != null) {
|
||||||
|
data['font'] = this.fonts!.map((v) => v.toJson()).toList();
|
||||||
|
}
|
||||||
|
data['lang'] = this.lang;
|
||||||
|
data['variant'] = this.variant;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
60
lib/src/models/font.dart
Normal file
60
lib/src/models/font.dart
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
class Font {
|
||||||
|
String? weight;
|
||||||
|
String? style;
|
||||||
|
String? t;
|
||||||
|
String? fallbackFor;
|
||||||
|
Axis? axis;
|
||||||
|
String? index;
|
||||||
|
|
||||||
|
Font(
|
||||||
|
{this.weight,
|
||||||
|
this.style,
|
||||||
|
this.t,
|
||||||
|
this.fallbackFor,
|
||||||
|
this.axis,
|
||||||
|
this.index});
|
||||||
|
|
||||||
|
Font.fromJson(Map<String, dynamic> json) {
|
||||||
|
weight = json['weight'];
|
||||||
|
style = json['style'];
|
||||||
|
t = json[r'$t'];
|
||||||
|
fallbackFor = json['fallbackFor'];
|
||||||
|
if (json['axis'] is Map) {
|
||||||
|
axis = json['axis'] != null ? new Axis.fromJson(json['axis']) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
index = json['index'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||||
|
data['weight'] = this.weight;
|
||||||
|
data['style'] = this.style;
|
||||||
|
data[r'$t'] = this.t;
|
||||||
|
data['fallbackFor'] = this.fallbackFor;
|
||||||
|
if (this.axis != null) {
|
||||||
|
data['axis'] = this.axis!.toJson();
|
||||||
|
}
|
||||||
|
data['index'] = this.index;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Axis {
|
||||||
|
String? tag;
|
||||||
|
String? stylevalue;
|
||||||
|
|
||||||
|
Axis({this.tag, this.stylevalue});
|
||||||
|
|
||||||
|
Axis.fromJson(Map<String, dynamic> json) {
|
||||||
|
tag = json['tag'];
|
||||||
|
stylevalue = json['stylevalue'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||||
|
data['tag'] = this.tag;
|
||||||
|
data['stylevalue'] = this.stylevalue;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
9
lib/src/models/system_font.dart
Normal file
9
lib/src/models/system_font.dart
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
class SystemFont {
|
||||||
|
String? name;
|
||||||
|
String? path;
|
||||||
|
|
||||||
|
SystemFont(String name, String path) {
|
||||||
|
this.name = name;
|
||||||
|
this.path = path;
|
||||||
|
}
|
||||||
|
}
|
101
lib/src/utils/font_list_parser.dart
Normal file
101
lib/src/utils/font_list_parser.dart
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:rich_editor/src/models/alias.dart';
|
||||||
|
import 'package:rich_editor/src/models/config.dart';
|
||||||
|
import 'package:rich_editor/src/models/family.dart';
|
||||||
|
import 'package:rich_editor/src/models/font.dart';
|
||||||
|
import 'package:rich_editor/src/models/system_font.dart';
|
||||||
|
import 'package:xml2json/xml2json.dart';
|
||||||
|
|
||||||
|
// A simple port of FontListParser from Java to Kotlin
|
||||||
|
// See https://stackoverflow.com/a/29533686/10835183
|
||||||
|
class FontListParser {
|
||||||
|
File androidFontsFile = File("/system/etc/fonts.xml");
|
||||||
|
File androidSystemFontsFile = File("/system/etc/system_fonts.xml");
|
||||||
|
|
||||||
|
List<SystemFont> getSystemFonts() {
|
||||||
|
String fontsXml;
|
||||||
|
if (androidFontsFile.existsSync()) {
|
||||||
|
fontsXml = androidFontsFile.path;
|
||||||
|
} else if (androidSystemFontsFile.existsSync()) {
|
||||||
|
fontsXml = androidSystemFontsFile.path;
|
||||||
|
} else {
|
||||||
|
throw ("fonts.xml does not exist on this system");
|
||||||
|
}
|
||||||
|
Xml2Json xml2json = new Xml2Json();
|
||||||
|
xml2json.parse(File(fontsXml).readAsStringSync());
|
||||||
|
Map json = jsonDecode(xml2json.toGData());
|
||||||
|
Config parser = Config.fromJson(json['familyset']);
|
||||||
|
List<SystemFont> fonts = <SystemFont>[];
|
||||||
|
|
||||||
|
for (Family family in parser.families!) {
|
||||||
|
if (family.name != null) {
|
||||||
|
Font font = Font();
|
||||||
|
for (Font f in family.fonts!) {
|
||||||
|
font = f;
|
||||||
|
if (int.tryParse(f.weight!) == 400) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SystemFont systemFont = new SystemFont(family.name!, font.t ?? '');
|
||||||
|
if (fonts.contains(systemFont)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
fonts.add(new SystemFont(family.name!, font.t ?? ''));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Alias alias in parser.aliases!) {
|
||||||
|
if (alias.name == null ||
|
||||||
|
alias.to == null ||
|
||||||
|
int.tryParse(alias.weight ?? '') == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (Family family in parser.families!) {
|
||||||
|
if (family.name == null || family.name! == alias.to) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (Font font in family.fonts!) {
|
||||||
|
if (font.weight == alias.weight) {
|
||||||
|
fonts.add(new SystemFont(alias.name!, font.t ?? ''));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fonts.isEmpty) {
|
||||||
|
throw Exception("No system fonts found.");
|
||||||
|
}
|
||||||
|
// fonts
|
||||||
|
// print(fonts);
|
||||||
|
return fonts;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<SystemFont> safelyGetSystemFonts() {
|
||||||
|
try {
|
||||||
|
return getSystemFonts();
|
||||||
|
} catch (e) {
|
||||||
|
List<List> defaultSystemFonts = [
|
||||||
|
["cursive", "DancingScript-Regular.ttf"],
|
||||||
|
["monospace", "DroidSansMono.ttf"],
|
||||||
|
["sans-serif", "Roboto-Regular.ttf"],
|
||||||
|
["sans-serif-light" "Roboto-Light.ttf"],
|
||||||
|
["sans-serif-medium", "Roboto-Medium.ttf"],
|
||||||
|
["sans-serif-black", "Roboto-Black.ttf"],
|
||||||
|
["sans-serif-condensed", "RobotoCondensed-Regular.ttf"],
|
||||||
|
["sans-serif-thin", "Roboto-Thin.ttf"],
|
||||||
|
["serif", "NotoSerif-Regular.ttf"]
|
||||||
|
];
|
||||||
|
List<SystemFont> fonts = <SystemFont>[];
|
||||||
|
for (List names in defaultSystemFonts) {
|
||||||
|
File file = new File("/system/fonts/"+ names[1]);
|
||||||
|
if (file.existsSync()) {
|
||||||
|
fonts.add(new SystemFont(names[0], file.path));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fonts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,8 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:rich_editor/src/extensions/extensions.dart';
|
import 'package:rich_editor/src/extensions/extensions.dart';
|
||||||
|
import 'package:rich_editor/src/models/editor_state.dart';
|
||||||
import 'package:rich_editor/src/models/enum.dart';
|
import 'package:rich_editor/src/models/enum.dart';
|
||||||
import 'package:webview_flutter/webview_flutter.dart';
|
import 'package:webview_flutter/webview_flutter.dart';
|
||||||
|
|
||||||
@ -15,6 +18,7 @@ class JavascriptExecutorBase {
|
|||||||
String defaultEncoding = "UTF-8";
|
String defaultEncoding = "UTF-8";
|
||||||
|
|
||||||
String? htmlField = "";
|
String? htmlField = "";
|
||||||
|
var didHtmlChange = false;
|
||||||
Map<CommandName, CommandState> commandStates = {};
|
Map<CommandName, CommandState> commandStates = {};
|
||||||
|
|
||||||
init(WebViewController controller) {
|
init(WebViewController controller) {
|
||||||
@ -196,4 +200,88 @@ class JavascriptExecutorBase {
|
|||||||
static encodeHtml(String html) {
|
static encodeHtml(String html) {
|
||||||
return Uri.encodeFull(html);
|
return Uri.encodeFull(html);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// bool shouldOverrideUrlLoading(String url) {
|
||||||
|
// String decodedUrl;
|
||||||
|
// try {
|
||||||
|
// decodedUrl = decodeHtml(url);
|
||||||
|
// } catch (e) {
|
||||||
|
// // No handling
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (url.indexOf(editorStateChangedCallbackScheme) == 0) {
|
||||||
|
// editorStateChanged(
|
||||||
|
// decodedUrl.substring(editorStateChangedCallbackScheme.length));
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// editorStateChanged(String statesString) {
|
||||||
|
// try {
|
||||||
|
// var editorState = EditorState.fromJson(jsonDecode(statesString));
|
||||||
|
//
|
||||||
|
// bool currentHtmlChanged = this.htmlField != editorState.html;
|
||||||
|
// this.htmlField = editorState.html;
|
||||||
|
//
|
||||||
|
// retrievedEditorState(editorState.didHtmlChange, editorState.commandStates)
|
||||||
|
//
|
||||||
|
// if (currentHtmlChanged) {
|
||||||
|
// fireHtmlChangedListenersAsync(editorState.html);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// catch (e) {
|
||||||
|
// throw("Could not parse command states: $statesString $e");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// retrievedEditorState(bool didHtmlChange,
|
||||||
|
// Map<CommandName, CommandState> commandStates) {
|
||||||
|
// if (this.didHtmlChange != didHtmlChange) {
|
||||||
|
// this.didHtmlChange = didHtmlChange;
|
||||||
|
// didHtmlChangeListeners.forEach {
|
||||||
|
// it.didHtmlChange(didHtmlChange);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// handleRetrievedCommandStates(commandStates)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// handleRetrievedCommandStates(Map<CommandName, CommandState> commandStates) {
|
||||||
|
// determineDerivedCommandStates(commandStates)
|
||||||
|
//
|
||||||
|
// this.commandStates = commandStates;
|
||||||
|
//
|
||||||
|
// commandStatesChangedListeners.forEach {
|
||||||
|
// it.invoke(this.commandStates)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// determineDerivedCommandStates(Map<CommandName, CommandState> commandStates) {
|
||||||
|
// commandStates[CommandName.FORMATBLOCK]?.let { formatCommandState ->
|
||||||
|
// commandStates.put(CommandName.H1, CommandState(formatCommandState.executable, isFormatActivated(formatCommandState, "h1")))
|
||||||
|
// commandStates.put(CommandName.H2, CommandState(formatCommandState.executable, isFormatActivated(formatCommandState, "h2")))
|
||||||
|
// commandStates.put(CommandName.H3, CommandState(formatCommandState.executable, isFormatActivated(formatCommandState, "h3")))
|
||||||
|
// commandStates.put(CommandName.H4, CommandState(formatCommandState.executable, isFormatActivated(formatCommandState, "h4")))
|
||||||
|
// commandStates.put(CommandName.H5, CommandState(formatCommandState.executable, isFormatActivated(formatCommandState, "h5")))
|
||||||
|
// commandStates.put(CommandName.H6, CommandState(formatCommandState.executable, isFormatActivated(formatCommandState, "h6")))
|
||||||
|
// commandStates.put(CommandName.P, CommandState(formatCommandState.executable, isFormatActivated(formatCommandState, "p")))
|
||||||
|
// commandStates.put(CommandName.PRE, CommandState(formatCommandState.executable, isFormatActivated(formatCommandState, "pre")))
|
||||||
|
// commandStates.put(CommandName.BR, CommandState(formatCommandState.executable, isFormatActivated(formatCommandState, "")))
|
||||||
|
// commandStates.put(CommandName.BLOCKQUOTE, CommandState(formatCommandState.executable, isFormatActivated(formatCommandState, "blockquote")))
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// commandStates[CommandName.INSERTHTML]?.let { insertHtmlState ->
|
||||||
|
// commandStates.put(CommandName.INSERTLINK, insertHtmlState)
|
||||||
|
// commandStates.put(CommandName.INSERTIMAGE, insertHtmlState)
|
||||||
|
// commandStates.put(CommandName.INSERTCHECKBOX, insertHtmlState)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// String isFormatActivated(CommandState formatCommandState, String format) {
|
||||||
|
// return (formatCommandState.value == format)
|
||||||
|
// .toString(); // rich_text_editor.js reports boolean values as string, so we also have to convert it to string
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
@ -177,11 +177,16 @@ class EditorToolBar extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
TabButton(
|
// TODO: Show font button on iOS
|
||||||
|
Visibility(
|
||||||
|
visible: Platform.isAndroid,
|
||||||
|
child: TabButton(
|
||||||
tooltip: 'Font face',
|
tooltip: 'Font face',
|
||||||
icon: Icons.font_download,
|
icon: Icons.font_download,
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
_closeKeyboard();
|
Directory fontsDir = Directory("/system/fonts/");
|
||||||
|
File file = File('/system/etc/fonts.xml');
|
||||||
|
// debugPrint(await file.readAsString());
|
||||||
var command = await showDialog(
|
var command = await showDialog(
|
||||||
// isScrollControlled: true,
|
// isScrollControlled: true,
|
||||||
context: context,
|
context: context,
|
||||||
@ -193,6 +198,7 @@ class EditorToolBar extends StatelessWidget {
|
|||||||
await javascriptExecutorBase.setFontName(command);
|
await javascriptExecutorBase.setFontName(command);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
),
|
||||||
TabButton(
|
TabButton(
|
||||||
icon: Icons.format_size,
|
icon: Icons.format_size,
|
||||||
tooltip: 'Font Size',
|
tooltip: 'Font Size',
|
||||||
|
@ -1,17 +1,15 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_html/flutter_html.dart';
|
import 'package:flutter_html/flutter_html.dart';
|
||||||
|
import 'package:path/path.dart';
|
||||||
|
import 'package:rich_editor/src/models/system_font.dart';
|
||||||
|
import 'package:rich_editor/src/utils/font_list_parser.dart';
|
||||||
|
|
||||||
class FontsDialog extends StatelessWidget {
|
class FontsDialog extends StatelessWidget {
|
||||||
List fonts = [
|
List<SystemFont> getSystemFonts() {
|
||||||
{
|
return FontListParser().getSystemFonts();
|
||||||
'id': 'cursive',
|
|
||||||
'title': '<p style="font-family:cursive">This is a paragraph.</p>'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'id': 'monospace',
|
|
||||||
'title': '<p style="font-family:monospace">This is a paragraph.</p>'
|
|
||||||
}
|
}
|
||||||
];
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -21,14 +19,23 @@ class FontsDialog extends StatelessWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
for (Map font in fonts)
|
for (SystemFont font in getSystemFonts())
|
||||||
InkWell(
|
InkWell(
|
||||||
child: Html(data: font['title']),
|
child: Html(data: '<p style="font-family:${font.name}">'
|
||||||
onTap: () => Navigator.pop(context, font['id']),
|
'${basename(font.path!)}</p>'),
|
||||||
|
onTap: () => Navigator.pop(context, font.path),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fontSlug(FileSystemEntity font) {
|
||||||
|
String name = basename(font.path);
|
||||||
|
String slug = name.toLowerCase();
|
||||||
|
slug = slug.replaceAll(extension(font.path), '');
|
||||||
|
// print(slug);
|
||||||
|
return slug;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -220,7 +220,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
path:
|
path:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: path
|
name: path
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
@ -420,6 +420,13 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.1.1"
|
version: "5.1.1"
|
||||||
|
xml2json:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: xml2json
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "5.2.0"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=2.13.0 <3.0.0"
|
dart: ">=2.13.0 <3.0.0"
|
||||||
flutter: ">=2.0.0"
|
flutter: ">=2.0.0"
|
||||||
|
@ -15,6 +15,8 @@ dependencies:
|
|||||||
image_picker: ^0.7.5+3
|
image_picker: ^0.7.5+3
|
||||||
flutter_html: ^2.0.0
|
flutter_html: ^2.0.0
|
||||||
flutter_colorpicker: ^0.4.0
|
flutter_colorpicker: ^0.4.0
|
||||||
|
path: ^1.8.0
|
||||||
|
xml2json: ^5.2.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
Loading…
Reference in New Issue
Block a user