Add initial basic focus mode implementation

merge-requests/67/merge
Hank Grabowski 2024-07-24 11:42:24 -04:00
rodzic 0e18e02b3a
commit f5241a72fa
5 zmienionych plików z 332 dodań i 253 usunięć

Wyświetl plik

@ -0,0 +1,55 @@
import 'dart:async';
import 'package:flutter/material.dart';
import '../utils/dateutils.dart';
class AppBottomFocusModeStatus extends StatefulWidget {
final DateTime? disableTime;
const AppBottomFocusModeStatus({super.key, required this.disableTime});
@override
State<AppBottomFocusModeStatus> createState() =>
_AppBottomFocusModeStatusState();
}
class _AppBottomFocusModeStatusState extends State<AppBottomFocusModeStatus> {
Timer? updateTimer;
Duration? timeUntil;
@override
void initState() {
super.initState();
_updateTimeUntil();
updateTimer = Timer.periodic(Duration(seconds: 1), (_) {
setState(() {
_updateTimeUntil();
});
});
}
@override
void dispose() {
print('Disposing');
updateTimer?.cancel();
super.dispose();
}
void _updateTimeUntil() {
timeUntil = widget.disableTime?.difference(DateTime.now());
}
@override
Widget build(BuildContext context) {
final title = timeUntil == null
? 'Focus Mode'
: 'Focus Mode for ${timeUntil!.simpleLabel}';
return Text(
title,
style: Theme.of(context).textTheme.headlineSmall!.copyWith(
fontWeight: FontWeight.bold,
),
);
}
}

Wyświetl plik

@ -5,6 +5,7 @@ import 'package:logging/logging.dart';
import '../globals.dart'; import '../globals.dart';
import '../routes.dart'; import '../routes.dart';
import '../services/auth_service.dart'; import '../services/auth_service.dart';
import 'focus_mode_menu_item.dart';
import 'login_aware_cached_network_image.dart'; import 'login_aware_cached_network_image.dart';
class StandardAppDrawer extends StatelessWidget { class StandardAppDrawer extends StatelessWidget {
@ -62,6 +63,7 @@ class StandardAppDrawer extends StatelessWidget {
'Manage Profiles', 'Manage Profiles',
() => context.pushNamed(ScreenPaths.manageProfiles), () => context.pushNamed(ScreenPaths.manageProfiles),
), ),
const FocusModeMenuItem(),
const Divider(), const Divider(),
buildMenuButton( buildMenuButton(
context, context,

Wyświetl plik

@ -1,4 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart' as fr;
import 'package:go_router/go_router.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:media_kit/media_kit.dart'; import 'package:media_kit/media_kit.dart';
import 'package:multi_trigger_autocomplete/multi_trigger_autocomplete.dart'; import 'package:multi_trigger_autocomplete/multi_trigger_autocomplete.dart';
@ -8,6 +10,7 @@ import 'package:provider/provider.dart';
import 'app_theme.dart'; import 'app_theme.dart';
import 'di_initialization.dart'; import 'di_initialization.dart';
import 'globals.dart'; import 'globals.dart';
import 'riverpod_controllers/focus_mode.dart';
import 'routes.dart'; import 'routes.dart';
import 'services/auth_service.dart'; import 'services/auth_service.dart';
import 'services/blocks_manager.dart'; import 'services/blocks_manager.dart';
@ -51,7 +54,7 @@ void main() async {
// enabled: !kReleaseMode && enablePreview, // enabled: !kReleaseMode && enablePreview,
// builder: (context) => const App(), // builder: (context) => const App(),
// )); // ));
runApp(const App()); runApp(const fr.ProviderScope(child: App()));
} }
Future<void> setupPackageInfoAndUserAgent() async { Future<void> setupPackageInfoAndUserAgent() async {
@ -60,13 +63,45 @@ Future<void> setupPackageInfoAndUserAgent() async {
userAgent = 'Relatica/$appVersion'; userAgent = 'Relatica/$appVersion';
} }
class App extends StatelessWidget { class App extends fr.ConsumerStatefulWidget {
const App({super.key}); const App({super.key});
// This widget is the root of your application. // This widget is the root of your application.
@override
fr.ConsumerState<App> createState() => _AppState();
}
class _AppState extends fr.ConsumerState<App> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final settingsService = getIt<SettingsService>(); final settingsService = getIt<SettingsService>();
final authService = getIt<AccountsService>();
final appRouter = GoRouter(
initialLocation: ScreenPaths.timelines,
debugLogDiagnostics: true,
refreshListenable: authService,
redirect: (context, state) async {
final loggedIn = authService.loggedIn;
final focusMode = ref.read(focusModeProvider);
print('Focus mode? $focusMode');
if (!loggedIn && authService.initializing) {
return ScreenPaths.splash;
}
if (!loggedIn && !allowedLoggedOut.contains(state.uri.toString())) {
return ScreenPaths.signin;
}
if (loggedIn && allowedLoggedOut.contains(state.uri.toString())) {
return ScreenPaths.timelines;
}
return null;
},
routes: routes,
);
return AnimatedBuilder( return AnimatedBuilder(
builder: (context, child) { builder: (context, child) {
Logger.root.level = settingsService.logLevel; Logger.root.level = settingsService.logLevel;

Wyświetl plik

@ -1,6 +1,5 @@
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'globals.dart';
import 'models/interaction_type_enum.dart'; import 'models/interaction_type_enum.dart';
import 'screens/blocks_screen.dart'; import 'screens/blocks_screen.dart';
import 'screens/circle_add_users_screen.dart'; import 'screens/circle_add_users_screen.dart';
@ -29,7 +28,6 @@ import 'screens/sign_in.dart';
import 'screens/splash.dart'; import 'screens/splash.dart';
import 'screens/user_posts_screen.dart'; import 'screens/user_posts_screen.dart';
import 'screens/user_profile_screen.dart'; import 'screens/user_profile_screen.dart';
import 'services/auth_service.dart';
class ScreenPaths { class ScreenPaths {
static String blocks = '/blocks'; static String blocks = '/blocks';
@ -56,35 +54,13 @@ class ScreenPaths {
} }
bool needAuthChangeInitialized = true; bool needAuthChangeInitialized = true;
final _authService = getIt<AccountsService>();
final allowedLoggedOut = [ final allowedLoggedOut = [
ScreenPaths.splash, ScreenPaths.splash,
ScreenPaths.signin, ScreenPaths.signin,
ScreenPaths.signup ScreenPaths.signup
]; ];
final appRouter = GoRouter( final routes = [
initialLocation: ScreenPaths.timelines,
debugLogDiagnostics: true,
refreshListenable: _authService,
redirect: (context, state) async {
final loggedIn = _authService.loggedIn;
if (!loggedIn && _authService.initializing) {
return ScreenPaths.splash;
}
if (!loggedIn && !allowedLoggedOut.contains(state.uri.toString())) {
return ScreenPaths.signin;
}
if (loggedIn && allowedLoggedOut.contains(state.uri.toString())) {
return ScreenPaths.timelines;
}
return null;
},
routes: [
GoRoute( GoRoute(
path: ScreenPaths.blocks, path: ScreenPaths.blocks,
name: ScreenPaths.blocks, name: ScreenPaths.blocks,
@ -129,8 +105,8 @@ final appRouter = GoRouter(
GoRoute( GoRoute(
path: '/connect/:id', path: '/connect/:id',
name: ScreenPaths.connectHandle, name: ScreenPaths.connectHandle,
builder: (context, state) => FollowRequestAdjudicationScreen( builder: (context, state) =>
userId: state.pathParameters['id']!), FollowRequestAdjudicationScreen(userId: state.pathParameters['id']!),
), ),
GoRoute( GoRoute(
path: ScreenPaths.timelines, path: ScreenPaths.timelines,
@ -158,8 +134,8 @@ final appRouter = GoRouter(
GoRoute( GoRoute(
name: ScreenPaths.thread, name: ScreenPaths.thread,
path: ScreenPaths.thread, path: ScreenPaths.thread,
builder: (context, state) => MessageThreadScreen( builder: (context, state) =>
parentThreadId: state.uri.queryParameters['uri']!), MessageThreadScreen(parentThreadId: state.uri.queryParameters['uri']!),
), ),
GoRoute( GoRoute(
name: ScreenPaths.circleManagement, name: ScreenPaths.circleManagement,
@ -323,4 +299,4 @@ final appRouter = GoRouter(
child: LogViewerScreen(), child: LogViewerScreen(),
), ),
), ),
]); ];

Wyświetl plik

@ -1,7 +1,10 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:relatica/controls/focus_mode_status_headline.dart';
import 'package:relatica/riverpod_controllers/focus_mode.dart';
import '../controls/app_bottom_nav_bar.dart'; import '../controls/app_bottom_nav_bar.dart';
import '../controls/linear_status_indicator.dart'; import '../controls/linear_status_indicator.dart';
@ -16,14 +19,14 @@ import '../services/network_status_service.dart';
import '../services/timeline_manager.dart'; import '../services/timeline_manager.dart';
import '../utils/active_profile_selector.dart'; import '../utils/active_profile_selector.dart';
class HomeScreen extends StatefulWidget { class HomeScreen extends ConsumerStatefulWidget {
const HomeScreen({super.key}); const HomeScreen({super.key});
@override @override
State<HomeScreen> createState() => _HomeScreenState(); ConsumerState<HomeScreen> createState() => _HomeScreenState();
} }
class _HomeScreenState extends State<HomeScreen> { class _HomeScreenState extends ConsumerState<HomeScreen> {
final _logger = Logger('$HomeScreen'); final _logger = Logger('$HomeScreen');
TimelineIdentifiers currentTimeline = TimelineIdentifiers.home(); TimelineIdentifiers currentTimeline = TimelineIdentifiers.home();
@ -49,8 +52,12 @@ class _HomeScreenState extends State<HomeScreen> {
_logger.finest('Build'); _logger.finest('Build');
final accountService = getIt<AccountsService>(); final accountService = getIt<AccountsService>();
final nss = getIt<NetworkStatusService>(); final nss = getIt<NetworkStatusService>();
final focusMode = ref.watch(focusModeProvider);
final timeline = TimelinePanel(timeline: currentTimeline); final timeline = TimelinePanel(
timeline: focusMode.enabled
? TimelineIdentifiers.myPosts()
: currentTimeline);
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
@ -65,7 +72,9 @@ class _HomeScreenState extends State<HomeScreen> {
}) })
: null, : null,
backgroundColor: Theme.of(context).canvasColor, backgroundColor: Theme.of(context).canvasColor,
title: buildTimelineSelector(context), title: focusMode.enabled
? AppBottomFocusModeStatus(disableTime: focusMode.disableTime)
: buildTimelineSelector(context),
), ),
body: Center( body: Center(
child: Column( child: Column(
@ -78,7 +87,9 @@ class _HomeScreenState extends State<HomeScreen> {
), ),
), ),
drawer: const StandardAppDrawer(), drawer: const StandardAppDrawer(),
bottomNavigationBar: AppBottomNavBar( bottomNavigationBar: focusMode.enabled
? null
: AppBottomNavBar(
currentButton: NavBarButtons.timelines, currentButton: NavBarButtons.timelines,
onHomeButtonReclick: () => timeline.scrollToTop(), onHomeButtonReclick: () => timeline.scrollToTop(),
), ),