add first screens

This commit is contained in:
kodjodevf 2023-04-03 12:52:30 +01:00
parent 9a3f9ab545
commit 07b2a656fc
21 changed files with 362 additions and 113 deletions

3
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,3 @@
{
"java.configuration.updateBuildConfiguration": "interactive"
}

View file

@ -44,7 +44,7 @@ android {
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.example.mangayomi"
applicationId "com.kodjodevf.mangayomi"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdkVersion flutter.minSdkVersion

View file

@ -1,5 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.mangayomi">
package="com.kodjodevf.mangayomi">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.

View file

@ -1,5 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.mangayomi">
package="com.kodjodevf.mangayomi">
<application
android:label="mangayomi"
android:name="${applicationName}"

View file

@ -1,4 +1,4 @@
package com.example.mangayomi
package com.kodjodevf.mangayomi
import io.flutter.embedding.android.FlutterActivity

View file

@ -1,5 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.mangayomi">
package="com.kodjodevf.mangayomi">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.

View file

@ -296,7 +296,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.mangayomi;
PRODUCT_BUNDLE_IDENTIFIER = com.kodjodevf.mangayomi;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
@ -424,7 +424,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.mangayomi;
PRODUCT_BUNDLE_IDENTIFIER = com.kodjodevf.mangayomi;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@ -446,7 +446,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.mangayomi;
PRODUCT_BUNDLE_IDENTIFIER = com.kodjodevf.mangayomi;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;

View file

@ -1,115 +1,24 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mangayomi/router/router.dart';
void main() {
runApp(const MyApp());
runApp(const ProviderScope(child: MyApp()));
}
class MyApp extends StatelessWidget {
class MyApp extends ConsumerWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
// This call to setState tells the Flutter framework that something has
// changed in this State, which causes it to rerun the build method below
// so that the display can reflect the updated values. If we changed
// _counter without calling setState(), then the build method would not be
// called again, and so nothing would appear to happen.
_counter++;
});
}
@override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: Column(
// Column is also a layout widget. It takes a list of children and
// arranges them vertically. By default, it sizes itself to fit its
// children horizontally, and tries to be as tall as its parent.
//
// Invoke "debug painting" (press "p" in the console, choose the
// "Toggle Debug Paint" action from the Flutter Inspector in Android
// Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
// to see the wireframe for each widget.
//
// Column has various properties to control how it sizes itself and
// how it positions its children. Here we use mainAxisAlignment to
// center the children vertically; the main axis here is the vertical
// axis because Columns are vertical (the cross axis would be
// horizontal).
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
Widget build(BuildContext context, WidgetRef ref) {
final router = ref.watch(routerProvider);
return MaterialApp.router(
debugShowCheckedModeBanner: false,
routeInformationParser: router.routeInformationParser,
routerDelegate: router.routerDelegate,
routeInformationProvider: router.routeInformationProvider,
title: 'MangaYomi',
);
}
}

85
lib/router/router.dart Normal file
View file

@ -0,0 +1,85 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:mangayomi/views/browse/browse_screen.dart';
import 'package:mangayomi/views/general/general_screen.dart';
import 'package:mangayomi/views/history/history_screen.dart';
import 'package:mangayomi/views/library/library_screen.dart';
import 'package:mangayomi/views/more/more_screen.dart';
import 'package:mangayomi/views/updates/updates_screen.dart';
final routerProvider = Provider<GoRouter>((ref) {
final router = AsyncRouterNotifier();
return GoRouter(
initialLocation: '/library',
debugLogDiagnostics: false,
refreshListenable: router,
routes: router._routes,
);
});
class AsyncRouterNotifier extends ChangeNotifier {
List<RouteBase> get _routes => [
ShellRoute(
builder: (context, state, child) => GeneralScreen(child: child),
routes: [
GoRoute(
name: "library",
path: '/library',
builder: (context, state) => const LibraryScreen(),
pageBuilder: (context, state) => CustomTransition(
key: state.pageKey,
child: const LibraryScreen(),
),
),
GoRoute(
name: "updates",
path: '/updates',
builder: (context, state) => const UpdatesScreen(),
pageBuilder: (context, state) => CustomTransition(
key: state.pageKey,
child: const UpdatesScreen(),
),
),
GoRoute(
name: "history",
path: '/history',
builder: (context, state) => const HistoryScreen(),
pageBuilder: (context, state) => CustomTransition(
key: state.pageKey,
child: const HistoryScreen(),
),
),
GoRoute(
name: "browse",
path: '/browse',
builder: (context, state) => const BrowseScreen(),
pageBuilder: (context, state) => CustomTransition(
key: state.pageKey,
child: const BrowseScreen(),
),
),
GoRoute(
name: "more",
path: '/more',
builder: (context, state) => const MoreScreen(),
pageBuilder: (context, state) => CustomTransition(
key: state.pageKey,
child: const MoreScreen(),
),
),
]),
];
}
class CustomTransition extends CustomTransitionPage {
CustomTransition({required LocalKey key, required Widget child})
: super(
key: key,
transitionsBuilder: (context, animation, secondaryAnimation, child) {
return FadeTransition(opacity: animation, child: child);
},
child: child,
);
}

View file

@ -0,0 +1,9 @@
import 'package:flutter/material.dart';
mediaHeight(BuildContext context, double data) {
return MediaQuery.of(context).size.height * data;
}
mediaWidth(BuildContext context, double data) {
return MediaQuery.of(context).size.width * data;
}

View file

@ -0,0 +1,10 @@
import 'package:flutter/material.dart';
class BrowseScreen extends StatelessWidget {
const BrowseScreen({super.key});
@override
Widget build(BuildContext context) {
return const Placeholder();
}
}

View file

@ -0,0 +1,131 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:hidable/hidable.dart';
import 'package:mangayomi/views/general/scroll_controller_provider.dart';
import 'package:mangayomi/utils/media_query.dart';
class GeneralScreen extends ConsumerStatefulWidget {
const GeneralScreen({super.key, required this.child});
final Widget child;
@override
ConsumerState<GeneralScreen> createState() => _GeneralScreenState();
}
class _GeneralScreenState extends ConsumerState<GeneralScreen> {
@override
Widget build(BuildContext context) {
final scrollController = ref.watch(scrollControllerProvider);
final route = GoRouter.of(context);
int currentIndex = route.location == '/library'
? 0
: route.location == '/updates'
? 1
: route.location == '/history'
? 2
: route.location == '/browse'
? 3
: 4;
return Scaffold(
body: widget.child,
bottomNavigationBar: SizedBox(
width: mediaWidth(context, 1),
height: route.location != '/library' &&
route.location != '/updates' &&
route.location != '/history' &&
route.location != '/browse' &&
route.location != '/more'
? 0
: null,
child: Hidable(
controller: scrollController,
wOpacity: true,
child: NavigationBarTheme(
data: NavigationBarThemeData(
labelTextStyle: MaterialStateProperty.all(
const TextStyle(fontWeight: FontWeight.w500)),
indicatorShape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12)),
height: 20,
labelBehavior: NavigationDestinationLabelBehavior.alwaysShow,
),
child: ClipRRect(
child: NavigationBar(
animationDuration: const Duration(seconds: 1),
selectedIndex: currentIndex,
destinations: const [
NavigationDestination(
selectedIcon: Icon(
Icons.collections_bookmark,
color: Colors.white,
),
icon: Icon(
Icons.collections_bookmark_outlined,
),
label: 'Library'),
NavigationDestination(
selectedIcon: Icon(
Icons.new_releases,
color: Colors.white,
),
icon: Icon(
Icons.new_releases_outlined,
),
label: 'Updates'),
NavigationDestination(
selectedIcon: Icon(
Icons.history,
color: Colors.white,
),
icon: Icon(
Icons.history_outlined,
),
label: "History"),
NavigationDestination(
selectedIcon: Icon(
Icons.explore,
color: Colors.white,
),
icon: Icon(
Icons.explore_outlined,
),
label: "Browse"),
NavigationDestination(
selectedIcon: Icon(
Icons.more_horiz,
color: Colors.white,
),
icon: Icon(
Icons.more_horiz_outlined,
),
label: "More"),
],
onDestinationSelected: (int newIndex) {
if (mounted) {
setState(() {
currentIndex = newIndex;
});
}
if (newIndex == 0) {
route.go('/library');
} else if (newIndex == 1) {
route.go('/updates');
} else if (newIndex == 2) {
route.go('/history');
} else if (newIndex == 3) {
route.go('/browse');
} else if (newIndex == 4) {
route.go('/more');
}
},
),
),
),
),
),
);
}
}

View file

@ -0,0 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
final scrollControllerProvider =
Provider<ScrollController>((ref) => ScrollController());

View file

@ -0,0 +1,10 @@
import 'package:flutter/material.dart';
class HistoryScreen extends StatelessWidget {
const HistoryScreen({super.key});
@override
Widget build(BuildContext context) {
return const Placeholder();
}
}

View file

@ -0,0 +1,10 @@
import 'package:flutter/material.dart';
class LibraryScreen extends StatelessWidget {
const LibraryScreen({super.key});
@override
Widget build(BuildContext context) {
return const Placeholder();
}
}

View file

@ -0,0 +1,10 @@
import 'package:flutter/material.dart';
class MoreScreen extends StatelessWidget {
const MoreScreen({super.key});
@override
Widget build(BuildContext context) {
return const Placeholder();
}
}

View file

@ -0,0 +1,10 @@
import 'package:flutter/material.dart';
class UpdatesScreen extends StatelessWidget {
const UpdatesScreen({super.key});
@override
Widget build(BuildContext context) {
return const Placeholder();
}
}

View file

@ -7,7 +7,7 @@ project(runner LANGUAGES CXX)
set(BINARY_NAME "mangayomi")
# The unique GTK application identifier for this application. See:
# https://wiki.gnome.org/HowDoI/ChooseApplicationID
set(APPLICATION_ID "com.example.mangayomi")
set(APPLICATION_ID "com.kodjodevf.mangayomi")
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
# versions of CMake.

View file

@ -8,7 +8,7 @@
PRODUCT_NAME = mangayomi
// The application's bundle identifier
PRODUCT_BUNDLE_IDENTIFIER = com.example.mangayomi
PRODUCT_BUNDLE_IDENTIFIER = com.kodjodevf.mangayomi
// The copyright displayed in application information
PRODUCT_COPYRIGHT = Copyright © 2023 com.example. All rights reserved.

View file

@ -70,11 +70,40 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.1"
flutter_riverpod:
dependency: "direct main"
description:
name: flutter_riverpod
sha256: b3c3a8a9714b7f88dd2a41e1efbc47f76d620b06ab427c62ae7bc82298cd7dbb
url: "https://pub.dev"
source: hosted
version: "2.3.2"
flutter_test:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
flutter_web_plugins:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
go_router:
dependency: "direct main"
description:
name: go_router
sha256: "6af43e0948b9f64a812afbb9ac3f76e2c8f5abe4efaba4188702a56af46b98c2"
url: "https://pub.dev"
source: hosted
version: "6.5.2"
hidable:
dependency: "direct main"
description:
name: hidable
sha256: abe6f3ce1037a8de18e996d1e6417306949217010daea56799d6203a9d8f1c48
url: "https://pub.dev"
source: hosted
version: "1.0.3"
js:
dependency: transitive
description:
@ -91,6 +120,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.1"
logging:
dependency: transitive
description:
name: logging
sha256: "04094f2eb032cbb06c6f6e8d3607edcfcb0455e2bb6cbc010cb01171dcb64e6d"
url: "https://pub.dev"
source: hosted
version: "1.1.1"
matcher:
dependency: transitive
description:
@ -123,6 +160,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.8.2"
riverpod:
dependency: transitive
description:
name: riverpod
sha256: b0fbf7927333c5c318f7e2c22c8b4fd2542ba294de0373e80ecdb34e0dcd8dc4
url: "https://pub.dev"
source: hosted
version: "2.3.2"
sky_engine:
dependency: transitive
description: flutter
@ -144,6 +189,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.11.0"
state_notifier:
dependency: transitive
description:
name: state_notifier
sha256: "8fe42610f179b843b12371e40db58c9444f8757f8b69d181c97e50787caed289"
url: "https://pub.dev"
source: hosted
version: "0.7.2+1"
stream_channel:
dependency: transitive
description:
@ -186,3 +239,4 @@ packages:
version: "2.1.4"
sdks:
dart: ">=2.19.5 <3.0.0"
flutter: ">=3.3.0"

View file

@ -30,6 +30,9 @@ environment:
dependencies:
flutter:
sdk: flutter
go_router: ^6.5.2
flutter_riverpod: ^2.3.2
hidable: ^1.0.3
# The following adds the Cupertino Icons font to your application.