From 7ca032b3f55c45842a2e2808b3a82863bf5cd8df Mon Sep 17 00:00:00 2001 From: zarzet Date: Tue, 13 Jan 2026 18:18:03 +0700 Subject: [PATCH] fix: remove unnecessary PopScope to prevent back gesture freeze Removes PopScope wrapper from settings pages that don't need it. PopScope with canPop: true was causing race condition with Android gesture navigation, freezing the app. --- CHANGELOG.md | 1 + lib/screens/settings/about_page.dart | 77 ++++++------- .../settings/appearance_settings_page.dart | 43 ++++--- .../settings/download_settings_page.dart | 87 +++++++-------- lib/screens/settings/log_screen.dart | 105 +++++++++--------- .../settings/options_settings_page.dart | 87 +++++++-------- 6 files changed, 193 insertions(+), 207 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b9f50f7..1fcc236 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ ### Fixed - Extension packages now preserve directory structure (subdirectories supported) +- Back gesture freeze in settings pages on Android gesture navigation --- diff --git a/lib/screens/settings/about_page.dart b/lib/screens/settings/about_page.dart index c29298f..c1bbc2a 100644 --- a/lib/screens/settings/about_page.dart +++ b/lib/screens/settings/about_page.dart @@ -12,46 +12,44 @@ class AboutPage extends StatelessWidget { final colorScheme = Theme.of(context).colorScheme; final topPadding = MediaQuery.of(context).padding.top; - return PopScope( - canPop: true, - child: Scaffold( - body: CustomScrollView( - slivers: [ - // Collapsing App Bar with back button - SliverAppBar( - expandedHeight: 120 + topPadding, - collapsedHeight: kToolbarHeight, - floating: false, - pinned: true, - backgroundColor: colorScheme.surface, - surfaceTintColor: Colors.transparent, - leading: IconButton( - icon: const Icon(Icons.arrow_back), - onPressed: () => Navigator.pop(context), - ), - flexibleSpace: LayoutBuilder( - builder: (context, constraints) { - final maxHeight = 120 + topPadding; - final minHeight = kToolbarHeight + topPadding; - final expandRatio = ((constraints.maxHeight - minHeight) / (maxHeight - minHeight)).clamp(0.0, 1.0); - // When collapsed (expandRatio=0): left=56 to avoid back button - // When expanded (expandRatio=1): left=24 for normal padding - final leftPadding = 56 - (32 * expandRatio); // 56 -> 24 - return FlexibleSpaceBar( - expandedTitleScale: 1.0, - titlePadding: EdgeInsets.only(left: leftPadding, bottom: 16), - title: Text( - 'About', - style: TextStyle( - fontSize: 20 + (8 * expandRatio), // 20 -> 28 - fontWeight: FontWeight.bold, - color: colorScheme.onSurface, - ), - ), - ); - }, - ), + return Scaffold( + body: CustomScrollView( + slivers: [ + // Collapsing App Bar with back button + SliverAppBar( + expandedHeight: 120 + topPadding, + collapsedHeight: kToolbarHeight, + floating: false, + pinned: true, + backgroundColor: colorScheme.surface, + surfaceTintColor: Colors.transparent, + leading: IconButton( + icon: const Icon(Icons.arrow_back), + onPressed: () => Navigator.pop(context), ), + flexibleSpace: LayoutBuilder( + builder: (context, constraints) { + final maxHeight = 120 + topPadding; + final minHeight = kToolbarHeight + topPadding; + final expandRatio = ((constraints.maxHeight - minHeight) / (maxHeight - minHeight)).clamp(0.0, 1.0); + // When collapsed (expandRatio=0): left=56 to avoid back button + // When expanded (expandRatio=1): left=24 for normal padding + final leftPadding = 56 - (32 * expandRatio); // 56 -> 24 + return FlexibleSpaceBar( + expandedTitleScale: 1.0, + titlePadding: EdgeInsets.only(left: leftPadding, bottom: 16), + title: Text( + 'About', + style: TextStyle( + fontSize: 20 + (8 * expandRatio), // 20 -> 28 + fontWeight: FontWeight.bold, + color: colorScheme.onSurface, + ), + ), + ); + }, + ), + ), // App header card with logo and description SliverToBoxAdapter( @@ -220,7 +218,6 @@ class AboutPage extends StatelessWidget { const SliverToBoxAdapter(child: SizedBox(height: 16)), ], ), - ), ); } diff --git a/lib/screens/settings/appearance_settings_page.dart b/lib/screens/settings/appearance_settings_page.dart index 8412913..88c50de 100644 --- a/lib/screens/settings/appearance_settings_page.dart +++ b/lib/screens/settings/appearance_settings_page.dart @@ -14,28 +14,26 @@ class AppearanceSettingsPage extends ConsumerWidget { final colorScheme = Theme.of(context).colorScheme; final topPadding = MediaQuery.of(context).padding.top; - return PopScope( - canPop: true, - child: Scaffold( - body: CustomScrollView( - slivers: [ - // Collapsing App Bar with back button - SliverAppBar( - expandedHeight: 120 + topPadding, - collapsedHeight: kToolbarHeight, - floating: false, - pinned: true, - backgroundColor: colorScheme.surface, - surfaceTintColor: Colors.transparent, - leading: IconButton( - icon: const Icon(Icons.arrow_back), - onPressed: () => Navigator.pop(context), - ), - flexibleSpace: _AppBarTitle( - title: 'Appearance', - topPadding: topPadding, - ), + return Scaffold( + body: CustomScrollView( + slivers: [ + // Collapsing App Bar with back button + SliverAppBar( + expandedHeight: 120 + topPadding, + collapsedHeight: kToolbarHeight, + floating: false, + pinned: true, + backgroundColor: colorScheme.surface, + surfaceTintColor: Colors.transparent, + leading: IconButton( + icon: const Icon(Icons.arrow_back), + onPressed: () => Navigator.pop(context), ), + flexibleSpace: _AppBarTitle( + title: 'Appearance', + topPadding: topPadding, + ), + ), // Preview Section SliverToBoxAdapter( @@ -131,8 +129,7 @@ class AppearanceSettingsPage extends ConsumerWidget { ), ], ), - ), - ); + ); } } diff --git a/lib/screens/settings/download_settings_page.dart b/lib/screens/settings/download_settings_page.dart index c712621..0fec3ed 100644 --- a/lib/screens/settings/download_settings_page.dart +++ b/lib/screens/settings/download_settings_page.dart @@ -22,50 +22,48 @@ class DownloadSettingsPage extends ConsumerWidget { // Check if current service is built-in (supports quality options) final isBuiltInService = _builtInServices.contains(settings.defaultService); - return PopScope( - canPop: true, - child: Scaffold( - body: CustomScrollView( - slivers: [ - // Collapsing App Bar with back button - SliverAppBar( - expandedHeight: 120 + topPadding, - collapsedHeight: kToolbarHeight, - floating: false, - pinned: true, - backgroundColor: colorScheme.surface, - surfaceTintColor: Colors.transparent, - leading: IconButton( - icon: const Icon(Icons.arrow_back), - onPressed: () => Navigator.pop(context), - ), - flexibleSpace: LayoutBuilder( - builder: (context, constraints) { - final maxHeight = 120 + topPadding; - final minHeight = kToolbarHeight + topPadding; - final expandRatio = - ((constraints.maxHeight - minHeight) / - (maxHeight - minHeight)) - .clamp(0.0, 1.0); - final leftPadding = 56 - (32 * expandRatio); // 56 -> 24 - return FlexibleSpaceBar( - expandedTitleScale: 1.0, - titlePadding: EdgeInsets.only( - left: leftPadding, - bottom: 16, - ), - title: Text( - 'Download', - style: TextStyle( - fontSize: 20 + (8 * expandRatio), // 20 -> 28 - fontWeight: FontWeight.bold, - color: colorScheme.onSurface, - ), - ), - ); - }, - ), + return Scaffold( + body: CustomScrollView( + slivers: [ + // Collapsing App Bar with back button + SliverAppBar( + expandedHeight: 120 + topPadding, + collapsedHeight: kToolbarHeight, + floating: false, + pinned: true, + backgroundColor: colorScheme.surface, + surfaceTintColor: Colors.transparent, + leading: IconButton( + icon: const Icon(Icons.arrow_back), + onPressed: () => Navigator.pop(context), ), + flexibleSpace: LayoutBuilder( + builder: (context, constraints) { + final maxHeight = 120 + topPadding; + final minHeight = kToolbarHeight + topPadding; + final expandRatio = + ((constraints.maxHeight - minHeight) / + (maxHeight - minHeight)) + .clamp(0.0, 1.0); + final leftPadding = 56 - (32 * expandRatio); // 56 -> 24 + return FlexibleSpaceBar( + expandedTitleScale: 1.0, + titlePadding: EdgeInsets.only( + left: leftPadding, + bottom: 16, + ), + title: Text( + 'Download', + style: TextStyle( + fontSize: 20 + (8 * expandRatio), // 20 -> 28 + fontWeight: FontWeight.bold, + color: colorScheme.onSurface, + ), + ), + ); + }, + ), + ), // Service section const SliverToBoxAdapter( @@ -217,8 +215,7 @@ class DownloadSettingsPage extends ConsumerWidget { const SliverToBoxAdapter(child: SizedBox(height: 32)), ], ), - ), - ); + ); } void _showFormatEditor(BuildContext context, WidgetRef ref, String current) { diff --git a/lib/screens/settings/log_screen.dart b/lib/screens/settings/log_screen.dart index 46ba3c4..5e33ec4 100644 --- a/lib/screens/settings/log_screen.dart +++ b/lib/screens/settings/log_screen.dart @@ -124,60 +124,58 @@ class _LogScreenState extends State { final topPadding = MediaQuery.of(context).padding.top; final logs = _filteredLogs; - return PopScope( - canPop: true, - child: Scaffold( - body: CustomScrollView( - controller: _scrollController, - slivers: [ - // Collapsing App Bar with back button - same as other settings pages - SliverAppBar( - expandedHeight: 120 + topPadding, - collapsedHeight: kToolbarHeight, - floating: false, - pinned: true, - backgroundColor: colorScheme.surface, - surfaceTintColor: Colors.transparent, - leading: IconButton( - icon: const Icon(Icons.arrow_back), - onPressed: () => Navigator.pop(context), + return Scaffold( + body: CustomScrollView( + controller: _scrollController, + slivers: [ + // Collapsing App Bar with back button - same as other settings pages + SliverAppBar( + expandedHeight: 120 + topPadding, + collapsedHeight: kToolbarHeight, + floating: false, + pinned: true, + backgroundColor: colorScheme.surface, + surfaceTintColor: Colors.transparent, + leading: IconButton( + icon: const Icon(Icons.arrow_back), + onPressed: () => Navigator.pop(context), + ), + actions: [ + IconButton( + icon: Icon(_autoScroll ? Icons.vertical_align_bottom : Icons.vertical_align_center), + tooltip: _autoScroll ? 'Auto-scroll ON' : 'Auto-scroll OFF', + onPressed: () => setState(() => _autoScroll = !_autoScroll), ), - actions: [ - IconButton( - icon: Icon(_autoScroll ? Icons.vertical_align_bottom : Icons.vertical_align_center), - tooltip: _autoScroll ? 'Auto-scroll ON' : 'Auto-scroll OFF', - onPressed: () => setState(() => _autoScroll = !_autoScroll), - ), - IconButton( - icon: const Icon(Icons.copy), - tooltip: 'Copy logs', - onPressed: _copyLogs, - ), - PopupMenuButton( - icon: const Icon(Icons.more_vert), - onSelected: (value) { - switch (value) { - case 'share': - _shareLogs(); - break; - case 'clear': - _clearLogs(); - break; - } - }, - itemBuilder: (context) => [ - const PopupMenuItem( - value: 'share', - child: ListTile( - leading: Icon(Icons.share), - title: Text('Share logs'), - contentPadding: EdgeInsets.zero, - ), + IconButton( + icon: const Icon(Icons.copy), + tooltip: 'Copy logs', + onPressed: _copyLogs, + ), + PopupMenuButton( + icon: const Icon(Icons.more_vert), + onSelected: (value) { + switch (value) { + case 'share': + _shareLogs(); + break; + case 'clear': + _clearLogs(); + break; + } + }, + itemBuilder: (context) => [ + const PopupMenuItem( + value: 'share', + child: ListTile( + leading: Icon(Icons.share), + title: Text('Share logs'), + contentPadding: EdgeInsets.zero, ), - const PopupMenuItem( - value: 'clear', - child: ListTile( - leading: Icon(Icons.delete_outline), + ), + const PopupMenuItem( + value: 'clear', + child: ListTile( + leading: Icon(Icons.delete_outline), title: Text('Clear logs'), contentPadding: EdgeInsets.zero, ), @@ -380,8 +378,7 @@ class _LogScreenState extends State { const SliverToBoxAdapter(child: SizedBox(height: 32)), ], ), - ), - ); + ); } } diff --git a/lib/screens/settings/options_settings_page.dart b/lib/screens/settings/options_settings_page.dart index 06113cb..f95c5da 100644 --- a/lib/screens/settings/options_settings_page.dart +++ b/lib/screens/settings/options_settings_page.dart @@ -17,50 +17,48 @@ class OptionsSettingsPage extends ConsumerWidget { final colorScheme = Theme.of(context).colorScheme; final topPadding = MediaQuery.of(context).padding.top; - return PopScope( - canPop: true, - child: Scaffold( - body: CustomScrollView( - slivers: [ - // Collapsing App Bar with back button - SliverAppBar( - expandedHeight: 120 + topPadding, - collapsedHeight: kToolbarHeight, - floating: false, - pinned: true, - backgroundColor: colorScheme.surface, - surfaceTintColor: Colors.transparent, - leading: IconButton( - icon: const Icon(Icons.arrow_back), - onPressed: () => Navigator.pop(context), - ), - flexibleSpace: LayoutBuilder( - builder: (context, constraints) { - final maxHeight = 120 + topPadding; - final minHeight = kToolbarHeight + topPadding; - final expandRatio = - ((constraints.maxHeight - minHeight) / - (maxHeight - minHeight)) - .clamp(0.0, 1.0); - final leftPadding = 56 - (32 * expandRatio); // 56 -> 24 - return FlexibleSpaceBar( - expandedTitleScale: 1.0, - titlePadding: EdgeInsets.only( - left: leftPadding, - bottom: 16, - ), - title: Text( - 'Options', - style: TextStyle( - fontSize: 20 + (8 * expandRatio), // 20 -> 28 - fontWeight: FontWeight.bold, - color: colorScheme.onSurface, - ), - ), - ); - }, - ), + return Scaffold( + body: CustomScrollView( + slivers: [ + // Collapsing App Bar with back button + SliverAppBar( + expandedHeight: 120 + topPadding, + collapsedHeight: kToolbarHeight, + floating: false, + pinned: true, + backgroundColor: colorScheme.surface, + surfaceTintColor: Colors.transparent, + leading: IconButton( + icon: const Icon(Icons.arrow_back), + onPressed: () => Navigator.pop(context), ), + flexibleSpace: LayoutBuilder( + builder: (context, constraints) { + final maxHeight = 120 + topPadding; + final minHeight = kToolbarHeight + topPadding; + final expandRatio = + ((constraints.maxHeight - minHeight) / + (maxHeight - minHeight)) + .clamp(0.0, 1.0); + final leftPadding = 56 - (32 * expandRatio); // 56 -> 24 + return FlexibleSpaceBar( + expandedTitleScale: 1.0, + titlePadding: EdgeInsets.only( + left: leftPadding, + bottom: 16, + ), + title: Text( + 'Options', + style: TextStyle( + fontSize: 20 + (8 * expandRatio), // 20 -> 28 + fontWeight: FontWeight.bold, + color: colorScheme.onSurface, + ), + ), + ); + }, + ), + ), // Search Source section const SliverToBoxAdapter( @@ -273,8 +271,7 @@ class OptionsSettingsPage extends ConsumerWidget { const SliverToBoxAdapter(child: SizedBox(height: 32)), ], ), - ), - ); + ); } void _showClearHistoryDialog(