diff --git a/frontend/android/app/build.gradle.kts b/frontend/android/app/build.gradle.kts index b0933e4..909eb6a 100644 --- a/frontend/android/app/build.gradle.kts +++ b/frontend/android/app/build.gradle.kts @@ -6,7 +6,7 @@ plugins { } android { - namespace = "com.example.frontend" + namespace = "app.odweta.novehlasky" compileSdk = flutter.compileSdkVersion ndkVersion = flutter.ndkVersion @@ -21,7 +21,7 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId = "com.example.frontend" + applicationId = "app.odweta.novehlasky" // You can update the following values to match your application needs. // For more information, see: https://flutter.dev/to/review-gradle-config. minSdk = flutter.minSdkVersion diff --git a/frontend/devtools_options.yaml b/frontend/devtools_options.yaml new file mode 100644 index 0000000..fa0b357 --- /dev/null +++ b/frontend/devtools_options.yaml @@ -0,0 +1,3 @@ +description: This file stores settings for Dart & Flutter DevTools. +documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states +extensions: diff --git a/frontend/lib/main.dart b/frontend/lib/main.dart index 244a702..bb57294 100644 --- a/frontend/lib/main.dart +++ b/frontend/lib/main.dart @@ -1,122 +1,45 @@ import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; + +import 'strings.dart'; +import 'main_scaffold.dart'; + +// pages +import 'pages/list.dart'; +import 'pages/add.dart'; +import 'pages/flashcards.dart'; +import 'pages/leaderboard.dart'; +import 'pages/settings.dart'; void main() { - runApp(const MyApp()); + runApp(HlaskovnikFrontendApp()); } -class MyApp extends StatelessWidget { - const MyApp({super.key}); +class HlaskovnikFrontendApp extends StatelessWidget { + HlaskovnikFrontendApp({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 THIS: Try running your application with "flutter run". You'll see - // the application has a purple toolbar. Then, without quitting the app, - // try changing the seedColor in the colorScheme below to Colors.green - // and then invoke "hot reload" (save your changes or press the "hot - // reload" button in a Flutter-supported IDE, or press "r" if you used - // the command line to start the app). - // - // Notice that the counter didn't reset back to zero; the application - // state is not lost during the reload. To reset the state, use hot - // restart instead. - // - // This works for code too, not just values: Most code changes can be - // tested with just a hot reload. - colorScheme: .fromSeed(seedColor: Colors.deepPurple), + final _router = GoRouter( + routes: [ + ShellRoute( + builder: (context, state, child) { + return MainScaffold(child: child); + }, + routes: [ + GoRoute(path: '/', builder: (context, state) => ListPage()), + GoRoute(path: '/add', builder: (context, state) => AddPage()), + GoRoute(path: '/flashcards', builder: (context, state) => FlashcardsPage()), + GoRoute(path: '/leaderboard', builder: (context, state) => LeaderboardPage()), + GoRoute(path: '/settings', builder: (context, state) => SettingsPage()), + ], ), - 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 createState() => _MyHomePageState(); -} - -class _MyHomePageState extends State { - 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( - // TRY THIS: Try changing the color here to a specific color (to - // Colors.amber, perhaps?) and trigger a hot reload to see the AppBar - // change color while the other colors stay the same. - backgroundColor: Theme.of(context).colorScheme.inversePrimary, - // 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. - // - // 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). - // - // TRY THIS: Invoke "debug painting" (choose the "Toggle Debug Paint" - // action in the IDE, or press "p" in the console), to see the - // wireframe for each widget. - mainAxisAlignment: .center, - children: [ - 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), - ), + return MaterialApp.router( + title: Strings.appName, + routerConfig: _router, ); } -} +} \ No newline at end of file diff --git a/frontend/lib/main_scaffold.dart b/frontend/lib/main_scaffold.dart new file mode 100644 index 0000000..2bfa2da --- /dev/null +++ b/frontend/lib/main_scaffold.dart @@ -0,0 +1,53 @@ +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'strings.dart'; + +class MainScaffold extends StatelessWidget { + final Widget child; + + const MainScaffold({super.key, required this.child}); + + int _locationToIndex(String location) { + switch (location) { + case '/': return 0; + case '/add': return 1; + case '/flashcards': return 2; + case '/leaderboard': return 3; + case '/settings': return 4; + default: return 0; + } + } + + @override + Widget build(BuildContext context) { + final location = GoRouterState.of(context).uri.toString(); + final currentIndex = _locationToIndex(location); + + return Scaffold( + body: child, + + bottomNavigationBar: BottomNavigationBar( + type: BottomNavigationBarType.fixed, + currentIndex: currentIndex, + + onTap: (index) { + switch (index) { + case 0: context.go('/'); break; + case 1: context.go('/add'); break; + case 2: context.go('/flashcards'); break; + case 3: context.go('/leaderboard'); break; + case 4: context.go('/settings'); break; + } + }, + + items: [ + BottomNavigationBarItem(icon: Icon(Icons.list), label: Strings.list), + BottomNavigationBarItem(icon: Icon(Icons.add), label: Strings.add), + BottomNavigationBarItem(icon: Icon(Icons.repeat), label: Strings.flashcards), + BottomNavigationBarItem(icon: Icon(Icons.leaderboard), label: Strings.leaderboard), + BottomNavigationBarItem(icon: Icon(Icons.settings), label: Strings.settings), + ], + ), + ); + } +} \ No newline at end of file diff --git a/frontend/lib/model/quote.dart b/frontend/lib/model/quote.dart new file mode 100644 index 0000000..b5aadf7 --- /dev/null +++ b/frontend/lib/model/quote.dart @@ -0,0 +1,13 @@ +// quote model class + +class Quote{ + final int index; + final String author; + final String body; + + const Quote({ + required this.index, + required this.author, + required this.body, + }); +} \ No newline at end of file diff --git a/frontend/lib/pages/add.dart b/frontend/lib/pages/add.dart new file mode 100644 index 0000000..84e3853 --- /dev/null +++ b/frontend/lib/pages/add.dart @@ -0,0 +1,10 @@ +import 'package:flutter/material.dart'; + +class AddPage extends StatelessWidget { + const AddPage({super.key}); + + @override + Widget build(BuildContext context) { + return const Center(child: Text('add page!')); + } +} \ No newline at end of file diff --git a/frontend/lib/pages/flashcards.dart b/frontend/lib/pages/flashcards.dart new file mode 100644 index 0000000..c1df1f8 --- /dev/null +++ b/frontend/lib/pages/flashcards.dart @@ -0,0 +1,10 @@ +import 'package:flutter/material.dart'; + +class FlashcardsPage extends StatelessWidget { + const FlashcardsPage({super.key}); + + @override + Widget build(BuildContext context) { + return const Center(child: Text('flashcards! flip flip')); + } +} \ No newline at end of file diff --git a/frontend/lib/pages/leaderboard.dart b/frontend/lib/pages/leaderboard.dart new file mode 100644 index 0000000..5b99915 --- /dev/null +++ b/frontend/lib/pages/leaderboard.dart @@ -0,0 +1,10 @@ +import 'package:flutter/material.dart'; + +class LeaderboardPage extends StatelessWidget { + const LeaderboardPage({super.key}); + + @override + Widget build(BuildContext context) { + return const Center(child: Text('top 3!')); + } +} \ No newline at end of file diff --git a/frontend/lib/pages/list.dart b/frontend/lib/pages/list.dart new file mode 100644 index 0000000..3c7c344 --- /dev/null +++ b/frontend/lib/pages/list.dart @@ -0,0 +1,10 @@ +import 'package:flutter/material.dart'; + +class ListPage extends StatelessWidget { + const ListPage({super.key}); + + @override + Widget build(BuildContext context) { + return Center(child: const Text('list page!')); + } +} \ No newline at end of file diff --git a/frontend/lib/pages/settings.dart b/frontend/lib/pages/settings.dart new file mode 100644 index 0000000..74b01b2 --- /dev/null +++ b/frontend/lib/pages/settings.dart @@ -0,0 +1,10 @@ +import 'package:flutter/material.dart'; + +class SettingsPage extends StatelessWidget { + const SettingsPage({super.key}); + + @override + Widget build(BuildContext context) { + return const Center(child: Text('let\'s set something up!')); + } +} \ No newline at end of file diff --git a/frontend/lib/repository/quote_repository.dart b/frontend/lib/repository/quote_repository.dart new file mode 100644 index 0000000..e062da7 --- /dev/null +++ b/frontend/lib/repository/quote_repository.dart @@ -0,0 +1,7 @@ +// talks to the DB itself +// TODO: mock for now! + +class QuoteRepository { + final String _dbBaseUrl = 'https://hlaskovnik-reimagined-latest.onrender.com'; + +} \ No newline at end of file diff --git a/frontend/lib/service/get_quotes.dart b/frontend/lib/service/get_quotes.dart new file mode 100644 index 0000000..c2c5f61 --- /dev/null +++ b/frontend/lib/service/get_quotes.dart @@ -0,0 +1 @@ +// gets all quotes from the database and returns them in a list \ No newline at end of file diff --git a/frontend/lib/strings.dart b/frontend/lib/strings.dart new file mode 100644 index 0000000..ed63582 --- /dev/null +++ b/frontend/lib/strings.dart @@ -0,0 +1,10 @@ +class Strings { + static const String appName = "Nový Hláškovník"; + static const String apiKey = "2ogD5kc4sw3JVZoouQSV0w3LGRjSj5IjVFnAnk7IRCIK0ktONCeoOYinbNLSIHuU"; + + static const String list = "Seznam"; + static const String add = "Přidat"; + static const String flashcards = "Flashkarty"; + static const String leaderboard = "Žebříčky"; + static const String settings = "Nastavení"; +} \ No newline at end of file diff --git a/frontend/pubspec.lock b/frontend/pubspec.lock index e279f98..d11c78d 100644 --- a/frontend/pubspec.lock +++ b/frontend/pubspec.lock @@ -75,6 +75,19 @@ packages: 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: "7974313e217a7771557add6ff2238acb63f635317c35fa590d348fb238f00896" + url: "https://pub.dev" + source: hosted + version: "17.1.0" leak_tracker: dependency: transitive description: @@ -107,6 +120,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.1.0" + logging: + dependency: transitive + description: + name: logging + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 + url: "https://pub.dev" + source: hosted + version: "1.3.0" matcher: dependency: transitive description: @@ -131,6 +152,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.17.0" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" path: dependency: transitive description: @@ -139,6 +168,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.9.1" + provider: + dependency: "direct main" + description: + name: provider + sha256: "4e82183fa20e5ca25703ead7e05de9e4cceed1fbd1eadc1ac3cb6f565a09f272" + url: "https://pub.dev" + source: hosted + version: "6.1.5+1" sky_engine: dependency: transitive description: flutter @@ -210,4 +247,4 @@ packages: version: "15.0.2" sdks: dart: ">=3.11.3 <4.0.0" - flutter: ">=3.18.0-18.0.pre.54" + flutter: ">=3.35.0" diff --git a/frontend/pubspec.yaml b/frontend/pubspec.yaml index 41c88e2..132d0c8 100644 --- a/frontend/pubspec.yaml +++ b/frontend/pubspec.yaml @@ -34,6 +34,8 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.8 + provider: + go_router: dev_dependencies: flutter_test: