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

Add navigation

parent 637e33e6
No related branches found
No related tags found
1 merge request!31Resolve "Add navigation"
Pipeline #4483 passed
org.gradle.jvmargs=-Xmx1536M org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true android.useAndroidX=true
android.enableJetifier=true android.enableJetifier=true
app.versionName=1.0.22 app.versionName=1.0.23
app.versionCode=23 app.versionCode=24
{ {
"app_name": "Random application", "app_name": "Random application",
"bottom_nav_sample": "Sample",
"bottom_nav_chart": "Graph",
"TOP": "TOP", "TOP": "TOP",
"BOTTOM": "BOTTOM" "BOTTOM": "BOTTOM"
......
{ {
"app_name": "Random application", "app_name": "Random application",
"bottom_nav_sample": "Démo",
"bottom_nav_chart": "Graph",
"TOP": "HAUT", "TOP": "HAUT",
"BOTTOM": "BAS" "BOTTOM": "BAS"
......
...@@ -2,39 +2,10 @@ import 'package:easy_localization/easy_localization.dart'; ...@@ -2,39 +2,10 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class ActivityDemoPage extends StatelessWidget { class ActivityDemoPage extends StatelessWidget {
static const String code = 'demo'; const ActivityDemoPage({super.key});
static const String route = '/' + code;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Scaffold pageContent = Scaffold(
appBar: AppBar(
elevation: 0,
actions: <Widget>[
IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () {
print('reset activity');
Navigator.pop(context);
},
),
],
),
backgroundColor: Theme.of(context).colorScheme.background,
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Text('TOP').tr(),
SizedBox(height: 2),
Text('BOTTOM').tr(),
],
),
),
);
return SizedBox.expand( return SizedBox.expand(
child: Container( child: Container(
child: FittedBox( child: FittedBox(
...@@ -43,7 +14,18 @@ class ActivityDemoPage extends StatelessWidget { ...@@ -43,7 +14,18 @@ class ActivityDemoPage extends StatelessWidget {
child: SizedBox( child: SizedBox(
height: (MediaQuery.of(context).size.height), height: (MediaQuery.of(context).size.height),
width: (MediaQuery.of(context).size.width), width: (MediaQuery.of(context).size.width),
child: pageContent, child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Text('TOP').tr(),
SizedBox(height: 2),
Text('BOTTOM').tr(),
],
),
),
), ),
), ),
), ),
......
...@@ -2,56 +2,12 @@ import 'package:flutter/material.dart'; ...@@ -2,56 +2,12 @@ import 'package:flutter/material.dart';
import 'package:random/painters/GraphPainter.dart'; import 'package:random/painters/GraphPainter.dart';
class ActivityGraphPage extends StatelessWidget { class ActivityGraphPage extends StatelessWidget {
static const String code = 'graph'; const ActivityGraphPage({super.key});
static const String route = '/' + code;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
double boardWidth = MediaQuery.of(context).size.width; double boardWidth = MediaQuery.of(context).size.width;
Scaffold pageContent = Scaffold(
appBar: AppBar(
elevation: 0,
actions: <Widget>[
IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () {
print('reset activity');
Navigator.pop(context);
},
),
],
),
backgroundColor: Theme.of(context).colorScheme.background,
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Center(
child: GestureDetector(
onTapUp: (details) {
double xTap = details.localPosition.dx;
double yTap = details.localPosition.dy;
print('[' + xTap.toString() + ',' + yTap.toString() + ']');
},
child: Container(
margin: EdgeInsets.all(4),
padding: EdgeInsets.all(4),
child: CustomPaint(
size: Size(boardWidth, boardWidth),
willChange: false,
painter: GraphPainter(),
isComplex: true,
),
),
),
),
],
),
),
);
return SizedBox.expand( return SizedBox.expand(
child: Container( child: Container(
child: FittedBox( child: FittedBox(
...@@ -60,7 +16,33 @@ class ActivityGraphPage extends StatelessWidget { ...@@ -60,7 +16,33 @@ class ActivityGraphPage extends StatelessWidget {
child: SizedBox( child: SizedBox(
height: (MediaQuery.of(context).size.height), height: (MediaQuery.of(context).size.height),
width: (MediaQuery.of(context).size.width), width: (MediaQuery.of(context).size.width),
child: pageContent, child: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Center(
child: GestureDetector(
onTapUp: (details) {
double xTap = details.localPosition.dx;
double yTap = details.localPosition.dy;
print('[' + xTap.toString() + ',' + yTap.toString() + ']');
},
child: Container(
margin: EdgeInsets.all(4),
padding: EdgeInsets.all(4),
child: CustomPaint(
size: Size(boardWidth, boardWidth),
willChange: false,
painter: GraphPainter(),
isComplex: true,
),
),
),
),
],
),
),
), ),
), ),
), ),
......
import 'package:hydrated_bloc/hydrated_bloc.dart';
class BottomNavCubit extends HydratedCubit<int> {
BottomNavCubit() : super(0);
void updateIndex(int index) => emit(index);
void getFirstScreen() => emit(0);
void getSecondScreen() => emit(1);
@override
int? fromJson(Map<String, dynamic> json) {
return json['pageIndex'] as int?;
}
@override
Map<String, dynamic>? toJson(int state) {
return <String, int>{'pageIndex': state};
}
}
import 'dart:io';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:hydrated_bloc/hydrated_bloc.dart';
import 'package:path_provider/path_provider.dart';
import 'package:random/ui/screens/skeleton_screen.dart'; import 'package:random/ui/screens/skeleton_screen.dart';
import 'package:random/config/theme.dart'; import 'package:random/config/theme.dart';
import 'package:random/activities/ActivityDemoPage.dart';
import 'package:random/activities/ActivityGraphPage.dart';
void main() async { void main() async {
/// Initialize packages
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
await EasyLocalization.ensureInitialized(); await EasyLocalization.ensureInitialized();
final Directory tmpDir = await getTemporaryDirectory();
Hive.init(tmpDir.toString());
HydratedBloc.storage = await HydratedStorage.build(
storageDirectory: tmpDir,
);
runApp( runApp(
EasyLocalization( EasyLocalization(
...@@ -33,32 +42,6 @@ class MyApp extends StatelessWidget { ...@@ -33,32 +42,6 @@ class MyApp extends StatelessWidget {
title: 'Random application', title: 'Random application',
theme: appTheme, theme: appTheme,
home: SkeletonScreen(), home: SkeletonScreen(),
onGenerateRoute: (settings) {
switch (settings.name) {
case ActivityDemoPage.route:
{
return MaterialPageRoute(
builder: (context) => ActivityDemoPage(),
);
}
case ActivityGraphPage.route:
{
return MaterialPageRoute(
builder: (context) => ActivityGraphPage(),
);
}
default:
{
print("Unknown menu entry: " + settings.name.toString());
}
break;
}
return null;
},
// Localization stuff
localizationsDelegates: context.localizationDelegates, localizationsDelegates: context.localizationDelegates,
supportedLocales: context.supportedLocales, supportedLocales: context.supportedLocales,
locale: context.locale, locale: context.locale,
......
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:random/activities/ActivityDemoPage.dart'; import 'package:random/activities/ActivityDemoPage.dart';
import 'package:random/activities/ActivityGraphPage.dart'; import 'package:random/activities/ActivityGraphPage.dart';
import 'package:random/cubit/bottom_nav_cubit.dart';
import 'package:random/ui/widgets/custom_app_bar.dart';
import 'package:random/ui/widgets/bottom_nav_bar.dart';
class SkeletonScreen extends StatelessWidget { class SkeletonScreen extends StatelessWidget {
static const String id = 'home'; const SkeletonScreen({super.key});
@override
Widget build(BuildContext context) { Widget build(BuildContext context) {
double screenWidth = MediaQuery.of(context).size.width; const List<Widget> pageNavigation = <Widget>[
ActivityDemoPage(),
ActivityGraphPage(),
];
Container _menuItem(String activityCode) { return BlocProvider<BottomNavCubit>(
double imageSize = screenWidth / 4; create: (BuildContext context) => BottomNavCubit(),
child: Scaffold(
String imageAsset = 'assets/menu/' + activityCode + '.png'; extendBodyBehindAppBar: true,
appBar: const CustomAppBarGone(),
return Container( body: BlocBuilder<BottomNavCubit, int>(
margin: EdgeInsets.all(2), builder: (BuildContext context, int state) {
child: TextButton( return AnimatedSwitcher(
style: TextButton.styleFrom( duration: const Duration(milliseconds: 300),
padding: EdgeInsets.all(4), child: pageNavigation.elementAt(state));
backgroundColor: Theme.of(context).colorScheme.background,
),
child: Image(
image: AssetImage(imageAsset),
width: imageSize,
height: imageSize,
fit: BoxFit.fill,
),
onPressed: () {
Navigator.pushNamed(
context,
'/' + activityCode,
);
}, },
), ),
); bottomNavigationBar: const BottomNavBar(),
} backgroundColor: Theme.of(context).colorScheme.background,
return Scaffold(
extendBodyBehindAppBar: true,
backgroundColor: Theme.of(context).colorScheme.background,
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
_menuItem(ActivityDemoPage.code),
_menuItem(ActivityGraphPage.code),
],
),
), ),
); );
} }
......
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:ionicons/ionicons.dart';
import 'package:random/cubit/bottom_nav_cubit.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.surfaceVariant,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(16),
topRight: Radius.circular(16),
),
),
child: BlocBuilder<BottomNavCubit, int>(builder: (BuildContext context, int state) {
return BottomNavigationBar(
currentIndex: state,
onTap: (int index) => context.read<BottomNavCubit>().updateIndex(index),
type: BottomNavigationBarType.fixed,
elevation: 0,
backgroundColor: Colors.transparent,
selectedItemColor: Theme.of(context).colorScheme.primary,
unselectedItemColor: Theme.of(context).textTheme.bodySmall!.color,
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: const Icon(Ionicons.image_outline),
label: tr('bottom_nav_sample'),
),
BottomNavigationBarItem(
icon: const Icon(Ionicons.pencil_outline),
label: tr('bottom_nav_chart'),
),
],
);
}),
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class CustomAppBarGone extends StatelessWidget implements PreferredSizeWidget {
const CustomAppBarGone({super.key});
@override
Widget build(BuildContext context) {
final Brightness brightness = Theme.of(context).colorScheme.brightness;
return AppBar(
systemOverlayStyle: SystemUiOverlayStyle(
statusBarBrightness: brightness,
systemStatusBarContrastEnforced: false,
statusBarColor: Theme.of(context).colorScheme.background,
statusBarIconBrightness:
brightness == Brightness.dark ? Brightness.light : Brightness.dark,
),
backgroundColor: Colors.transparent,
excludeHeaderSemantics: true,
shadowColor: Colors.transparent,
scrolledUnderElevation: 0,
surfaceTintColor: Colors.transparent,
foregroundColor: Colors.transparent,
elevation: 0,
bottomOpacity: 0,
toolbarOpacity: 0,
);
}
@override
Size get preferredSize => const Size.fromHeight(0);
}
...@@ -9,6 +9,14 @@ packages: ...@@ -9,6 +9,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.2" version: "2.4.2"
bloc:
dependency: transitive
description:
name: bloc
sha256: "3820f15f502372d979121de1f6b97bfcf1630ebff8fe1d52fb2b0bfa49be5b49"
url: "https://pub.dev"
source: hosted
version: "8.1.2"
characters: characters:
dependency: transitive dependency: transitive
description: description:
...@@ -33,6 +41,14 @@ packages: ...@@ -33,6 +41,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.17.2" version: "1.17.2"
crypto:
dependency: transitive
description:
name: crypto
sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
url: "https://pub.dev"
source: hosted
version: "3.0.3"
easy_localization: easy_localization:
dependency: "direct main" dependency: "direct main"
description: description:
...@@ -70,6 +86,14 @@ packages: ...@@ -70,6 +86,14 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
flutter_bloc:
dependency: "direct main"
description:
name: flutter_bloc
sha256: e74efb89ee6945bcbce74a5b3a5a3376b088e5f21f55c263fc38cbdc6237faae
url: "https://pub.dev"
source: hosted
version: "8.1.3"
flutter_localizations: flutter_localizations:
dependency: transitive dependency: transitive
description: flutter description: flutter
...@@ -80,6 +104,22 @@ packages: ...@@ -80,6 +104,22 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
hive:
dependency: transitive
description:
name: hive
sha256: "8dcf6db979d7933da8217edcec84e9df1bdb4e4edc7fc77dbd5aa74356d6d941"
url: "https://pub.dev"
source: hosted
version: "2.2.3"
hydrated_bloc:
dependency: "direct main"
description:
name: hydrated_bloc
sha256: "24994e61f64904d911683cce1a31dc4ef611619da5253f1de2b7b8fc6f79a118"
url: "https://pub.dev"
source: hosted
version: "9.1.2"
intl: intl:
dependency: transitive dependency: transitive
description: description:
...@@ -88,6 +128,14 @@ packages: ...@@ -88,6 +128,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.18.1" version: "0.18.1"
ionicons:
dependency: "direct main"
description:
name: ionicons
sha256: "5496bc65a16115ecf05b15b78f494ee4a8869504357668f0a11d689e970523cf"
url: "https://pub.dev"
source: hosted
version: "0.2.2"
material_color_utilities: material_color_utilities:
dependency: transitive dependency: transitive
description: description:
...@@ -104,6 +152,14 @@ packages: ...@@ -104,6 +152,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.9.1" version: "1.9.1"
nested:
dependency: transitive
description:
name: nested
sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
path: path:
dependency: transitive dependency: transitive
description: description:
...@@ -112,6 +168,30 @@ packages: ...@@ -112,6 +168,30 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.8.3" version: "1.8.3"
path_provider:
dependency: "direct main"
description:
name: path_provider
sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa
url: "https://pub.dev"
source: hosted
version: "2.1.1"
path_provider_android:
dependency: transitive
description:
name: path_provider_android
sha256: e595b98692943b4881b219f0a9e3945118d3c16bd7e2813f98ec6e532d905f72
url: "https://pub.dev"
source: hosted
version: "2.2.1"
path_provider_foundation:
dependency: transitive
description:
name: path_provider_foundation
sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d"
url: "https://pub.dev"
source: hosted
version: "2.3.1"
path_provider_linux: path_provider_linux:
dependency: transitive dependency: transitive
description: description:
...@@ -152,6 +232,14 @@ packages: ...@@ -152,6 +232,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.6" version: "2.1.6"
provider:
dependency: transitive
description:
name: provider
sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f
url: "https://pub.dev"
source: hosted
version: "6.0.5"
shared_preferences: shared_preferences:
dependency: transitive dependency: transitive
description: description:
...@@ -213,6 +301,22 @@ packages: ...@@ -213,6 +301,22 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.99" version: "0.0.99"
synchronized:
dependency: transitive
description:
name: synchronized
sha256: "5fcbd27688af6082f5abd611af56ee575342c30e87541d0245f7ff99faa02c60"
url: "https://pub.dev"
source: hosted
version: "3.1.0"
typed_data:
dependency: transitive
description:
name: typed_data
sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
url: "https://pub.dev"
source: hosted
version: "1.3.2"
vector_math: vector_math:
dependency: transitive dependency: transitive
description: description:
......
...@@ -3,7 +3,7 @@ description: A random application, for testing purpose only. ...@@ -3,7 +3,7 @@ description: A random application, for testing purpose only.
publish_to: 'none' publish_to: 'none'
version: 1.0.22+23 version: 1.0.23+24
environment: environment:
sdk: '^3.0.0' sdk: '^3.0.0'
...@@ -13,9 +13,13 @@ dependencies: ...@@ -13,9 +13,13 @@ dependencies:
sdk: flutter sdk: flutter
easy_localization: ^3.0.1 easy_localization: ^3.0.1
flutter_bloc: ^8.1.1
path_provider: ^2.0.11
hydrated_bloc: ^9.0.0
ionicons: ^0.2.2
flutter: flutter:
uses-material-design: true uses-material-design: false
assets: assets:
- assets/menu/ - assets/menu/
- assets/translations/ - assets/translations/
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment