UI changes dashboard

This commit is contained in:
Surendiran 2025-05-28 17:17:51 +05:30
commit 154f18a59b
9 changed files with 764 additions and 254 deletions

View File

@ -1,8 +1,19 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application <application
android:label="frontend" android:label="frontend"
android:name="${applicationName}" android:name="${applicationName}"
android:icon="@mipmap/ic_launcher"> android:icon="@mipmap/ic_launcher">
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true" >
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:exported="true" android:exported="true"
@ -30,6 +41,8 @@
<meta-data <meta-data
android:name="flutterEmbedding" android:name="flutterEmbedding"
android:value="2" /> android:value="2" />
</application> </application>
<!-- Required to query activities that can process text, see: <!-- Required to query activities that can process text, see:
https://developer.android.com/training/package-visibility and https://developer.android.com/training/package-visibility and

View File

@ -5,6 +5,7 @@
<!-- Show a splash screen on the activity. Automatically removed when <!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame --> the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item> <item name="android:windowBackground">@drawable/launch_background</item>
</style> </style>
<!-- Theme applied to the Android Window as soon as the process has started. <!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your This theme determines the color of the Android Window while your
@ -15,4 +16,7 @@
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar"> <style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item> <item name="android:windowBackground">?android:colorBackground</item>
</style> </style>
<paths>
<cache-path name="cache" path="." />
</paths>
</resources> </resources>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<cache-path name="cache" path="." />
<external-path name="external" path="." />
<!-- You can add more paths as needed -->
</paths>

View File

@ -0,0 +1,244 @@
import 'dart:convert';
import 'dart:io' as io show Directory, File;
import 'package:flutter_quill/flutter_quill.dart' hide Text;
import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart' hide Text;
import 'package:flutter_quill_extensions/flutter_quill_extensions.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_quill/flutter_quill_internal.dart';
import 'package:flutter_quill/quill_delta.dart';
import 'package:flutter_quill_extensions/flutter_quill_extensions.dart';
import 'package:frontend/Screens/myTemplates/quill_delta_sample.dart';
import 'package:go_router/go_router.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:path/path.dart' as path;
import 'package:responsive_builder/responsive_builder.dart';
import '../../routes/custom_appBar.dart';
import '../../routes/custom_drawer.dart';
import '../../services/apiService.dart';
import '../../utils/auth_utils.dart';
import '../../widgets/custom_user_travel.dart';
class Template extends StatefulWidget {
final Map<String, dynamic>? templateData;
const Template({super.key, required this.templateData});
static Template fromState(GoRouterState state) {
return Template(templateData: state.extra as Map<String, dynamic>?);
}
@override
TemplateState createState() => TemplateState();
}
class TemplateState extends State<Template> {
final ApiService apiService = ApiService();
// final QuillController _controller = QuillController.basic();
Color layoutColor = Colors.redAccent;
Color bodyColor = Colors.white;
final Map<String, TextEditingController> controllers = {};
List<String> dataHeader = ["subject"];
Map<String, dynamic> get TemplateData {
final data = {
// "org_id": orgId;
"template_name": controllers["templateName"]?.text,
"subject": controllers["subject"]?.text,
"body_html": controllers["bodyData"]?.text,
"placeholder": [],
// "created_by": userId
};
// Only add group_id if it's an edit operation
// if (widget.templateData != null && widget.templateData!.containsKey('group_id')) {
// data["template_id"] = templateData;
// }
return data;
}
@override
void initState() {
super.initState();
for (var field in dataHeader) {
controllers[field] = TextEditingController();
}
updateData();
loadInitialData();
}
@override
// void dispose() {
// // controllers.dispose();
// // _editorScrollController.dispose();
// _editorFocusNode.dispose();
// super.dispose();
// }
void loadInitialData() async {
String? layoutString = await getLayoutColor();
String? bodyStringColor = await getBodyColor();
setState(() {
layoutColor = layoutString != null
? Color(int.parse(layoutString))
: Colors.redAccent;
bodyColor = bodyStringColor != null
? Color(int.parse(bodyStringColor))
: Colors.white;
});
}
Future<void> updateData() async {
// Ensure apiselectedUser is not null before printing
if (widget.templateData != null) {
print("API Selected User Has Data - ${widget.templateData}");
print(
"API Selected User Has - ${widget.templateData?["templateData"]?["subject"]}");
setState(() {
// ✅ Wrap in setState to update the UI
controllers["subject"]?.text =
widget.templateData?["templateData"]?["subject"] ?? "";
// if (widget.group?["international_policy_id"] != null) {
// selectedInternational =
// widget.group!["international_policy_id"].toString();
// }
});
} else {
print("API Selected User Has Data - No data available yet");
}
}
@override
Widget build(BuildContext context) {
return ResponsiveBuilder(builder: (context, sizingInfo) {
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
return Scaffold(
backgroundColor: const Color(0xFFf5f5f5),
appBar: CustomAppBar(isDesktop: isDesktop),
drawer: CustomDrawer(isDesktop: false),
body: Padding(
padding: isDesktop
? EdgeInsets.symmetric(
horizontal: MediaQuery.of(context).size.width *
0.1, // 30% of screen width as horizontal padding
vertical: MediaQuery.of(context).size.height *
0, // 5% of screen height as vertical padding
)
: EdgeInsets.all(0),
child: Row(
children: [
// if (isDesktop) CustomDrawer(isDesktop: true),
Expanded(
child: buildUserTable(
isDesktop, context, bodyColor, layoutColor)),
],
),
),
);
});
}
Widget buildUserTable(
bool isDesktop, context, Color? bodyColor, Color layoutColor) {
return Container(
margin: isDesktop ? const EdgeInsets.only(top: 10.0, bottom: 10.0) : null,
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: isDesktop ? Colors.white : Color(0xFFFCFCFC),
),
child: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text("Editor"),
SizedBox(
height: 20,
),
buildTempalteSubject(isDesktop),
IconButton(
icon: const Icon(Icons.output),
tooltip: 'Print Delta JSON to log',
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content: Text(
'The JSON Delta has been printed to the console.')));
},
),
SizedBox(
height: 20,
),
buildTempalteBody(isDesktop)
],
),
),
);
}
Widget buildTempalteSubject(bool isDesktop) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Subject",
style: GoogleFonts.poppins(
fontSize: 12, fontWeight: FontWeight.w400, color: Colors.black),
),
SizedBox(height: 5),
CustomTextFieldUserTravellerWrapper(
isFocused: false,
isDesktop: isDesktop,
child: SizedBox(
height: 40,
child: TextField(
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
controller: controllers["subject"],
onChanged: (value) {
// _clearError("local_id_num");
},
decoration: InputDecoration(
labelText: "enter the subject",
labelStyle:
GoogleFonts.poppins(fontSize: 12, color: Colors.grey),
floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(vertical: 16),
),
),
),
),
],
);
}
Widget buildTempalteBody(bool isDesktop) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Content",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w400,
color: Colors.black,
),
),
const SizedBox(height: 10),
],
);
}
}

482
lib/Screens/myTemplates/tem Normal file
View File

@ -0,0 +1,482 @@
import 'dart:convert';
import 'dart:io' as io show Directory, File;
import 'package:flutter_quill/flutter_quill.dart' hide Text;
import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart' hide Text;
import 'package:flutter_quill_extensions/flutter_quill_extensions.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_quill/flutter_quill_internal.dart';
import 'package:flutter_quill/quill_delta.dart';
import 'package:flutter_quill_extensions/flutter_quill_extensions.dart';
import 'package:frontend/Screens/myTemplates/quill_delta_sample.dart';
import 'package:go_router/go_router.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:path/path.dart' as path;
import 'package:responsive_builder/responsive_builder.dart';
import '../../routes/custom_appBar.dart';
import '../../routes/custom_drawer.dart';
import '../../services/apiService.dart';
import '../../utils/auth_utils.dart';
import '../../widgets/custom_user_travel.dart';
class Template extends StatefulWidget {
final Map<String, dynamic>? templateData;
const Template({super.key, required this.templateData});
static Template fromState(GoRouterState state) {
return Template(templateData: state.extra as Map<String, dynamic>?);
}
@override
TemplateState createState() => TemplateState();
}
class TemplateState extends State<Template> {
final ApiService apiService = ApiService();
final QuillController _controller = () {
return QuillController.basic(
config: QuillControllerConfig(
clipboardConfig: QuillClipboardConfig(
enableExternalRichPaste: true,
onImagePaste: (imageBytes) async {
if (kIsWeb) {
// Dart IO is unsupported on the web.
return null;
}
// Save the image somewhere and return the image URL that will be
// stored in the Quill Delta JSON (the document).
final newFileName =
'image-file-${DateTime.now().toIso8601String()}.png';
final newPath = path.join(
io.Directory.systemTemp.path,
newFileName,
);
final file = await io.File(
newPath,
).writeAsBytes(imageBytes, flush: true);
return file.path;
},
),
));
}();
final FocusNode _editorFocusNode = FocusNode();
final ScrollController _editorScrollController = ScrollController();
// final QuillController _controller = QuillController.basic();
Color layoutColor = Colors.redAccent;
Color bodyColor = Colors.white;
final Map<String, TextEditingController> controllers = {};
List<String> dataHeader = ["subject"];
Map<String, dynamic> get TemplateData {
final data = {
// "org_id": orgId;
"template_name": controllers["templateName"]?.text,
"subject": controllers["subject"]?.text,
"body_html": controllers["bodyData"]?.text,
"placeholder": [],
// "created_by": userId
};
// Only add group_id if it's an edit operation
// if (widget.templateData != null && widget.templateData!.containsKey('group_id')) {
// data["template_id"] = templateData;
// }
return data;
}
@override
void initState() {
super.initState();
for (var field in dataHeader) {
controllers[field] = TextEditingController();
}
WidgetsBinding.instance.addPostFrameCallback((_) {
_editorFocusNode.requestFocus(); // ✅ Ensure focus is requested
});
_controller.document = Document.fromJson(kQuillDefaultSample);
// _controller.document = Document.fromJson(kQuillDefaultSample);
// _controller.document = Document.fromJson();
// _controller.document.toPlainText();
// _controller.readOnly = false;
updateData();
loadInitialData();
}
@override
// void dispose() {
// // controllers.dispose();
// // _editorScrollController.dispose();
// _editorFocusNode.dispose();
// super.dispose();
// }
void dispose() {
_controller.dispose();
_editorScrollController.dispose();
_editorFocusNode.dispose();
super.dispose();
}
void loadInitialData() async {
String? layoutString = await getLayoutColor();
String? bodyStringColor = await getBodyColor();
setState(() {
layoutColor = layoutString != null
? Color(int.parse(layoutString))
: Colors.redAccent;
bodyColor = bodyStringColor != null
? Color(int.parse(bodyStringColor))
: Colors.white;
});
}
Future<void> updateData() async {
// Ensure apiselectedUser is not null before printing
if (widget.templateData != null) {
print("API Selected User Has Data - ${widget.templateData}");
print(
"API Selected User Has - ${widget.templateData?["templateData"]?["subject"]}");
setState(() {
// ✅ Wrap in setState to update the UI
controllers["subject"]?.text =
widget.templateData?["templateData"]?["subject"] ?? "";
// if (widget.group?["international_policy_id"] != null) {
// selectedInternational =
// widget.group!["international_policy_id"].toString();
// }
});
} else {
print("API Selected User Has Data - No data available yet");
}
}
@override
Widget build(BuildContext context) {
return ResponsiveBuilder(builder: (context, sizingInfo) {
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
return Scaffold(
backgroundColor: const Color(0xFFf5f5f5),
appBar: CustomAppBar(isDesktop: isDesktop),
drawer: CustomDrawer(isDesktop: false),
body: Padding(
padding: isDesktop
? EdgeInsets.symmetric(
horizontal: MediaQuery.of(context).size.width *
0.1, // 30% of screen width as horizontal padding
vertical: MediaQuery.of(context).size.height *
0, // 5% of screen height as vertical padding
)
: EdgeInsets.all(0),
child: Row(
children: [
// if (isDesktop) CustomDrawer(isDesktop: true),
Expanded(
child: buildUserTable(
isDesktop, context, bodyColor, layoutColor)),
],
),
),
);
});
}
Widget buildUserTable(
bool isDesktop, context, Color? bodyColor, Color layoutColor) {
return Container(
margin: isDesktop ? const EdgeInsets.only(top: 10.0, bottom: 10.0) : null,
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: isDesktop ? Colors.white : Color(0xFFFCFCFC),
),
child: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text("Editor"),
SizedBox(
height: 20,
),
buildTempalteSubject(isDesktop),
IconButton(
icon: const Icon(Icons.output),
tooltip: 'Print Delta JSON to log',
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content: Text(
'The JSON Delta has been printed to the console.')));
debugPrint(jsonEncode(_controller.document.toDelta().toJson()));
},
),
SizedBox(
height: 20,
),
buildTempalteBody(isDesktop)
],
),
),
);
}
Widget buildTempalteSubject(bool isDesktop) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Subject",
style: GoogleFonts.poppins(
fontSize: 12, fontWeight: FontWeight.w400, color: Colors.black),
),
SizedBox(height: 5),
CustomTextFieldUserTravellerWrapper(
isFocused: false,
isDesktop: isDesktop,
child: SizedBox(
height: 40,
child: TextField(
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
controller: controllers["subject"],
onChanged: (value) {
// _clearError("local_id_num");
},
decoration: InputDecoration(
labelText: "enter the subject",
labelStyle:
GoogleFonts.poppins(fontSize: 12, color: Colors.grey),
floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(vertical: 16),
),
),
),
),
],
);
}
Widget buildTempalteBody(bool isDesktop) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Content",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w400,
color: Colors.black,
),
),
const SizedBox(height: 10),
// Expanded(
//
// child: QuillEditor(
// focusNode: _editorFocusNode,
// scrollController: _editorScrollController,
// controller: _controller,
// config: QuillEditorConfig(
// placeholder: 'Start writing your notes...',
// padding: const EdgeInsets.all(16),
// embedBuilders: [
// ...FlutterQuillEmbeds.editorBuilders(
// imageEmbedConfig: QuillEditorImageEmbedConfig(
// imageProviderBuilder: (context, imageUrl) {
// // https://pub.dev/packages/flutter_quill_extensions#-image-assets
// if (imageUrl.startsWith('assets/')) {
// return AssetImage(imageUrl);
// }
// return null;
// },
// ),
// videoEmbedConfig: QuillEditorVideoEmbedConfig(
// customVideoBuilder: (videoUrl, readOnly) {
// // To load YouTube videos https://github.com/singerdmx/flutter-quill/releases/tag/v10.8.0
// return null;
// },
// ),
// ),
// TimeStampEmbedBuilder(),
// ],
// ),
// ),
// ),
// ✅ Modern toolbar
QuillSimpleToolbar(
controller: _controller,
config: QuillSimpleToolbarConfig(
embedButtons: FlutterQuillEmbeds.toolbarButtons(),
showClipboardPaste: true,
customButtons: [
QuillToolbarCustomButtonOptions(
icon: const Icon(Icons.add_alarm_rounded),
onPressed: () {
_controller.document.insert(
_controller.selection.extentOffset,
TimeStampEmbed(
DateTime.now().toString(),
),
);
_controller.readOnly = true;
_controller.updateSelection(
TextSelection.collapsed(
offset: _controller.selection.extentOffset + 1,
),
ChangeSource.local,
);
},
),
],
buttonOptions: QuillSimpleToolbarButtonOptions(
base: QuillToolbarBaseButtonOptions(
afterButtonPressed: () {
final isDesktop = {
TargetPlatform.linux,
TargetPlatform.windows,
TargetPlatform.macOS
}.contains(defaultTargetPlatform);
if (isDesktop) {
_editorFocusNode.requestFocus();
}
},
),
linkStyle: QuillToolbarLinkStyleButtonOptions(
validateLink: (link) {
// Treats all links as valid. When launching the URL,
// `https://` is prefixed if the link is incomplete (e.g., `google.com` → `https://google.com`)
// however this happens only within the editor.
return true;
},
),
),
),
),
const SizedBox(height: 10),
// // ✅ Modern editor
Container(
height: 200,
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(8),
),
child: QuillEditor(
focusNode: _editorFocusNode,
scrollController: _editorScrollController,
controller: _controller,
config: QuillEditorConfig(
placeholder: 'Start writing your notes...',
padding: const EdgeInsets.all(16),
embedBuilders: [
...FlutterQuillEmbeds.editorBuilders(
imageEmbedConfig: QuillEditorImageEmbedConfig(
imageProviderBuilder: (context, imageUrl) {
// https://pub.dev/packages/flutter_quill_extensions#-image-assets
if (imageUrl.startsWith('assets/')) {
return AssetImage(imageUrl);
}
return null;
},
),
videoEmbedConfig: QuillEditorVideoEmbedConfig(
customVideoBuilder: (videoUrl, readOnly) {
// To load YouTube videos https://github.com/singerdmx/flutter-quill/releases/tag/v10.8.0
return null;
},
),
),
TimeStampEmbedBuilder(),
],
),
),
),
// child: QuillEditor.basic(
// focusNode: _editorFocusNode,
// scrollController: _editorScrollController,
// controller: _controller,
// // readOnly: true,
// config: QuillEditorConfig(
// requestKeyboardFocusOnCheckListChanged: false,
// // readOnlyMouseCursor: SystemMouseCursors.text,
// enableScribble: true,
// // readOnly: false,
// padding: const EdgeInsets.all(8),
// placeholder: 'Type something...',
// embedBuilders: [
// ...FlutterQuillEmbeds.editorBuilders(
// imageEmbedConfig: QuillEditorImageEmbedConfig(
// imageProviderBuilder: (context, imageUrl) {
// // https://pub.dev/packages/flutter_quill_extensions#-image-assets
// if (imageUrl.startsWith('assets/')) {
// return AssetImage(imageUrl);
// }
// return null;
// },
// ),
// videoEmbedConfig: QuillEditorVideoEmbedConfig(
// customVideoBuilder: (videoUrl, readOnly) {
// // To load YouTube videos https://github.com/singerdmx/flutter-quill/releases/tag/v10.8.0
// return null;
// },
// ),
// ),
// TimeStampEmbedBuilder(),
// ],
// ),
// ),
],
);
}
}
class TimeStampEmbed extends Embeddable {
const TimeStampEmbed(
String value,
) : super(timeStampType, value);
static const String timeStampType = 'timeStamp';
static TimeStampEmbed fromDocument(Document document) =>
TimeStampEmbed(jsonEncode(document.toDelta().toJson()));
Document get document => Document.fromJson(jsonDecode(data));
}
class TimeStampEmbedBuilder extends EmbedBuilder {
@override
String get key => 'timeStamp';
@override
String toPlainText(Embed node) {
return node.value.data;
}
@override
Widget build(
BuildContext context,
EmbedContext embedContext,
) {
return Row(
children: [
const Icon(Icons.access_time_rounded),
Text(embedContext.node.value.data as String),
],
);
}
}

View File

@ -39,34 +39,7 @@ class Template extends StatefulWidget {
class TemplateState extends State<Template> { class TemplateState extends State<Template> {
final ApiService apiService = ApiService(); final ApiService apiService = ApiService();
final QuillController _controller = () {
return QuillController.basic(
config: QuillControllerConfig(
clipboardConfig: QuillClipboardConfig(
enableExternalRichPaste: true,
onImagePaste: (imageBytes) async {
if (kIsWeb) {
// Dart IO is unsupported on the web.
return null;
}
// Save the image somewhere and return the image URL that will be
// stored in the Quill Delta JSON (the document).
final newFileName =
'image-file-${DateTime.now().toIso8601String()}.png';
final newPath = path.join(
io.Directory.systemTemp.path,
newFileName,
);
final file = await io.File(
newPath,
).writeAsBytes(imageBytes, flush: true);
return file.path;
},
),
));
}();
final FocusNode _editorFocusNode = FocusNode();
final ScrollController _editorScrollController = ScrollController();
// final QuillController _controller = QuillController.basic(); // final QuillController _controller = QuillController.basic();
Color layoutColor = Colors.redAccent; Color layoutColor = Colors.redAccent;
Color bodyColor = Colors.white; Color bodyColor = Colors.white;
@ -99,14 +72,6 @@ class TemplateState extends State<Template> {
controllers[field] = TextEditingController(); controllers[field] = TextEditingController();
} }
WidgetsBinding.instance.addPostFrameCallback((_) {
_editorFocusNode.requestFocus(); // Ensure focus is requested
});
_controller.document = Document.fromJson(kQuillDefaultSample);
// _controller.document = Document.fromJson(kQuillDefaultSample);
// _controller.document = Document.fromJson();
// _controller.document.toPlainText();
// _controller.readOnly = false;
updateData(); updateData();
loadInitialData(); loadInitialData();
@ -120,13 +85,6 @@ class TemplateState extends State<Template> {
// super.dispose(); // super.dispose();
// } // }
void dispose() {
_controller.dispose();
_editorScrollController.dispose();
_editorFocusNode.dispose();
super.dispose();
}
void loadInitialData() async { void loadInitialData() async {
String? layoutString = await getLayoutColor(); String? layoutString = await getLayoutColor();
String? bodyStringColor = await getBodyColor(); String? bodyStringColor = await getBodyColor();
@ -219,7 +177,6 @@ class TemplateState extends State<Template> {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar( ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content: Text( content: Text(
'The JSON Delta has been printed to the console.'))); 'The JSON Delta has been printed to the console.')));
debugPrint(jsonEncode(_controller.document.toDelta().toJson()));
}, },
), ),
SizedBox( SizedBox(
@ -280,202 +237,7 @@ class TemplateState extends State<Template> {
color: Colors.black, color: Colors.black,
), ),
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
// Expanded(
//
// child: QuillEditor(
// focusNode: _editorFocusNode,
// scrollController: _editorScrollController,
// controller: _controller,
// config: QuillEditorConfig(
// placeholder: 'Start writing your notes...',
// padding: const EdgeInsets.all(16),
// embedBuilders: [
// ...FlutterQuillEmbeds.editorBuilders(
// imageEmbedConfig: QuillEditorImageEmbedConfig(
// imageProviderBuilder: (context, imageUrl) {
// // https://pub.dev/packages/flutter_quill_extensions#-image-assets
// if (imageUrl.startsWith('assets/')) {
// return AssetImage(imageUrl);
// }
// return null;
// },
// ),
// videoEmbedConfig: QuillEditorVideoEmbedConfig(
// customVideoBuilder: (videoUrl, readOnly) {
// // To load YouTube videos https://github.com/singerdmx/flutter-quill/releases/tag/v10.8.0
// return null;
// },
// ),
// ),
// TimeStampEmbedBuilder(),
// ],
// ),
// ),
// ),
// Modern toolbar
QuillSimpleToolbar(
controller: _controller,
config: QuillSimpleToolbarConfig(
embedButtons: FlutterQuillEmbeds.toolbarButtons(),
showClipboardPaste: true,
customButtons: [
QuillToolbarCustomButtonOptions(
icon: const Icon(Icons.add_alarm_rounded),
onPressed: () {
_controller.document.insert(
_controller.selection.extentOffset,
TimeStampEmbed(
DateTime.now().toString(),
),
);
_controller.readOnly = true;
_controller.updateSelection(
TextSelection.collapsed(
offset: _controller.selection.extentOffset + 1,
),
ChangeSource.local,
);
},
),
],
buttonOptions: QuillSimpleToolbarButtonOptions(
base: QuillToolbarBaseButtonOptions(
afterButtonPressed: () {
final isDesktop = {
TargetPlatform.linux,
TargetPlatform.windows,
TargetPlatform.macOS
}.contains(defaultTargetPlatform);
if (isDesktop) {
_editorFocusNode.requestFocus();
}
},
),
linkStyle: QuillToolbarLinkStyleButtonOptions(
validateLink: (link) {
// Treats all links as valid. When launching the URL,
// `https://` is prefixed if the link is incomplete (e.g., `google.com` `https://google.com`)
// however this happens only within the editor.
return true;
},
),
),
),
),
const SizedBox(height: 10),
// // Modern editor
Container(
height: 200,
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(8),
),
child: QuillEditor(
focusNode: _editorFocusNode,
scrollController: _editorScrollController,
controller: _controller,
config: QuillEditorConfig(
placeholder: 'Start writing your notes...',
padding: const EdgeInsets.all(16),
embedBuilders: [
...FlutterQuillEmbeds.editorBuilders(
imageEmbedConfig: QuillEditorImageEmbedConfig(
imageProviderBuilder: (context, imageUrl) {
// https://pub.dev/packages/flutter_quill_extensions#-image-assets
if (imageUrl.startsWith('assets/')) {
return AssetImage(imageUrl);
}
return null;
},
),
videoEmbedConfig: QuillEditorVideoEmbedConfig(
customVideoBuilder: (videoUrl, readOnly) {
// To load YouTube videos https://github.com/singerdmx/flutter-quill/releases/tag/v10.8.0
return null;
},
),
),
TimeStampEmbedBuilder(),
],
),
),
),
// child: QuillEditor.basic(
// focusNode: _editorFocusNode,
// scrollController: _editorScrollController,
// controller: _controller,
// // readOnly: true,
// config: QuillEditorConfig(
// requestKeyboardFocusOnCheckListChanged: false,
// // readOnlyMouseCursor: SystemMouseCursors.text,
// enableScribble: true,
// // readOnly: false,
// padding: const EdgeInsets.all(8),
// placeholder: 'Type something...',
// embedBuilders: [
// ...FlutterQuillEmbeds.editorBuilders(
// imageEmbedConfig: QuillEditorImageEmbedConfig(
// imageProviderBuilder: (context, imageUrl) {
// // https://pub.dev/packages/flutter_quill_extensions#-image-assets
// if (imageUrl.startsWith('assets/')) {
// return AssetImage(imageUrl);
// }
// return null;
// },
// ),
// videoEmbedConfig: QuillEditorVideoEmbedConfig(
// customVideoBuilder: (videoUrl, readOnly) {
// // To load YouTube videos https://github.com/singerdmx/flutter-quill/releases/tag/v10.8.0
// return null;
// },
// ),
// ),
// TimeStampEmbedBuilder(),
// ],
// ),
// ),
],
);
}
}
class TimeStampEmbed extends Embeddable {
const TimeStampEmbed(
String value,
) : super(timeStampType, value);
static const String timeStampType = 'timeStamp';
static TimeStampEmbed fromDocument(Document document) =>
TimeStampEmbed(jsonEncode(document.toDelta().toJson()));
Document get document => Document.fromJson(jsonDecode(data));
}
class TimeStampEmbedBuilder extends EmbedBuilder {
@override
String get key => 'timeStamp';
@override
String toPlainText(Embed node) {
return node.value.data;
}
@override
Widget build(
BuildContext context,
EmbedContext embedContext,
) {
return Row(
children: [
const Icon(Icons.access_time_rounded),
Text(embedContext.node.value.data as String),
], ],
); );
} }

View File

@ -780,7 +780,8 @@ class _PolicyState extends State<Policy> {
return Container( return Container(
margin: const EdgeInsets.only(top: 8.0), margin: const EdgeInsets.only(top: 8.0),
// color: Colors.white, // color: Colors.white,
height: isDesktop ? MediaQuery.of(context).size.height * 0.55 : null, height: isDesktop ? 350 : null,
// height: isDesktop ? MediaQuery.of(context).size.height * 0.55 : null,
// color: Colors.blueGrey.shade200, // color: Colors.blueGrey.shade200,
width: isDesktop ? MediaQuery.of(context).size.width * 0.15 : null, width: isDesktop ? MediaQuery.of(context).size.width * 0.15 : null,
decoration: BoxDecoration( decoration: BoxDecoration(
@ -966,11 +967,10 @@ class _PolicyState extends State<Policy> {
child: isDesktop child: isDesktop
? Container( ? Container(
// color: Colors.amber, // color: Colors.amber,
child: Expanded(
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [_buildPolicyServiceOrdering(isDesktop)], children: [_buildPolicyServiceOrdering(isDesktop)],
),
), ),
) )
: Container( : Container(
@ -995,7 +995,7 @@ class _PolicyState extends State<Policy> {
List<String> services = List<String> services =
ServicesChoosed!.map((service) => service['name'].toString()).toList(); ServicesChoosed!.map((service) => service['name'].toString()).toList();
return Expanded( return Container(
child: SingleChildScrollView( child: SingleChildScrollView(
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
child: Flex( child: Flex(

View File

@ -270,6 +270,11 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.3.2" version: "0.3.2"
flutter_quill:
git:
url: https://github.com/singerdmx/flutter-quill.git
ref: v11.4.1
flutter_localizations: flutter_localizations:
dependency: transitive dependency: transitive
description: flutter description: flutter
@ -283,14 +288,7 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.27" version: "2.0.27"
flutter_quill:
dependency: "direct main"
description:
name: flutter_quill
sha256: "7e60963632bbc8615627f0bae8e178515f69ecb378ad49fa68c43c2aabf33e21"
url: "https://pub.dev"
source: hosted
version: "11.4.1"
flutter_quill_delta_from_html: flutter_quill_delta_from_html:
dependency: transitive dependency: transitive
description: description:

View File

@ -54,6 +54,7 @@ dependencies:
flutter_quill_extensions: ^11.0.0 flutter_quill_extensions: ^11.0.0
flutter_localization: ^0.3.2 flutter_localization: ^0.3.2
reorderables: ^0.6.0 reorderables: ^0.6.0
html_editor_enhanced: ^1.8.0
dev_dependencies: dev_dependencies: