💄 Better bottom navigation
This commit is contained in:
		@@ -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/listener_shell.dart';
 | 
					 | 
				
			||||||
import 'package:solian/theme.dart';
 | 
					import 'package:solian/theme.dart';
 | 
				
			||||||
import 'package:solian/translations.dart';
 | 
					import 'package:solian/translations.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -83,15 +82,14 @@ class SolianApp extends StatelessWidget {
 | 
				
			|||||||
      routerDelegate: AppRouter.instance.routerDelegate,
 | 
					      routerDelegate: AppRouter.instance.routerDelegate,
 | 
				
			||||||
      routeInformationParser: AppRouter.instance.routeInformationParser,
 | 
					      routeInformationParser: AppRouter.instance.routeInformationParser,
 | 
				
			||||||
      routeInformationProvider: AppRouter.instance.routeInformationProvider,
 | 
					      routeInformationProvider: AppRouter.instance.routeInformationProvider,
 | 
				
			||||||
 | 
					      backButtonDispatcher: AppRouter.instance.backButtonDispatcher,
 | 
				
			||||||
      translations: SolianMessages(),
 | 
					      translations: SolianMessages(),
 | 
				
			||||||
      locale: Get.deviceLocale,
 | 
					      locale: Get.deviceLocale,
 | 
				
			||||||
      fallbackLocale: const Locale('en', 'US'),
 | 
					      fallbackLocale: const Locale('en', 'US'),
 | 
				
			||||||
      onInit: () => _initializeProviders(context),
 | 
					      onInit: () => _initializeProviders(context),
 | 
				
			||||||
      builder: (context, child) {
 | 
					      builder: (context, child) {
 | 
				
			||||||
        return ListenerShell(
 | 
					        return ScaffoldMessenger(
 | 
				
			||||||
          child: ScaffoldMessenger(
 | 
					          child: child ?? const SizedBox(),
 | 
				
			||||||
            child: child ?? Container(),
 | 
					 | 
				
			||||||
          ),
 | 
					 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,10 +13,10 @@ import 'package:solian/screens/realms.dart';
 | 
				
			|||||||
import 'package:solian/screens/realms/realm_detail.dart';
 | 
					import 'package:solian/screens/realms/realm_detail.dart';
 | 
				
			||||||
import 'package:solian/screens/realms/realm_organize.dart';
 | 
					import 'package:solian/screens/realms/realm_organize.dart';
 | 
				
			||||||
import 'package:solian/screens/realms/realm_view.dart';
 | 
					import 'package:solian/screens/realms/realm_view.dart';
 | 
				
			||||||
import 'package:solian/screens/social.dart';
 | 
					import 'package:solian/screens/feed.dart';
 | 
				
			||||||
import 'package:solian/screens/posts/post_publish.dart';
 | 
					import 'package:solian/screens/posts/post_publish.dart';
 | 
				
			||||||
import 'package:solian/shells/basic_shell.dart';
 | 
					import 'package:solian/shells/basic_shell.dart';
 | 
				
			||||||
import 'package:solian/shells/nav_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';
 | 
				
			||||||
@@ -25,29 +25,35 @@ abstract class AppRouter {
 | 
				
			|||||||
  static GoRouter instance = GoRouter(
 | 
					  static GoRouter instance = GoRouter(
 | 
				
			||||||
    routes: [
 | 
					    routes: [
 | 
				
			||||||
      ShellRoute(
 | 
					      ShellRoute(
 | 
				
			||||||
        builder: (context, state, child) => NavShell(
 | 
					        builder: (context, state, child) => RootShell(
 | 
				
			||||||
          state: state,
 | 
					          state: state,
 | 
				
			||||||
          showAppBar: false,
 | 
					 | 
				
			||||||
          showSidebar: false,
 | 
					 | 
				
			||||||
          child: child,
 | 
					          child: child,
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        routes: [
 | 
					        routes: [
 | 
				
			||||||
          ShellRoute(
 | 
					          _feedRoute,
 | 
				
			||||||
 | 
					          _chatRoute,
 | 
				
			||||||
 | 
					          _realmRoute,
 | 
				
			||||||
 | 
					          _accountRoute,
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static final ShellRoute _feedRoute = ShellRoute(
 | 
				
			||||||
    builder: (context, state, child) => BasicShell(
 | 
					    builder: (context, state, child) => BasicShell(
 | 
				
			||||||
      state: state,
 | 
					      state: state,
 | 
				
			||||||
      sidebarFirst: true,
 | 
					      sidebarFirst: true,
 | 
				
			||||||
      showAppBar: false,
 | 
					      showAppBar: false,
 | 
				
			||||||
              sidebar: const SocialScreen(),
 | 
					      sidebar: const FeedScreen(),
 | 
				
			||||||
      child: child,
 | 
					      child: child,
 | 
				
			||||||
    ),
 | 
					    ),
 | 
				
			||||||
    routes: [
 | 
					    routes: [
 | 
				
			||||||
      GoRoute(
 | 
					      GoRoute(
 | 
				
			||||||
        path: '/',
 | 
					        path: '/',
 | 
				
			||||||
                name: 'social',
 | 
					        name: 'feed',
 | 
				
			||||||
                builder: (context, state) =>
 | 
					        builder: (context, state) => SolianTheme.isExtraLargeScreen(context)
 | 
				
			||||||
                    SolianTheme.isExtraLargeScreen(context)
 | 
					 | 
				
			||||||
            ? const EmptyPagePlaceholder()
 | 
					            ? const EmptyPagePlaceholder()
 | 
				
			||||||
                        : const SocialScreen(),
 | 
					            : const FeedScreen(),
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
      GoRoute(
 | 
					      GoRoute(
 | 
				
			||||||
        path: '/posts/view/:alias',
 | 
					        path: '/posts/view/:alias',
 | 
				
			||||||
@@ -73,8 +79,9 @@ abstract class AppRouter {
 | 
				
			|||||||
        },
 | 
					        },
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
          ),
 | 
					  );
 | 
				
			||||||
          ShellRoute(
 | 
					
 | 
				
			||||||
 | 
					  static final ShellRoute _chatRoute = ShellRoute(
 | 
				
			||||||
    builder: (context, state, child) => BasicShell(
 | 
					    builder: (context, state, child) => BasicShell(
 | 
				
			||||||
      state: state,
 | 
					      state: state,
 | 
				
			||||||
      sidebarFirst: true,
 | 
					      sidebarFirst: true,
 | 
				
			||||||
@@ -86,8 +93,7 @@ abstract class AppRouter {
 | 
				
			|||||||
      GoRoute(
 | 
					      GoRoute(
 | 
				
			||||||
        path: '/chat',
 | 
					        path: '/chat',
 | 
				
			||||||
        name: 'chat',
 | 
					        name: 'chat',
 | 
				
			||||||
                builder: (context, state) =>
 | 
					        builder: (context, state) => SolianTheme.isExtraLargeScreen(context)
 | 
				
			||||||
                    SolianTheme.isExtraLargeScreen(context)
 | 
					 | 
				
			||||||
            ? const EmptyPagePlaceholder()
 | 
					            ? const EmptyPagePlaceholder()
 | 
				
			||||||
            : const ChatScreen(),
 | 
					            : const ChatScreen(),
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
@@ -128,8 +134,9 @@ abstract class AppRouter {
 | 
				
			|||||||
        },
 | 
					        },
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
          ),
 | 
					  );
 | 
				
			||||||
          ShellRoute(
 | 
					
 | 
				
			||||||
 | 
					  static final ShellRoute _realmRoute = ShellRoute(
 | 
				
			||||||
    builder: (context, state, child) => BasicShell(
 | 
					    builder: (context, state, child) => BasicShell(
 | 
				
			||||||
      state: state,
 | 
					      state: state,
 | 
				
			||||||
      sidebarFirst: true,
 | 
					      sidebarFirst: true,
 | 
				
			||||||
@@ -141,8 +148,7 @@ abstract class AppRouter {
 | 
				
			|||||||
      GoRoute(
 | 
					      GoRoute(
 | 
				
			||||||
        path: '/realms',
 | 
					        path: '/realms',
 | 
				
			||||||
        name: 'realms',
 | 
					        name: 'realms',
 | 
				
			||||||
                builder: (context, state) =>
 | 
					        builder: (context, state) => SolianTheme.isExtraLargeScreen(context)
 | 
				
			||||||
                    SolianTheme.isExtraLargeScreen(context)
 | 
					 | 
				
			||||||
            ? const EmptyPagePlaceholder()
 | 
					            ? const EmptyPagePlaceholder()
 | 
				
			||||||
            : const RealmListScreen(),
 | 
					            : const RealmListScreen(),
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
@@ -177,8 +183,9 @@ abstract class AppRouter {
 | 
				
			|||||||
        },
 | 
					        },
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
          ),
 | 
					  );
 | 
				
			||||||
          ShellRoute(
 | 
					
 | 
				
			||||||
 | 
					  static final ShellRoute _accountRoute = ShellRoute(
 | 
				
			||||||
    builder: (context, state, child) => BasicShell(
 | 
					    builder: (context, state, child) => BasicShell(
 | 
				
			||||||
      state: state,
 | 
					      state: state,
 | 
				
			||||||
      sidebarFirst: true,
 | 
					      sidebarFirst: true,
 | 
				
			||||||
@@ -190,8 +197,7 @@ abstract class AppRouter {
 | 
				
			|||||||
      GoRoute(
 | 
					      GoRoute(
 | 
				
			||||||
        path: '/account',
 | 
					        path: '/account',
 | 
				
			||||||
        name: 'account',
 | 
					        name: 'account',
 | 
				
			||||||
                builder: (context, state) =>
 | 
					        builder: (context, state) => SolianTheme.isExtraLargeScreen(context)
 | 
				
			||||||
                    SolianTheme.isExtraLargeScreen(context)
 | 
					 | 
				
			||||||
            ? const EmptyPagePlaceholder()
 | 
					            ? const EmptyPagePlaceholder()
 | 
				
			||||||
            : const AccountScreen(),
 | 
					            : const AccountScreen(),
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
@@ -220,9 +226,5 @@ abstract class AppRouter {
 | 
				
			|||||||
        ),
 | 
					        ),
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
          ),
 | 
					 | 
				
			||||||
        ],
 | 
					 | 
				
			||||||
      ),
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,11 @@
 | 
				
			|||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
import 'package:get/get.dart';
 | 
					import 'package:get/get.dart';
 | 
				
			||||||
 | 
					import 'package:protocol_handler/protocol_handler.dart';
 | 
				
			||||||
import 'package:solian/exts.dart';
 | 
					import 'package:solian/exts.dart';
 | 
				
			||||||
import 'package:solian/providers/account.dart';
 | 
					import 'package:solian/providers/account.dart';
 | 
				
			||||||
import 'package:solian/providers/auth.dart';
 | 
					import 'package:solian/providers/auth.dart';
 | 
				
			||||||
import 'package:solian/services.dart';
 | 
					import 'package:solian/services.dart';
 | 
				
			||||||
 | 
					import 'package:url_launcher/url_launcher.dart';
 | 
				
			||||||
import 'package:url_launcher/url_launcher_string.dart';
 | 
					import 'package:url_launcher/url_launcher_string.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SignInPopup extends StatefulWidget {
 | 
					class SignInPopup extends StatefulWidget {
 | 
				
			||||||
@@ -13,13 +15,13 @@ class SignInPopup extends StatefulWidget {
 | 
				
			|||||||
  State<SignInPopup> createState() => _SignInPopupState();
 | 
					  State<SignInPopup> createState() => _SignInPopupState();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class _SignInPopupState extends State<SignInPopup> {
 | 
					class _SignInPopupState extends State<SignInPopup> with ProtocolListener {
 | 
				
			||||||
  bool _isBusy = false;
 | 
					  bool _isBusy = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  final _usernameController = TextEditingController();
 | 
					  final _usernameController = TextEditingController();
 | 
				
			||||||
  final _passwordController = TextEditingController();
 | 
					  final _passwordController = TextEditingController();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void requestResetPassword(BuildContext context) async {
 | 
					  void requestResetPassword() async {
 | 
				
			||||||
    final username = _usernameController.value.text;
 | 
					    final username = _usernameController.value.text;
 | 
				
			||||||
    if (username.isEmpty) {
 | 
					    if (username.isEmpty) {
 | 
				
			||||||
      context.showErrorDialog('signinResetPasswordHint'.tr);
 | 
					      context.showErrorDialog('signinResetPasswordHint'.tr);
 | 
				
			||||||
@@ -49,7 +51,7 @@ class _SignInPopupState extends State<SignInPopup> {
 | 
				
			|||||||
    context.showModalDialog('done'.tr, 'signinResetPasswordSent'.tr);
 | 
					    context.showModalDialog('done'.tr, 'signinResetPasswordSent'.tr);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void performAction(BuildContext context) async {
 | 
					  void performAction() async {
 | 
				
			||||||
    final AuthProvider provider = Get.find();
 | 
					    final AuthProvider provider = Get.find();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    final username = _usernameController.value.text;
 | 
					    final username = _usernameController.value.text;
 | 
				
			||||||
@@ -96,6 +98,27 @@ class _SignInPopupState extends State<SignInPopup> {
 | 
				
			|||||||
    Navigator.pop(context, true);
 | 
					    Navigator.pop(context, true);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  void initState() {
 | 
				
			||||||
 | 
					    protocolHandler.addListener(this);
 | 
				
			||||||
 | 
					    super.initState();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  void dispose() {
 | 
				
			||||||
 | 
					    protocolHandler.removeListener(this);
 | 
				
			||||||
 | 
					    super.dispose();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  void onProtocolUrlReceived(String url) {
 | 
				
			||||||
 | 
					    final uri = url.replaceFirst('solink://', '');
 | 
				
			||||||
 | 
					    if (uri == 'auth?status=done') {
 | 
				
			||||||
 | 
					      closeInAppWebView();
 | 
				
			||||||
 | 
					      performAction();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Widget build(BuildContext context) {
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
    return SizedBox(
 | 
					    return SizedBox(
 | 
				
			||||||
@@ -144,20 +167,19 @@ class _SignInPopupState extends State<SignInPopup> {
 | 
				
			|||||||
                ),
 | 
					                ),
 | 
				
			||||||
                onTapOutside: (_) =>
 | 
					                onTapOutside: (_) =>
 | 
				
			||||||
                    FocusManager.instance.primaryFocus?.unfocus(),
 | 
					                    FocusManager.instance.primaryFocus?.unfocus(),
 | 
				
			||||||
                onSubmitted: (_) => performAction(context),
 | 
					                onSubmitted: (_) => performAction(),
 | 
				
			||||||
              ),
 | 
					              ),
 | 
				
			||||||
              const SizedBox(height: 12),
 | 
					              const SizedBox(height: 12),
 | 
				
			||||||
              Row(
 | 
					              Row(
 | 
				
			||||||
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
 | 
					                mainAxisAlignment: MainAxisAlignment.spaceBetween,
 | 
				
			||||||
                children: [
 | 
					                children: [
 | 
				
			||||||
                  TextButton(
 | 
					                  TextButton(
 | 
				
			||||||
                    onPressed:
 | 
					                    onPressed: _isBusy ? null : () => requestResetPassword(),
 | 
				
			||||||
                        _isBusy ? null : () => requestResetPassword(context),
 | 
					 | 
				
			||||||
                    style: TextButton.styleFrom(foregroundColor: Colors.grey),
 | 
					                    style: TextButton.styleFrom(foregroundColor: Colors.grey),
 | 
				
			||||||
                    child: Text('forgotPassword'.tr),
 | 
					                    child: Text('forgotPassword'.tr),
 | 
				
			||||||
                  ),
 | 
					                  ),
 | 
				
			||||||
                  TextButton(
 | 
					                  TextButton(
 | 
				
			||||||
                    onPressed: _isBusy ? null : () => performAction(context),
 | 
					                    onPressed: _isBusy ? null : () => performAction(),
 | 
				
			||||||
                    child: Row(
 | 
					                    child: Row(
 | 
				
			||||||
                      mainAxisSize: MainAxisSize.min,
 | 
					                      mainAxisSize: MainAxisSize.min,
 | 
				
			||||||
                      children: [
 | 
					                      children: [
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,14 +12,14 @@ import 'package:solian/widgets/app_bar_title.dart';
 | 
				
			|||||||
import 'package:solian/widgets/current_state_action.dart';
 | 
					import 'package:solian/widgets/current_state_action.dart';
 | 
				
			||||||
import 'package:solian/widgets/posts/post_list.dart';
 | 
					import 'package:solian/widgets/posts/post_list.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SocialScreen extends StatefulWidget {
 | 
					class FeedScreen extends StatefulWidget {
 | 
				
			||||||
  const SocialScreen({super.key});
 | 
					  const FeedScreen({super.key});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  State<SocialScreen> createState() => _SocialScreenState();
 | 
					  State<FeedScreen> createState() => _FeedScreenState();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class _SocialScreenState extends State<SocialScreen> {
 | 
					class _FeedScreenState extends State<FeedScreen> {
 | 
				
			||||||
  final PagingController<int, Post> _pagingController =
 | 
					  final PagingController<int, Post> _pagingController =
 | 
				
			||||||
      PagingController(firstPageKey: 0);
 | 
					      PagingController(firstPageKey: 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -52,26 +52,7 @@ class _SocialScreenState extends State<SocialScreen> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Widget build(BuildContext context) {
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
    final AuthProvider auth = Get.find();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return Scaffold(
 | 
					    return Scaffold(
 | 
				
			||||||
      floatingActionButton: FutureBuilder(
 | 
					 | 
				
			||||||
          future: auth.isAuthorized,
 | 
					 | 
				
			||||||
          builder: (context, snapshot) {
 | 
					 | 
				
			||||||
            if (snapshot.hasData && snapshot.data == true) {
 | 
					 | 
				
			||||||
              return FloatingActionButton(
 | 
					 | 
				
			||||||
                child: const Icon(Icons.add),
 | 
					 | 
				
			||||||
                onPressed: () async {
 | 
					 | 
				
			||||||
                  final value =
 | 
					 | 
				
			||||||
                      await AppRouter.instance.pushNamed('postPublishing');
 | 
					 | 
				
			||||||
                  if (value != null) {
 | 
					 | 
				
			||||||
                    _pagingController.refresh();
 | 
					 | 
				
			||||||
                  }
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
              );
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return Container();
 | 
					 | 
				
			||||||
          }),
 | 
					 | 
				
			||||||
      body: Material(
 | 
					      body: Material(
 | 
				
			||||||
        color: Theme.of(context).colorScheme.surface,
 | 
					        color: Theme.of(context).colorScheme.surface,
 | 
				
			||||||
        child: RefreshIndicator(
 | 
					        child: RefreshIndicator(
 | 
				
			||||||
@@ -79,7 +60,7 @@ class _SocialScreenState extends State<SocialScreen> {
 | 
				
			|||||||
          child: CustomScrollView(
 | 
					          child: CustomScrollView(
 | 
				
			||||||
            slivers: [
 | 
					            slivers: [
 | 
				
			||||||
              SliverAppBar(
 | 
					              SliverAppBar(
 | 
				
			||||||
                title: AppBarTitle('social'.tr),
 | 
					                title: AppBarTitle('feed'.tr),
 | 
				
			||||||
                centerTitle: false,
 | 
					                centerTitle: false,
 | 
				
			||||||
                floating: true,
 | 
					                floating: true,
 | 
				
			||||||
                titleSpacing: SolianTheme.titleSpacing(context),
 | 
					                titleSpacing: SolianTheme.titleSpacing(context),
 | 
				
			||||||
@@ -87,6 +68,7 @@ class _SocialScreenState extends State<SocialScreen> {
 | 
				
			|||||||
                actions: [
 | 
					                actions: [
 | 
				
			||||||
                  const BackgroundStateWidget(),
 | 
					                  const BackgroundStateWidget(),
 | 
				
			||||||
                  const NotificationButton(),
 | 
					                  const NotificationButton(),
 | 
				
			||||||
 | 
					                  const FeedCreationButton(),
 | 
				
			||||||
                  SizedBox(
 | 
					                  SizedBox(
 | 
				
			||||||
                    width: SolianTheme.isLargeScreen(context) ? 8 : 16,
 | 
					                    width: SolianTheme.isLargeScreen(context) ? 8 : 16,
 | 
				
			||||||
                  ),
 | 
					                  ),
 | 
				
			||||||
@@ -100,3 +82,26 @@ class _SocialScreenState extends State<SocialScreen> {
 | 
				
			|||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class FeedCreationButton extends StatelessWidget {
 | 
				
			||||||
 | 
					  const FeedCreationButton({super.key});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
 | 
					    final AuthProvider auth = Get.find();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return FutureBuilder(
 | 
				
			||||||
 | 
					        future: auth.isAuthorized,
 | 
				
			||||||
 | 
					        builder: (context, snapshot) {
 | 
				
			||||||
 | 
					          if (snapshot.hasData && snapshot.data == true) {
 | 
				
			||||||
 | 
					            return IconButton(
 | 
				
			||||||
 | 
					              icon: const Icon(Icons.add_circle),
 | 
				
			||||||
 | 
					              onPressed: () {
 | 
				
			||||||
 | 
					                AppRouter.instance.pushNamed('postPublishing');
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          return const SizedBox();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,39 +0,0 @@
 | 
				
			|||||||
import 'package:flutter/material.dart';
 | 
					 | 
				
			||||||
import 'package:protocol_handler/protocol_handler.dart';
 | 
					 | 
				
			||||||
import 'package:url_launcher/url_launcher.dart';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class ListenerShell extends StatefulWidget {
 | 
					 | 
				
			||||||
  final Widget child;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const ListenerShell({super.key, required this.child});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @override
 | 
					 | 
				
			||||||
  State<ListenerShell> createState() => _ListenerShellState();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class _ListenerShellState extends State<ListenerShell> with ProtocolListener {
 | 
					 | 
				
			||||||
  @override
 | 
					 | 
				
			||||||
  void initState() {
 | 
					 | 
				
			||||||
    protocolHandler.addListener(this);
 | 
					 | 
				
			||||||
    super.initState();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @override
 | 
					 | 
				
			||||||
  void dispose() {
 | 
					 | 
				
			||||||
    protocolHandler.removeListener(this);
 | 
					 | 
				
			||||||
    super.dispose();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @override
 | 
					 | 
				
			||||||
  Widget build(BuildContext context) {
 | 
					 | 
				
			||||||
    return widget.child;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @override
 | 
					 | 
				
			||||||
  void onProtocolUrlReceived(String url) {
 | 
					 | 
				
			||||||
    final uri = url.replaceFirst('solink://', '');
 | 
					 | 
				
			||||||
    if (uri == 'auth?status=done') {
 | 
					 | 
				
			||||||
      closeInAppWebView();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,6 +1,5 @@
 | 
				
			|||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
import 'package:get/get.dart';
 | 
					import 'package:get/get.dart';
 | 
				
			||||||
import 'package:go_router/go_router.dart';
 | 
					 | 
				
			||||||
import 'package:solian/router.dart';
 | 
					import 'package:solian/router.dart';
 | 
				
			||||||
import 'package:solian/theme.dart';
 | 
					import 'package:solian/theme.dart';
 | 
				
			||||||
import 'package:solian/widgets/navigation/app_navigation.dart';
 | 
					import 'package:solian/widgets/navigation/app_navigation.dart';
 | 
				
			||||||
@@ -14,7 +13,6 @@ class NavShell 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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  final bool sidebarFirst;
 | 
					  final bool sidebarFirst;
 | 
				
			||||||
@@ -23,7 +21,6 @@ class NavShell extends StatelessWidget {
 | 
				
			|||||||
  const NavShell({
 | 
					  const NavShell({
 | 
				
			||||||
    super.key,
 | 
					    super.key,
 | 
				
			||||||
    required this.child,
 | 
					    required this.child,
 | 
				
			||||||
    required this.state,
 | 
					 | 
				
			||||||
    this.showAppBar = true,
 | 
					    this.showAppBar = true,
 | 
				
			||||||
    this.showSidebar = true,
 | 
					    this.showSidebar = true,
 | 
				
			||||||
    this.showNavigation = true,
 | 
					    this.showNavigation = true,
 | 
				
			||||||
@@ -60,7 +57,7 @@ class NavShell extends StatelessWidget {
 | 
				
			|||||||
    return Scaffold(
 | 
					    return Scaffold(
 | 
				
			||||||
      appBar: showAppBar
 | 
					      appBar: showAppBar
 | 
				
			||||||
          ? AppBar(
 | 
					          ? AppBar(
 | 
				
			||||||
              title: Text(state.topRoute?.name?.tr ?? 'page'.tr),
 | 
					              title: Text(routeName ?? 'page'.tr),
 | 
				
			||||||
              centerTitle: false,
 | 
					              centerTitle: false,
 | 
				
			||||||
              titleSpacing: canPop ? null : 24,
 | 
					              titleSpacing: canPop ? null : 24,
 | 
				
			||||||
              elevation: SolianTheme.isLargeScreen(context) ? 1 : 0,
 | 
					              elevation: SolianTheme.isLargeScreen(context) ? 1 : 0,
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										63
									
								
								lib/shells/root_shell.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								lib/shells/root_shell.dart
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,63 @@
 | 
				
			|||||||
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
 | 
					import 'package:flutter_animate/flutter_animate.dart';
 | 
				
			||||||
 | 
					import 'package:go_router/go_router.dart';
 | 
				
			||||||
 | 
					import 'package:solian/router.dart';
 | 
				
			||||||
 | 
					import 'package:solian/theme.dart';
 | 
				
			||||||
 | 
					import 'package:solian/widgets/navigation/app_navigation.dart';
 | 
				
			||||||
 | 
					import 'package:solian/widgets/navigation/app_navigation_bottom_bar.dart';
 | 
				
			||||||
 | 
					import 'package:solian/widgets/navigation/app_navigation_rail.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RootShell extends StatelessWidget {
 | 
				
			||||||
 | 
					  final bool showSidebar;
 | 
				
			||||||
 | 
					  final bool showNavigation;
 | 
				
			||||||
 | 
					  final bool? showBottomNavigation;
 | 
				
			||||||
 | 
					  final GoRouterState state;
 | 
				
			||||||
 | 
					  final Widget child;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const RootShell({
 | 
				
			||||||
 | 
					    super.key,
 | 
				
			||||||
 | 
					    required this.state,
 | 
				
			||||||
 | 
					    required this.child,
 | 
				
			||||||
 | 
					    this.showSidebar = true,
 | 
				
			||||||
 | 
					    this.showNavigation = true,
 | 
				
			||||||
 | 
					    this.showBottomNavigation,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
 | 
					    final routeName = AppRouter
 | 
				
			||||||
 | 
					        .instance.routerDelegate.currentConfiguration.lastOrNull?.route.name;
 | 
				
			||||||
 | 
					    final showBottom = showBottomNavigation ??
 | 
				
			||||||
 | 
					        AppNavigation.destinationPages.contains(routeName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return Scaffold(
 | 
				
			||||||
 | 
					      body: SolianTheme.isLargeScreen(context)
 | 
				
			||||||
 | 
					          ? Row(
 | 
				
			||||||
 | 
					              children: [
 | 
				
			||||||
 | 
					                if (showNavigation) const AppNavigationRail(),
 | 
				
			||||||
 | 
					                if (showNavigation)
 | 
				
			||||||
 | 
					                  const VerticalDivider(thickness: 0.3, width: 1),
 | 
				
			||||||
 | 
					                Expanded(child: child),
 | 
				
			||||||
 | 
					              ],
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					          : Stack(
 | 
				
			||||||
 | 
					              children: [
 | 
				
			||||||
 | 
					                child,
 | 
				
			||||||
 | 
					                Positioned(
 | 
				
			||||||
 | 
					                  bottom: 0,
 | 
				
			||||||
 | 
					                  left: 0,
 | 
				
			||||||
 | 
					                  right: 0,
 | 
				
			||||||
 | 
					                  child: const AppNavigationBottomBar()
 | 
				
			||||||
 | 
					                      .animate(target: showBottom ? 0 : 1)
 | 
				
			||||||
 | 
					                      .slideY(
 | 
				
			||||||
 | 
					                        duration: 250.ms,
 | 
				
			||||||
 | 
					                        begin: 0,
 | 
				
			||||||
 | 
					                        end: 1,
 | 
				
			||||||
 | 
					                        curve: Curves.easeInToLinear,
 | 
				
			||||||
 | 
					                      ),
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					              ],
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -10,7 +10,7 @@ class SolianMessages extends Translations {
 | 
				
			|||||||
          'next': 'Next',
 | 
					          'next': 'Next',
 | 
				
			||||||
          'reset': 'Reset',
 | 
					          'reset': 'Reset',
 | 
				
			||||||
          'page': 'Page',
 | 
					          'page': 'Page',
 | 
				
			||||||
          'social': 'Social',
 | 
					          'feed': 'Feed',
 | 
				
			||||||
          'chat': 'Chat',
 | 
					          'chat': 'Chat',
 | 
				
			||||||
          'apply': 'Apply',
 | 
					          'apply': 'Apply',
 | 
				
			||||||
          'cancel': 'Cancel',
 | 
					          'cancel': 'Cancel',
 | 
				
			||||||
@@ -263,7 +263,7 @@ class SolianMessages extends Translations {
 | 
				
			|||||||
          'edit': '编辑',
 | 
					          'edit': '编辑',
 | 
				
			||||||
          'delete': '删除',
 | 
					          'delete': '删除',
 | 
				
			||||||
          'page': '页面',
 | 
					          'page': '页面',
 | 
				
			||||||
          'social': '社交',
 | 
					          'feed': '资讯',
 | 
				
			||||||
          'chat': '聊天',
 | 
					          'chat': '聊天',
 | 
				
			||||||
          'apply': '应用',
 | 
					          'apply': '应用',
 | 
				
			||||||
          'search': '搜索',
 | 
					          'search': '搜索',
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,9 +4,9 @@ import 'package:get/utils.dart';
 | 
				
			|||||||
abstract class AppNavigation {
 | 
					abstract class AppNavigation {
 | 
				
			||||||
  static List<AppNavigationDestination> destinations = [
 | 
					  static List<AppNavigationDestination> destinations = [
 | 
				
			||||||
    AppNavigationDestination(
 | 
					    AppNavigationDestination(
 | 
				
			||||||
      icon: const Icon(Icons.public),
 | 
					      icon: const Icon(Icons.feed),
 | 
				
			||||||
      label: 'social'.tr,
 | 
					      label: 'feed'.tr,
 | 
				
			||||||
      page: 'social',
 | 
					      page: 'feed',
 | 
				
			||||||
    ),
 | 
					    ),
 | 
				
			||||||
    AppNavigationDestination(
 | 
					    AppNavigationDestination(
 | 
				
			||||||
      icon: const Icon(Icons.forum),
 | 
					      icon: const Icon(Icons.forum),
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user