From 5d3e60064509b0e2ca7268d5d845829b0e0161be Mon Sep 17 00:00:00 2001 From: Ellet Date: Tue, 14 Nov 2023 12:15:15 +0300 Subject: [PATCH] Second step of remaking the example --- example/analysis_options.yaml | 4 + example/lib/logic/empty.dart | 0 example/lib/main.dart | 78 ++++++-- .../home/widgets/example_item.dart | 51 +++++ .../home/widgets/home_screen.dart | 120 +++++++++--- .../quill/quill_images_screen.dart | 102 ++++++++++ .../lib/presentation/quill/quill_screen.dart | 92 +++++++++ .../settings/cubit/settings_cubit.dart | 24 ++- .../cubit/settings_cubit.freezed.dart | 175 ++++++++++++++++++ .../settings/cubit/settings_cubit.g.dart | 36 ++++ .../settings/cubit/settings_state.dart | 21 ++- .../settings/widgets/settings_screen.dart | 105 +++++++++++ .../shared/widgets/dialog_action.dart | 63 +++++++ .../shared/widgets/home_screen_button.dart | 24 +++ .../Flutter/GeneratedPluginRegistrant.swift | 2 + example/pubspec.yaml | 14 ++ .../flutter/generated_plugin_registrant.cc | 3 + .../windows/flutter/generated_plugins.cmake | 1 + .../embeds/widgets/image_resizer.dart | 15 +- 19 files changed, 875 insertions(+), 55 deletions(-) create mode 100644 example/lib/logic/empty.dart create mode 100644 example/lib/presentation/home/widgets/example_item.dart create mode 100644 example/lib/presentation/quill/quill_images_screen.dart create mode 100644 example/lib/presentation/quill/quill_screen.dart create mode 100644 example/lib/presentation/settings/cubit/settings_cubit.freezed.dart create mode 100644 example/lib/presentation/settings/cubit/settings_cubit.g.dart create mode 100644 example/lib/presentation/shared/widgets/dialog_action.dart create mode 100644 example/lib/presentation/shared/widgets/home_screen_button.dart diff --git a/example/analysis_options.yaml b/example/analysis_options.yaml index d8d4bb89..735e0400 100644 --- a/example/analysis_options.yaml +++ b/example/analysis_options.yaml @@ -1,5 +1,9 @@ include: package:flutter_lints/flutter.yaml +analyzer: + errors: + invalid_annotation_target: ignore + linter: rules: always_declare_return_types: true diff --git a/example/lib/logic/empty.dart b/example/lib/logic/empty.dart new file mode 100644 index 00000000..e69de29b diff --git a/example/lib/main.dart b/example/lib/main.dart index 5aa625e8..d2fffc87 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,5 +1,6 @@ import 'package:flutter/foundation.dart' show kIsWeb; import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_localizations/flutter_localizations.dart' show GlobalCupertinoLocalizations, @@ -12,6 +13,9 @@ import 'package:path_provider/path_provider.dart' show getApplicationDocumentsDirectory; import 'presentation/home/widgets/home_screen.dart'; +import 'presentation/quill/quill_images_screen.dart'; +import 'presentation/settings/cubit/settings_cubit.dart'; +import 'presentation/settings/widgets/settings_screen.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -28,20 +32,68 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { - return MaterialApp( - title: 'Flutter Quill Demo', - theme: ThemeData.light(useMaterial3: true), - darkTheme: ThemeData.dark(useMaterial3: true), - themeMode: ThemeMode.system, - debugShowCheckedModeBanner: false, - localizationsDelegates: const [ - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, - FlutterQuillLocalizations.delegate, + return MultiBlocProvider( + providers: [ + BlocProvider( + create: (context) => SettingsCubit(), + ), ], - supportedLocales: FlutterQuillLocalizations.supportedLocales, - home: const HomePage(), + child: BlocBuilder( + builder: (context, state) { + return MaterialApp( + title: 'Flutter Quill Demo', + theme: ThemeData.light(useMaterial3: true), + darkTheme: ThemeData.dark(useMaterial3: true), + themeMode: state.themeMode, + debugShowCheckedModeBanner: false, + localizationsDelegates: const [ + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + FlutterQuillLocalizations.delegate, + ], + supportedLocales: FlutterQuillLocalizations.supportedLocales, + routes: { + SettingsScreen.routeName: (context) => const SettingsScreen(), + QuillImagesScreen.routeName: (context) => + const QuillImagesScreen(), + }, + home: Builder( + builder: (context) { + final screen = switch (state.defaultScreen) { + DefaultScreen.home => const HomePage(), + DefaultScreen.settings => const SettingsScreen(), + DefaultScreen.images => const QuillImagesScreen(), + DefaultScreen.videos => null, + DefaultScreen.text => null, + }; + return AnimatedSwitcher( + duration: const Duration(milliseconds: 330), + transitionBuilder: (child, animation) { + // This animation is from flutter.dev example + const begin = Offset(0, 1); + const end = Offset.zero; + const curve = Curves.ease; + + final tween = Tween( + begin: begin, + end: end, + ).chain( + CurveTween(curve: curve), + ); + + return SlideTransition( + position: animation.drive(tween), + child: child, + ); + }, + child: screen, + ); + }, + ), + ); + }, + ), ); } } diff --git a/example/lib/presentation/home/widgets/example_item.dart b/example/lib/presentation/home/widgets/example_item.dart new file mode 100644 index 00000000..91425491 --- /dev/null +++ b/example/lib/presentation/home/widgets/example_item.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +class HomeScreenExampleItem extends StatelessWidget { + const HomeScreenExampleItem({ + required this.title, + required this.icon, + required this.text, + required this.onPressed, + super.key, + }); + final String title; + final Widget icon; + final String text; + final VoidCallback onPressed; + + @override + Widget build(BuildContext context) { + return Column( + children: [ + SizedBox( + height: 200, + width: double.infinity, + child: GestureDetector( + onTap: onPressed, + child: Card( + child: Column( + children: [ + const SizedBox(height: 2), + Text( + title, + style: Theme.of(context).textTheme.titleLarge, + ), + const SizedBox(height: 8), + icon, + const SizedBox(height: 8), + Padding( + padding: const EdgeInsets.all(8), + child: Text( + text, + style: Theme.of(context).textTheme.bodyMedium, + ), + ), + ], + ), + ), + ), + ), + ], + ); + } +} diff --git a/example/lib/presentation/home/widgets/home_screen.dart b/example/lib/presentation/home/widgets/home_screen.dart index 3fa33dba..11718ad3 100644 --- a/example/lib/presentation/home/widgets/home_screen.dart +++ b/example/lib/presentation/home/widgets/home_screen.dart @@ -1,39 +1,111 @@ import 'package:flutter/material.dart'; import 'package:flutter_quill/flutter_quill.dart'; -class HomePage extends StatefulWidget { - const HomePage({super.key}); +import '../../quill/quill_images_screen.dart'; +import '../../quill/quill_screen.dart'; +import '../../settings/widgets/settings_screen.dart'; +import 'example_item.dart'; - @override - State createState() => _HomePageState(); -} +class HomePage extends StatelessWidget { + const HomePage({super.key}); -class _HomePageState extends State { - final _controller = QuillController.basic(); @override Widget build(BuildContext context) { - return QuillProvider( - configurations: QuillConfigurations( - controller: _controller, - sharedConfigurations: QuillSharedConfigurations( - animationConfigurations: QuillAnimationConfigurations.disableAll(), - ), + return Scaffold( + appBar: AppBar( + title: const Text('Flutter Quill Demo'), ), - child: Scaffold( - appBar: AppBar( - title: const Text('Flutter Quill Demo'), + drawer: Drawer( + child: ListView( + children: [ + const DrawerHeader( + child: Text( + 'Flutter Quill Demo', + ), + ), + ListTile( + title: const Text('Settings'), + leading: const Icon(Icons.settings), + onTap: () { + Navigator.of(context) + ..pop() + ..pushNamed(SettingsScreen.routeName); + }, + ), + ], ), - body: Column( + ), + body: SafeArea( + child: Column( children: [ - const QuillToolbar(), + SizedBox( + width: double.infinity, + child: Text( + 'Welcome to Flutter Quill Demo!', + style: Theme.of(context).textTheme.titleLarge, + textAlign: TextAlign.center, + ), + ), Expanded( - child: QuillEditor.basic( - configurations: const QuillEditorConfigurations( - scrollable: true, - padding: EdgeInsets.all(16), - ), + child: ListView( + padding: const EdgeInsets.all(16), + children: [ + HomeScreenExampleItem( + title: 'Images', + icon: const Icon( + Icons.image, + size: 50, + ), + text: 'If you want to see how the editor work with images, ' + 'see any samples or you are working on it', + onPressed: () { + Navigator.of(context) + .pushNamed(QuillImagesScreen.routeName); + }, + ), + const SizedBox(height: 4), + HomeScreenExampleItem( + title: 'Videos', + icon: const Icon( + Icons.video_chat, + size: 50, + ), + text: 'If you want to see how the editor work with videos, ' + 'see any samples or you are working on it', + onPressed: () {}, + ), + HomeScreenExampleItem( + title: 'Text', + icon: const Icon( + Icons.edit_document, + size: 50, + ), + text: 'If you want to see how the editor work with text, ' + 'see any samples or you are working on it', + onPressed: () {}, + ), + HomeScreenExampleItem( + title: 'Empty', + icon: const Icon( + Icons.insert_drive_file, + size: 50, + ), + text: 'Want start clean? be my guest', + onPressed: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) { + return QuillScreen( + document: Document(), + ); + }, + ), + ); + }, + ), + ], ), - ) + ), ], ), ), diff --git a/example/lib/presentation/quill/quill_images_screen.dart b/example/lib/presentation/quill/quill_images_screen.dart new file mode 100644 index 00000000..874ce37e --- /dev/null +++ b/example/lib/presentation/quill/quill_images_screen.dart @@ -0,0 +1,102 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_quill/flutter_quill.dart' show Document; + +import '../../gen/assets.gen.dart'; +import 'quill_screen.dart'; + +class QuillImagesScreen extends StatelessWidget { + const QuillImagesScreen({super.key}); + + static const routeName = '/images'; + + @override + Widget build(BuildContext context) { + return QuillScreen( + document: Document.fromJson(_sample), + ); + } +} + +final _sample = [ + {'insert': 'This is an asset image: \n'}, + {'insert': '\n'}, + { + 'insert': {'image': Assets.images.screenshot1.path}, + 'attributes': { + 'width': '100', + 'height': '100', + 'style': 'width:500px; height:350px;' + } + }, + {'insert': '\n'}, + {'insert': 'Here is a network image: \n'}, + {'insert': '\n'}, + { + 'insert': { + 'image': + 'https://helpx.adobe.com/content/dam/help/en/photoshop/using/convert-color-image-black-white/jcr_content/main-pars/before_and_after/image-before/Landscape-Color.jpg' + }, + 'attributes': { + 'width': '100', + 'height': '100', + 'style': 'width:250px; height:250px;' + } + }, + {'insert': '\n'}, + {'insert': '\n'}, + { + 'insert': + '\nThe image above have 250px width and height in the css style attribute which will be used for web, and 100 width and height that is in the attributes which will be used for desktop and mobile\n' + }, + {'insert': '\n'}, + { + 'insert': { + 'image': + '/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoHCBYWFRgWFRUYGRgaGBgYGhoYGBgaGhgYGBgaGRoaGBwcIS4lHB4rIRgYJjgmKy8xNTU1GiQ7QDszPy40NTEBDAwMEA8QHhISHjYkJCs0NDY2NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDY0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NP/AABEIALEBHQMBIgACEQEDEQH/xAAbAAACAwEBAQAAAAAAAAAAAAAAAwECBAUGB//EADkQAAEDAgMECAUEAgEFAAAAAAEAAhEDIQQxQRJRYXEFIlKBkaHR8BMUMpKxBmLB4ULxFSNTcoKy/8QAGQEAAwEBAQAAAAAAAAAAAAAAAAECAwQF/8QALBEAAgIBAwMDAwMFAAAAAAAAAAECESEDEjEEE0EiUWEUkaEFQnEVIzJSgf/aAAwDAQACEQMRAD8A+TseQpN10MRhHDNnG2ixERmFommaz05RdMvRiCD3KGUpMKWmcldpJysfymNU6GMoltyYniPwpczkfJUBn6s+Ofih7SDYqcmuEsLBDsONx9FmfSIW2lWj6itDgHCzxyMeR1RbXIu1GStcnKa4qWt1WmtRM6dxSmkixVowcWnTGPgwY4JlPDzeQBvKVKlgMyJQ0aJq8qxjxIIGnmsTwuiynORvySH0N+9JBOLeTLTNwVsfRsHaFIDIK30q7Q0sdkbtO47uRTeBacU7TwZDVgRqqHepqNl3imsp9XvhMVNuh+HEgjh/az1KUStNFhkAZgyr1GmTIzHkp4Zu47omN4BaL3iElqa9u5KGapGD5HFshIfktFHcqOYgJK1ZmhS0qXNVqQumjKslnsS015S4TG+SrwqkWTHBVcEEsoxspxsFNNh0HsqXsjNAVixGzK6WFbsQcoafNYmG40T31paecD1UtWaabUXYrEPkczKzhsprm2VC+ECbt2x9LE/+XirVagP0kcQshaQpISoruSqmSQRl4KzHb57lDHxvWho3T5ICKvgWDJzPemlh1mVX4aY185oLS9wps0KH0IyunhivVZZKzXZjJla+NEuJOa0ihItmqtokFO0Q4SxfAksK14XDTmmGNVJdIAGYRZpGEYu3kz4inExoYSmui575/K6TMPInyVquGaGzpqlfgrtN+pYOa9sxAPelOYVpa0tJbeFpp0AU7M9jkIwuGm58/wCEVeo4gQW5iOK14l+xZu6RwScMzbhuWg/vzQvcval6VyWwDuuHbuYCdiiCTExMzqTu5KcXR2C1g+odZ3hYK1KkC3NTjk3jFpPTOa+ne2SVVp3nRa8SyDAV6TAWOnfPkndKznencnEwMtdMYJlWNEjkmUYVMhRd0zDVaq0QnYkJTbBNGE1UijyrsbaUuJTn5QmSsiiqgKxCEyRzK2zlnP8ApJe6VRXSHbeC7W2JPD1VaTSfeQV3mx7o8FLGZjKw8SgpRyD2zkqupN3+Cs1si2iz1M1DLapcFmmc0MbHJUa5NaUyU7LVGRqDxCbQeB3pb3znf8qgJQXuUXaNNip+GlNctm1LRlMaT5pPBrGpcht2j+FQ3VXlRRdcfyihuWaY6ky8LUynNvBZ3G9vfehrzndQzaLSdF67IKZQbbcrE7Weau2mRCVmih6rXAtry0hVc8kxock0gG0KatMti3cFSYOLr4LYbCbTgHeJSq31m0AQO4WT2VpETBV6lPa628AH3vU27yabIyjUTDUp6xPFUw745rc2j1SLpDMMJmVUWZS0pJpo07W20PIuLHkq0KRBIBV8M/YJ/B13wtjmgwW5HPepbrB0RimrfPk5lTDEyTnuSmN2XQ+wIWikNp0HMT7CdicM0kck7rDMdm71ROdiARYXAy4hKczKE7EsLbbsuSJ6seCpcGMo3J2Z6tKVkqsW90xByWZzLxvKqJhqRRFLDHYL9xhKcF38RhtimG74PkuI5iIy3WVraHapPmhQbOSoWLbhmXuDAH+lmqG9lV5OZxxZnIVg1XayUx0JkJFWiZPJOpM2p4m/IKNieq3P8J9PqsIzvpGSiXBvpxzngQx+zI0IM/wsVXNNe8pClImc/CJhXaoa9MseCohEICtsHNDRGiodFgzJaGUjGnvcq0HgWcJB8uKY5kQJnOD7ySZrFJZK1WkC4SV12bIA2htNIAHWFjF1hq4W20zLmD+OSlM0np+UUY7Ja7EW9lYGv0hOpm9j4puIQnWDWam7vn0XQwtTaAkXGXsLl0XdbetzCBkBM2I3e96zlE7dGebbFOeWPuLTcLazZc4DaAERfPu3rFin3mb/AJVsMWky4kEZIatDjOpNeLNTsKAZE9xVWYgNgeI0jwVn4oCwOf53FVGH22yCJGlvGNVOa9Rs6v8At8j8RTBBdOYELNgLkx9Q0WukzZGzYgg7hHOLarDQGy8jI70ReGg1LUk6/kfVwpcXEC41Rh2FtnfTIGc+UBbMMyoTf6SDCc9jS2TbllPCMlDl4NVpJ+rhnCxDYeDMZ+/Na6WKcXfTtTYmMgq9I4cm4GXvNasBScGEbTTlkQfwSVo2nGzlhGS1XFY8nMxjNB7CzPqWjculjKUaQf4K5uzzTi8GWtBqTIgkC5KTk9vAhdLDt/aO9Z6jOsTG5WpGUtNqmdjpj6BG4fhee2F3cY8vptPALAGQMllo4R1dat8017IyYt4b1Wm035rCQn12GVWmxdEcI8qduVAynZVcxPcICq5ylyK7eBVNhBBORMKcTVnLkqPfKoQir5E5bVSEuUFqYWqibMKDZUwmQiEytpUEpnxJzUbKkNQNWXsck5rtPZWcNTBKdFpjHAxY23KaWKIscp00VFXYRVj3NO0aq8ZjXXLvWZ7NZlWAUtQo0De7kii4jVa2YrxWZwUBiGkxxlKOEbmO2hI8FRzt/wDrks7SU6m8ze6W00WpYmo4gxK34DFlptnHvvWasySltsbEEd/8hDimhRnKErTPSYfFMcQ2QHHKJA7wd6XisBBDjkezc9wWDBuBERff6LrPxQazYMHOSc44ELCUalg9OOvGcPUZamIa1ogm3+JPmpoVGPHWcZM2E7swuZiCCbJDHlpkEhadtNHM+rallWjqVq5HUfPppfgtuBwzXMlj+twtuXBq1HO6xJJOafgK7wYEj3qlKHpwEOoT1Latfk71TCy2XZ3EmMxoVi/407JLBN96s/H7DSJknfYepSMN0wWG3LK0ctVioS5R2S19JtKRjfIsQQQhhkR5r0FSm2o0HYAcdRMELmPwhHIajK/EJqSarhkvRae5O0Q1+0wNjXyUPa0y2chbitD6OwwkmIsD/iZ4ysNNhngBJPD3CItU6HqJ2k1yYK4lZnG601DJnjlqstYrTdg86cKbZDnKuatTpklMfSjNTuyPZJqxGyquTnMUFkK9xk4GchV2E5xVSEnJkbUP+Ej4S6LaKn5dPca9o5opKfhLpDDI+WT3i7LOcKasKa3/AC6t8snvH2mYRTU/CW8UEwUEbhrRZzhSR8FdIYZT8sjeHZZzfgqfhLpjDKlemGNLjojegek0rOd8NKfVa0wXCd2qw4npVzpDRsjK1z4rnc/evcpcznlJXg7jukGCZJJ4DNYqnSTjk0AeJWAqQJUObE5SkaW9JVBdro5AKW9JVZJ2iZEXgjwKQynKsKShyZSUvcsMbU7R7wPRWHSD5m3KLJfw1QsvmmpP3JcWb6PSejx3j0W3D9INNtqOdvNcEqQfeatTYlJxZ6Vjw+4O15pnwDuXmaFdzCHMMHf/AAdF6DorpX4jg14AJ1mJ7j/Ce9m+nOMnUuTp4LFuZbMbjuXZovY8yI2gL6G3fuuuY7DQhjSDr5rKUVLKPT0taWl6XlD+mLsERIzkZnS29c6oNmmLHrCSSD/AXcovEbTjJk2tPvJJxzWEWgxcczosVujivJ2PZO3aujy7i3Qgc80gtJPuy246BaPZSGUH5xA3n3daqR509P1Vz/A6kNgTqlCk5xlXpgzJPvlmnGTvjgIQmW43FLwZ30g3VZajwtb6RSvg3vbvVJnPOLeEqMoBOiNkrWSBkElz1VmLhR320kwUk8NRsrKzuUEJFJT8JODVcNRuL2Iz/CV20eCeGqwCW4agjP8ABV20Vpa1MYxTvKUEIZRVxh1paxPa0KXMtQRiGGXD/Vb9ilA2ZcYubxrsjU+q9UTC8r07+n31qwe02Ih0kAN2cgLE35FOEs5OfqYvY1FW2eNoYfavIA4mL896vTY3Xa2p1sLTY7jluyK19J4H4VQU3OB+klrZJAOgtnF0us9pAYGNadr6y51hFg4kx6Qt7PF206fJb5Zjg0M+oi7bkzJmd1t/DmodgjNhJuSGyYA4opS36QQf8ocC0gXaWunPPImy6FDFA5ghwjZAygznnfLzUSdG2nC2ZMPhSYjzGROXkt2G6P3tJMGwtaM76T70XQ6OwpfoLNbmf2mBnHGN67rOjn/WwbO1YBs2EDjf6fErmnq0enp9NFrJ4x+AOYBjfGmsCbhY34QlxGZgk7pE2nJe2xXRRaNghoJlwcbRAiAcrxPcRmVwK5DXdYDZl4dsF2RIkC/LXTxuGpZlraCStHIbgJbtSIAkxnESRB15bwlVmssG7rkTv1Ha4X5rdisS4kta3ZEnZJMGAZG1Ag6Wyk8Vz3tEFwIEQeses46xw9890zz5Roq2m1xMdUR/kbcp1N7WUYd5p1GmQNk65RN5ibJlaoHAkMa3KNkERGcifMDRJYxzyGtaS4mBxJ0GgVGfnB9FwzNtoMgjOQU8U4sAk9A9H/BotaSScyJEBxzA4LqFgsYWDlk9tJuKbVMzUuj3OvkE44BoF3SeY/2ukKzS2AALa71y6uHe6esO4yO9ZT1ZfwdWho6by2c/E4SnMwCdy5+JuYtbdl3+i67sEG5unjB9IhZ3YZgyI8D/AAs4ydndJQapHFdTJMD+/wCldlB+QHeuoKbNxPcU1j4yYfABa9w5Hp5wmckdHPO9NHQx1Hius2sRp5kqj8Q85DwB/JR3fYT6a8tHJqdFgZx4eqyuwrRu8l0q7ah/xPiFz6uHfOg7wtFqfJy6ug1wjrhymV4L5l/bf97vVW+Zf23/AHO9Vv2/k4F1vwe8EK0rwYxT+2/73eqn5h/bf9zvVLt/I/rfg94HKwevBDEP7b/ud6qRWf23fcfVHavyV9b8H0BhT2L50Kr+277irio/tu+4pdj5KXW/H5PpLGpwYvmjaj+077irNc/tO8Sk+mfuUusT8fk+h1EMavBsL+0fErSwP7R8SjsNeTWOvu8HqsZ0NSqElzGkkESBDoIjMXWEfpyiA1oaeqLHaJ33M2Jv7Fly2U37ynMpO3+f9JKDXkfbhJ24m6p+m2Cm9rHPbtCdluwZ2bgbJEG4GoJymMuTU/TdZjC8kFgkkWaQDHW2chraf8e5b2MO8+K00id6mUZe5UemjdrAdC9E1s2gggTcObIIiJI1BI7l9K/S9Sm1kPADg2OsADHhy8F4rCv4rH+puk3sbT2XES5wnhAXJKLUk0aa+lu06vB3+n8EatQ/CBa2HXuGxNxuPJeLxH6frPf1Wk3glwLQBlMuF9fpnK0r1tWuSIk2EBc6s528o0oy5NFoeja2cnD/AKJkzVqzlIa0HIW6zgbAzpuXQH6Pw4BGzY2zvG7az80qpUf2neJ9VlqV6vbf9x9V07ZPyYPpoR8Wdan+ksPLf+m3qgtGZEHtXvzK3N6Kp07Ma1utgBc8l5N9at23/e71SH4mt23/AHu9Udmb/cJbIu1Gv+HtPhDgoNMLwdTFVe2/7nLM/F1f+4/73Jrp5e5M+ogvDPoL3BuqyPxf7o7gvBvxVQ5vf9zvVKdXf23/AHFKXSSlywj1+nD9r+57l2Jn/I++QSDif3eX9rxJrv7bvuKoaz+277il9G15Kf6rDxF/c9yMUO049/oFLsUB7v5rwhxD+2/7iqnEP7bvuPqj6V+4f1WNf4v7nvDjkt+P9yvCmu/tu+4qhrO7bvuKpdJ8mcv1Vf6/k9nVxnELI7FDteS8r8V3bd4lRtu7R8SqXT15MpfqSf7SAphRKkLrPJRIClQFIKQ7LhWASw5WBTKTGNV2lKDlcP4popMe0+7JjZ9grMH8kxruCClI2Mf79haqT/c3XPY/mnMfzPc0pNG0NSjqNefYTw/n3gj+FzG1QNR9npATWVRw32MeAlZuJ0w1WdFtRWZVg5rnVcaxou4bjtTPJcut02BIYO/RZSRu+ohHlntaFfiPfJcL9Y4jq094c7/5/pcB3T1XQgeKyYjGvfG07ai91nsd2yNXrISg4xu2fTqWJlufvuUPfx/C+d0um6rRAdI4ick6n+pKwN4I7wlGDRquv0ms2e0quWJ9T37C49L9SNdZwLcr3PO6eMe1ws6Z4wDP/tc8FrFe4pdTCS9LNb38/NJqP3z3gDzssz6w48QAe7MpT38PJoWyic09Zk1X8vH+1me/3f0Uvefdx+El7/crRI5ZTshx95Jbioc/kluf7ugyciSqFBcqEoJskqpCC5VlImwIUEIJUFAmyFBUyhBJEoUBSEASrBVlUNYBJtIBwUrK6uVRzydVLkh2bC8DVHzLd/ksKEbmG42nFN4o+cHZKxIRuYbmbh0h+3zTG9KftP3f0uagJbmNSaOoelj2fP0ASK2Pe60wNwkf7WRCTbZW6T8kucTmSUSoQkKywcjaVUJUO2X21UuUIQFsJQHRkhCYjSzHPFptxAV/+SfrB8fVY1Up2wcn7m49IHsjzVfnj2QsaE9zFuZr+c/aj5vh5rIhG5itmv5kcVYVWnVYkJ7mFm7aCgrGHEZFXbWKFJBY8oS21AVeVadiAqJQoQBQ1FBqJaFnuYElxKhCFIAhCEACEIQAIQhAAhCEATKFCAgdlkKFKCgRKEJUAIUKJTE2ShQhArJJUIQgQIQhAAhCEACEIQAIQhAApBUIQBcPKn4iWhPcwBCEJACEIQAIQhAAhCEACEIQAIQhAAhCEASFKEIKQIQhAyCoQhBDBCEIAEIQgAQhCABCEIAEIQgAQhCABCEIAEIQgD//2Q==' + }, + 'attributes': { + 'width': '100', + 'height': '100', + 'style': 'width:250px; height:250px;' + } + }, + {'insert': '\n'}, + { + 'insert': + '\nThe source of the above image is image base 64 directly without `data:image/png;base64,` in the start' + }, + {'insert': '\n'}, + {'insert': '\n'}, + {'insert': ''}, + { + 'insert': { + 'image': + 'data:image/png;base64,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' + }, + 'attributes': { + 'width': '100', + 'height': '100', + 'style': 'width:250px; height:250px;' + } + }, + {'insert': '\n'}, + {'insert': '\n'}, + { + 'insert': + 'The source of the above image is also image base 64 but this time it start with `data:image/png;base64,`' + }, + {'insert': '\n'}, + {'insert': '\n'}, + { + 'insert': {'video': 'https://youtu.be/xz6_AlJkDPA'}, + 'attributes': { + 'width': '300', + 'height': '300', + 'style': 'width:400px; height:500px;' + } + }, + {'insert': '\n'}, + {'insert': '\n'}, + {'insert': 'And this is just a youtube video'}, + {'insert': '\n'} +]; diff --git a/example/lib/presentation/quill/quill_screen.dart b/example/lib/presentation/quill/quill_screen.dart new file mode 100644 index 00000000..e44bf105 --- /dev/null +++ b/example/lib/presentation/quill/quill_screen.dart @@ -0,0 +1,92 @@ +import 'package:flutter/material.dart'; + +import 'package:flutter_quill/flutter_quill.dart'; +import 'package:flutter_quill_extensions/flutter_quill_extensions.dart'; +import 'package:share_plus/share_plus.dart' show Share; + +class QuillScreen extends StatefulWidget { + const QuillScreen({ + required this.document, + super.key, + }); + + final Document document; + + @override + State createState() => _QuillScreenState(); +} + +class _QuillScreenState extends State { + final _controller = QuillController.basic(); + final _isReadOnly = false; + + @override + void initState() { + super.initState(); + _controller.document = widget.document; + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Flutter Quill'), + actions: [ + IconButton( + onPressed: () { + final plainText = _controller.document.toPlainText( + FlutterQuillEmbeds.defaultEditorBuilders(), + ); + if (plainText.trim().isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text( + "We can't share empty document, please enter some text first", + ), + ), + ); + return; + } + Share.share(plainText); + }, + icon: const Icon(Icons.share), + ), + ], + ), + body: QuillProvider( + configurations: QuillConfigurations( + controller: _controller, + sharedConfigurations: QuillSharedConfigurations( + animationConfigurations: QuillAnimationConfigurations.disableAll(), + extraConfigurations: const { + QuillSharedExtensionsConfigurations.key: + QuillSharedExtensionsConfigurations( + assetsPrefix: 'assets', + ), + }, + ), + ), + child: Column( + children: [ + QuillToolbar( + configurations: QuillToolbarConfigurations( + embedButtons: FlutterQuillEmbeds.toolbarButtons(), + ), + ), + Expanded( + child: QuillEditor.basic( + configurations: QuillEditorConfigurations( + scrollable: true, + readOnly: _isReadOnly, + placeholder: 'Start writting your notes...', + padding: const EdgeInsets.all(16), + embedBuilders: FlutterQuillEmbeds.defaultEditorBuilders(), + ), + ), + ), + ], + ), + ), + ); + } +} diff --git a/example/lib/presentation/settings/cubit/settings_cubit.dart b/example/lib/presentation/settings/cubit/settings_cubit.dart index 5f15fdd6..11bd2042 100644 --- a/example/lib/presentation/settings/cubit/settings_cubit.dart +++ b/example/lib/presentation/settings/cubit/settings_cubit.dart @@ -1,8 +1,26 @@ import 'package:bloc/bloc.dart'; -import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart' show ThemeMode; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:hydrated_bloc/hydrated_bloc.dart' show HydratedMixin; part 'settings_state.dart'; +part 'settings_cubit.freezed.dart'; +part 'settings_cubit.g.dart'; -class SettingsCubit extends Cubit { - SettingsCubit() : super(SettingsInitial()); +class SettingsCubit extends Cubit with HydratedMixin { + SettingsCubit() : super(const SettingsState()); + + void updateSettings(SettingsState newSettingsState) { + emit(newSettingsState); + } + + @override + SettingsState? fromJson(Map json) { + return SettingsState.fromJson(json); + } + + @override + Map? toJson(SettingsState state) { + return state.toJson(); + } } diff --git a/example/lib/presentation/settings/cubit/settings_cubit.freezed.dart b/example/lib/presentation/settings/cubit/settings_cubit.freezed.dart new file mode 100644 index 00000000..b3d2c042 --- /dev/null +++ b/example/lib/presentation/settings/cubit/settings_cubit.freezed.dart @@ -0,0 +1,175 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'settings_cubit.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +SettingsState _$SettingsStateFromJson(Map json) { + return _SettingsState.fromJson(json); +} + +/// @nodoc +mixin _$SettingsState { + ThemeMode get themeMode => throw _privateConstructorUsedError; + DefaultScreen get defaultScreen => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $SettingsStateCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $SettingsStateCopyWith<$Res> { + factory $SettingsStateCopyWith( + SettingsState value, $Res Function(SettingsState) then) = + _$SettingsStateCopyWithImpl<$Res, SettingsState>; + @useResult + $Res call({ThemeMode themeMode, DefaultScreen defaultScreen}); +} + +/// @nodoc +class _$SettingsStateCopyWithImpl<$Res, $Val extends SettingsState> + implements $SettingsStateCopyWith<$Res> { + _$SettingsStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? themeMode = null, + Object? defaultScreen = null, + }) { + return _then(_value.copyWith( + themeMode: null == themeMode + ? _value.themeMode + : themeMode // ignore: cast_nullable_to_non_nullable + as ThemeMode, + defaultScreen: null == defaultScreen + ? _value.defaultScreen + : defaultScreen // ignore: cast_nullable_to_non_nullable + as DefaultScreen, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$SettingsStateImplCopyWith<$Res> + implements $SettingsStateCopyWith<$Res> { + factory _$$SettingsStateImplCopyWith( + _$SettingsStateImpl value, $Res Function(_$SettingsStateImpl) then) = + __$$SettingsStateImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({ThemeMode themeMode, DefaultScreen defaultScreen}); +} + +/// @nodoc +class __$$SettingsStateImplCopyWithImpl<$Res> + extends _$SettingsStateCopyWithImpl<$Res, _$SettingsStateImpl> + implements _$$SettingsStateImplCopyWith<$Res> { + __$$SettingsStateImplCopyWithImpl( + _$SettingsStateImpl _value, $Res Function(_$SettingsStateImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? themeMode = null, + Object? defaultScreen = null, + }) { + return _then(_$SettingsStateImpl( + themeMode: null == themeMode + ? _value.themeMode + : themeMode // ignore: cast_nullable_to_non_nullable + as ThemeMode, + defaultScreen: null == defaultScreen + ? _value.defaultScreen + : defaultScreen // ignore: cast_nullable_to_non_nullable + as DefaultScreen, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$SettingsStateImpl implements _SettingsState { + const _$SettingsStateImpl( + {this.themeMode = ThemeMode.system, + this.defaultScreen = DefaultScreen.home}); + + factory _$SettingsStateImpl.fromJson(Map json) => + _$$SettingsStateImplFromJson(json); + + @override + @JsonKey() + final ThemeMode themeMode; + @override + @JsonKey() + final DefaultScreen defaultScreen; + + @override + String toString() { + return 'SettingsState(themeMode: $themeMode, defaultScreen: $defaultScreen)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$SettingsStateImpl && + (identical(other.themeMode, themeMode) || + other.themeMode == themeMode) && + (identical(other.defaultScreen, defaultScreen) || + other.defaultScreen == defaultScreen)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, themeMode, defaultScreen); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$SettingsStateImplCopyWith<_$SettingsStateImpl> get copyWith => + __$$SettingsStateImplCopyWithImpl<_$SettingsStateImpl>(this, _$identity); + + @override + Map toJson() { + return _$$SettingsStateImplToJson( + this, + ); + } +} + +abstract class _SettingsState implements SettingsState { + const factory _SettingsState( + {final ThemeMode themeMode, + final DefaultScreen defaultScreen}) = _$SettingsStateImpl; + + factory _SettingsState.fromJson(Map json) = + _$SettingsStateImpl.fromJson; + + @override + ThemeMode get themeMode; + @override + DefaultScreen get defaultScreen; + @override + @JsonKey(ignore: true) + _$$SettingsStateImplCopyWith<_$SettingsStateImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/example/lib/presentation/settings/cubit/settings_cubit.g.dart b/example/lib/presentation/settings/cubit/settings_cubit.g.dart new file mode 100644 index 00000000..92c0b759 --- /dev/null +++ b/example/lib/presentation/settings/cubit/settings_cubit.g.dart @@ -0,0 +1,36 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'settings_cubit.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$SettingsStateImpl _$$SettingsStateImplFromJson(Map json) => + _$SettingsStateImpl( + themeMode: $enumDecodeNullable(_$ThemeModeEnumMap, json['themeMode']) ?? + ThemeMode.system, + defaultScreen: + $enumDecodeNullable(_$DefaultScreenEnumMap, json['defaultScreen']) ?? + DefaultScreen.home, + ); + +Map _$$SettingsStateImplToJson(_$SettingsStateImpl instance) => + { + 'themeMode': _$ThemeModeEnumMap[instance.themeMode]!, + 'defaultScreen': _$DefaultScreenEnumMap[instance.defaultScreen]!, + }; + +const _$ThemeModeEnumMap = { + ThemeMode.system: 'system', + ThemeMode.light: 'light', + ThemeMode.dark: 'dark', +}; + +const _$DefaultScreenEnumMap = { + DefaultScreen.home: 'home', + DefaultScreen.settings: 'settings', + DefaultScreen.images: 'images', + DefaultScreen.videos: 'videos', + DefaultScreen.text: 'text', +}; diff --git a/example/lib/presentation/settings/cubit/settings_state.dart b/example/lib/presentation/settings/cubit/settings_state.dart index 9dcca0aa..1331157e 100644 --- a/example/lib/presentation/settings/cubit/settings_state.dart +++ b/example/lib/presentation/settings/cubit/settings_state.dart @@ -1,10 +1,19 @@ part of 'settings_cubit.dart'; -sealed class SettingsState extends Equatable { - const SettingsState(); - - @override - List get props => []; +enum DefaultScreen { + home, + settings, + images, + videos, + text, } -final class SettingsInitial extends SettingsState {} +@freezed +class SettingsState with _$SettingsState { + const factory SettingsState({ + @Default(ThemeMode.system) ThemeMode themeMode, + @Default(DefaultScreen.home) DefaultScreen defaultScreen, + }) = _SettingsState; + factory SettingsState.fromJson(Map json) => + _$SettingsStateFromJson(json); +} diff --git a/example/lib/presentation/settings/widgets/settings_screen.dart b/example/lib/presentation/settings/widgets/settings_screen.dart index e69de29b..2545265a 100644 --- a/example/lib/presentation/settings/widgets/settings_screen.dart +++ b/example/lib/presentation/settings/widgets/settings_screen.dart @@ -0,0 +1,105 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_quill/translations.dart'; + +import '../../shared/widgets/dialog_action.dart'; +import '../../shared/widgets/home_screen_button.dart'; +import '../cubit/settings_cubit.dart'; + +class SettingsScreen extends StatelessWidget { + const SettingsScreen({super.key}); + + static const routeName = '/settings'; + + @override + Widget build(BuildContext context) { + final materialTheme = Theme.of(context); + final isDark = materialTheme.brightness == Brightness.dark; + return Scaffold( + appBar: AppBar( + title: const Text('Settings'), + actions: const [ + HomeScreenButton(), + ], + ), + body: BlocBuilder( + builder: (context, state) { + return ListView( + children: [ + CheckboxListTile.adaptive( + value: isDark, + onChanged: (value) { + final isNewValueDark = value ?? false; + context.read().updateSettings( + state.copyWith( + themeMode: + isNewValueDark ? ThemeMode.dark : ThemeMode.light, + ), + ); + }, + title: const Text('Dark Theme'), + subtitle: const Text( + 'By default we will use your system theme, but you can set if you want dark or light theme', + ), + secondary: Icon(isDark ? Icons.nightlight : Icons.sunny), + ), + ListTile( + title: const Text('Default screen'), + subtitle: const Text( + 'Which screen should be used when the flutter app starts?', + ), + leading: const Icon(Icons.home), + onTap: () async { + final settingsBloc = context.read(); + final newDefaultScreen = + await showAdaptiveDialog( + context: context, + builder: (context) { + return AlertDialog.adaptive( + title: const Text('Select default screen'), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + ...DefaultScreen.values.map( + (e) => ListTile( + onTap: () { + Navigator.of(context).pop(e); + }, + title: Text(e.name), + leading: CircleAvatar( + child: Text((e.index + 1).toString()), + ), + ), + ), + ], + ), + actions: [ + AppDialogAction( + onPressed: () => Navigator.of(context).pop(null), + options: const DialogActionOptions( + cupertinoDialogActionOptions: + CupertinoDialogActionOptions( + isDefaultAction: true, + ), + ), + child: const Text('Cancel'), + ), + ], + ); + }, + ); + if (newDefaultScreen != null) { + settingsBloc.updateSettings( + settingsBloc.state + .copyWith(defaultScreen: newDefaultScreen), + ); + } + }, + ), + ], + ); + }, + ), + ); + } +} diff --git a/example/lib/presentation/shared/widgets/dialog_action.dart b/example/lib/presentation/shared/widgets/dialog_action.dart new file mode 100644 index 00000000..0761e066 --- /dev/null +++ b/example/lib/presentation/shared/widgets/dialog_action.dart @@ -0,0 +1,63 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_quill/extensions.dart'; + +@immutable +final class CupertinoDialogActionOptions { + const CupertinoDialogActionOptions({ + this.isDefaultAction = false, + }); + + final bool isDefaultAction; +} + +@immutable +final class MaterialDialogActionOptions { + const MaterialDialogActionOptions({ + this.textStyle, + }); + + final ButtonStyle? textStyle; +} + +@immutable +class DialogActionOptions { + const DialogActionOptions({ + this.cupertinoDialogActionOptions, + this.materialDialogActionOptions, + }); + + final CupertinoDialogActionOptions? cupertinoDialogActionOptions; + final MaterialDialogActionOptions? materialDialogActionOptions; +} + +class AppDialogAction extends StatelessWidget { + const AppDialogAction({ + required this.child, + required this.onPressed, + this.options, + super.key, + }); + + final VoidCallback? onPressed; + final Widget child; + + final DialogActionOptions? options; + + @override + Widget build(BuildContext context) { + if (isAppleOS(supportWeb: true)) { + return CupertinoDialogAction( + onPressed: onPressed, + isDefaultAction: + options?.cupertinoDialogActionOptions?.isDefaultAction ?? false, + child: child, + ); + } + return TextButton( + onPressed: onPressed, + style: options?.materialDialogActionOptions?.textStyle, + child: child, + ); + } +} diff --git a/example/lib/presentation/shared/widgets/home_screen_button.dart b/example/lib/presentation/shared/widgets/home_screen_button.dart new file mode 100644 index 00000000..b1ac053a --- /dev/null +++ b/example/lib/presentation/shared/widgets/home_screen_button.dart @@ -0,0 +1,24 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +import '../../settings/cubit/settings_cubit.dart'; + +class HomeScreenButton extends StatelessWidget { + const HomeScreenButton({super.key}); + + @override + Widget build(BuildContext context) { + return IconButton( + onPressed: () { + final settingsCubit = context.read(); + settingsCubit.updateSettings( + settingsCubit.state.copyWith( + defaultScreen: DefaultScreen.home, + ), + ); + }, + icon: const Icon(Icons.home), + tooltip: 'Set the default to home screen', + ); + } +} diff --git a/example/macos/Flutter/GeneratedPluginRegistrant.swift b/example/macos/Flutter/GeneratedPluginRegistrant.swift index ac927005..99b22612 100644 --- a/example/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -11,6 +11,7 @@ import file_selector_macos import gal import pasteboard import path_provider_foundation +import share_plus import url_launcher_macos import video_player_avfoundation @@ -21,6 +22,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { GalPlugin.register(with: registry.registrar(forPlugin: "GalPlugin")) PasteboardPlugin.register(with: registry.registrar(forPlugin: "PasteboardPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) FVPVideoPlayerPlugin.register(with: registry.registrar(forPlugin: "FVPVideoPlayerPlugin")) } diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 4e2edb42..96734a0a 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -20,12 +20,19 @@ dependencies: # Normal Packages path: ^1.8.3 + equatable: ^2.0.5 # Bloc libraries bloc: ^8.1.2 flutter_bloc: ^8.1.3 hydrated_bloc: ^9.1.2 + # Freezed + freezed_annotation: ^2.4.1 + + # Json + json_annotation: ^4.8.1 + # Plugins image_cropper: ^5.0.0 path_provider: ^2.1.1 @@ -33,6 +40,8 @@ dependencies: desktop_drop: ^0.4.4 # For picking quill document files file_picker: ^6.1.1 + # For sharing text + share_plus: ^7.2.1 dependency_overrides: flutter_quill: @@ -50,6 +59,11 @@ dev_dependencies: flutter_lints: ^3.0.1 build_runner: ^2.4.6 flutter_gen_runner: ^5.3.2 + + # Freezed + freezed: ^2.4.5 + # Json + json_serializable: ^6.7.1 flutter: uses-material-design: true assets: diff --git a/example/windows/flutter/generated_plugin_registrant.cc b/example/windows/flutter/generated_plugin_registrant.cc index 9e89e3c8..ef6dc906 100644 --- a/example/windows/flutter/generated_plugin_registrant.cc +++ b/example/windows/flutter/generated_plugin_registrant.cc @@ -10,6 +10,7 @@ #include #include #include +#include #include void RegisterPlugins(flutter::PluginRegistry* registry) { @@ -21,6 +22,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { registry->GetRegistrarForPlugin("GalPluginCApi")); PasteboardPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("PasteboardPlugin")); + SharePlusWindowsPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi")); UrlLauncherWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("UrlLauncherWindows")); } diff --git a/example/windows/flutter/generated_plugins.cmake b/example/windows/flutter/generated_plugins.cmake index f3449e49..abc6f627 100644 --- a/example/windows/flutter/generated_plugins.cmake +++ b/example/windows/flutter/generated_plugins.cmake @@ -7,6 +7,7 @@ list(APPEND FLUTTER_PLUGIN_LIST file_selector_windows gal pasteboard + share_plus url_launcher_windows ) diff --git a/flutter_quill_extensions/lib/presentation/embeds/widgets/image_resizer.dart b/flutter_quill_extensions/lib/presentation/embeds/widgets/image_resizer.dart index 844381fb..0e7f90cf 100644 --- a/flutter_quill_extensions/lib/presentation/embeds/widgets/image_resizer.dart +++ b/flutter_quill_extensions/lib/presentation/embeds/widgets/image_resizer.dart @@ -82,19 +82,18 @@ class ImageResizerState extends State { } Widget _slider({ - required double value, - required bool isHeight, + required bool isWidth, required ValueChanged onChanged, }) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 8), child: Card( child: Slider( - value: value, - max: widget.maxWidth, + value: isWidth ? _width : _height, + max: isWidth ? widget.maxWidth : widget.maxHeight, divisions: 1000, // Might need to be changed - label: isHeight ? context.loc.height : context.loc.width, + label: isWidth ? context.loc.width : context.loc.height, onChanged: (val) { setState(() { onChanged(val); @@ -108,8 +107,7 @@ class ImageResizerState extends State { Widget _heightSlider() { return _slider( - value: _height, - isHeight: true, + isWidth: false, onChanged: (value) { _height = value; }, @@ -118,8 +116,7 @@ class ImageResizerState extends State { Widget _widthSlider() { return _slider( - value: _width, - isHeight: false, + isWidth: true, onChanged: (value) { _width = value; },