Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions lib/src/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ import 'package:lichess_mobile/src/model/correspondence/correspondence_service.d
import 'package:lichess_mobile/src/model/notifications/notification_service.dart';
import 'package:lichess_mobile/src/model/settings/board_preferences.dart';
import 'package:lichess_mobile/src/model/settings/general_preferences.dart';
import 'package:lichess_mobile/src/navigation.dart';
import 'package:lichess_mobile/src/network/connectivity.dart';
import 'package:lichess_mobile/src/network/socket.dart';
import 'package:lichess_mobile/src/tab_scaffold.dart';
import 'package:lichess_mobile/src/theme.dart';
import 'package:lichess_mobile/src/utils/navigation.dart';
import 'package:lichess_mobile/src/utils/screen.dart';
Expand Down Expand Up @@ -120,15 +120,18 @@ class _AppState extends ConsumerState<Application> {
title: 'lichess.org',
locale: generalPrefs.locale,
theme: theme.copyWith(
navigationBarTheme: NavigationBarTheme.of(context).copyWith(
height: isIOS || remainingHeight < kSmallRemainingHeightLeftBoardThreshold ? 60 : null,
),
navigationBarTheme:
isIOS
? null
: NavigationBarTheme.of(context).copyWith(
height: remainingHeight < kSmallRemainingHeightLeftBoardThreshold ? 60 : null,
),
),
onGenerateRoute:
(settings) =>
settings.name != null ? resolveAppLinkUri(context, Uri.parse(settings.name!)) : null,
onGenerateInitialRoutes: (initialRoute) {
final homeRoute = buildScreenRoute<void>(context, screen: const BottomNavScaffold());
final homeRoute = buildScreenRoute<void>(context, screen: const MainTabScaffold());
return <Route<dynamic>?>[
homeRoute,
resolveAppLinkUri(context, Uri.parse(initialRoute)),
Expand Down
2 changes: 1 addition & 1 deletion lib/src/constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ const kMaxClockTextScaleFactor = 1.94;
const kEmptyWidget = SizedBox.shrink();
const kEmptyFen = '8/8/8/8/8/8/8/8 w - - 0 1';
const kTabletBoardTableSidePadding = 16.0;
const kBottomBarHeight = 56.0;
const kBottomBarHeight = 50.0;
const kMaterialPopupMenuMaxWidth = 500.0;

/// The threshold to detect screens with a small remaining height left board.
Expand Down
2 changes: 1 addition & 1 deletion lib/src/model/account/account_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import 'package:lichess_mobile/src/model/notifications/notification_service.dart
import 'package:lichess_mobile/src/model/notifications/notifications.dart'
show LocalNotification, PlaybanNotification;
import 'package:lichess_mobile/src/model/user/user.dart' show TemporaryBan, User;
import 'package:lichess_mobile/src/navigation.dart' show currentNavigatorKeyProvider;
import 'package:lichess_mobile/src/network/http.dart';
import 'package:lichess_mobile/src/tab_scaffold.dart' show currentNavigatorKeyProvider;
import 'package:lichess_mobile/src/view/play/playban.dart';
import 'package:lichess_mobile/src/widgets/platform_alert_dialog.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
Expand Down
2 changes: 1 addition & 1 deletion lib/src/model/challenge/challenge_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import 'package:lichess_mobile/src/model/challenge/challenge_repository.dart';
import 'package:lichess_mobile/src/model/common/id.dart';
import 'package:lichess_mobile/src/model/notifications/notification_service.dart';
import 'package:lichess_mobile/src/model/notifications/notifications.dart';
import 'package:lichess_mobile/src/navigation.dart';
import 'package:lichess_mobile/src/network/socket.dart';
import 'package:lichess_mobile/src/tab_scaffold.dart' show currentNavigatorKeyProvider;
import 'package:lichess_mobile/src/utils/l10n_context.dart';
import 'package:lichess_mobile/src/view/game/game_screen.dart';
import 'package:lichess_mobile/src/view/user/challenge_requests_screen.dart';
Expand Down
2 changes: 1 addition & 1 deletion lib/src/model/correspondence/correspondence_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ import 'package:lichess_mobile/src/model/game/game_socket_events.dart';
import 'package:lichess_mobile/src/model/game/playable_game.dart';
import 'package:lichess_mobile/src/model/notifications/notification_service.dart';
import 'package:lichess_mobile/src/model/notifications/notifications.dart';
import 'package:lichess_mobile/src/navigation.dart';
import 'package:lichess_mobile/src/network/http.dart';
import 'package:lichess_mobile/src/network/socket.dart';
import 'package:lichess_mobile/src/tab_scaffold.dart' show currentNavigatorKeyProvider;
import 'package:lichess_mobile/src/view/game/game_screen.dart';
import 'package:logging/logging.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
Expand Down
2 changes: 1 addition & 1 deletion lib/src/model/http_log/http_log_paginator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ part 'http_log_paginator.freezed.dart';
part 'http_log_paginator.g.dart';

/// The number of HTTP logs to fetch per page.
const _pageSize = 12;
const _pageSize = 20;

/// A Riverpod controller for managing HTTP logs.
///
Expand Down
8 changes: 0 additions & 8 deletions lib/src/model/lobby/game_setup_preferences.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,6 @@ class GameSetupPreferences extends _$GameSetupPreferences
return save(state.copyWith(quickPairingTimeIncrement: timeInc));
}

Future<void> setCustomTimeControl(TimeControl control) {
return save(state.copyWith(customTimeControl: control));
}

Future<void> setCustomTimeSeconds(int seconds) {
return save(state.copyWith(customTimeSeconds: seconds));
}
Expand All @@ -62,15 +58,12 @@ class GameSetupPreferences extends _$GameSetupPreferences
}
}

enum TimeControl { realTime, correspondence }

@Freezed(fromJson: true, toJson: true)
class GameSetupPrefs with _$GameSetupPrefs implements Serializable {
const GameSetupPrefs._();

const factory GameSetupPrefs({
required TimeIncrement quickPairingTimeIncrement,
required TimeControl customTimeControl,
required int customTimeSeconds,
required int customIncrementSeconds,
required int customDaysPerTurn,
Expand All @@ -81,7 +74,6 @@ class GameSetupPrefs with _$GameSetupPrefs implements Serializable {

static const defaults = GameSetupPrefs(
quickPairingTimeIncrement: TimeIncrement(600, 0),
customTimeControl: TimeControl.realTime,
customTimeSeconds: 180,
customIncrementSeconds: 0,
customVariant: Variant.standard,
Expand Down
4 changes: 2 additions & 2 deletions lib/src/model/puzzle/puzzle_streak.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import 'package:lichess_mobile/src/model/puzzle/puzzle.dart';
import 'package:lichess_mobile/src/model/puzzle/puzzle_providers.dart';
import 'package:lichess_mobile/src/model/puzzle/puzzle_repository.dart';
import 'package:lichess_mobile/src/model/puzzle/streak_storage.dart';
import 'package:lichess_mobile/src/navigation.dart';
import 'package:lichess_mobile/src/network/http.dart';
import 'package:lichess_mobile/src/tab_scaffold.dart' show currentNavigatorKeyProvider;
import 'package:lichess_mobile/src/widgets/feedback.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'puzzle_streak.g.dart';
part 'puzzle_streak.freezed.dart';
part 'puzzle_streak.g.dart';

typedef Streak = IList<PuzzleId>;

Expand Down
173 changes: 102 additions & 71 deletions lib/src/navigation.dart → lib/src/tab_scaffold.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:lichess_mobile/l10n/l10n.dart';
import 'package:lichess_mobile/src/constants.dart';
import 'package:lichess_mobile/src/utils/l10n_context.dart';
import 'package:lichess_mobile/src/view/home/home_tab_screen.dart';
import 'package:lichess_mobile/src/view/puzzle/puzzle_tab_screen.dart';
Expand Down Expand Up @@ -108,50 +108,51 @@ class _BottomTabInteraction extends ChangeNotifier {
}
}

/// Implements a tabbed (iOS style) root layout and behavior structure.
///
/// This widget is intended to be used as the root of the app, and it provides
/// the structure necessary to display tabs in iOS style. It also defines the
/// tab bar and tab switching behavior, but does not define the contents of
/// each tab.
class BottomNavScaffold extends ConsumerWidget {
const BottomNavScaffold({super.key});
/// Main scaffold that provides the bottom navigation bar and tab switching view.
class MainTabScaffold extends ConsumerWidget {
const MainTabScaffold({super.key});

@override
Widget build(BuildContext context, WidgetRef ref) {
final currentTab = ref.watch(currentBottomTabProvider);

final extendBody = Theme.of(context).platform == TargetPlatform.iOS;

return FullScreenBackground(
child: Scaffold(
body: _TabSwitchingView(currentTab: currentTab, tabBuilder: _tabBuilder),
bottomNavigationBar:
Theme.of(context).platform == TargetPlatform.iOS
? CupertinoTabBar(
height: kBottomBarHeight,
backgroundColor: ColorScheme.of(context).surfaceContainer,
border: const Border(top: BorderSide(color: Colors.transparent)),
activeColor: ColorScheme.of(context).onSurface,
currentIndex: currentTab.index,
items: [
for (final tab in BottomTab.values)
BottomNavigationBarItem(
icon: Icon(tab.icon, fill: tab == currentTab ? 1 : 0),
label: tab.label(context.l10n),
),
],
onTap: (i) => _onItemTapped(ref, i),
)
: NavigationBar(
selectedIndex: currentTab.index,
destinations: [
for (final tab in BottomTab.values)
NavigationDestination(
icon: Icon(tab.icon, fill: tab == currentTab ? 1 : 0),
label: tab.label(context.l10n),
),
],
onDestinationSelected: (i) => _onItemTapped(ref, i),
),
child: MainTabScaffoldProperties(
extendBody: extendBody,
child: Scaffold(
body: _TabSwitchingView(currentTab: currentTab, tabBuilder: _tabBuilder),
extendBody: extendBody,
bottomNavigationBar:
Theme.of(context).platform == TargetPlatform.iOS
? CupertinoTabBar(
height: 50,
backgroundColor: NavigationBarTheme.of(context).backgroundColor,
border: const Border(top: BorderSide(color: Colors.transparent)),
activeColor: ColorScheme.of(context).onSurface,
currentIndex: currentTab.index,
items: [
for (final tab in BottomTab.values)
BottomNavigationBarItem(
icon: Icon(tab.icon, fill: tab == currentTab ? 1 : 0),
label: tab.label(context.l10n),
),
],
onTap: (i) => _onItemTapped(ref, i),
)
: NavigationBar(
selectedIndex: currentTab.index,
destinations: [
for (final tab in BottomTab.values)
NavigationDestination(
icon: Icon(tab.icon, fill: tab == currentTab ? 1 : 0),
label: tab.label(context.l10n),
),
],
onDestinationSelected: (i) => _onItemTapped(ref, i),
),
),
),
);
}
Expand Down Expand Up @@ -192,37 +193,68 @@ class BottomNavScaffold extends ConsumerWidget {
ref.read(currentBottomTabProvider.notifier).state = tappedTab;
}
}

Widget _tabBuilder(BuildContext context, int index) {
switch (index) {
case 0:
return _MaterialTabView(
navigatorKey: homeNavigatorKey,
tab: BottomTab.home,
builder: (context) => const HomeTabScreen(),
);
case 1:
return _MaterialTabView(
navigatorKey: puzzlesNavigatorKey,
tab: BottomTab.puzzles,
builder: (context) => const PuzzleTabScreen(),
);
case 2:
return _MaterialTabView(
navigatorKey: watchNavigatorKey,
tab: BottomTab.watch,
builder: (context) => const WatchTabScreen(),
);
case 3:
return _MaterialTabView(
navigatorKey: toolsNavigatorKey,
tab: BottomTab.tools,
builder: (context) => const ToolsTabScreen(),
);
default:
assert(false, 'Unexpected tab');
return const SizedBox.shrink();
}
}
}

Widget _tabBuilder(BuildContext context, int index) {
switch (index) {
case 0:
return _MaterialTabView(
navigatorKey: homeNavigatorKey,
tab: BottomTab.home,
builder: (context) => const HomeTabScreen(),
);
case 1:
return _MaterialTabView(
navigatorKey: puzzlesNavigatorKey,
tab: BottomTab.puzzles,
builder: (context) => const PuzzleTabScreen(),
);
case 2:
return _MaterialTabView(
navigatorKey: watchNavigatorKey,
tab: BottomTab.watch,
builder: (context) => const WatchTabScreen(),
);
case 3:
return _MaterialTabView(
navigatorKey: toolsNavigatorKey,
tab: BottomTab.tools,
builder: (context) => const ToolsTabScreen(),
);
default:
assert(false, 'Unexpected tab');
return const SizedBox.shrink();
/// [InheritedWidget] providing [Scaffold] properties of the [MainTabScaffold].
class MainTabScaffoldProperties extends InheritedWidget {
/// Constructs a new [MainTabScaffoldProperties].
const MainTabScaffoldProperties({required super.child, required this.extendBody, super.key});

/// The value of [Scaffold.extendBody] defined in the [MainTabScaffold].
final bool extendBody;

@override
bool updateShouldNotify(MainTabScaffoldProperties oldWidget) {
return extendBody != oldWidget.extendBody;
}

/// Retrieve the [MainTabScaffoldProperties] background color from the context.
static MainTabScaffoldProperties? maybeOf(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<MainTabScaffoldProperties>();
}

/// Returns true if the [MainTabScaffold] has an extended body.
static bool hasExtendedBody(BuildContext context) {
final properties = maybeOf(context);
return properties != null && properties.extendBody;
}

@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(DiagnosticsProperty<bool>('extendBody', extendBody));
}
}

Expand Down Expand Up @@ -281,9 +313,8 @@ class _TabSwitchingViewState extends State<_TabSwitchingView> {
tabFocusNodes.addAll(
List<FocusScopeNode>.generate(
BottomTab.values.length - tabFocusNodes.length,
(int index) => FocusScopeNode(
debugLabel: '$BottomNavScaffold Tab ${index + tabFocusNodes.length}',
),
(int index) =>
FocusScopeNode(debugLabel: '$MainTabScaffold Tab ${index + tabFocusNodes.length}'),
),
);
}
Expand Down
Loading