Skip to content
Snippets Groups Projects
Commit 4a5963f8 authored by Benoît Harrault's avatar Benoît Harrault
Browse files

Use navigation tools from flutter_custom_toolbox

parent 86ee3201
No related branches found
No related tags found
1 merge request!22Resolve "Use navigation widgets from flutter_custom_toolbox"
Pipeline #7145 passed
This commit is part of merge request !22. Comments created here will be created in the context of that merge request.
Showing
with 120 additions and 444 deletions
Use navigation tools from flutter_custom_toolbox.
Utilisation des outils de navigation entre pages depuis flutter_custom_toolbox.
import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:awale/cubit/activity/activity_cubit.dart';
import 'package:awale/config/application_config.dart';
import 'package:awale/models/activity/activity.dart';
import 'package:awale/ui/pages/game.dart';
class ActivityPageItem {
final String code;
final Icon icon;
final Widget Function({required Activity currentActivity})? builder;
const ActivityPageItem({
required this.code,
required this.icon,
required this.builder,
});
}
class ActivityPage {
static const bool displayBottomNavBar = false;
static const indexHome = 0;
static final ActivityPageItem pageHome = ActivityPageItem(
code: 'page_home',
icon: Icon(UniconsLine.home),
builder: ({required Activity currentActivity}) {
return PageParameters(
config: ApplicationConfig.config,
canBeResumed: currentActivity.canBeResumed,
);
},
);
static const indexGame = 1;
static final pageGame = ActivityPageItem(
code: 'page_game',
icon: Icon(UniconsLine.star),
builder: ({required Activity currentActivity}) {
return PageGame();
},
);
static final Map<int, ActivityPageItem> items = {
indexHome: pageHome,
indexGame: pageGame,
};
static int defaultPageIndex = indexHome;
static bool isIndexAllowed(int pageIndex) {
return items.keys.contains(pageIndex);
}
static Widget getWidget(int pageIndex) {
return BlocBuilder<ActivityCubit, ActivityState>(
builder: (BuildContext context, ActivityState activityState) {
final Activity currentActivity = activityState.currentActivity;
if (items.keys.contains(pageIndex)) {
return items[pageIndex]?.builder!(currentActivity: currentActivity) ?? Text('oups');
} else {
return getWidget(defaultPageIndex);
}
},
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:awale/common/ui/screens/about.dart';
import 'package:awale/common/ui/screens/activity.dart';
import 'package:awale/common/ui/screens/settings.dart';
class ScreenItem {
final String code;
final Icon icon;
final Widget screen;
const ScreenItem({
required this.code,
required this.icon,
required this.screen,
});
}
class Screen {
static const indexActivity = 0;
static const screenActivity = ScreenItem(
code: 'screen_activity',
icon: Icon(UniconsLine.home),
screen: ScreenActivity(),
);
static const indexSettings = 1;
static const screenSettings = ScreenItem(
code: 'screen_settings',
icon: Icon(UniconsLine.setting),
screen: ScreenSettings(),
);
static const indexAbout = 2;
static const screenAbout = ScreenItem(
code: 'screen_about',
icon: Icon(UniconsLine.info_circle),
screen: ScreenAbout(),
);
static Map<int, ScreenItem> items = {
indexActivity: screenActivity,
indexSettings: screenSettings,
indexAbout: screenAbout,
};
static bool isIndexAllowed(int screenIndex) {
return items.keys.contains(screenIndex);
}
static Widget getWidget(int screenIndex) {
return items[screenIndex]?.screen ?? screenActivity.screen;
}
}
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:awale/common/config/activity_page.dart';
class NavCubitPage extends HydratedCubit<int> {
NavCubitPage() : super(0);
void updateIndex(int index) {
if (ActivityPage.isIndexAllowed(index)) {
emit(index);
} else {
emit(ActivityPage.indexHome);
}
}
void goToPageHome() {
updateIndex(ActivityPage.indexHome);
}
void goToPageGame() {
updateIndex(ActivityPage.indexGame);
}
@override
int fromJson(Map<String, dynamic> json) {
return ActivityPage.indexHome;
}
@override
Map<String, dynamic>? toJson(int state) {
return <String, int>{'index': state};
}
}
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:awale/common/config/screen.dart';
class NavCubitScreen extends HydratedCubit<int> {
NavCubitScreen() : super(0);
void updateIndex(int index) {
if (Screen.isIndexAllowed(index)) {
emit(index);
} else {
goToScreenActivity();
}
}
void goToScreenActivity() {
emit(Screen.indexActivity);
}
void goToScreenSettings() {
emit(Screen.indexSettings);
}
void goToScreenAbout() {
emit(Screen.indexAbout);
}
@override
int fromJson(Map<String, dynamic> json) {
return Screen.indexActivity;
}
@override
Map<String, dynamic>? toJson(int state) {
return <String, int>{'index': state};
}
}
import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:awale/common/config/activity_page.dart';
import 'package:awale/common/cubit/nav/nav_cubit_pages.dart';
class BottomNavBar extends StatelessWidget {
const BottomNavBar({super.key});
@override
Widget build(BuildContext context) {
return Card(
margin: const EdgeInsets.only(top: 1, right: 4, left: 4),
elevation: 4,
shadowColor: Theme.of(context).colorScheme.shadow,
color: Theme.of(context).colorScheme.surfaceContainerHighest,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(16),
topRight: Radius.circular(16),
),
),
child: BlocBuilder<NavCubitPage, int>(builder: (BuildContext context, int state) {
final List<BottomNavigationBarItem> items = [];
ActivityPage.items.forEach((int pageIndex, ActivityPageItem item) {
items.add(BottomNavigationBarItem(
icon: item.icon,
label: tr(item.code),
));
});
return BottomNavigationBar(
currentIndex: state,
onTap: (int index) => BlocProvider.of<NavCubitPage>(context).updateIndex(index),
type: BottomNavigationBarType.fixed,
elevation: 0,
backgroundColor: Colors.transparent,
selectedItemColor: Theme.of(context).colorScheme.primary,
unselectedItemColor: Theme.of(context).textTheme.bodySmall!.color,
items: items,
);
}),
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:awale/common/config/screen.dart';
import 'package:awale/common/cubit/nav/nav_cubit_pages.dart';
import 'package:awale/common/cubit/nav/nav_cubit_screens.dart';
import 'package:awale/cubit/activity/activity_cubit.dart';
import 'package:awale/models/activity/activity.dart';
class GlobalAppBar extends StatelessWidget implements PreferredSizeWidget {
const GlobalAppBar({super.key});
@override
Widget build(BuildContext context) {
return BlocBuilder<ActivityCubit, ActivityState>(
builder: (BuildContext context, ActivityState activityState) {
return BlocBuilder<NavCubitScreen, int>(
builder: (BuildContext context, int pageIndex) {
final Activity currentActivity = activityState.currentActivity;
final List<Widget> menuActions = [];
if (currentActivity.isRunning && !currentActivity.isFinished) {
menuActions.add(ActivityButtonQuit(
onPressed: () {},
onLongPress: () {
BlocProvider.of<ActivityCubit>(context).quitActivity();
BlocProvider.of<NavCubitPage>(context).goToPageHome();
},
));
} else {
if (pageIndex == Screen.indexActivity) {
// go to Settings page
menuActions.add(ElevatedButton(
onPressed: () {
BlocProvider.of<NavCubitScreen>(context).goToScreenSettings();
},
style: ElevatedButton.styleFrom(
shape: const CircleBorder(),
),
child: Screen.screenSettings.icon,
));
// go to About page
menuActions.add(ElevatedButton(
onPressed: () {
BlocProvider.of<NavCubitScreen>(context).goToScreenAbout();
},
style: ElevatedButton.styleFrom(
shape: const CircleBorder(),
),
child: Screen.screenAbout.icon,
));
} else {
// back to Home page
menuActions.add(ElevatedButton(
onPressed: () {
BlocProvider.of<NavCubitScreen>(context).goToScreenActivity();
},
style: ElevatedButton.styleFrom(
shape: const CircleBorder(),
),
child: Screen.screenActivity.icon,
));
}
}
return AppBar(
title: const AppHeader(text: 'app_name'),
actions: menuActions,
);
},
);
},
);
}
@override
Size get preferredSize => const Size.fromHeight(50);
}
import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
class ScreenAbout extends StatelessWidget {
const ScreenAbout({super.key});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
const SizedBox(height: 8),
const AppTitle(text: 'about_title'),
const Text('about_content').tr(),
FutureBuilder<PackageInfo>(
future: PackageInfo.fromPlatform(),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.done:
return const Text('about_version').tr(
namedArgs: {
'version': snapshot.data!.version,
},
);
default:
return const SizedBox();
}
},
),
],
),
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:awale/common/config/activity_page.dart';
import 'package:awale/common/cubit/nav/nav_cubit_pages.dart';
class ScreenActivity extends StatelessWidget {
const ScreenActivity({super.key});
@override
Widget build(BuildContext context) {
return BlocBuilder<NavCubitPage, int>(
builder: (BuildContext context, int pageIndex) {
return ActivityPage.getWidget(pageIndex);
},
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
class ScreenSettings extends StatelessWidget {
const ScreenSettings({super.key});
@override
Widget build(BuildContext context) {
return const Padding(
padding: EdgeInsets.symmetric(horizontal: 8),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
SizedBox(height: 8),
AppTitle(text: 'settings_title'),
SizedBox(height: 8),
ApplicationSettingsForm(),
],
),
);
}
}
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:awale/common/cubit/nav/nav_cubit_pages.dart';
import 'package:awale/cubit/activity/activity_cubit.dart'; import 'package:awale/cubit/activity/activity_cubit.dart';
import 'package:awale/ui/pages/game.dart';
class ApplicationConfig { class ApplicationConfig {
// known parameters // activity parameter: skin
static const String parameterCodeSkin = 'global.skin'; static const String parameterCodeSkin = 'global.skin';
static const String parameterCodeGameMode = 'activity.gameMode';
// skin values
static const String skinValueDefault = 'default'; static const String skinValueDefault = 'default';
// game mode values // activity parameter: game mode
static const String parameterCodeGameMode = 'activity.gameMode';
static const String gameModeHumanVsHuman = 'human-vs-human'; static const String gameModeHumanVsHuman = 'human-vs-human';
static const String gameModeHumanVsRobot = 'human-vs-robot'; static const String gameModeHumanVsRobot = 'human-vs-robot';
static const String gameModeRobotVsHuman = 'robot-vs-human'; static const String gameModeRobotVsHuman = 'robot-vs-human';
static const String gameModeRobotVsRobot = 'robot-vs-robot'; static const String gameModeRobotVsRobot = 'robot-vs-robot';
// activity pages
static const int activityPageIndexHome = 0;
static const int activityPageIndexGame = 1;
static final ApplicationConfigDefinition config = ApplicationConfigDefinition( static final ApplicationConfigDefinition config = ApplicationConfigDefinition(
appTitle: 'Awale', appTitle: 'Awale',
activitySettings: [ activitySettings: [
// game mode // activity parameter: game mode
ApplicationSettingsParameter( ApplicationSettingsParameter(
code: parameterCodeGameMode, code: parameterCodeGameMode,
values: [ values: [
...@@ -50,7 +51,7 @@ class ApplicationConfig { ...@@ -50,7 +51,7 @@ class ApplicationConfig {
], ],
), ),
// skin // activity parameter: skin
ApplicationSettingsParameter( ApplicationSettingsParameter(
code: parameterCodeSkin, code: parameterCodeSkin,
displayedOnTop: false, displayedOnTop: false,
...@@ -64,14 +65,66 @@ class ApplicationConfig { ...@@ -64,14 +65,66 @@ class ApplicationConfig {
], ],
startNewActivity: (BuildContext context) { startNewActivity: (BuildContext context) {
BlocProvider.of<ActivityCubit>(context).startNewActivity(context); BlocProvider.of<ActivityCubit>(context).startNewActivity(context);
BlocProvider.of<NavCubitPage>(context).goToPageGame(); BlocProvider.of<NavCubitPage>(context)
.updateIndex(ApplicationConfig.activityPageIndexGame);
},
quitCurrentActivity: (BuildContext context) {
BlocProvider.of<ActivityCubit>(context).quitActivity();
BlocProvider.of<NavCubitPage>(context)
.updateIndex(ApplicationConfig.activityPageIndexHome);
}, },
deleteCurrentActivity: (BuildContext context) { deleteCurrentActivity: (BuildContext context) {
BlocProvider.of<ActivityCubit>(context).deleteSavedActivity(); BlocProvider.of<ActivityCubit>(context).deleteSavedActivity();
}, },
resumeActivity: (BuildContext context) { resumeActivity: (BuildContext context) {
BlocProvider.of<ActivityCubit>(context).resumeSavedActivity(); BlocProvider.of<ActivityCubit>(context).resumeSavedActivity();
BlocProvider.of<NavCubitPage>(context).goToPageGame(); BlocProvider.of<NavCubitPage>(context)
.updateIndex(ApplicationConfig.activityPageIndexGame);
},
navigation: ApplicationNavigation(
screenActivity: ScreenItem(
code: 'screen_activity',
icon: Icon(UniconsLine.home),
screen: ({required ApplicationConfigDefinition appConfig}) =>
ScreenActivity(appConfig: appConfig),
),
screenSettings: ScreenItem(
code: 'screen_settings',
icon: Icon(UniconsLine.setting),
screen: ({required ApplicationConfigDefinition appConfig}) => ScreenSettings(),
),
screenAbout: ScreenItem(
code: 'screen_about',
icon: Icon(UniconsLine.info_circle),
screen: ({required ApplicationConfigDefinition appConfig}) => ScreenAbout(),
),
activityPages: {
activityPageIndexHome: ActivityPageItem(
code: 'page_home',
icon: Icon(UniconsLine.home),
builder: ({required ApplicationConfigDefinition appConfig}) {
return BlocBuilder<ActivityCubit, ActivityState>(
builder: (BuildContext context, ActivityState activityState) {
return PageParameters(
appConfig: appConfig,
canBeResumed: activityState.currentActivity.canBeResumed,
);
},
);
},
),
activityPageIndexGame: ActivityPageItem(
code: 'page_game',
icon: Icon(UniconsLine.star),
builder: ({required ApplicationConfigDefinition appConfig}) {
return BlocBuilder<ActivityCubit, ActivityState>(
builder: (BuildContext context, ActivityState activityState) {
return PageGame();
}, },
); );
},
),
},
),
);
} }
...@@ -4,9 +4,6 @@ import 'package:flutter/material.dart'; ...@@ -4,9 +4,6 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:awale/common/cubit/nav/nav_cubit_pages.dart';
import 'package:awale/common/cubit/nav/nav_cubit_screens.dart';
import 'package:awale/config/application_config.dart'; import 'package:awale/config/application_config.dart';
import 'package:awale/cubit/activity/activity_cubit.dart'; import 'package:awale/cubit/activity/activity_cubit.dart';
import 'package:awale/ui/skeleton.dart'; import 'package:awale/ui/skeleton.dart';
...@@ -48,7 +45,7 @@ class MyApp extends StatelessWidget { ...@@ -48,7 +45,7 @@ class MyApp extends StatelessWidget {
providers: [ providers: [
// default providers // default providers
BlocProvider<NavCubitPage>( BlocProvider<NavCubitPage>(
create: (context) => NavCubitPage(), create: (context) => NavCubitPage(appConfig: ApplicationConfig.config),
), ),
BlocProvider<NavCubitScreen>( BlocProvider<NavCubitScreen>(
create: (context) => NavCubitScreen(), create: (context) => NavCubitScreen(),
......
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:awale/common/config/activity_page.dart'; import 'package:awale/config/application_config.dart';
import 'package:awale/common/config/screen.dart'; import 'package:awale/cubit/activity/activity_cubit.dart';
import 'package:awale/common/cubit/nav/nav_cubit_screens.dart'; import 'package:awale/models/activity/activity.dart';
import 'package:awale/common/ui/nav/global_app_bar.dart';
import 'package:awale/common/ui/nav/bottom_nav_bar.dart';
class SkeletonScreen extends StatelessWidget { class SkeletonScreen extends StatelessWidget {
const SkeletonScreen({super.key}); const SkeletonScreen({super.key});
...@@ -14,8 +12,25 @@ class SkeletonScreen extends StatelessWidget { ...@@ -14,8 +12,25 @@ class SkeletonScreen extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocBuilder<NavCubitScreen, int>( return BlocBuilder<NavCubitScreen, int>(
builder: (BuildContext context, int screenIndex) { builder: (BuildContext context, int screenIndex) {
return BlocBuilder<ActivityCubit, ActivityState>(
builder: (BuildContext context, ActivityState activityState) {
return BlocBuilder<NavCubitPage, int>(
builder: (BuildContext context, int pageIndex) {
final Activity currentActivity = activityState.currentActivity;
// autostart activity
if (ApplicationConfig.config.autoStartActivity &&
(!currentActivity.isRunning)) {
ApplicationConfig.config.startNewActivity(context);
}
return Scaffold( return Scaffold(
appBar: const GlobalAppBar(), appBar: GlobalAppBar(
appConfig: ApplicationConfig.config,
pageIndex: pageIndex,
isActivityRunning:
currentActivity.isRunning && !currentActivity.isFinished,
),
extendBodyBehindAppBar: false, extendBodyBehindAppBar: false,
body: Material( body: Material(
color: Theme.of(context).colorScheme.surface, color: Theme.of(context).colorScheme.surface,
...@@ -25,11 +40,20 @@ class SkeletonScreen extends StatelessWidget { ...@@ -25,11 +40,20 @@ class SkeletonScreen extends StatelessWidget {
left: 2, left: 2,
right: 2, right: 2,
), ),
child: Screen.getWidget(screenIndex), child: ApplicationConfig.config.navigation.getScreenWidget(
appConfig: ApplicationConfig.config,
screenIndex: screenIndex,
),
), ),
), ),
backgroundColor: Theme.of(context).colorScheme.surface, backgroundColor: Theme.of(context).colorScheme.surface,
bottomNavigationBar: ActivityPage.displayBottomNavBar ? const BottomNavBar() : null, bottomNavigationBar: ApplicationConfig.config.navigation.displayBottomNavBar
? BottomNavBar(appConfig: ApplicationConfig.config)
: null,
);
},
);
},
); );
}, },
); );
......
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:awale/common/cubit/nav/nav_cubit_pages.dart'; import 'package:awale/config/application_config.dart';
import 'package:awale/cubit/activity/activity_cubit.dart'; import 'package:awale/cubit/activity/activity_cubit.dart';
import 'package:awale/models/activity/activity.dart'; import 'package:awale/models/activity/activity.dart';
...@@ -72,7 +72,8 @@ class GameEndWidget extends StatelessWidget { ...@@ -72,7 +72,8 @@ class GameEndWidget extends StatelessWidget {
child: ActivityButtonQuit( child: ActivityButtonQuit(
onPressed: () { onPressed: () {
BlocProvider.of<ActivityCubit>(context).quitActivity(); BlocProvider.of<ActivityCubit>(context).quitActivity();
BlocProvider.of<NavCubitPage>(context).goToPageHome(); BlocProvider.of<NavCubitPage>(context)
.updateIndex(ApplicationConfig.activityPageIndexHome);
}, },
), ),
), ),
......
...@@ -122,11 +122,11 @@ packages: ...@@ -122,11 +122,11 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
path: "." path: "."
ref: "0.5.0" ref: "0.6.0"
resolved-ref: b8164a50489ba981ea57d9f02e2334f09cb8c6a7 resolved-ref: dfe0f6b7b49f9aa32f085e4a5d3ea320b3611eed
url: "https://git.harrault.fr/android/flutter-toolbox.git" url: "https://git.harrault.fr/android/flutter-toolbox.git"
source: git source: git
version: "0.5.0" version: "0.6.0"
flutter_lints: flutter_lints:
dependency: "direct dev" dependency: "direct dev"
description: description:
......
...@@ -3,7 +3,7 @@ description: Awale game ...@@ -3,7 +3,7 @@ description: Awale game
publish_to: "none" publish_to: "none"
version: 0.4.0+19 version: 0.5.0+20
environment: environment:
sdk: "^3.0.0" sdk: "^3.0.0"
...@@ -16,7 +16,7 @@ dependencies: ...@@ -16,7 +16,7 @@ dependencies:
flutter_custom_toolbox: flutter_custom_toolbox:
git: git:
url: https://git.harrault.fr/android/flutter-toolbox.git url: https://git.harrault.fr/android/flutter-toolbox.git
ref: 0.5.0 ref: 0.6.0
# specific # specific
# (none) # (none)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment