✨ Account status on sidebar
This commit is contained in:
parent
3b1b6ec8d6
commit
48b76ed574
@ -19,7 +19,6 @@ import 'package:solian/providers/content/realm.dart';
|
|||||||
import 'package:solian/providers/friend.dart';
|
import 'package:solian/providers/friend.dart';
|
||||||
import 'package:solian/providers/account_status.dart';
|
import 'package:solian/providers/account_status.dart';
|
||||||
import 'package:solian/router.dart';
|
import 'package:solian/router.dart';
|
||||||
import 'package:solian/shells/root_shell.dart';
|
|
||||||
import 'package:solian/shells/system_shell.dart';
|
import 'package:solian/shells/system_shell.dart';
|
||||||
import 'package:solian/theme.dart';
|
import 'package:solian/theme.dart';
|
||||||
import 'package:solian/translations.dart';
|
import 'package:solian/translations.dart';
|
||||||
@ -88,10 +87,8 @@ class SolianApp extends StatelessWidget {
|
|||||||
onInit: () => _initializeProviders(context),
|
onInit: () => _initializeProviders(context),
|
||||||
builder: (context, child) {
|
builder: (context, child) {
|
||||||
return SystemShell(
|
return SystemShell(
|
||||||
child: RootShell(
|
child: ScaffoldMessenger(
|
||||||
child: ScaffoldMessenger(
|
child: child ?? const SizedBox(),
|
||||||
child: child ?? const SizedBox(),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -94,9 +94,10 @@ class StatusProvider extends GetConnect {
|
|||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
static (Widget, String) determineStatus(AccountStatus status,
|
static (Widget, Color, String) determineStatus(AccountStatus status,
|
||||||
{double size = 14}) {
|
{double size = 14}) {
|
||||||
Widget icon;
|
Widget icon;
|
||||||
|
Color color;
|
||||||
String? text;
|
String? text;
|
||||||
|
|
||||||
if (!presetStatuses.keys.contains(status.status?.type)) {
|
if (!presetStatuses.keys.contains(status.status?.type)) {
|
||||||
@ -104,15 +105,18 @@ class StatusProvider extends GetConnect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (status.isDisturbable && status.isOnline) {
|
if (status.isDisturbable && status.isOnline) {
|
||||||
icon = Icon(Icons.circle, color: Colors.green, size: size);
|
color = Colors.green;
|
||||||
|
icon = Icon(Icons.circle, color: color, size: size);
|
||||||
text ??= 'accountStatusOnline'.tr;
|
text ??= 'accountStatusOnline'.tr;
|
||||||
} else if (!status.isDisturbable && status.isOnline) {
|
} else if (!status.isDisturbable && status.isOnline) {
|
||||||
icon = Icon(Icons.do_not_disturb_on, color: Colors.red, size: size);
|
color = Colors.red;
|
||||||
|
icon = Icon(Icons.do_not_disturb_on, color: color, size: size);
|
||||||
text ??= 'accountStatusSilent'.tr;
|
text ??= 'accountStatusSilent'.tr;
|
||||||
} else {
|
} else {
|
||||||
icon = Icon(Icons.circle, color: Colors.grey, size: size);
|
color = Colors.grey;
|
||||||
|
icon = Icon(Icons.circle, color: color, size: size);
|
||||||
text ??= 'accountStatusOffline'.tr;
|
text ??= 'accountStatusOffline'.tr;
|
||||||
}
|
}
|
||||||
return (icon, text);
|
return (icon, color, text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -218,4 +218,10 @@ class AuthProvider extends GetConnect {
|
|||||||
|
|
||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<Response?> getProfileWithCheck({noCache = false}) async {
|
||||||
|
if (!await isAuthorized) return null;
|
||||||
|
|
||||||
|
return await getProfile(noCache: noCache);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ import 'package:solian/screens/realms/realm_view.dart';
|
|||||||
import 'package:solian/screens/feed.dart';
|
import 'package:solian/screens/feed.dart';
|
||||||
import 'package:solian/screens/posts/post_editor.dart';
|
import 'package:solian/screens/posts/post_editor.dart';
|
||||||
import 'package:solian/shells/basic_shell.dart';
|
import 'package:solian/shells/basic_shell.dart';
|
||||||
|
import 'package:solian/shells/root_shell.dart';
|
||||||
import 'package:solian/shells/title_shell.dart';
|
import 'package:solian/shells/title_shell.dart';
|
||||||
import 'package:solian/theme.dart';
|
import 'package:solian/theme.dart';
|
||||||
import 'package:solian/widgets/sidebar/empty_placeholder.dart';
|
import 'package:solian/widgets/sidebar/empty_placeholder.dart';
|
||||||
@ -27,10 +28,18 @@ import 'package:solian/widgets/sidebar/empty_placeholder.dart';
|
|||||||
abstract class AppRouter {
|
abstract class AppRouter {
|
||||||
static GoRouter instance = GoRouter(
|
static GoRouter instance = GoRouter(
|
||||||
routes: [
|
routes: [
|
||||||
_feedRoute,
|
ShellRoute(
|
||||||
_chatRoute,
|
builder: (context, state, child) => RootShell(
|
||||||
_realmRoute,
|
state: state,
|
||||||
_accountRoute,
|
child: child,
|
||||||
|
),
|
||||||
|
routes: [
|
||||||
|
_feedRoute,
|
||||||
|
_chatRoute,
|
||||||
|
_realmRoute,
|
||||||
|
_accountRoute,
|
||||||
|
],
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:solian/theme.dart';
|
import 'package:solian/theme.dart';
|
||||||
import 'package:solian/widgets/navigation/app_navigation_drawer.dart';
|
import 'package:solian/widgets/navigation/app_navigation_drawer.dart';
|
||||||
import 'package:solian/widgets/navigation/app_navigation_rail.dart';
|
import 'package:solian/widgets/navigation/app_navigation_rail.dart';
|
||||||
@ -9,10 +10,12 @@ class RootShell extends StatelessWidget {
|
|||||||
final bool showSidebar;
|
final bool showSidebar;
|
||||||
final bool showNavigation;
|
final bool showNavigation;
|
||||||
final bool? showBottomNavigation;
|
final bool? showBottomNavigation;
|
||||||
|
final GoRouterState state;
|
||||||
final Widget child;
|
final Widget child;
|
||||||
|
|
||||||
const RootShell({
|
const RootShell({
|
||||||
super.key,
|
super.key,
|
||||||
|
required this.state,
|
||||||
required this.child,
|
required this.child,
|
||||||
this.showSidebar = true,
|
this.showSidebar = true,
|
||||||
this.showNavigation = true,
|
this.showNavigation = true,
|
||||||
@ -25,9 +28,14 @@ class RootShell extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final routeName = state.topRoute?.name;
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
key: rootScaffoldKey,
|
key: rootScaffoldKey,
|
||||||
drawer: const AppNavigationDrawer(),
|
drawer: AppNavigationDrawer(
|
||||||
|
key: const ValueKey('navigation-drawer'),
|
||||||
|
routeName: routeName,
|
||||||
|
),
|
||||||
body: SolianTheme.isLargeScreen(context)
|
body: SolianTheme.isLargeScreen(context)
|
||||||
? Row(
|
? Row(
|
||||||
children: [
|
children: [
|
||||||
|
@ -124,7 +124,7 @@ class AccountHeadingWidget extends StatelessWidget {
|
|||||||
child: Row(
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Text(info.$2),
|
Text(info.$3),
|
||||||
if (!status.isOnline && status.lastSeenAt != null)
|
if (!status.isOnline && status.lastSeenAt != null)
|
||||||
Opacity(
|
Opacity(
|
||||||
opacity: 0.75,
|
opacity: 0.75,
|
||||||
|
@ -1,36 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:solian/router.dart';
|
|
||||||
import 'package:solian/widgets/navigation/app_navigation.dart';
|
|
||||||
|
|
||||||
class AppNavigationBottomBar extends StatefulWidget {
|
|
||||||
const AppNavigationBottomBar({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<AppNavigationBottomBar> createState() => _AppNavigationBottomBarState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _AppNavigationBottomBarState extends State<AppNavigationBottomBar> {
|
|
||||||
int _selectedIndex = 0;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return BottomNavigationBar(
|
|
||||||
items: AppNavigation.destinations
|
|
||||||
.map(
|
|
||||||
(e) => BottomNavigationBarItem(
|
|
||||||
icon: e.icon,
|
|
||||||
label: e.label,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.toList(),
|
|
||||||
type: BottomNavigationBarType.fixed,
|
|
||||||
landscapeLayout: BottomNavigationBarLandscapeLayout.centered,
|
|
||||||
currentIndex: _selectedIndex,
|
|
||||||
showUnselectedLabels: false,
|
|
||||||
onTap: (idx) {
|
|
||||||
setState(() => _selectedIndex = idx);
|
|
||||||
AppRouter.instance.goNamed(AppNavigation.destinations[idx].page);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +1,19 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
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';
|
||||||
import 'package:solian/router.dart';
|
import 'package:solian/router.dart';
|
||||||
import 'package:solian/shells/root_shell.dart';
|
import 'package:solian/shells/root_shell.dart';
|
||||||
|
import 'package:solian/widgets/account/account_avatar.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;
|
||||||
|
|
||||||
class AppNavigationDrawer extends StatefulWidget {
|
class AppNavigationDrawer extends StatefulWidget {
|
||||||
const AppNavigationDrawer({super.key});
|
final String? routeName;
|
||||||
|
|
||||||
|
const AppNavigationDrawer({super.key, this.routeName});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<AppNavigationDrawer> createState() => _AppNavigationDrawerState();
|
State<AppNavigationDrawer> createState() => _AppNavigationDrawerState();
|
||||||
@ -12,9 +21,45 @@ class AppNavigationDrawer extends StatefulWidget {
|
|||||||
|
|
||||||
class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
|
class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
|
||||||
int _selectedIndex = 0;
|
int _selectedIndex = 0;
|
||||||
|
AccountStatus? _accountStatus;
|
||||||
|
|
||||||
|
void getStatus() async {
|
||||||
|
final StatusProvider provider = Get.find();
|
||||||
|
|
||||||
|
final resp = await provider.getCurrentStatus();
|
||||||
|
final status = AccountStatus.fromJson(resp.body);
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
_accountStatus = status;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void detectSelectedIndex() {
|
||||||
|
if (widget.routeName == null) return;
|
||||||
|
|
||||||
|
final nameList = AppNavigation.destinations.map((x) => x.page).toList();
|
||||||
|
final idx = nameList.indexOf(widget.routeName!);
|
||||||
|
|
||||||
|
_selectedIndex = idx != -1 ? idx : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
detectSelectedIndex();
|
||||||
|
getStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didChangeDependencies() {
|
||||||
|
super.didChangeDependencies();
|
||||||
|
detectSelectedIndex();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final AuthProvider auth = Get.find();
|
||||||
|
|
||||||
return NavigationDrawer(
|
return NavigationDrawer(
|
||||||
selectedIndex: _selectedIndex,
|
selectedIndex: _selectedIndex,
|
||||||
onDestinationSelected: (idx) {
|
onDestinationSelected: (idx) {
|
||||||
@ -23,6 +68,68 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
|
|||||||
rootScaffoldKey.currentState!.closeDrawer();
|
rootScaffoldKey.currentState!.closeDrawer();
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
|
FutureBuilder(
|
||||||
|
future: auth.getProfileWithCheck(),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (!snapshot.hasData || snapshot.data == null) {
|
||||||
|
return const SizedBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
ListTile(
|
||||||
|
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
|
title: Text(snapshot.data!.body['nick']),
|
||||||
|
subtitle: Builder(
|
||||||
|
builder: (context) {
|
||||||
|
if (_accountStatus == null) {
|
||||||
|
return Text('loading'.tr);
|
||||||
|
}
|
||||||
|
final info = StatusProvider.determineStatus(
|
||||||
|
_accountStatus!,
|
||||||
|
);
|
||||||
|
return Text(info.$3);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
leading: Builder(builder: (context) {
|
||||||
|
final badgeColor = _accountStatus != null
|
||||||
|
? StatusProvider.determineStatus(
|
||||||
|
_accountStatus!,
|
||||||
|
).$2
|
||||||
|
: Colors.grey;
|
||||||
|
|
||||||
|
return badges.Badge(
|
||||||
|
showBadge: _accountStatus != null,
|
||||||
|
badgeStyle: badges.BadgeStyle(badgeColor: badgeColor),
|
||||||
|
position: badges.BadgePosition.bottomEnd(
|
||||||
|
bottom: 0,
|
||||||
|
end: -2,
|
||||||
|
),
|
||||||
|
child: AccountAvatar(
|
||||||
|
content: snapshot.data!.body['avatar'],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
onTap: () {
|
||||||
|
showModalBottomSheet(
|
||||||
|
useRootNavigator: true,
|
||||||
|
context: context,
|
||||||
|
builder: (context) => AccountStatusAction(
|
||||||
|
currentStatus: _accountStatus!.status,
|
||||||
|
),
|
||||||
|
).then((val) {
|
||||||
|
if (val == true) getStatus();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const Divider(thickness: 0.3, height: 1).paddingOnly(
|
||||||
|
bottom: 16,
|
||||||
|
top: 8,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
...AppNavigation.destinations.map(
|
...AppNavigation.destinations.map(
|
||||||
(e) => NavigationDrawerDestination(
|
(e) => NavigationDrawerDestination(
|
||||||
icon: e.icon,
|
icon: e.icon,
|
||||||
|
Loading…
Reference in New Issue
Block a user