diff --git a/lib/ui/settings/email_settings.dart b/lib/ui/settings/email_settings.dart index fa558e3f4..7247c6f22 100644 --- a/lib/ui/settings/email_settings.dart +++ b/lib/ui/settings/email_settings.dart @@ -156,7 +156,7 @@ class _EmailSettingsState extends State label: localization.enableMarkup, helpLabel: localization.enableMarkupHelp, value: settings.enableEmailMarkup, - iconData: FontAwesomeIcons.envelope, + iconData: FontAwesomeIcons.solidEnvelope, showBlank: state.settingsUIState.isFiltered, onChanged: (value) => viewModel.onSettingsChanged( settings.rebuild((b) => b..enableEmailMarkup = value)), diff --git a/lib/ui/settings/templates_and_reminders.dart b/lib/ui/settings/templates_and_reminders.dart index ade2f24b5..f1d829f3b 100644 --- a/lib/ui/settings/templates_and_reminders.dart +++ b/lib/ui/settings/templates_and_reminders.dart @@ -1,10 +1,30 @@ +import 'dart:async'; +import 'dart:convert'; + import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:invoiceninja_flutter/ui/app/form_card.dart'; import 'package:invoiceninja_flutter/ui/app/forms/app_form.dart'; +import 'package:invoiceninja_flutter/ui/app/forms/decorated_form_field.dart'; import 'package:invoiceninja_flutter/ui/settings/settings_scaffold.dart'; import 'package:invoiceninja_flutter/ui/settings/templates_and_reminders_vm.dart'; import 'package:invoiceninja_flutter/utils/localization.dart'; -import 'package:invoiceninja_flutter/utils/platforms.dart'; +import 'package:webview_flutter/webview_flutter.dart'; + +const String kExamplePage = ''' + +Navigation Delegate Example + +

+The navigation delegate is set to block navigation to the youtube website. +

+ + + +'''; class TemplatesAndReminders extends StatefulWidget { const TemplatesAndReminders({ @@ -18,12 +38,10 @@ class TemplatesAndReminders extends StatefulWidget { _TemplatesAndRemindersState createState() => _TemplatesAndRemindersState(); } -class _TemplatesAndRemindersState extends State - with SingleTickerProviderStateMixin { +class _TemplatesAndRemindersState extends State { static final GlobalKey _formKey = GlobalKey(); FocusScopeNode _focusNode; - TabController _controller; bool autoValidate = false; @@ -35,13 +53,11 @@ class _TemplatesAndRemindersState extends State void initState() { super.initState(); _focusNode = FocusScopeNode(); - _controller = TabController(vsync: this, length: 7); } @override void dispose() { _focusNode.dispose(); - _controller.dispose(); _controllers.forEach((dynamic controller) { controller.removeListener(_onChanged); controller.dispose(); @@ -82,62 +98,148 @@ class _TemplatesAndRemindersState extends State final localization = AppLocalization.of(context); final viewModel = widget.viewModel; final state = viewModel.state; + final settings = viewModel.settings; + + final String contentBase64 = + base64Encode(const Utf8Encoder().convert(kExamplePage)); + final url = 'data:text/html;base64,$contentBase64'; + print('url: $url'); + return SettingsScaffold( title: localization.templatesAndReminders, onSavePressed: viewModel.onSavePressed, - appBarBottom: TabBar( - key: ValueKey(state.settingsUIState.updatedAt), - controller: _controller, - isScrollable: true, - tabs: [ - Tab( - text: localization.invoices, - ), - Tab( - text: localization.quotes, - ), - Tab( - text: localization.payments, - ), - Tab( - text: localization.firstReminder, - ), - Tab( - text: localization.secondReminder, - ), - Tab( - text: localization.thirdReminder, - ), - Tab( - text: localization.endlessReminder, - ), - ], - ), - body: AppTabForm( - tabController: _controller, - formKey: _formKey, - focusNode: _focusNode, + body: Column( children: [ - TemplateEditor(), - TemplateEditor(), - TemplateEditor(), - TemplateEditor(), - TemplateEditor(), - TemplateEditor(), - TemplateEditor(), + AppForm( + formKey: _formKey, + children: [ + FormCard( + children: [ + DecoratedFormField( + label: localization.subject, + //controller: _subjectController, + ), + DecoratedFormField( + label: localization.body, + //controller: _bodyController, + maxLines: 8, + ), + ], + ), + ], + ), + Expanded( + child: Padding( + padding: const EdgeInsets.all(15), + child: WebView( + initialUrl: url, + ), + ), + ), ], ), ); } } -class TemplateEditor extends StatelessWidget { +class TemplateEditor extends StatefulWidget { + const TemplateEditor({this.subject, this.body}); + + final String subject; + final String body; + + @override + _TemplateEditorState createState() => _TemplateEditorState(); +} + +class _TemplateEditorState extends State { + + final Completer _controller = + Completer(); + + final _subjectController = TextEditingController(); + final _bodyController = TextEditingController(); + + List _controllers = []; + + @override + void didChangeDependencies() { + _controllers = [ + _subjectController, + _bodyController, + ]; + + _controllers + .forEach((dynamic controller) => controller.removeListener(_onChanged)); + + _subjectController.text = widget.subject; + _bodyController.text = widget.body; + + _controllers + .forEach((dynamic controller) => controller.addListener(_onChanged)); + + super.didChangeDependencies(); + } + + @override + void dispose() { + _controllers.forEach((dynamic controller) { + controller.removeListener(_onChanged); + controller.dispose(); + }); + super.dispose(); + } + + void _onChanged() { + print('## CHANGED: ${_subjectController.text} - ${_bodyController.text}'); + /* + final product = widget.viewModel.product.rebuild((b) => b + ..customValue2 = _custom2Controller.text.trim()); + if (product != widget.viewModel.product) { + widget.viewModel.onChanged(product); + } + */ + } + @override Widget build(BuildContext context) { + final localization = AppLocalization.of(context); + return ListView( children: [ - Text('test') + FormCard( + children: [ + DecoratedFormField( + label: localization.subject, + controller: _subjectController, + ), + DecoratedFormField( + label: localization.body, + controller: _bodyController, + maxLines: 8, + ), + ], + ), + FormCard( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + WebView( + //initialUrl: url, + initialUrl: 'https://flutter.dev', + javascriptMode: JavascriptMode.unrestricted, + onWebViewCreated: (WebViewController webViewController) { + _controller.complete(webViewController); + }, + onPageFinished: (String url) { + print('Page finished loading: $url'); + }, + ), + Text('subject'), + SizedBox(height: 15), + Text('body'), + ], + ), ], ); } diff --git a/pubspec.lock b/pubspec.lock index ee1ca8723..489c60ec2 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -14,7 +14,7 @@ packages: name: analyzer_plugin url: "https://pub.dartlang.org" source: hosted - version: "0.1.0" + version: "0.2.1" args: dependency: transitive description: @@ -42,7 +42,7 @@ packages: name: build url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.2.1" build_config: dependency: transitive description: @@ -63,7 +63,7 @@ packages: name: build_resolvers url: "https://pub.dartlang.org" source: hosted - version: "1.1.1" + version: "1.2.1" build_runner: dependency: "direct dev" description: @@ -91,21 +91,21 @@ packages: name: built_value url: "https://pub.dartlang.org" source: hosted - version: "6.7.1" + version: "6.8.2" built_value_generator: dependency: "direct dev" description: name: built_value_generator url: "https://pub.dartlang.org" source: hosted - version: "6.7.1" + version: "6.8.2" cached_network_image: dependency: "direct main" description: name: cached_network_image url: "https://pub.dartlang.org" source: hosted - version: "1.1.1" + version: "1.1.2+1" charcode: dependency: transitive description: @@ -217,7 +217,7 @@ packages: name: fixnum url: "https://pub.dartlang.org" source: hosted - version: "0.10.9" + version: "0.10.11" flutter: dependency: "direct main" description: flutter @@ -229,7 +229,7 @@ packages: name: flutter_cache_manager url: "https://pub.dartlang.org" source: hosted - version: "1.1.1" + version: "1.1.3" flutter_colorpicker: dependency: "direct main" description: @@ -267,7 +267,7 @@ packages: name: flutter_slidable url: "https://pub.dartlang.org" source: hosted - version: "0.5.3" + version: "0.5.4" flutter_test: dependency: transitive description: flutter @@ -298,14 +298,14 @@ packages: name: glob url: "https://pub.dartlang.org" source: hosted - version: "1.1.7" + version: "1.2.0" google_sign_in: dependency: "direct main" description: name: google_sign_in url: "https://pub.dartlang.org" source: hosted - version: "4.0.7" + version: "4.0.11" graphs: dependency: transitive description: @@ -347,14 +347,14 @@ packages: name: image_picker url: "https://pub.dartlang.org" source: hosted - version: "0.6.1+4" + version: "0.6.1+10" in_app_purchase: dependency: "direct main" description: name: in_app_purchase url: "https://pub.dartlang.org" source: hosted - version: "0.2.1+4" + version: "0.2.2+2" intl: dependency: "direct main" description: @@ -453,6 +453,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.6.0" + node_interop: + dependency: transitive + description: + name: node_interop + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.3" + node_io: + dependency: transitive + description: + name: node_io + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1+2" node_preamble: dependency: transitive description: @@ -494,7 +508,7 @@ packages: name: path_provider url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.4.0" pedantic: dependency: transitive description: @@ -578,21 +592,21 @@ packages: name: sentry url: "https://pub.dartlang.org" source: hosted - version: "2.2.0" + version: "2.3.1" share: dependency: "direct main" description: name: share url: "https://pub.dartlang.org" source: hosted - version: "0.6.2+1" + version: "0.6.3+1" shared_preferences: dependency: "direct main" description: name: shared_preferences url: "https://pub.dartlang.org" source: hosted - version: "0.5.3+4" + version: "0.5.4+3" shelf: dependency: transitive description: @@ -660,7 +674,7 @@ packages: name: sqflite url: "https://pub.dartlang.org" source: hosted - version: "1.1.7" + version: "1.1.7+2" stack_trace: dependency: transitive description: @@ -744,7 +758,7 @@ packages: name: url_launcher url: "https://pub.dartlang.org" source: hosted - version: "5.1.4" + version: "5.2.1" usage: dependency: transitive description: @@ -787,6 +801,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.15" + webview_flutter: + dependency: "direct main" + description: + name: webview_flutter + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.15+1" yaml: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index b1c169da9..03db26e90 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -38,6 +38,7 @@ dependencies: native_pdf_renderer: any flutter_colorpicker: any flutter_json_widget: ^1.0.2 + webview_flutter: ^0.3.15+1 #quick_actions: ^0.2.1 dev_dependencies: