diff --git a/lib/main.dart b/lib/main.dart index 3a940d9..bd33810 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:get/get.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:hive_flutter/adapters.dart'; @@ -33,7 +34,7 @@ void main() async { Get.put(SearchBarController()); Get.put(CacheData()); - runApp(const App()); + runApp(const ProviderScope(child: App())); } class App extends StatelessWidget { diff --git a/lib/models/hive/convertor.dart b/lib/models/hive/convertor.dart index 9b48d86..d7fa6cf 100644 --- a/lib/models/hive/convertor.dart +++ b/lib/models/hive/convertor.dart @@ -1,3 +1,4 @@ +import 'package:flutter/material.dart'; import 'package:movielab/models/hive/models/show_preview.dart'; import 'package:movielab/models/show_models/show_preview_model.dart'; @@ -43,7 +44,10 @@ HiveShowPreview convertShowPreviewToHive(ShowPreview showPreview) { } Future convertFullShowToHive( - FullShow fullShow, String rank) async { + {required FullShow fullShow, + required String rank, + DateTime? date, + TimeOfDay? time}) async { String crew = ""; await getShowCrew(fullShow: fullShow).then((value) => crew = value); return HiveShowPreview() @@ -61,7 +65,9 @@ Future convertFullShowToHive( ..domestic = fullShow.domestic ..domesticLifetimeGross = fullShow.domesticLifetimeGross ..foreign = fullShow.foreign - ..foreignLifetimeGross = fullShow.foreignLifetimeGross; + ..foreignLifetimeGross = fullShow.foreignLifetimeGross + ..watchDate = date + ..watchTime = time; } Future getShowCrew({required FullShow fullShow}) async { diff --git a/lib/models/hive/hive_helper/fields/show_preview_fields.dart b/lib/models/hive/hive_helper/fields/show_preview_fields.dart index 1a68616..63fb8fe 100644 --- a/lib/models/hive/hive_helper/fields/show_preview_fields.dart +++ b/lib/models/hive/hive_helper/fields/show_preview_fields.dart @@ -14,4 +14,6 @@ class ShowPreviewFields { static const int domestic = 12; static const int foreignLifetimeGross = 13; static const int foreign = 14; + static const int watchDate = 15; + static const int watchTime = 16; } diff --git a/lib/models/hive/models/show_preview.dart b/lib/models/hive/models/show_preview.dart index 107ad70..223bd47 100644 --- a/lib/models/hive/models/show_preview.dart +++ b/lib/models/hive/models/show_preview.dart @@ -1,3 +1,4 @@ +import 'package:flutter/material.dart'; import 'package:hive/hive.dart'; import '../hive_helper/fields/show_preview_fields.dart'; import '../hive_helper/hive_adapters.dart'; @@ -37,4 +38,8 @@ class HiveShowPreview extends HiveObject { late String foreignLifetimeGross; @HiveField(ShowPreviewFields.foreign) late String foreign; + @HiveField(ShowPreviewFields.watchDate) + late DateTime? watchDate; + @HiveField(ShowPreviewFields.watchTime) + late TimeOfDay? watchTime; } diff --git a/lib/models/show_models/show_preview_model.dart b/lib/models/show_models/show_preview_model.dart index cf67bea..522bcfd 100644 --- a/lib/models/show_models/show_preview_model.dart +++ b/lib/models/show_models/show_preview_model.dart @@ -1,5 +1,7 @@ import 'dart:convert'; +import 'package:flutter/material.dart'; + // Movie or TV show preview model class class ShowPreview { final String id; @@ -17,6 +19,8 @@ class ShowPreview { final String domestic; final String foreignLifetimeGross; final String foreign; + final DateTime? watchDate; + final TimeOfDay? watchTime; const ShowPreview({ required this.id, @@ -34,6 +38,8 @@ class ShowPreview { required this.domestic, required this.foreignLifetimeGross, required this.foreign, + this.watchDate, + this.watchTime, }); factory ShowPreview.fromJson(Map json) { diff --git a/lib/modules/capitalizer.dart b/lib/modules/capitalizer.dart new file mode 100644 index 0000000..5d92948 --- /dev/null +++ b/lib/modules/capitalizer.dart @@ -0,0 +1,5 @@ +extension StringExtension on String { + String capitalize() { + return "${this[0].toUpperCase()}${substring(1).toLowerCase()}"; + } +} diff --git a/lib/modules/preferences_shareholder.dart b/lib/modules/preferences_shareholder.dart index 434571a..609d61a 100644 --- a/lib/modules/preferences_shareholder.dart +++ b/lib/modules/preferences_shareholder.dart @@ -1,4 +1,5 @@ import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; import 'package:hive_flutter/adapters.dart'; import '../models/hive/convertor.dart'; import '../models/hive/models/show_preview.dart'; @@ -16,10 +17,16 @@ class PreferencesShareholder { // Add an item to a list in the shared preferences Future addShowToList( - {required FullShow fullShow, required String listName}) async { + {required FullShow fullShow, + required String listName, + DateTime? date, + TimeOfDay? time}) async { Box list = Hive.box(listName); - HiveShowPreview hiveShow = - await convertFullShowToHive(fullShow, (list.length + 1).toString()); + HiveShowPreview hiveShow = await convertFullShowToHive( + fullShow: fullShow, + rank: (list.length + 1).toString(), + date: date, + time: time); list.put(list.length + 1, hiveShow); if (kDebugMode) { print("The item added to $listName"); @@ -48,17 +55,21 @@ class PreferencesShareholder { List listNames = ["collection", "watchlist", "history"]; Map result = {}; for (String listName in listNames) { - Box collection = Hive.box(listName); - for (int i = 0; i < collection.length; i++) { - if (collection.getAt(i)?.id == showId) { + Box list = Hive.box(listName); + for (int i = 0; i < list.length; i++) { + if (list.getAt(i)?.id == showId) { if (kDebugMode) { print("Item is in $listName"); } result[listName] = true; break; + } else { + result[listName] = false; } } - result[listName] = false; + if (result[listName] != true) { + result[listName] = false; + } } return result; } diff --git a/lib/pages/show/show_page/sections/bottom_bar/bottom_bar.dart b/lib/pages/show/show_page/sections/bottom_bar/bottom_bar.dart index ad8ceb3..62b9454 100644 --- a/lib/pages/show/show_page/sections/bottom_bar/bottom_bar.dart +++ b/lib/pages/show/show_page/sections/bottom_bar/bottom_bar.dart @@ -1,12 +1,40 @@ +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import '../../../../../constants/colors.dart'; +import '../../../../../models/show_models/full_show_model.dart'; +import '../../../../../modules/preferences_shareholder.dart'; +import 'sections/lists_info/lists_info.dart'; -class ShowPageBottonBar extends StatelessWidget { - const ShowPageBottonBar({Key? key}) : super(key: key); +class ShowPageBottonBar extends StatefulWidget { + final FullShow show; + final Map isThereInLists; + const ShowPageBottonBar( + {Key? key, required this.show, required this.isThereInLists}) + : super(key: key); + + @override + State createState() => _ShowPageBottonBarState(); +} + +class _ShowPageBottonBarState extends State + with TickerProviderStateMixin { + final PreferencesShareholder _preferencesShareholder = + PreferencesShareholder(); + late FToast fToast; + @override + void initState() { + super.initState(); + fToast = FToast(); + fToast.init(context); + } @override Widget build(BuildContext context) { + if (kDebugMode) { + print(widget.isThereInLists); + } return SizedBox( height: 60, child: Row( @@ -34,23 +62,12 @@ class ShowPageBottonBar extends StatelessWidget { )), clipBehavior: Clip.antiAliasWithSaveLayer, backgroundColor: kSecondaryColor, + transitionAnimationController: AnimationController( + duration: const Duration(milliseconds: 235), vsync: this), builder: (context) { - return Container( - padding: const EdgeInsets.symmetric(vertical: 20), - height: 235, - child: Column( - children: [ - button(context, - icon: FontAwesomeIcons.circle, - text: 'Mark as watched'), - button(context, - icon: FontAwesomeIcons.bookmark, - text: 'Add to watchlist'), - button(context, - icon: FontAwesomeIcons.rectangleList, - text: 'Add to collection'), - ], - ), + return ShowPageListsInfo( + show: widget.show, + isThereInLists: widget.isThereInLists, ); }, ); @@ -108,44 +125,4 @@ class ShowPageBottonBar extends StatelessWidget { ), ); } - - Widget button(BuildContext context, - {required String text, - required IconData icon, - EdgeInsets margin = const EdgeInsets.symmetric(vertical: 7.5)}) { - return Container( - height: 50, - margin: margin, - width: MediaQuery.of(context).size.width - 100, - decoration: BoxDecoration( - color: const Color(0xff2a425f).withOpacity(0.75), - borderRadius: BorderRadius.circular(15)), - child: TextButton( - onPressed: () {}, - style: TextButton.styleFrom( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(15), - ), - ), - child: Row( - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 30), - child: Icon( - icon, - color: Colors.white, - size: 20, - ), - ), - Text( - text, - style: const TextStyle( - color: Colors.white, - fontSize: 15, - fontWeight: FontWeight.w800), - ), - ], - )), - ); - } } diff --git a/lib/pages/show/show_page/sections/bottom_bar/sections/lists_info/lists_info.dart b/lib/pages/show/show_page/sections/bottom_bar/sections/lists_info/lists_info.dart new file mode 100644 index 0000000..f74b346 --- /dev/null +++ b/lib/pages/show/show_page/sections/bottom_bar/sections/lists_info/lists_info.dart @@ -0,0 +1,142 @@ +import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:movielab/modules/capitalizer.dart'; +import '../../../../../../../constants/colors.dart'; +import '../../../../../../../models/show_models/full_show_model.dart'; +import '../../../../../../../modules/preferences_shareholder.dart'; +import '../../../../../../../widgets/buttons/activeable_button.dart'; +import '../../../../../../../widgets/toast.dart'; +import '../../watchtime.dart'; + +class ShowPageListsInfo extends StatefulWidget { + final FullShow show; + final Map isThereInLists; + const ShowPageListsInfo( + {Key? key, required this.show, required this.isThereInLists}) + : super(key: key); + + @override + State createState() => _ShowPageListsInfoState(); +} + +class _ShowPageListsInfoState extends State + with TickerProviderStateMixin { + final PreferencesShareholder _preferencesShareholder = + PreferencesShareholder(); + late FToast fToast; + @override + void initState() { + super.initState(); + fToast = FToast(); + fToast.init(context); + } + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.symmetric(vertical: 20), + height: 235, + child: Column( + children: [ + ActiveableButton( + icon: FontAwesomeIcons.circle, + activeIcon: FontAwesomeIcons.solidCircle, + text: 'Mark as watched', + activeText: 'Watched', + activeColor: kPrimaryColor, + isActive: widget.isThereInLists['history'] ?? false, + onTap: () async { + if (widget.isThereInLists["history"] == false) { + Navigator.pop(context); + await Future.delayed(const Duration(milliseconds: 200)); + showModalBottomSheet( + context: context, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.vertical( + top: Radius.circular(20), + )), + clipBehavior: Clip.antiAliasWithSaveLayer, + backgroundColor: kSecondaryColor, + transitionAnimationController: AnimationController( + duration: const Duration(milliseconds: 225), + vsync: this), + builder: (context) { + return ShowPageAddWatchDate( + show: widget.show, + ); + }); + } else { + handleOnTap(listName: "history"); + } + }), + ActiveableButton( + icon: FontAwesomeIcons.bookmark, + activeIcon: FontAwesomeIcons.solidBookmark, + text: 'Add to watchlist', + activeText: 'Listed on watchlist', + activeColor: kAccentColor, + isActive: widget.isThereInLists['watchlist'] ?? false, + onTap: () { + handleOnTap(listName: "watchlist"); + }), + ActiveableButton( + icon: FontAwesomeIcons.rectangleList, + activeIcon: FontAwesomeIcons.bookBookmark, + text: 'Add to collection', + activeText: 'Collected', + activeColor: kImdbColor, + isActive: widget.isThereInLists['collection'] ?? false, + onTap: () { + handleOnTap(listName: "collection"); + }), + ], + ), + ); + } + + void handleOnTap({ + required String listName, + }) async { + if (widget.isThereInLists[listName] == false) { + _preferencesShareholder.addShowToList( + fullShow: widget.show, listName: listName); + setState(() { + widget.isThereInLists[listName] = true; + }); + await Future.delayed(const Duration(milliseconds: 200)); + // ignore: use_build_context_synchronously + Navigator.pop(context); + await Future.delayed(const Duration(milliseconds: 200)); + fToast.showToast( + child: ToastWidget( + mainText: "Saved to ${listName.capitalize()}", + buttonText: "See list", + buttonColor: kAccentColor, + buttonOnTap: () {}, + ), + gravity: ToastGravity.BOTTOM, + toastDuration: const Duration(seconds: 3), + ); + } else { + _preferencesShareholder.deleteFromList( + showId: widget.show.id, listName: listName); + setState(() { + widget.isThereInLists[listName] = false; + }); + await Future.delayed(const Duration(milliseconds: 200)); + // ignore: use_build_context_synchronously + Navigator.pop(context); + await Future.delayed(const Duration(milliseconds: 200)); + fToast.showToast( + child: ToastWidget( + mainText: "Ramoved from ${listName.capitalize()}", + buttonText: "Undo", + buttonColor: kPrimaryColor, + buttonOnTap: () {}), + gravity: ToastGravity.BOTTOM, + toastDuration: const Duration(seconds: 3), + ); + } + } +} diff --git a/lib/pages/show/show_page/sections/watchtime.dart b/lib/pages/show/show_page/sections/bottom_bar/watchtime.dart similarity index 84% rename from lib/pages/show/show_page/sections/watchtime.dart rename to lib/pages/show/show_page/sections/bottom_bar/watchtime.dart index 81505d9..49e10d0 100644 --- a/lib/pages/show/show_page/sections/watchtime.dart +++ b/lib/pages/show/show_page/sections/bottom_bar/watchtime.dart @@ -1,101 +1,57 @@ import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:fluttertoast/fluttertoast.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:movielab/constants/colors.dart'; import 'package:movielab/models/show_models/full_show_model.dart'; import 'package:movielab/widgets/buttons/glassmorphism_button.dart'; +import '../../../../../modules/preferences_shareholder.dart'; +import '../../../../../widgets/toast.dart'; -// ignore: must_be_immutable -class ShowPageAddWatchTime extends StatefulWidget { +class ShowPageAddWatchDate extends ConsumerStatefulWidget { final FullShow show; - const ShowPageAddWatchTime({Key? key, required this.show}) : super(key: key); + const ShowPageAddWatchDate({Key? key, required this.show}) : super(key: key); @override - State createState() => _ShowPageAddWatchTimeState(); + ShowPageAddWatchDateState createState() => ShowPageAddWatchDateState(); } -class _ShowPageAddWatchTimeState extends State { - bool isOtherDateSectionOpen = false; - bool showDateSelector = false; - DateTime selectedDate = DateTime.now(); - TimeOfDay selectedTime = TimeOfDay.now(); - List months = [ - 'January', - 'February', - 'March', - 'April', - 'May', - 'June', - 'July', - 'August', - 'September', - 'October', - 'November', - 'December' - ]; +class ShowPageAddWatchDateState extends ConsumerState { + final PreferencesShareholder _preferencesShareholder = + PreferencesShareholder(); + late bool isOtherDateSectionOpen, showDateSelector; + late TimeOfDay selectedTime; + late DateTime selectedDate; + late List months; + late FToast fToast; - Future _selectDate(BuildContext context) async { - final DateTime? picked = await showDatePicker( - context: context, - builder: (BuildContext context, child) { - return Theme( - data: Theme.of(context).copyWith( - dialogBackgroundColor: kSecondaryColor, - primaryColor: kPrimaryColor, - colorScheme: const ColorScheme.light( - primary: kPrimaryColor, - onPrimary: Colors.white, - onSurface: Colors.white, - ), - textButtonTheme: TextButtonThemeData( - style: TextButton.styleFrom( - primary: kPrimaryColor, - ), - ), - ), - child: child!); - }, - initialDate: selectedDate, - currentDate: DateTime.now(), - selectableDayPredicate: (DateTime date) => - date.isAfter(DateTime.now()) ? false : true, - firstDate: DateTime(1901), - lastDate: DateTime(2101)); - if (picked != null && picked != selectedDate) { - setState(() { - selectedDate = picked; - print(selectedDate); - }); - } - } + @override + void initState() { + super.initState(); + isOtherDateSectionOpen = false; + showDateSelector = false; - Future _selectTime(BuildContext context) async { - final TimeOfDay? timeOfDay = await showTimePicker( - context: context, - builder: (BuildContext context, child) { - return Theme( - data: ThemeData.dark().copyWith( - primaryColor: kPrimaryColor, - timePickerTheme: const TimePickerThemeData( - backgroundColor: kSecondaryColor, - dialTextColor: Colors.white, - ), - textButtonTheme: TextButtonThemeData( - style: TextButton.styleFrom( - primary: Colors.white, - ), - ), - ), - child: child!); - }, - initialTime: selectedTime, - initialEntryMode: TimePickerEntryMode.dial, - ); - if (timeOfDay != null && timeOfDay != selectedTime) { - setState(() { - selectedTime = timeOfDay; - }); - } + selectedTime = TimeOfDay.now(); + selectedDate = DateTime.now(); + + months = [ + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December' + ]; + + fToast = FToast(); + fToast.init(context); } @override @@ -121,7 +77,9 @@ class _ShowPageAddWatchTimeState extends State { ], ), TextButton( - onPressed: () {}, + onPressed: () { + markAsWatched(date: DateTime.now(), time: TimeOfDay.now()); + }, style: TextButton.styleFrom( padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 10)), @@ -145,7 +103,11 @@ class _ShowPageAddWatchTimeState extends State { ), ), TextButton( - onPressed: () {}, + onPressed: () { + markAsWatched( + date: DateTime.parse(widget.show.releaseDate), + time: TimeOfDay.fromDateTime(DateTime.parse("00:00"))); + }, style: TextButton.styleFrom( padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 10)), @@ -332,4 +294,86 @@ class _ShowPageAddWatchTimeState extends State { ), ); } + + Future _selectDate(BuildContext context) async { + final DateTime? picked = await showDatePicker( + context: context, + builder: (BuildContext context, child) { + return Theme( + data: Theme.of(context).copyWith( + dialogBackgroundColor: kSecondaryColor, + primaryColor: kPrimaryColor, + colorScheme: const ColorScheme.light( + primary: kPrimaryColor, + onPrimary: Colors.white, + onSurface: Colors.white, + ), + textButtonTheme: TextButtonThemeData( + style: TextButton.styleFrom( + primary: kPrimaryColor, + ), + ), + ), + child: child!); + }, + initialDate: selectedDate, + currentDate: DateTime.now(), + selectableDayPredicate: (DateTime date) => + date.isAfter(DateTime.now()) ? false : true, + firstDate: DateTime(1901), + lastDate: DateTime(2101)); + if (picked != null && picked != selectedDate) { + setState(() { + selectedDate = picked; + }); + } + } + + Future _selectTime(BuildContext context) async { + final TimeOfDay? timeOfDay = await showTimePicker( + context: context, + builder: (BuildContext context, child) { + return Theme( + data: ThemeData.dark().copyWith( + primaryColor: kPrimaryColor, + timePickerTheme: const TimePickerThemeData( + backgroundColor: kSecondaryColor, + dialTextColor: Colors.white, + ), + textButtonTheme: TextButtonThemeData( + style: TextButton.styleFrom( + primary: Colors.white, + ), + ), + ), + child: child!); + }, + initialTime: selectedTime, + initialEntryMode: TimePickerEntryMode.dial, + ); + if (timeOfDay != null && timeOfDay != selectedTime) { + setState(() { + selectedTime = timeOfDay; + }); + } + } + + markAsWatched({required DateTime date, required TimeOfDay time}) async { + _preferencesShareholder.addShowToList( + fullShow: widget.show, listName: "history", date: date, time: time); + await Future.delayed(const Duration(milliseconds: 200)); + // ignore: use_build_context_synchronously + Navigator.pop(context); + await Future.delayed(const Duration(milliseconds: 200)); + fToast.showToast( + child: ToastWidget( + mainText: "Saved to History}", + buttonText: "See list", + buttonColor: kAccentColor, + buttonOnTap: () {}, + ), + gravity: ToastGravity.BOTTOM, + toastDuration: const Duration(seconds: 3), + ); + } } diff --git a/lib/pages/show/show_page/show_page.dart b/lib/pages/show/show_page/show_page.dart index fd071b7..df46a8b 100644 --- a/lib/pages/show/show_page/show_page.dart +++ b/lib/pages/show/show_page/show_page.dart @@ -12,7 +12,7 @@ import '../../../modules/preferences_shareholder.dart'; import 'get_show_info.dart'; import 'sections/bottom_bar/bottom_bar.dart'; import 'sections/index.dart'; -import 'sections/watchtime.dart'; +import 'sections/bottom_bar/watchtime.dart'; // ignore: must_be_immutable class ShowPage extends StatefulWidget { @@ -90,12 +90,15 @@ class _ShowPageState extends State with TickerProviderStateMixin { duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, height: _isBottomAppBarVisible ? 60 : 0.0, - child: const BottomAppBar( - shape: CircularNotchedRectangle(), + child: BottomAppBar( + shape: const CircularNotchedRectangle(), clipBehavior: Clip.antiAlias, notchMargin: 7.5, color: kSecondaryColor, - child: ShowPageBottonBar()), + child: ShowPageBottonBar( + show: show, + isThereInLists: _isThereInLists, + )), ), floatingActionButton: FloatingActionButton( onPressed: () { @@ -112,7 +115,7 @@ class _ShowPageState extends State with TickerProviderStateMixin { duration: const Duration(milliseconds: 225), vsync: this), builder: (context) { - return ShowPageAddWatchTime( + return ShowPageAddWatchDate( show: show, ); }) diff --git a/lib/widgets/buttons/activeable_button.dart b/lib/widgets/buttons/activeable_button.dart new file mode 100644 index 0000000..61244ba --- /dev/null +++ b/lib/widgets/buttons/activeable_button.dart @@ -0,0 +1,67 @@ +import 'package:flutter/material.dart'; + +class ActiveableButton extends StatelessWidget { + final String text; + final String? activeText; + final IconData icon; + final IconData? activeIcon; + final VoidCallback onTap; + final bool isActive; + final Color backgroundColor; + final Color? activeColor; + final EdgeInsets margin; + const ActiveableButton( + {Key? key, + required this.isActive, + required this.text, + this.activeText, + required this.icon, + this.activeIcon, + required this.onTap, + this.activeColor, + this.margin = const EdgeInsets.symmetric(vertical: 7.5), + this.backgroundColor = const Color(0xff2a425f)}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return AnimatedContainer( + height: 50, + margin: margin, + width: MediaQuery.of(context).size.width - 100, + decoration: BoxDecoration( + color: isActive + ? activeColor?.withOpacity(0.75) ?? + backgroundColor.withOpacity(0.75) + : backgroundColor.withOpacity(0.75), + borderRadius: BorderRadius.circular(15)), + duration: const Duration(milliseconds: 150), + child: TextButton( + onPressed: onTap, + style: TextButton.styleFrom( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15), + ), + ), + child: Row( + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 25), + child: Icon( + isActive ? activeIcon ?? icon : icon, + color: Colors.white, + size: 20, + ), + ), + Text( + isActive ? activeText ?? text : text, + style: const TextStyle( + color: Colors.white, + fontSize: 15, + fontWeight: FontWeight.w800), + ), + ], + )), + ); + } +} diff --git a/lib/widgets/toast.dart b/lib/widgets/toast.dart new file mode 100644 index 0000000..d6a8530 --- /dev/null +++ b/lib/widgets/toast.dart @@ -0,0 +1,50 @@ +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; + +class ToastWidget extends StatelessWidget { + final String mainText; + final String buttonText; + final Color buttonColor; + final VoidCallback buttonOnTap; + const ToastWidget( + {Key? key, + required this.mainText, + required this.buttonText, + required this.buttonColor, + required this.buttonOnTap}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 15), + margin: EdgeInsets.zero, + width: double.infinity, + height: 50, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10.0), + color: Colors.white.withOpacity(0.95), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + mainText, + style: GoogleFonts.ubuntu( + fontWeight: FontWeight.w600, + ), + ), + TextButton( + onPressed: buttonOnTap, + style: + TextButton.styleFrom(primary: buttonColor.withOpacity(0.5)), + child: Text( + buttonText, + style: GoogleFonts.ubuntu( + fontWeight: FontWeight.w600, color: buttonColor), + )) + ], + ), + ); + } +} diff --git a/pubspec.lock b/pubspec.lock index e77bdae..aea3ad3 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -15,6 +15,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "4.1.0" + ansicolor: + dependency: "direct dev" + description: + name: ansicolor + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" args: dependency: transitive description: @@ -258,6 +265,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "4.0.0" + flutter_riverpod: + dependency: "direct main" + description: + name: flutter_riverpod + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.4" flutter_slidable: dependency: "direct main" description: @@ -289,6 +303,13 @@ packages: description: flutter source: sdk version: "0.0.0" + fluttertoast: + dependency: "direct main" + description: + name: fluttertoast + url: "https://pub.dartlang.org" + source: hosted + version: "8.0.9" font_awesome_flutter: dependency: "direct main" description: @@ -604,6 +625,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.0" + riverpod: + dependency: transitive + description: + name: riverpod + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.3" rxdart: dependency: transitive description: @@ -770,6 +798,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.10.0" + state_notifier: + dependency: transitive + description: + name: state_notifier + url: "https://pub.dartlang.org" + source: hosted + version: "0.7.2+1" stream_channel: dependency: transitive description: @@ -912,4 +947,4 @@ packages: version: "3.1.0" sdks: dart: ">=2.17.0-206.0.dev <3.0.0" - flutter: ">=2.10.0-0" + flutter: ">=3.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 234bdde..5d647d4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -19,6 +19,7 @@ dependencies: font_awesome_flutter: ^10.1.0 google_fonts: ^3.0.1 ms_undraw: ^3.0.1+1 + fluttertoast: ^8.0.9 flutter_spinkit: ^5.1.0 flutter_rating_bar: ^4.0.0 google_nav_bar: ^5.0.5 @@ -35,6 +36,9 @@ dependencies: http: ^0.13.4 cached_network_image: ^3.2.0 speech_to_text: ^5.6.0 + flutter_riverpod: ^1.0.4 + + dev_dependencies: flutter_test: @@ -43,6 +47,7 @@ dev_dependencies: test: ^1.17.12 build_runner: ^2.1.7 hive_generator: ^1.1.2 + ansicolor: ^2.0.1 flutter: uses-material-design: true diff --git a/res/layout/toast_custom.xml b/res/layout/toast_custom.xml new file mode 100644 index 0000000..28f10d1 --- /dev/null +++ b/res/layout/toast_custom.xml @@ -0,0 +1,23 @@ + + + + + \ No newline at end of file