diff --git a/lib/providers/app_model.dart b/lib/providers/app_model.dart index 2fa6864a..218de0dd 100644 --- a/lib/providers/app_model.dart +++ b/lib/providers/app_model.dart @@ -5,6 +5,7 @@ import "package:only_bible_app/screens/bible_select_screen.dart"; import "package:only_bible_app/screens/book_select_screen.dart"; import "package:only_bible_app/models.dart"; import "package:only_bible_app/widgets/actions_sheet.dart"; +import "package:only_bible_app/widgets/highlight_button.dart"; import "package:only_bible_app/widgets/note_sheet.dart"; import "package:only_bible_app/widgets/settings_sheet.dart"; import "package:provider/provider.dart"; @@ -27,6 +28,7 @@ class AppModel extends ChangeNotifier { bool fontBold = false; double textScaleFactor = 0; bool actionsShown = false; + bool highlightMenuShown = false; final TextEditingController noteTextController = TextEditingController(); List history = []; final box = GetStorage("only-bible-app-backup"); @@ -180,7 +182,8 @@ class AppModel extends ChangeNotifier { actionsShown = true; Scaffold.of(context).showBottomSheet( enableDrag: false, - (context) => const ActionsSheet(), + clipBehavior: Clip.antiAliasWithSaveLayer, + (context) => const ActionsSheet(), ); notifyListeners(); } @@ -232,4 +235,86 @@ class AppModel extends ChangeNotifier { hideNoteField(BuildContext context) { Navigator.of(context).pop(); } + + static Color fromHexS(String hexString) { + return Color(int.parse(hexString, radix: 16)); + } + + String toHexS(Color c) => '${c.alpha.toRadixString(16).padLeft(2, '0')}' + '${c.red.toRadixString(16).padLeft(2, '0')}' + '${c.green.toRadixString(16).padLeft(2, '0')}' + '${c.blue.toRadixString(16).padLeft(2, '0')}'; + + Color? getHighlight(Verse v) { + final key = "${v.book}:${v.chapter}:${v.index}:highlight"; + if (box.hasData(key)) { + // box.remove(key); + // print(box.read(key)); + return fromHexS(box.read(key)); + } + return null; + } + + void setHighlight(BuildContext context, List verses, Color c) { + for (final v in verses) { + box.write("${v.book}:${v.chapter}:${v.index}:highlight", toHexS(c)); + } + box.save(); + } + + void removeHighlight(BuildContext context, List verses) { + for (final v in verses) { + box.remove("${v.book}:${v.chapter}:${v.index}:highlight"); + } + box.save(); + } + + void showHighlightMenu(BuildContext context, List verses, Offset position) { + hideHighlightMenu(context); + highlightMenuShown = true; + final overlay = Overlay.of(context).context.findRenderObject(); + onTap(c) => setHighlight(context, verses, c); + + showMenu( + context: context, + position: RelativeRect.fromRect( + Rect.fromLTWH(position.dx, position.dy + 30, 100, 100), + Rect.fromLTWH(0, 0, overlay!.paintBounds.size.width, overlay.paintBounds.size.height), + ), + items: [ + PopupMenuItem( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + HighlightButton( + color: const Color(0xFFDAEFFE), + onColorSelected: onTap, + ), + HighlightButton( + color: const Color(0xFFFFFBB1), + onColorSelected: onTap, + ), + HighlightButton( + color: const Color(0xFFFFDEF3), + onColorSelected: onTap, + ), + HighlightButton( + color: const Color(0xFFE6FCC3), + onColorSelected: onTap, + ), + HighlightButton( + color: const Color(0xFFEADDFF), + onColorSelected: onTap, + ), + ], + ), + ), + ]); + } + + void hideHighlightMenu(BuildContext context) { + if (highlightMenuShown) { + Navigator.of(context).pop(); + } + } } diff --git a/lib/providers/chapter_view_model.dart b/lib/providers/chapter_view_model.dart index f768b750..d91542d1 100644 --- a/lib/providers/chapter_view_model.dart +++ b/lib/providers/chapter_view_model.dart @@ -97,6 +97,13 @@ class ChapterViewModel extends ChangeNotifier { } void clearSelections(BuildContext context) { + AppModel.ofEvent(context).removeHighlight(context, selectedVerses); + selectedVerses.clear(); + AppModel.ofEvent(context).hideActions(context); + notifyListeners(); + } + + void closeActions(BuildContext context) { selectedVerses.clear(); AppModel.ofEvent(context).hideActions(context); notifyListeners(); @@ -184,4 +191,4 @@ class ChapterViewModel extends ChangeNotifier { } } } -} \ No newline at end of file +} diff --git a/lib/theme.dart b/lib/theme.dart index 96b2e927..40f4757e 100644 --- a/lib/theme.dart +++ b/lib/theme.dart @@ -7,6 +7,7 @@ const lightColorScheme = ColorScheme.light( secondary: Color(0xFFFFC351), surfaceTint: Colors.black, shadow: Colors.black, + outline: Colors.grey, ); const darkColorScheme = ColorScheme.dark( diff --git a/lib/utils.dart b/lib/utils.dart index ac874eb9..dfd5a286 100644 --- a/lib/utils.dart +++ b/lib/utils.dart @@ -1,10 +1,10 @@ import "dart:convert"; +import 'package:flutter/gestures.dart'; import "package:flutter/foundation.dart" show defaultTargetPlatform, TargetPlatform; import "package:flutter/material.dart"; import "package:flutter/services.dart"; import "package:only_bible_app/models.dart"; - bool isDesktop() { return defaultTargetPlatform == TargetPlatform.macOS || defaultTargetPlatform == TargetPlatform.windows || @@ -20,7 +20,7 @@ bool isWide(BuildContext context) { return false; } final width = MediaQuery.of(context).size.width; - return width > 600; + return width > 700; } createNoTransitionPageRoute(Widget page) { diff --git a/lib/widgets/actions_sheet.dart b/lib/widgets/actions_sheet.dart index 728e7cdd..8946dd1f 100644 --- a/lib/widgets/actions_sheet.dart +++ b/lib/widgets/actions_sheet.dart @@ -18,41 +18,46 @@ class ActionsSheet extends StatelessWidget { final model = ChapterViewModel.of(context); final audioIcon = model.isPlaying ? Icons.pause_circle_outline : Icons.play_circle_outline; final audioText = model.isPlaying ? "Pause" : "Play"; - final highlightRowEnabled = !isDesktop && false; + final highlightRowEnabled = !isDesktop; + onHighlight(Color c) { + final verses = ChapterViewModel.ofEvent(context).selectedVerses; + app.setHighlight(context, verses, c); + model.closeActions(context); + } + + ; return Container( height: highlightRowEnabled - ? 160 + ? 150 : isDesktop - ? 80 - : 100, + ? 95 + : isIOS() + ? 100 + : 70, color: Theme.of(context).colorScheme.background, - padding: EdgeInsets.only(left: 20, right: 20, top: isDesktop ? 10 : 0), + padding: EdgeInsets.only(left: 20, right: 20, top: isDesktop ? 10 : 10, bottom: 20), child: Column( mainAxisAlignment: highlightRowEnabled ? MainAxisAlignment.spaceAround : MainAxisAlignment.start, children: [ if (highlightRowEnabled) Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisAlignment: MainAxisAlignment.end, children: [ HighlightButton( color: const Color(0xFFDAEFFE), - onTap: () {}, + onColorSelected: onHighlight, ), HighlightButton( color: const Color(0xFFFFFBB1), - onTap: () {}, + onColorSelected: onHighlight, ), HighlightButton( color: const Color(0xFFFFDEF3), - onTap: () {}, + onColorSelected: onHighlight, ), HighlightButton( color: const Color(0xFFE6FCC3), - onTap: () {}, - ), - HighlightButton( - color: const Color(0xFFEADDFF), - onTap: () {}, + onColorSelected: onHighlight, ), ], ), @@ -105,14 +110,6 @@ class ActionsSheet extends StatelessWidget { ), trailing: Text("Share", style: bodySmall), ), - // IconButtonText( - // leading: IconButton( - // padding: EdgeInsets.zero, - // onPressed: () {}, - // icon: const Text(""), - // ), - // trailing: Text("", style: bodySmall), - // ) ], ), ], diff --git a/lib/widgets/chapter_app_bar.dart b/lib/widgets/chapter_app_bar.dart index 414f85bd..0c811b81 100644 --- a/lib/widgets/chapter_app_bar.dart +++ b/lib/widgets/chapter_app_bar.dart @@ -46,16 +46,51 @@ class ChapterAppBar extends StatelessWidget implements PreferredSizeWidget { child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ + if (isDesktop) + TextButton.icon( + onPressed: () => model.onPrevious(context, model.book, model.chapter), + style: TextButton.styleFrom( + elevation: 0, + padding: const EdgeInsets.symmetric(horizontal: 10), + shadowColor: Theme.of(context).shadowColor, + backgroundColor: Theme.of(context).colorScheme.background, + foregroundColor: Theme.of(context).colorScheme.primary, + ), + icon: const Icon(Icons.chevron_left), + label: const Text("Prev"), + ), + if (isDesktop) const SizedBox(width: 10), + if (isDesktop) + TextButton.icon( + onPressed: () => model.onNext(context, model.book, model.chapter), + style: TextButton.styleFrom( + elevation: 0, + padding: const EdgeInsets.symmetric(horizontal: 10), + shadowColor: Theme.of(context).shadowColor, + backgroundColor: Theme.of(context).colorScheme.background, + foregroundColor: Theme.of(context).colorScheme.primary, + ), + icon: const Icon(Icons.chevron_right), + label: const Text("Next"), + ), + if (isDesktop) const SizedBox(width: 20), if (isDesktop) TextButton.icon( onPressed: () => app.changeBibleFromHeader(context), style: TextButton.styleFrom( padding: const EdgeInsets.symmetric(horizontal: 10), + shadowColor: Theme.of(context).shadowColor, + backgroundColor: Theme.of(context).colorScheme.background, + foregroundColor: Theme.of(context).colorScheme.primary, + shape: RoundedRectangleBorder( + side: BorderSide( + color: Theme.of(context).colorScheme.primary, + width: 1, + ), + ), ), icon: const Icon(Icons.book_outlined), - label: Text( - app.bible.name, - ), + label: Text(app.bible.name), ), Padding( padding: const EdgeInsets.only(left: 10), diff --git a/lib/widgets/highlight_button.dart b/lib/widgets/highlight_button.dart index 82a9e24e..6c33971b 100644 --- a/lib/widgets/highlight_button.dart +++ b/lib/widgets/highlight_button.dart @@ -2,20 +2,21 @@ import "package:flutter/material.dart"; class HighlightButton extends StatelessWidget { final Color color; - final VoidCallback onTap; + final Function(Color c) onColorSelected; - const HighlightButton({super.key, required this.color, required this.onTap}); + const HighlightButton({super.key, required this.color, required this.onColorSelected}); @override Widget build(BuildContext context) { return InkWell( - onTap: onTap, - child: DecoratedBox( + onTap: () => onColorSelected(color), + child: Container( + padding: EdgeInsets.symmetric(horizontal: 10), decoration: BoxDecoration( - color: color.withOpacity(0.6), + color: color.withOpacity(1), shape: BoxShape.circle, ), - child: const SizedBox(width: 45, height: 45), + child: const SizedBox(width: 30, height: 30), ), ); } diff --git a/lib/widgets/scaffold_menu.dart b/lib/widgets/scaffold_menu.dart index c12ea007..84ce6d89 100644 --- a/lib/widgets/scaffold_menu.dart +++ b/lib/widgets/scaffold_menu.dart @@ -9,6 +9,7 @@ class ScaffoldMenu extends StatelessWidget { @override Widget build(BuildContext context) { + final pageWidth = MediaQuery.of(context).size.width; return Scaffold( backgroundColor: Colors.transparent, body: SafeArea( @@ -17,7 +18,7 @@ class ScaffoldMenu extends StatelessWidget { margin: EdgeInsets.only(left: isWide(context) ? 250 : 0), child: Container( color: backgroundColor ?? Theme.of(context).colorScheme.background, - margin: EdgeInsets.only(right: isWide(context) ? 650 : 0), + margin: EdgeInsets.only(right: isWide(context) ? pageWidth - 750 : 0), child: child, ), ), diff --git a/lib/widgets/verses_view.dart b/lib/widgets/verses_view.dart index 62a0500c..c203cca9 100644 --- a/lib/widgets/verses_view.dart +++ b/lib/widgets/verses_view.dart @@ -72,10 +72,16 @@ class VersesView extends StatelessWidget { text: "${v.text}\n", style: context.watch().isVerseSelected(v) ? TextStyle( - backgroundColor: Theme.of(context).highlightColor, + backgroundColor: app.darkMode ? Colors.grey.shade800 : Colors.grey.shade200, ) - : null, - recognizer: TapGestureRecognizer()..onTap = () => model.onVerseSelected(context, v), + : TextStyle( + backgroundColor: app.getHighlight(v) ?? Theme.of(context).colorScheme.background, + ), + recognizer: TapGestureRecognizer() + ..onTap = () { + model.onVerseSelected(context, v); + // AppModel.ofEvent(context).showHighlightMenu(context, v, details.globalPosition); + }, ), const WidgetSpan( child: Padding(