From d7359cfd0d61e7f3f87752afab6bbd17be3fd6fd Mon Sep 17 00:00:00 2001
From: LittleSheep <littlesheep.code@hotmail.com>
Date: Mon, 24 Mar 2025 00:09:36 +0800
Subject: [PATCH] :bug: Fixes and optimization in programs

---
 lib/screens/account/programs.dart             | 152 +++++++++---------
 .../navigation/app_drawer_navigation.dart     |  78 ++++-----
 2 files changed, 111 insertions(+), 119 deletions(-)

diff --git a/lib/screens/account/programs.dart b/lib/screens/account/programs.dart
index eb0392e..74f6c8b 100644
--- a/lib/screens/account/programs.dart
+++ b/lib/screens/account/programs.dart
@@ -9,6 +9,7 @@ import 'package:surface/providers/sn_network.dart';
 import 'package:surface/types/account.dart';
 import 'package:surface/widgets/dialog.dart';
 import 'package:surface/widgets/loading_indicator.dart';
+import 'package:surface/widgets/markdown_content.dart';
 import 'package:surface/widgets/navigation/app_scaffold.dart';
 
 class AccountProgramScreen extends StatefulWidget {
@@ -86,14 +87,17 @@ class _AccountProgramScreenState extends State<AccountProgramScreen> {
                     borderRadius: BorderRadius.all(Radius.circular(8)),
                     onTap: () {
                       showModalBottomSheet(
+                        isScrollControlled: true,
                         context: context,
                         builder: (context) => _ProgramJoinPopup(
                           program: ele,
-                          isJoined: _programMembers
-                              .any((ele) => ele.programId == ele.id),
+                          isJoined:
+                              _programMembers.any((e) => e.programId == ele.id),
                         ),
                       ).then((value) {
-                        _fetchProgramMembers();
+                        if (value == true) {
+                          _fetchProgramMembers();
+                        }
                       });
                     },
                     child: Column(
@@ -137,7 +141,7 @@ class _AccountProgramScreenState extends State<AccountProgramScreen> {
                                       overflow: TextOverflow.ellipsis,
                                     ),
                                     if (_programMembers
-                                        .any((ele) => ele.programId == ele.id))
+                                        .any((e) => e.programId == ele.id))
                                       Text('accountProgramAlreadyJoined'.tr())
                                           .opacity(0.75),
                                   ],
@@ -205,80 +209,82 @@ class _ProgramJoinPopupState extends State<_ProgramJoinPopup> {
 
   @override
   Widget build(BuildContext context) {
-    return Column(
-      crossAxisAlignment: CrossAxisAlignment.start,
-      children: [
-        Row(
-          crossAxisAlignment: CrossAxisAlignment.center,
-          children: [
-            const Icon(Symbols.add, size: 24),
-            const Gap(16),
-            Text(
-              'accountProgramJoin',
-              style: Theme.of(context).textTheme.titleLarge,
-            ).tr(),
-          ],
-        ).padding(horizontal: 20, top: 16, bottom: 12),
-        Column(
+    return SizedBox(
+      height: MediaQuery.of(context).size.height * 0.75,
+      child: SingleChildScrollView(
+        child: Column(
           crossAxisAlignment: CrossAxisAlignment.start,
           children: [
-            if (widget.program.appearance['banner'] != null)
-              AspectRatio(
-                aspectRatio: 16 / 5,
-                child: ClipRRect(
-                  borderRadius: BorderRadius.circular(8),
-                  child: Container(
-                    color: Theme.of(context).colorScheme.surfaceVariant,
-                    child: Image.network(
-                      widget.program.appearance['banner'],
-                      color: Theme.of(context).colorScheme.onSurfaceVariant,
+            Row(
+              crossAxisAlignment: CrossAxisAlignment.center,
+              children: [
+                const Icon(Symbols.add, size: 24),
+                const Gap(16),
+                Text(
+                  'accountProgramJoin',
+                  style: Theme.of(context).textTheme.titleLarge,
+                ).tr(),
+              ],
+            ).padding(horizontal: 20, top: 16, bottom: 12),
+            Column(
+              crossAxisAlignment: CrossAxisAlignment.start,
+              children: [
+                if (widget.program.appearance['banner'] != null)
+                  AspectRatio(
+                    aspectRatio: 16 / 5,
+                    child: ClipRRect(
+                      borderRadius: BorderRadius.circular(8),
+                      child: Container(
+                        color: Theme.of(context).colorScheme.surfaceVariant,
+                        child: Image.network(
+                          widget.program.appearance['banner'],
+                          color: Theme.of(context).colorScheme.onSurfaceVariant,
+                        ),
+                      ),
                     ),
+                  ).padding(bottom: 12),
+                Text(
+                  widget.program.name,
+                  style: Theme.of(context).textTheme.titleMedium,
+                ).bold(),
+                MarkdownTextContent(content: widget.program.description),
+                const Gap(8),
+                Text(
+                  'accountProgramJoinRequirements',
+                  style: Theme.of(context).textTheme.titleMedium,
+                ).tr().bold(),
+                Text('≥EXP ${widget.program.expRequirement}'),
+                Text('≥Lv${getLevelFromExp(widget.program.expRequirement)}'),
+                const Gap(8),
+                Text(
+                  'accountProgramJoinPricing',
+                  style: Theme.of(context).textTheme.titleMedium,
+                ).tr().bold(),
+                Text('walletCurrency${widget.program.price['currency'].toString().capitalize().replaceFirst('Normal', '')}')
+                    .plural(widget.program.price['amount'].toDouble()),
+                Text('accountProgramJoinPricingHint').tr().opacity(0.75),
+                const Gap(8),
+                if (widget.isJoined)
+                  Text('accountProgramLeaveHint')
+                      .tr()
+                      .opacity(0.75)
+                      .padding(bottom: 8),
+                if (!widget.isJoined)
+                  ElevatedButton(
+                    onPressed: _isBusy ? null : _joinProgram,
+                    child: Text('join').tr(),
+                  )
+                else
+                  ElevatedButton(
+                    onPressed: _isBusy ? null : _leaveProgram,
+                    child: Text('leave').tr(),
                   ),
-                ),
-              ).padding(bottom: 12),
-            Text(
-              widget.program.name,
-              style: Theme.of(context).textTheme.titleMedium,
-            ).bold(),
-            Text(
-              widget.program.description,
-              maxLines: 3,
-              overflow: TextOverflow.ellipsis,
-            ),
-            const Gap(8),
-            Text(
-              'accountProgramJoinRequirements',
-              style: Theme.of(context).textTheme.titleMedium,
-            ).tr().bold(),
-            Text('≥EXP ${widget.program.expRequirement}'),
-            Text('≥Lv${getLevelFromExp(widget.program.expRequirement)}'),
-            const Gap(8),
-            Text(
-              'accountProgramJoinPricing',
-              style: Theme.of(context).textTheme.titleMedium,
-            ).tr().bold(),
-            Text('walletCurrency${widget.program.price['currency'].toString().capitalize().replaceFirst('Normal', '')}')
-                .plural(widget.program.price['amount'].toDouble()),
-            Text('accountProgramJoinPricingHint').tr().opacity(0.75),
-            const Gap(8),
-            if (widget.isJoined)
-              Text('accountProgramLeaveHint')
-                  .tr()
-                  .opacity(0.75)
-                  .padding(bottom: 8),
-            if (!widget.isJoined)
-              ElevatedButton(
-                onPressed: _isBusy ? null : _joinProgram,
-                child: Text('join').tr(),
-              )
-            else
-              ElevatedButton(
-                onPressed: _isBusy ? null : _leaveProgram,
-                child: Text('leave').tr(),
-              ),
+              ],
+            ).padding(horizontal: 24),
+            Gap(MediaQuery.of(context).padding.bottom),
           ],
-        ).padding(horizontal: 24),
-      ],
+        ),
+      ),
     );
   }
 }
diff --git a/lib/widgets/navigation/app_drawer_navigation.dart b/lib/widgets/navigation/app_drawer_navigation.dart
index 1b0df52..a008852 100644
--- a/lib/widgets/navigation/app_drawer_navigation.dart
+++ b/lib/widgets/navigation/app_drawer_navigation.dart
@@ -10,7 +10,6 @@ import 'package:gap/gap.dart';
 import 'package:go_router/go_router.dart';
 import 'package:material_symbols_icons/symbols.dart';
 import 'package:provider/provider.dart';
-import 'package:responsive_framework/responsive_framework.dart';
 import 'package:styled_widget/styled_widget.dart';
 import 'package:surface/providers/channel.dart';
 import 'package:surface/providers/config.dart';
@@ -48,17 +47,6 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
     final nav = context.watch<NavigationProvider>();
     final cfg = context.watch<ConfigProvider>();
 
-    final routeName = GoRouter.of(context)
-        .routerDelegate
-        .currentConfiguration
-        .last
-        .route
-        .name;
-    final showNavButtons = cfg.hideBottomNav ||
-        !(nav.showBottomNavScreen.contains(routeName)
-            ? ResponsiveBreakpoints.of(context).smallerOrEqualTo(MOBILE)
-            : false);
-
     final backgroundColor = cfg.drawerIsExpanded ? Colors.transparent : null;
 
     return ListenableBuilder(
@@ -67,7 +55,8 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
         return Drawer(
           elevation: widget.elevation,
           backgroundColor: backgroundColor,
-          shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(0))),
+          shape: const RoundedRectangleBorder(
+              borderRadius: BorderRadius.all(Radius.circular(0))),
           child: Column(
             mainAxisSize: MainAxisSize.max,
             crossAxisAlignment: CrossAxisAlignment.start,
@@ -92,42 +81,39 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
               Expanded(
                 child: _DrawerContentList(),
               ),
-              if (showNavButtons)
-                Row(
-                  spacing: 8,
-                  children:
-                      nav.destinations.where((ele) => ele.isPinned).mapIndexed(
-                    (idx, ele) {
-                      return Expanded(
-                        child: Tooltip(
-                          message: ele.label.tr(),
-                          child: IconButton(
-                            icon: ele.icon,
-                            color: nav.currentIndex == idx
-                                ? Theme.of(context)
-                                    .colorScheme
-                                    .onPrimaryContainer
-                                : Theme.of(context).colorScheme.onSurface,
-                            style: ButtonStyle(
-                              backgroundColor: WidgetStatePropertyAll(
-                                nav.currentIndex == idx
-                                    ? Theme.of(context)
-                                        .colorScheme
-                                        .primaryContainer
-                                    : Colors.transparent,
-                              ),
+              Row(
+                spacing: 8,
+                children:
+                    nav.destinations.where((ele) => ele.isPinned).mapIndexed(
+                  (idx, ele) {
+                    return Expanded(
+                      child: Tooltip(
+                        message: ele.label.tr(),
+                        child: IconButton(
+                          icon: ele.icon,
+                          color: nav.currentIndex == idx
+                              ? Theme.of(context).colorScheme.onPrimaryContainer
+                              : Theme.of(context).colorScheme.onSurface,
+                          style: ButtonStyle(
+                            backgroundColor: WidgetStatePropertyAll(
+                              nav.currentIndex == idx
+                                  ? Theme.of(context)
+                                      .colorScheme
+                                      .primaryContainer
+                                  : Colors.transparent,
                             ),
-                            onPressed: () {
-                              GoRouter.of(context).goNamed(ele.screen);
-                              Scaffold.of(context).closeDrawer();
-                              nav.setIndex(idx);
-                            },
                           ),
+                          onPressed: () {
+                            GoRouter.of(context).goNamed(ele.screen);
+                            Scaffold.of(context).closeDrawer();
+                            nav.setIndex(idx);
+                          },
                         ),
-                      );
-                    },
-                  ).toList(),
-                ).padding(horizontal: 16, bottom: 8),
+                      ),
+                    );
+                  },
+                ).toList(),
+              ).padding(horizontal: 16, bottom: 8),
               Align(
                 alignment: Alignment.bottomCenter,
                 child: ListTile(