diff --git a/lib/presentation/screens/misc/favorite_screen.dart b/lib/presentation/screens/misc/favorite_screen.dart index d46a351..6cf6dc7 100644 --- a/lib/presentation/screens/misc/favorite_screen.dart +++ b/lib/presentation/screens/misc/favorite_screen.dart @@ -1,59 +1,55 @@ +import 'package:context_menus/context_menus.dart'; import 'package:provider/provider.dart'; import 'package:flutter/material.dart'; import '/analytics/analytics.dart'; import '/presentation/widgets/misc/orderable_grid.dart'; import '/utilities/favorite_state.dart'; +import '/utilities/utils.dart'; -class FavoriteScreen extends StatefulWidget { - const FavoriteScreen({super.key, required this.analyticsHelper}); - +class FavoriteScreen extends StatelessWidget { + FavoriteScreen({super.key, required this.analyticsHelper}); final AnalyticsHelper analyticsHelper; - - @override - State createState() => _FavoriteScreenState(); -} - -class _FavoriteScreenState extends State { - final scrollController = ScrollController(); + final PageController pageController = PageController(); @override Widget build(BuildContext context) { - FavoriteState favoriteState = - Provider.of(context, listen: false); - List categories = - List.from(favoriteState.favoriteBox.keys.toList()); - final generatedChildren = List.generate( - categories.length, - (index) => OrderableGrid( - gridKey: GlobalKey(), - favoriteItems: favoriteState.getListOfType(categories[index]), - typeName: categories[index], - analyticsHelper: widget.analyticsHelper, - scrollController: scrollController, - ), - ); - return Scaffold( - appBar: AppBar( - title: const Text('Favorites'), - actions: [ - Consumer( - builder: (context, favoriteState, child) { - return IconButton( - onPressed: () { - favoriteState.toggleMultiSelect(); + final constraintsValues = getPreset(MediaQuery.of(context).size); + return ContextMenuOverlay( + child: Scaffold( + appBar: AppBar( + title: const Text('Favorites'), + ), + body: Consumer( + builder: (context, favoriteState, child) { + List categories = + List.from(favoriteState.favoriteBox.keys.toList()); + + return Scrollbar( + thumbVisibility: true, + thickness: 10, + scrollbarOrientation: ScrollbarOrientation.top, + radius: const Radius.circular(20), + controller: pageController, + child: PageView.builder( + itemCount: categories.length, + scrollDirection: Axis.horizontal, + controller: pageController, + itemBuilder: (context, index) { + return Padding( + padding: const EdgeInsets.all(20), + child: OrderableGrid( + items: favoriteState.getListOfType(categories[index]), + categoryType: categories[index], + globalKeyGridView: GlobalKey(), + constraints: constraintsValues, + analyticsHelper: analyticsHelper, + ), + ); }, - icon: Icon(!favoriteState.isMultiSelectMode - ? Icons.delete - : Icons.close), - ); - }, - ), - ], - ), - body: ListView( - shrinkWrap: true, - controller: scrollController, - children: generatedChildren, + ), + ); + }, + ), ), ); } diff --git a/lib/presentation/widgets/misc/draggable_pop_menu.dart b/lib/presentation/widgets/misc/draggable_pop_menu.dart new file mode 100644 index 0000000..07eed08 --- /dev/null +++ b/lib/presentation/widgets/misc/draggable_pop_menu.dart @@ -0,0 +1,36 @@ +import 'package:context_menus/context_menus.dart'; +import 'package:provider/provider.dart'; +import 'package:flutter/material.dart'; +import '/hive/favorite_model.dart'; +import '/utilities/favorite_state.dart'; + +class DraggablePopMenu extends StatelessWidget { + const DraggablePopMenu({ + required this.items, + required this.selectedItem, + super.key, + }); + final FavoriteModel selectedItem; + final List items; + + @override + Widget build(BuildContext context) { + return Consumer( + builder: (context, favoriteState, child) { + return GenericContextMenu( + buttonConfigs: [ + ContextMenuButtonConfig( + "Remove from favorites", + icon: const Icon(Icons.delete), + onPressed: () { + favoriteState.toggleFavoriteFunc( + context, favoriteState, selectedItem); + items.removeWhere((item) => item.id == selectedItem.id); + }, + ), + ], + ); + }, + ); + } +} diff --git a/lib/presentation/widgets/misc/favorite_card.dart b/lib/presentation/widgets/misc/favorite_card.dart index 90d9def..719dba0 100644 --- a/lib/presentation/widgets/misc/favorite_card.dart +++ b/lib/presentation/widgets/misc/favorite_card.dart @@ -28,10 +28,6 @@ class FavoriteCard extends StatelessWidget { return Consumer( builder: (context, favoriteState, child) { return InkWell( - onLongPress: () { - favoriteState.toggleFavoriteFunc(context, favoriteState, favItem); - favoriteItems.removeWhere((item) => item.id == favItem.id); - }, onTap: () { if (!favoriteState.isMultiSelectMode) { navigateToPage( diff --git a/lib/presentation/widgets/misc/orderable_grid.dart b/lib/presentation/widgets/misc/orderable_grid.dart index d17c9eb..9cfe51c 100644 --- a/lib/presentation/widgets/misc/orderable_grid.dart +++ b/lib/presentation/widgets/misc/orderable_grid.dart @@ -1,104 +1,77 @@ -import 'package:btd6wiki/hive/favorite_model.dart'; -import 'package:btd6wiki/presentation/widgets/misc/favorite_card.dart'; -import 'package:flutter_reorderable_grid_view/entities/order_update_entity.dart'; -import 'package:flutter_reorderable_grid_view/widgets/widgets.dart'; +import 'package:context_menus/context_menus.dart'; +import 'package:reorderables/reorderables.dart'; import 'package:provider/provider.dart'; import 'package:flutter/material.dart'; +import '/hive/favorite_model.dart'; import '/analytics/analytics.dart'; +import '/presentation/widgets/misc/favorite_card.dart'; import '/utilities/favorite_state.dart'; -import '/utilities/constants.dart'; -import '/utilities/strings.dart'; -import '/utilities/utils.dart'; + +import 'draggable_pop_menu.dart'; class OrderableGrid extends StatefulWidget { const OrderableGrid({ super.key, - required this.gridKey, - required this.typeName, - required this.favoriteItems, + required this.items, + required this.categoryType, + required this.globalKeyGridView, + required this.constraints, required this.analyticsHelper, - required this.scrollController, }); - - final GlobalKey gridKey; - final String typeName; - final List favoriteItems; + final List items; final AnalyticsHelper analyticsHelper; - final ScrollController scrollController; + + final String categoryType; + final GlobalKey globalKeyGridView; + final Map constraints; @override State createState() => _OrderableGridState(); } class _OrderableGridState extends State { - // @override - // void dispose() { - // // TODO: implement dispose - // widget.scrollController.detach(); - // super.dispose(); - // } + final ScrollController scrollController = ScrollController(); @override Widget build(BuildContext context) { - final constraintsValues = getPreset( - MediaQuery.of(context).size, + List orderedItems = List.generate( + widget.items.length, + (index) => SizedBox( + width: MediaQuery.of(context).size.width * 0.25, + height: MediaQuery.of(context).size.width * 0.25, + child: FavoriteCard( + favItem: widget.items[index], + favoriteItems: widget.items, + analyticsHelper: widget.analyticsHelper, + typeName: widget.categoryType, + constraintsValues: widget.constraints, + ), + ), ); return Consumer( builder: (context, favoriteState, child) { - List generatedChildren = List.generate( - widget.favoriteItems.length, - (index) { - FavoriteModel favItem = widget.favoriteItems.elementAt(index); - return FavoriteCard( - key: Key(favItem.id), - favItem: favItem, - favoriteItems: widget.favoriteItems, - analyticsHelper: widget.analyticsHelper, - typeName: widget.typeName, - constraintsValues: constraintsValues); + return ReorderableWrap( + spacing: MediaQuery.of(context).size.width * 0.04, + runSpacing: MediaQuery.of(context).size.width * 0.04, + reorderAnimationDuration: const Duration(milliseconds: 0), + scrollAnimationDuration: const Duration(milliseconds: 100), + controller: scrollController, + padding: const EdgeInsets.all(12), + onNoReorder: (index) { + context.contextMenuOverlay.show(DraggablePopMenu( + items: widget.items, + selectedItem: widget.items[index], + )); + }, + onReorder: (oldIndex, newIndex) { + setState(() { + final favItem = widget.items.removeAt(oldIndex); + widget.items.insert(newIndex, favItem); + }); + favoriteState.updateIndexes(widget.categoryType, widget.items); }, + children: orderedItems, ); - if (generatedChildren.isNotEmpty) { - return Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - children: [ - Text( - capitalizeEveryWord(widget.typeName), - style: bigTitleStyle, - ), - ReorderableBuilder( - enableLongPress: false, - scrollController: ScrollController(), - onReorder: (List orderUpdateEntities) { - for (final orderUpdateEntity in orderUpdateEntities) { - final favItem = widget.favoriteItems - .removeAt(orderUpdateEntity.oldIndex); - widget.favoriteItems - .insert(orderUpdateEntity.newIndex, favItem); - } - favoriteState.updateIndexes( - widget.typeName, widget.favoriteItems); - }, - builder: (children) { - return GridView( - key: widget.gridKey, - shrinkWrap: true, - physics: NeverScrollableScrollPhysics(), - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: constraintsValues[favItemCrossCount], - childAspectRatio: constraintsValues[favItemAspectRatio], - ), - children: children, - ); - }, - children: generatedChildren, - ), - ], - ), - ); - } - return Container(); }, ); } diff --git a/lib/utilities/favorite_state.dart b/lib/utilities/favorite_state.dart index 0b4977a..7966281 100644 --- a/lib/utilities/favorite_state.dart +++ b/lib/utilities/favorite_state.dart @@ -29,8 +29,10 @@ class FavoriteState extends ChangeNotifier { notifyListeners(); } - void toggleDrag() { - draggableMode = !draggableMode; + void toggleDrag(bool dragStatus) { + print('drag mode started as $draggableMode'); + print('drag mode changing to $dragStatus'); + draggableMode = dragStatus; notifyListeners(); } diff --git a/pubspec.lock b/pubspec.lock index bf26608..621348d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -201,6 +201,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.18.0" + context_menus: + dependency: "direct main" + description: + name: context_menus + sha256: "25313f2a17dc936f541f8012761648cb58d936c5d6f6bf7282f137a4b9dedddb" + url: "https://pub.dev" + source: hosted + version: "1.0.2" convert: dependency: transitive description: @@ -233,14 +241,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.4" - equatable: - dependency: transitive - description: - name: equatable - sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2 - url: "https://pub.dev" - source: hosted - version: "2.0.5" fake_async: dependency: transitive description: @@ -342,14 +342,6 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.1" - flutter_reorderable_grid_view: - dependency: "direct main" - description: - name: flutter_reorderable_grid_view - sha256: ac92a49a8411adfda40f75eff44d0958ee879b0f9d6776bb6154c74aa166aaf1 - url: "https://pub.dev" - source: hosted - version: "4.0.0" flutter_test: dependency: "direct dev" description: flutter @@ -664,6 +656,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.3" + reorderables: + dependency: "direct main" + description: + name: reorderables + sha256: "004a886e4878df1ee27321831c838bc1c976311f4ca6a74ce7d561e506540a77" + url: "https://pub.dev" + source: hosted + version: "0.6.0" shared_preferences: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index f0cec73..cfc4a56 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -48,7 +48,8 @@ dependencies: provider: ^6.1.1 hive: ^2.2.3 hive_flutter: ^1.1.0 - flutter_reorderable_grid_view: ^4.0.0 + reorderables: ^0.6.0 + context_menus: ^1.0.2 dev_dependencies: flutter_launcher_icons: ^0.13.1