💫 Animated collapsible sidebar
This commit is contained in:
		@@ -383,4 +383,6 @@ const i18nEnglish = {
 | 
				
			|||||||
      'Since the App has entered the background, there may be a time difference between the message list and the server. Click to Refresh.',
 | 
					      'Since the App has entered the background, there may be a time difference between the message list and the server. Click to Refresh.',
 | 
				
			||||||
  'messageHistoryWipe': 'Wipe local message history',
 | 
					  'messageHistoryWipe': 'Wipe local message history',
 | 
				
			||||||
  'unknown': 'Unknown',
 | 
					  'unknown': 'Unknown',
 | 
				
			||||||
 | 
					  'collapse': 'Collapse',
 | 
				
			||||||
 | 
					  'expand': 'Expand',
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -353,4 +353,6 @@ const i18nSimplifiedChinese = {
 | 
				
			|||||||
  'messageOutOfSyncCaption': '由于 App 进入后台,消息列表可能与服务器存在时差,点击刷新。',
 | 
					  'messageOutOfSyncCaption': '由于 App 进入后台,消息列表可能与服务器存在时差,点击刷新。',
 | 
				
			||||||
  'messageHistoryWipe': '清除消息记录',
 | 
					  'messageHistoryWipe': '清除消息记录',
 | 
				
			||||||
  'unknown': '未知',
 | 
					  'unknown': '未知',
 | 
				
			||||||
 | 
					  'collapse': '折叠',
 | 
				
			||||||
 | 
					  'expand': '展开',
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,7 +13,7 @@ import 'package:solian/widgets/account/account_avatar.dart';
 | 
				
			|||||||
import 'package:solian/widgets/account/account_status_action.dart';
 | 
					import 'package:solian/widgets/account/account_status_action.dart';
 | 
				
			||||||
import 'package:solian/widgets/navigation/app_navigation.dart';
 | 
					import 'package:solian/widgets/navigation/app_navigation.dart';
 | 
				
			||||||
import 'package:badges/badges.dart' as badges;
 | 
					import 'package:badges/badges.dart' as badges;
 | 
				
			||||||
import 'package:solian/widgets/navigation/app_navigation_regions.dart';
 | 
					import 'package:solian/widgets/navigation/app_navigation_region.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AppNavigationDrawer extends StatefulWidget {
 | 
					class AppNavigationDrawer extends StatefulWidget {
 | 
				
			||||||
  final String? routeName;
 | 
					  final String? routeName;
 | 
				
			||||||
@@ -24,8 +24,22 @@ class AppNavigationDrawer extends StatefulWidget {
 | 
				
			|||||||
  State<AppNavigationDrawer> createState() => _AppNavigationDrawerState();
 | 
					  State<AppNavigationDrawer> createState() => _AppNavigationDrawerState();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
 | 
					class _AppNavigationDrawerState extends State<AppNavigationDrawer>
 | 
				
			||||||
  bool _isCollapsed = true;
 | 
					    with TickerProviderStateMixin {
 | 
				
			||||||
 | 
					  bool _isCollapsed = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  late final AnimationController _drawerAnimationController =
 | 
				
			||||||
 | 
					      AnimationController(
 | 
				
			||||||
 | 
					    duration: const Duration(milliseconds: 500),
 | 
				
			||||||
 | 
					    vsync: this,
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					  late final Animation<double> _drawerAnimation = Tween<double>(
 | 
				
			||||||
 | 
					    begin: 80.0,
 | 
				
			||||||
 | 
					    end: 304.0,
 | 
				
			||||||
 | 
					  ).animate(CurvedAnimation(
 | 
				
			||||||
 | 
					    parent: _drawerAnimationController,
 | 
				
			||||||
 | 
					    curve: Curves.easeInOut,
 | 
				
			||||||
 | 
					  ));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  AccountStatus? _accountStatus;
 | 
					  AccountStatus? _accountStatus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -42,13 +56,19 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Color get _unFocusColor =>
 | 
				
			||||||
 | 
					      Theme.of(context).colorScheme.onSurface.withOpacity(0.75);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Widget _buildUserInfo() {
 | 
					  Widget _buildUserInfo() {
 | 
				
			||||||
    return Obx(() {
 | 
					    return Obx(() {
 | 
				
			||||||
      final AuthProvider auth = Get.find();
 | 
					      final AuthProvider auth = Get.find();
 | 
				
			||||||
      if (auth.isAuthorized.isFalse || auth.userProfile.value == null) {
 | 
					      if (auth.isAuthorized.isFalse || auth.userProfile.value == null) {
 | 
				
			||||||
        if (_isCollapsed) {
 | 
					        if (_isCollapsed) {
 | 
				
			||||||
          return InkWell(
 | 
					          return InkWell(
 | 
				
			||||||
            child: const Icon(Icons.account_circle).paddingAll(28),
 | 
					            child: const Icon(Icons.account_circle).paddingSymmetric(
 | 
				
			||||||
 | 
					              horizontal: 28,
 | 
				
			||||||
 | 
					              vertical: 20,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
            onTap: () {
 | 
					            onTap: () {
 | 
				
			||||||
              AppRouter.instance.goNamed('account');
 | 
					              AppRouter.instance.goNamed('account');
 | 
				
			||||||
              _closeDrawer();
 | 
					              _closeDrawer();
 | 
				
			||||||
@@ -70,9 +90,7 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      final leading = Obx(() {
 | 
					      final leading = Obx(() {
 | 
				
			||||||
        final statusBadgeColor = _accountStatus != null
 | 
					        final statusBadgeColor = _accountStatus != null
 | 
				
			||||||
            ? StatusProvider.determineStatus(
 | 
					            ? StatusProvider.determineStatus(_accountStatus!).$2
 | 
				
			||||||
                _accountStatus!,
 | 
					 | 
				
			||||||
              ).$2
 | 
					 | 
				
			||||||
            : Colors.grey;
 | 
					            : Colors.grey;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        final RelationshipProvider relations = Get.find();
 | 
					        final RelationshipProvider relations = Get.find();
 | 
				
			||||||
@@ -104,17 +122,23 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      return InkWell(
 | 
					      return InkWell(
 | 
				
			||||||
        child: !_isCollapsed
 | 
					        child: !_isCollapsed
 | 
				
			||||||
            ? ListTile(
 | 
					            ? Row(
 | 
				
			||||||
                contentPadding: const EdgeInsets.only(left: 20, right: 20),
 | 
					                children: [
 | 
				
			||||||
                title: Text(
 | 
					                  leading,
 | 
				
			||||||
 | 
					                  Expanded(
 | 
				
			||||||
 | 
					                    child: Column(
 | 
				
			||||||
 | 
					                      crossAxisAlignment: CrossAxisAlignment.start,
 | 
				
			||||||
 | 
					                      children: [
 | 
				
			||||||
 | 
					                        Text(
 | 
				
			||||||
                          auth.userProfile.value!['nick'],
 | 
					                          auth.userProfile.value!['nick'],
 | 
				
			||||||
                          maxLines: 1,
 | 
					                          maxLines: 1,
 | 
				
			||||||
                          overflow: TextOverflow.fade,
 | 
					                          overflow: TextOverflow.fade,
 | 
				
			||||||
                ),
 | 
					                          style: Theme.of(context).textTheme.bodyLarge,
 | 
				
			||||||
                subtitle: Builder(
 | 
					                        ).paddingOnly(left: 16),
 | 
				
			||||||
 | 
					                        Builder(
 | 
				
			||||||
                          builder: (context) {
 | 
					                          builder: (context) {
 | 
				
			||||||
                            if (_accountStatus == null) {
 | 
					                            if (_accountStatus == null) {
 | 
				
			||||||
                      return Text('loading'.tr);
 | 
					                              return Text('loading'.tr).paddingOnly(left: 16);
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                            final info = StatusProvider.determineStatus(
 | 
					                            final info = StatusProvider.determineStatus(
 | 
				
			||||||
                              _accountStatus!,
 | 
					                              _accountStatus!,
 | 
				
			||||||
@@ -123,12 +147,18 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
 | 
				
			|||||||
                              info.$3,
 | 
					                              info.$3,
 | 
				
			||||||
                              maxLines: 1,
 | 
					                              maxLines: 1,
 | 
				
			||||||
                              overflow: TextOverflow.fade,
 | 
					                              overflow: TextOverflow.fade,
 | 
				
			||||||
                    );
 | 
					                              style: TextStyle(
 | 
				
			||||||
 | 
					                                color: _unFocusColor,
 | 
				
			||||||
 | 
					                              ),
 | 
				
			||||||
 | 
					                            ).paddingOnly(left: 16);
 | 
				
			||||||
                          },
 | 
					                          },
 | 
				
			||||||
                        ),
 | 
					                        ),
 | 
				
			||||||
                leading: leading,
 | 
					                      ],
 | 
				
			||||||
              )
 | 
					                    ),
 | 
				
			||||||
            : leading.paddingAll(20),
 | 
					                  ),
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					              ).paddingSymmetric(horizontal: 20, vertical: 16)
 | 
				
			||||||
 | 
					            : leading.paddingSymmetric(horizontal: 20, vertical: 16),
 | 
				
			||||||
        onTap: () {
 | 
					        onTap: () {
 | 
				
			||||||
          AppRouter.instance.goNamed('account');
 | 
					          AppRouter.instance.goNamed('account');
 | 
				
			||||||
          _closeDrawer();
 | 
					          _closeDrawer();
 | 
				
			||||||
@@ -148,22 +178,59 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
 | 
				
			|||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void _expandDrawer() {
 | 
				
			||||||
 | 
					    _drawerAnimationController.animateTo(1);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void _collapseDrawer() {
 | 
				
			||||||
 | 
					    _drawerAnimationController.animateTo(0);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void _closeDrawer() {
 | 
					  void _closeDrawer() {
 | 
				
			||||||
 | 
					    _autoResize();
 | 
				
			||||||
    rootScaffoldKey.currentState!.closeDrawer();
 | 
					    rootScaffoldKey.currentState!.closeDrawer();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void _autoResize() {
 | 
				
			||||||
 | 
					    if (SolianTheme.isExtraLargeScreen(context)) {
 | 
				
			||||||
 | 
					      _expandDrawer();
 | 
				
			||||||
 | 
					    } else if (SolianTheme.isLargeScreen(context)) {
 | 
				
			||||||
 | 
					      _collapseDrawer();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  void initState() {
 | 
					  void initState() {
 | 
				
			||||||
    super.initState();
 | 
					    super.initState();
 | 
				
			||||||
    _getStatus();
 | 
					    _getStatus();
 | 
				
			||||||
 | 
					    Future.delayed(Duration.zero, () => _autoResize());
 | 
				
			||||||
 | 
					    _drawerAnimationController.addListener(() {
 | 
				
			||||||
 | 
					      if (_drawerAnimation.value > 180 && _isCollapsed) {
 | 
				
			||||||
 | 
					        setState(() => _isCollapsed = false);
 | 
				
			||||||
 | 
					      } else if (_drawerAnimation.value < 180 && !_isCollapsed) {
 | 
				
			||||||
 | 
					        setState(() => _isCollapsed = true);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  void dispose() {
 | 
				
			||||||
 | 
					    _drawerAnimationController.dispose();
 | 
				
			||||||
 | 
					    super.dispose();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Widget build(BuildContext context) {
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
 | 
					    return AnimatedBuilder(
 | 
				
			||||||
 | 
					      animation: _drawerAnimation,
 | 
				
			||||||
 | 
					      builder: (context, child) {
 | 
				
			||||||
        return Drawer(
 | 
					        return Drawer(
 | 
				
			||||||
      width: _isCollapsed ? 80 : null,
 | 
					          width: _drawerAnimation.value,
 | 
				
			||||||
          backgroundColor:
 | 
					          backgroundColor:
 | 
				
			||||||
              SolianTheme.isLargeScreen(context) ? Colors.transparent : null,
 | 
					              SolianTheme.isLargeScreen(context) ? Colors.transparent : null,
 | 
				
			||||||
 | 
					          child: child,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
      child: SafeArea(
 | 
					      child: SafeArea(
 | 
				
			||||||
        bottom: false,
 | 
					        bottom: false,
 | 
				
			||||||
        child: Column(
 | 
					        child: Column(
 | 
				
			||||||
@@ -175,7 +242,7 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
 | 
				
			|||||||
                  .map(
 | 
					                  .map(
 | 
				
			||||||
                    (e) => _isCollapsed
 | 
					                    (e) => _isCollapsed
 | 
				
			||||||
                        ? InkWell(
 | 
					                        ? InkWell(
 | 
				
			||||||
                            child: Icon(e.icon, size: 22).paddingSymmetric(
 | 
					                            child: Icon(e.icon, size: 20).paddingSymmetric(
 | 
				
			||||||
                              horizontal: 28,
 | 
					                              horizontal: 28,
 | 
				
			||||||
                              vertical: 16,
 | 
					                              vertical: 16,
 | 
				
			||||||
                            ),
 | 
					                            ),
 | 
				
			||||||
@@ -201,7 +268,7 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
 | 
				
			|||||||
            ),
 | 
					            ),
 | 
				
			||||||
            const Divider(thickness: 0.3, height: 1),
 | 
					            const Divider(thickness: 0.3, height: 1),
 | 
				
			||||||
            Expanded(
 | 
					            Expanded(
 | 
				
			||||||
              child: AppNavigationRegions(
 | 
					              child: AppNavigationRegion(
 | 
				
			||||||
                isCollapsed: _isCollapsed,
 | 
					                isCollapsed: _isCollapsed,
 | 
				
			||||||
                onSelected: (item) {
 | 
					                onSelected: (item) {
 | 
				
			||||||
                  _closeDrawer();
 | 
					                  _closeDrawer();
 | 
				
			||||||
@@ -211,29 +278,55 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
 | 
				
			|||||||
            const Divider(thickness: 0.3, height: 1),
 | 
					            const Divider(thickness: 0.3, height: 1),
 | 
				
			||||||
            Column(
 | 
					            Column(
 | 
				
			||||||
              children: [
 | 
					              children: [
 | 
				
			||||||
                _isCollapsed
 | 
					                if (_isCollapsed)
 | 
				
			||||||
                    ? InkWell(
 | 
					                  InkWell(
 | 
				
			||||||
                        child: const Icon(Icons.settings, size: 22)
 | 
					                    child: const Icon(
 | 
				
			||||||
                            .paddingSymmetric(
 | 
					                      Icons.settings,
 | 
				
			||||||
 | 
					                      size: 20,
 | 
				
			||||||
 | 
					                    ).paddingSymmetric(
 | 
				
			||||||
                      horizontal: 28,
 | 
					                      horizontal: 28,
 | 
				
			||||||
                          vertical: 16,
 | 
					                      vertical: 10,
 | 
				
			||||||
                    ),
 | 
					                    ),
 | 
				
			||||||
                    onTap: () {
 | 
					                    onTap: () {
 | 
				
			||||||
                      AppRouter.instance.pushNamed('settings');
 | 
					                      AppRouter.instance.pushNamed('settings');
 | 
				
			||||||
                      _closeDrawer();
 | 
					                      _closeDrawer();
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
                  )
 | 
					                  )
 | 
				
			||||||
                    : ListTile(
 | 
					                else
 | 
				
			||||||
 | 
					                  ListTile(
 | 
				
			||||||
 | 
					                    minTileHeight: 0,
 | 
				
			||||||
 | 
					                    contentPadding: const EdgeInsets.symmetric(
 | 
				
			||||||
 | 
					                      horizontal: 20,
 | 
				
			||||||
 | 
					                    ),
 | 
				
			||||||
 | 
					                    leading: const Icon(Icons.settings, size: 20).paddingAll(2),
 | 
				
			||||||
 | 
					                    title: Text('settings'.tr),
 | 
				
			||||||
 | 
					                    onTap: () {
 | 
				
			||||||
 | 
					                      AppRouter.instance.pushNamed('settings');
 | 
				
			||||||
 | 
					                      _closeDrawer();
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                  ),
 | 
				
			||||||
 | 
					                if (_isCollapsed)
 | 
				
			||||||
 | 
					                  InkWell(
 | 
				
			||||||
 | 
					                    child: const Icon(Icons.chevron_right, size: 20)
 | 
				
			||||||
 | 
					                        .paddingSymmetric(
 | 
				
			||||||
 | 
					                      horizontal: 28,
 | 
				
			||||||
 | 
					                      vertical: 10,
 | 
				
			||||||
 | 
					                    ),
 | 
				
			||||||
 | 
					                    onTap: () {
 | 
				
			||||||
 | 
					                      _expandDrawer();
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                  )
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                  ListTile(
 | 
				
			||||||
                    minTileHeight: 0,
 | 
					                    minTileHeight: 0,
 | 
				
			||||||
                    contentPadding: const EdgeInsets.symmetric(
 | 
					                    contentPadding: const EdgeInsets.symmetric(
 | 
				
			||||||
                      horizontal: 20,
 | 
					                      horizontal: 20,
 | 
				
			||||||
                    ),
 | 
					                    ),
 | 
				
			||||||
                    leading:
 | 
					                    leading:
 | 
				
			||||||
                            const Icon(Icons.settings, size: 20).paddingAll(2),
 | 
					                        const Icon(Icons.chevron_left, size: 20).paddingAll(2),
 | 
				
			||||||
                        title: Text('settings'.tr),
 | 
					                    title: Text('collapse'.tr),
 | 
				
			||||||
                    onTap: () {
 | 
					                    onTap: () {
 | 
				
			||||||
                          AppRouter.instance.pushNamed('settings');
 | 
					                      _collapseDrawer();
 | 
				
			||||||
                          _closeDrawer();
 | 
					 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
                  ),
 | 
					                  ),
 | 
				
			||||||
              ],
 | 
					              ],
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,11 +5,11 @@ import 'package:solian/providers/content/channel.dart';
 | 
				
			|||||||
import 'package:solian/router.dart';
 | 
					import 'package:solian/router.dart';
 | 
				
			||||||
import 'package:collection/collection.dart';
 | 
					import 'package:collection/collection.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AppNavigationRegions extends StatelessWidget {
 | 
					class AppNavigationRegion extends StatelessWidget {
 | 
				
			||||||
  final bool isCollapsed;
 | 
					  final bool isCollapsed;
 | 
				
			||||||
  final Function(Channel item) onSelected;
 | 
					  final Function(Channel item) onSelected;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const AppNavigationRegions({
 | 
					  const AppNavigationRegion({
 | 
				
			||||||
    super.key,
 | 
					    super.key,
 | 
				
			||||||
    required this.onSelected,
 | 
					    required this.onSelected,
 | 
				
			||||||
    this.isCollapsed = false,
 | 
					    this.isCollapsed = false,
 | 
				
			||||||
@@ -32,7 +32,7 @@ class AppNavigationRegions extends StatelessWidget {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (isCollapsed) {
 | 
					    if (isCollapsed) {
 | 
				
			||||||
      return InkWell(
 | 
					      return InkWell(
 | 
				
			||||||
        child: const Icon(Icons.tag_outlined).paddingSymmetric(
 | 
					        child: const Icon(Icons.tag_outlined, size: 20).paddingSymmetric(
 | 
				
			||||||
          horizontal: 20,
 | 
					          horizontal: 20,
 | 
				
			||||||
          vertical: 16,
 | 
					          vertical: 16,
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
@@ -2,7 +2,7 @@ name: solian
 | 
				
			|||||||
description: "The Solar Network App"
 | 
					description: "The Solar Network App"
 | 
				
			||||||
publish_to: "none"
 | 
					publish_to: "none"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
version: 1.2.1+20
 | 
					version: 1.2.1+21
 | 
				
			||||||
 | 
					
 | 
				
			||||||
environment:
 | 
					environment:
 | 
				
			||||||
  sdk: ">=3.3.4 <4.0.0"
 | 
					  sdk: ">=3.3.4 <4.0.0"
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user