From 044f6107d0e16a077a3a5b8ff2e19dea635fa946 Mon Sep 17 00:00:00 2001 From: MuZhou233 Date: Wed, 21 Feb 2024 04:00:06 +0000 Subject: [PATCH] fix(gebura): reduce render stuck --- lib/route.dart | 28 +- .../pages/gebura/gebura_library_detail.dart | 3 +- .../pages/gebura/gebura_library_overview.dart | 6 +- lib/view/pages/gebura/gebura_nav.dart | 264 +++++++++--------- pubspec.yaml | 1 + 5 files changed, 155 insertions(+), 147 deletions(-) diff --git a/lib/route.dart b/lib/route.dart index 03e5a4f..3b5c931 100644 --- a/lib/route.dart +++ b/lib/route.dart @@ -4,6 +4,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; +import 'package:local_hero/local_hero.dart'; import 'package:tuihub_protos/librarian/sephirah/v1/gebura.pb.dart'; import 'package:tuihub_protos/librarian/sephirah/v1/tiphereth.pb.dart'; import 'package:tuihub_protos/librarian/v1/common.pb.dart'; @@ -73,13 +74,13 @@ class AppRoutes { } } - void push(BuildContext context, {Object? extra}) { - unawaited(GoRouter.of(context).push(path, extra: extra)); - if (isAction) { - OverlappingPanels.of(context)?.reveal(RevealSide.right); - FramePage.of(context)?.openDrawer(); - } - } + // void push(BuildContext context, {Object? extra}) { + // unawaited(GoRouter.of(context).push(path, extra: extra)); + // if (isAction) { + // OverlappingPanels.of(context)?.reveal(RevealSide.right); + // FramePage.of(context)?.openDrawer(); + // } + // } void pop(BuildContext context) { if (isAction) { @@ -438,12 +439,15 @@ GoRouter getRouter(MainBloc mainBloc, ApiHelper apiHelper) { return CustomTransitionPage( key: state.pageKey, transitionsBuilder: (_, __, ___, child) => child, - child: FramePage( - selectedNav: ModuleName.gebura, - leftPart: GeburaNav( - function: function, + child: LocalHeroScope( + curve: Curves.easeInOut, + child: FramePage( + selectedNav: ModuleName.gebura, + leftPart: GeburaNav( + function: function, + ), + middlePart: page, ), - middlePart: page, ), ); }, diff --git a/lib/view/pages/gebura/gebura_library_detail.dart b/lib/view/pages/gebura/gebura_library_detail.dart index 275d8df..ff5a1d1 100644 --- a/lib/view/pages/gebura/gebura_library_detail.dart +++ b/lib/view/pages/gebura/gebura_library_detail.dart @@ -5,6 +5,7 @@ import 'package:fixnum/fixnum.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:local_hero/local_hero.dart'; import 'package:tuihub_protos/librarian/sephirah/v1/gebura.pb.dart'; import 'package:tuihub_protos/librarian/v1/common.pb.dart'; @@ -117,7 +118,7 @@ class GeburaLibraryDetailPage extends StatelessWidget { xxs: 3, child: Padding( padding: const EdgeInsets.all(8), - child: Hero( + child: LocalHero( tag: item.id.id.toString(), child: UrlHelper.isValidUrl(item.coverImageUrl) ? ExtendedImage.network( diff --git a/lib/view/pages/gebura/gebura_library_overview.dart b/lib/view/pages/gebura/gebura_library_overview.dart index 3d47042..73c98b2 100644 --- a/lib/view/pages/gebura/gebura_library_overview.dart +++ b/lib/view/pages/gebura/gebura_library_overview.dart @@ -1,6 +1,7 @@ import 'package:extended_image/extended_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:local_hero/local_hero.dart'; import 'package:tuihub_protos/librarian/v1/common.pb.dart'; import '../../../bloc/gebura/gebura_bloc.dart'; @@ -115,8 +116,7 @@ class _GeburaLibraryOverviewItemState context .read() .add(GeburaSetSelectedLibraryItemEvent(widget.item.id)); - AppRoutes.geburaLibraryDetail(widget.item.id.id.toInt()) - .push(context); + AppRoutes.geburaLibraryDetail(widget.item.id.id.toInt()).go(context); }, child: Stack( children: [ @@ -130,7 +130,7 @@ class _GeburaLibraryOverviewItemState child: Center(child: Text(noCoverImage ? name : '')), ), Center( - child: Hero( + child: LocalHero( tag: widget.item.id.id.toString(), child: noCoverImage ? Container() diff --git a/lib/view/pages/gebura/gebura_nav.dart b/lib/view/pages/gebura/gebura_nav.dart index e99ecfe..c496e7c 100644 --- a/lib/view/pages/gebura/gebura_nav.dart +++ b/lib/view/pages/gebura/gebura_nav.dart @@ -19,147 +19,149 @@ class GeburaNav extends StatelessWidget { Widget build(BuildContext context) { var firstBuild = true; final searchController = TextEditingController(); - return BlocBuilder(builder: (context, state) { - if (firstBuild) { - firstBuild = false; - if (state.libraryItems == null) { - context.read().add(GeburaInitEvent()); + return BlocBuilder( + buildWhen: (previous, current) { + return previous.libraryItems != current.libraryItems || + previous.selectedLibraryItem != current.selectedLibraryItem; + }, + builder: (context, state) { + if (firstBuild) { + firstBuild = false; + if (state.libraryItems == null) { + context.read().add(GeburaInitEvent()); + } } - } - return Column( - children: [ - ListTile( - leading: const Icon( - Icons.shopping_cart, - ), - onTap: () { - AppRoutes.geburaStore.go(context); - context - .read() - .add(GeburaSetSelectedLibraryItemEvent(null)); - OverlappingPanels.of(context)?.reveal(RevealSide.main); - }, - title: Text(S.of(context).store), - selected: function == GeburaFunctions.store, - ), - ListTile( - leading: const Icon( - Icons.apps, + return Column( + children: [ + ListTile( + leading: const Icon( + Icons.shopping_cart, + ), + onTap: () { + AppRoutes.geburaStore.go(context); + context + .read() + .add(GeburaSetSelectedLibraryItemEvent(null)); + OverlappingPanels.of(context)?.reveal(RevealSide.main); + }, + title: Text(S.of(context).store), + selected: function == GeburaFunctions.store, ), - onTap: () { - context - .read() - .add(GeburaSetSelectedLibraryItemEvent(null)); - AppRoutes.geburaLibrary.push(context); - OverlappingPanels.of(context)?.reveal(RevealSide.main); - }, - title: Text(S.of(context).library), - selected: function == GeburaFunctions.library && - state.selectedLibraryItem == null, - ), - SpacingHelper.defaultDivider, - Container( - padding: const EdgeInsets.only(bottom: 4), - child: TextField( - controller: searchController, - decoration: InputDecoration( - prefixIcon: const Icon(Icons.filter_alt_outlined), - suffixIcon: state.librarySettings?.query?.isNotEmpty ?? false - ? IconButton( - icon: const Icon(Icons.clear), - onPressed: () { - context - .read() - .add(GeburaApplyLibrarySettingsEvent(query: '')); - searchController.clear(); - }, - ) - : null, - contentPadding: EdgeInsets.zero, - enabledBorder: OutlineInputBorder( - borderRadius: SpacingHelper.defaultBorderRadius, - borderSide: const BorderSide( - style: BorderStyle.none, - ), - ), - focusedBorder: OutlineInputBorder( - borderRadius: SpacingHelper.defaultBorderRadius, - ), + ListTile( + leading: const Icon( + Icons.apps, ), - onChanged: (query) { + onTap: () { + AppRoutes.geburaLibrary.go(context); context .read() - .add(GeburaApplyLibrarySettingsEvent(query: query)); + .add(GeburaSetSelectedLibraryItemEvent(null)); + OverlappingPanels.of(context)?.reveal(RevealSide.main); }, + title: Text(S.of(context).library), + selected: function == GeburaFunctions.library && + state.selectedLibraryItem == null, + ), + SpacingHelper.defaultDivider, + Container( + padding: const EdgeInsets.only(bottom: 4), + child: TextField( + controller: searchController, + decoration: InputDecoration( + prefixIcon: const Icon(Icons.filter_alt_outlined), + suffixIcon: state.librarySettings?.query?.isNotEmpty ?? false + ? IconButton( + icon: const Icon(Icons.clear), + onPressed: () { + context.read().add( + GeburaApplyLibrarySettingsEvent(query: '')); + searchController.clear(); + }, + ) + : null, + contentPadding: EdgeInsets.zero, + enabledBorder: OutlineInputBorder( + borderRadius: SpacingHelper.defaultBorderRadius, + borderSide: const BorderSide( + style: BorderStyle.none, + ), + ), + focusedBorder: OutlineInputBorder( + borderRadius: SpacingHelper.defaultBorderRadius, + ), + ), + onChanged: (query) { + context + .read() + .add(GeburaApplyLibrarySettingsEvent(query: query)); + }, + ), ), - ), - Expanded( - child: DynMouseScroll( - builder: (context, controller, physics) { - return SingleChildScrollView( - controller: controller, - physics: physics, - child: (state.libraryItems != null && - state.libraryItems!.isNotEmpty) - ? Column( - children: [ - for (final AppInfoMixed app - in state.libraryItems ?? []) - ListTile( - selected: app.id.id.toInt() == - state.selectedLibraryItem, - onTap: () { - context.read().add( - GeburaSetSelectedLibraryItemEvent( - app.id)); - AppRoutes.geburaLibraryDetail( - app.id.id.toInt()) - .push(context); - OverlappingPanels.of(context) - ?.reveal(RevealSide.main); - }, - leading: Container( - decoration: app.iconImageUrl.isEmpty - ? const BoxDecoration() - : BoxDecoration( - borderRadius: - BorderRadius.circular(4), - image: DecorationImage( - image: ExtendedNetworkImageProvider( - app.iconImageUrl, - ), - fit: BoxFit.scaleDown, + Expanded( + child: DynMouseScroll( + builder: (context, controller, physics) { + return ListView( + controller: controller, + physics: physics, + children: [ + if (state.libraryItems != null && + state.libraryItems!.isNotEmpty) + for (final AppInfoMixed app + in state.libraryItems ?? []) + Material( + child: ListTile( + // https://github.com/flutter/flutter/issues/86584 + selected: app.id.id.toInt() == + state.selectedLibraryItem, + onTap: () { + AppRoutes.geburaLibraryDetail(app.id.id.toInt()) + .go(context); + context.read().add( + GeburaSetSelectedLibraryItemEvent(app.id)); + OverlappingPanels.of(context) + ?.reveal(RevealSide.main); + }, + leading: Container( + decoration: app.iconImageUrl.isEmpty + ? const BoxDecoration() + : BoxDecoration( + borderRadius: BorderRadius.circular(4), + image: DecorationImage( + image: ExtendedNetworkImageProvider( + app.iconImageUrl, ), + fit: BoxFit.scaleDown, ), - height: 24, - width: 24, - ), - title: Text(app.name.isEmpty - ? app.id.id.toHexString() - : app.name), - ) - ], - ) - : (state is GeburaRefreshLibraryState) - ? (state.processing) - ? const Center( - child: CircularProgressIndicator(), - ) - : (state.failed) - ? Center( - child: Text(S - .of(context) - .loadFailed(state.msg ?? '')), + ), + height: 24, + width: 24, + ), + title: Text(app.name.isEmpty + ? app.id.id.toHexString() + : app.name), + )) + else + (state is GeburaRefreshLibraryState) + ? (state.processing) + ? const Center( + child: CircularProgressIndicator(), ) - : Container() - : Container(), - ); - }, - ), - ) - ], - ); - }); + : (state.failed) + ? Center( + child: Text(S + .of(context) + .loadFailed(state.msg ?? '')), + ) + : Container() + : Container(), + ]); + }, + ), + ) + ], + ); + }, + ); } } diff --git a/pubspec.yaml b/pubspec.yaml index e3b5602..daf8958 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -80,6 +80,7 @@ dependencies: extended_image: ^8.2.0 font_awesome_flutter: ^10.7.0 buttons_tabbar: ^1.3.8 + local_hero: ^0.3.0 # rust bridge ffi: ^2.0.1