Solian/lib/widgets/navigation/app_navigation_drawer.dart

331 lines
10 KiB
Dart
Raw Normal View History

2024-08-10 16:36:27 +00:00
import 'dart:math' as math;
2024-07-12 03:39:44 +00:00
import 'package:flutter/material.dart';
2024-07-12 05:15:46 +00:00
import 'package:get/get.dart';
import 'package:solian/models/account_status.dart';
import 'package:solian/providers/account_status.dart';
import 'package:solian/providers/auth.dart';
2024-08-02 15:15:28 +00:00
import 'package:solian/providers/relation.dart';
2024-07-12 03:39:44 +00:00
import 'package:solian/router.dart';
import 'package:solian/shells/root_shell.dart';
import 'package:solian/theme.dart';
2024-07-12 05:15:46 +00:00
import 'package:solian/widgets/account/account_avatar.dart';
import 'package:solian/widgets/account/account_status_action.dart';
2024-07-12 03:39:44 +00:00
import 'package:solian/widgets/navigation/app_navigation.dart';
2024-07-12 05:15:46 +00:00
import 'package:badges/badges.dart' as badges;
2024-08-21 11:11:27 +00:00
import 'package:solian/widgets/navigation/app_navigation_region.dart';
2024-07-12 03:39:44 +00:00
class AppNavigationDrawer extends StatefulWidget {
2024-07-12 05:15:46 +00:00
final String? routeName;
const AppNavigationDrawer({super.key, this.routeName});
2024-07-12 03:39:44 +00:00
@override
State<AppNavigationDrawer> createState() => _AppNavigationDrawerState();
}
2024-08-21 11:11:27 +00:00
class _AppNavigationDrawerState extends State<AppNavigationDrawer>
with TickerProviderStateMixin {
bool _isCollapsed = true;
2024-08-21 11:11:27 +00:00
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,
));
2024-08-21 09:00:59 +00:00
2024-07-12 05:15:46 +00:00
AccountStatus? _accountStatus;
2024-07-31 05:29:26 +00:00
Future<void> _getStatus() async {
2024-07-12 05:15:46 +00:00
final StatusProvider provider = Get.find();
final resp = await provider.getCurrentStatus();
final status = AccountStatus.fromJson(resp.body);
if (mounted) {
setState(() {
_accountStatus = status;
});
}
2024-07-12 05:15:46 +00:00
}
2024-08-21 11:11:27 +00:00
Color get _unFocusColor =>
Theme.of(context).colorScheme.onSurface.withOpacity(0.75);
2024-08-21 09:00:59 +00:00
Widget _buildUserInfo() {
return Obx(() {
final AuthProvider auth = Get.find();
if (auth.isAuthorized.isFalse || auth.userProfile.value == null) {
if (_isCollapsed) {
return InkWell(
2024-08-21 11:11:27 +00:00
child: const Icon(Icons.account_circle).paddingSymmetric(
horizontal: 28,
vertical: 20,
),
2024-08-21 09:00:59 +00:00
onTap: () {
AppRouter.instance.goNamed('account');
_closeDrawer();
},
);
}
2024-07-12 05:15:46 +00:00
2024-08-21 09:00:59 +00:00
return ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 28),
leading: const Icon(Icons.account_circle),
title: !_isCollapsed ? Text('guest'.tr) : null,
subtitle: !_isCollapsed ? Text('unsignedIn'.tr) : null,
onTap: () {
AppRouter.instance.goNamed('account');
_closeDrawer();
},
);
}
2024-07-12 05:15:46 +00:00
2024-08-21 09:00:59 +00:00
final leading = Obx(() {
final statusBadgeColor = _accountStatus != null
2024-08-21 11:11:27 +00:00
? StatusProvider.determineStatus(_accountStatus!).$2
2024-08-21 09:00:59 +00:00
: Colors.grey;
2024-07-12 05:15:46 +00:00
2024-08-21 09:00:59 +00:00
final RelationshipProvider relations = Get.find();
final accountNotifications = relations.friendRequestCount.value;
return badges.Badge(
badgeContent: Text(
accountNotifications.toString(),
style: const TextStyle(color: Colors.white),
),
showBadge: accountNotifications > 0,
position: badges.BadgePosition.topEnd(
top: -10,
end: -6,
),
child: badges.Badge(
showBadge: _accountStatus != null,
badgeStyle: badges.BadgeStyle(badgeColor: statusBadgeColor),
position: badges.BadgePosition.bottomEnd(
bottom: 0,
end: -2,
),
child: AccountAvatar(
content: auth.userProfile.value!['avatar'],
),
),
);
});
2024-08-07 10:24:16 +00:00
2024-08-21 09:00:59 +00:00
return InkWell(
child: !_isCollapsed
2024-08-21 11:11:27 +00:00
? Row(
children: [
leading,
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
auth.userProfile.value!['nick'],
maxLines: 1,
overflow: TextOverflow.fade,
style: Theme.of(context).textTheme.bodyLarge,
).paddingOnly(left: 16),
Builder(
builder: (context) {
if (_accountStatus == null) {
2024-09-15 10:31:04 +00:00
return Text(
'loading'.tr,
maxLines: 1,
overflow: TextOverflow.fade,
style: TextStyle(
color: _unFocusColor,
),
).paddingOnly(left: 16);
2024-08-21 11:11:27 +00:00
}
final info = StatusProvider.determineStatus(
_accountStatus!,
);
return Text(
info.$3,
maxLines: 1,
overflow: TextOverflow.fade,
style: TextStyle(
color: _unFocusColor,
),
).paddingOnly(left: 16);
},
),
],
),
),
],
).paddingSymmetric(horizontal: 20, vertical: 16)
: leading.paddingSymmetric(horizontal: 20, vertical: 16),
2024-08-21 09:00:59 +00:00
onTap: () {
AppRouter.instance.goNamed('account');
_closeDrawer();
},
onLongPress: () {
showModalBottomSheet(
useRootNavigator: true,
context: context,
builder: (context) => AccountStatusAction(
currentStatus: _accountStatus!.status,
),
).then((val) {
if (val == true) _getStatus();
});
},
);
});
}
2024-08-21 11:11:27 +00:00
void _expandDrawer() {
_drawerAnimationController.animateTo(1);
}
void _collapseDrawer() {
_drawerAnimationController.animateTo(0);
}
2024-08-21 09:00:59 +00:00
void _closeDrawer() {
2024-08-21 11:11:27 +00:00
_autoResize();
2024-08-21 09:00:59 +00:00
rootScaffoldKey.currentState!.closeDrawer();
}
2024-08-21 11:11:27 +00:00
void _autoResize() {
if (AppTheme.isExtraLargeScreen(context)) {
2024-08-21 11:11:27 +00:00
_expandDrawer();
} else if (AppTheme.isLargeScreen(context)) {
2024-08-21 11:11:27 +00:00
_collapseDrawer();
} else {
2024-08-23 15:16:41 +00:00
_drawerAnimationController.value = 1;
2024-08-21 11:11:27 +00:00
}
}
2024-08-21 09:00:59 +00:00
@override
void initState() {
super.initState();
2024-09-15 08:54:07 +00:00
final AuthProvider auth = Get.find();
if (auth.isAuthorized.value) _getStatus();
2024-08-21 11:11:27 +00:00
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();
2024-08-21 09:00:59 +00:00
}
@override
Widget build(BuildContext context) {
2024-08-21 11:11:27 +00:00
return AnimatedBuilder(
animation: _drawerAnimation,
builder: (context, child) {
return Drawer(
width: _drawerAnimation.value,
backgroundColor:
AppTheme.isLargeScreen(context) ? Colors.transparent : null,
2024-08-21 11:11:27 +00:00
child: child,
);
},
2024-08-21 09:00:59 +00:00
child: SafeArea(
bottom: false,
child: Column(
children: [
_buildUserInfo().paddingSymmetric(vertical: 8),
2024-08-07 10:24:16 +00:00
const Divider(thickness: 0.3, height: 1),
SizedBox(
width: double.infinity,
child: Wrap(
runSpacing: 8,
spacing: 8,
alignment: WrapAlignment.spaceAround,
children: AppNavigation.destinations
.map(
(e) => Tooltip(
message: e.label,
child: InkWell(
borderRadius:
const BorderRadius.all(Radius.circular(8)),
child: Icon(
e.icon,
size: 22,
color: Theme.of(context).colorScheme.onSurface,
).paddingAll(16),
onTap: () {
AppRouter.instance.goNamed(e.page);
_closeDrawer();
},
),
),
)
.toList(),
).paddingSymmetric(vertical: 8, horizontal: 12),
2024-08-21 09:00:59 +00:00
),
2024-08-07 10:24:16 +00:00
const Divider(thickness: 0.3, height: 1),
Expanded(
2024-09-13 15:19:33 +00:00
child: Material(
color: Theme.of(context).colorScheme.surface,
child: AppNavigationRegion(
isCollapsed: _isCollapsed,
2024-09-15 10:25:04 +00:00
onSelected: () {
_closeDrawer();
},
2024-09-13 15:19:33 +00:00
),
2024-07-24 17:18:47 +00:00
),
2024-08-07 10:24:16 +00:00
),
2024-08-09 16:51:54 +00:00
const Divider(thickness: 0.3, height: 1),
Column(
children: [
2024-08-21 11:11:27 +00:00
if (_isCollapsed)
Tooltip(
message: 'expand'.tr,
child: InkWell(
child: const Icon(Icons.chevron_right, size: 20)
.paddingSymmetric(
horizontal: 28,
vertical: 10,
),
onTap: () {
_expandDrawer();
},
2024-08-21 11:11:27 +00:00
),
)
else
ListTile(
minTileHeight: 0,
contentPadding: const EdgeInsets.symmetric(
horizontal: 20,
),
leading:
const Icon(Icons.chevron_left, size: 20).paddingAll(2),
title: Text('collapse'.tr),
onTap: () {
_collapseDrawer();
},
),
2024-08-09 16:51:54 +00:00
],
2024-08-10 16:36:27 +00:00
).paddingOnly(
top: 8,
bottom: math.max(8, MediaQuery.of(context).padding.bottom),
),
2024-08-07 10:24:16 +00:00
],
),
),
2024-07-12 03:39:44 +00:00
);
}
}