From d524d452bddebd05a21a9e103d674505310f28ac Mon Sep 17 00:00:00 2001 From: Kima Date: Mon, 28 Aug 2023 18:25:20 +0200 Subject: [PATCH] some progress in goal planner (started goal state) --- .../images/subject_covers/math_light.png | Bin 0 -> 19672 bytes filcnaplo/lib/database/init.dart | 8 +- filcnaplo/lib/database/query.dart | 27 ++- filcnaplo/lib/database/store.dart | 16 ++ filcnaplo/pubspec.yaml | 1 + .../lib/common/round_border_icon.dart | 4 +- .../lib/pages/grades/grade_subject_view.dart | 6 +- .../goal_planner/goal_planner_screen.dart | 202 ++++++++------- .../goal_planner/goal_state_screen.dart | 229 ++++++++++++++++++ .../goal_planner/goal_state_screen.i18n.dart | 39 +++ 10 files changed, 440 insertions(+), 92 deletions(-) create mode 100644 filcnaplo/assets/images/subject_covers/math_light.png create mode 100644 filcnaplo_premium/lib/ui/mobile/goal_planner/goal_state_screen.dart create mode 100644 filcnaplo_premium/lib/ui/mobile/goal_planner/goal_state_screen.i18n.dart diff --git a/filcnaplo/assets/images/subject_covers/math_light.png b/filcnaplo/assets/images/subject_covers/math_light.png new file mode 100644 index 0000000000000000000000000000000000000000..eb3e2f518951b484985709a3292f0c0d3fc50c07 GIT binary patch literal 19672 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 createTable(Database db, DatabaseStruct struct) => @@ -99,8 +101,10 @@ Future initDB(DatabaseProvider database) async { "renamed_teachers": "{}", // "subject_lesson_count": "{}", // non kreta data "last_seen_grade": 0, - // goal plans // non kreta data + // goal planning // non kreta data "goal_plans": "{}", + "goal_averages": "{}", + "goal_befores": "{}", }); } catch (error) { print("ERROR: migrateDB: $error"); diff --git a/filcnaplo/lib/database/query.dart b/filcnaplo/lib/database/query.dart index 4706615..b3a6de8 100644 --- a/filcnaplo/lib/database/query.dart +++ b/filcnaplo/lib/database/query.dart @@ -192,6 +192,7 @@ class UserDatabaseQuery { return lastSeen; } + // renamed things Future> renamedSubjects({required String userId}) async { List userData = await db.query("user_data", where: "id = ?", whereArgs: [userId]); @@ -214,14 +215,36 @@ class UserDatabaseQuery { .map((key, value) => MapEntry(key.toString(), value.toString())); } + // goal planner Future> subjectGoalPlans({required String userId}) async { List userData = await db.query("user_data", where: "id = ?", whereArgs: [userId]); if (userData.isEmpty) return {}; - String? goalPlansJson = - userData.elementAt(0)["goal_plans"] as String?; + String? goalPlansJson = userData.elementAt(0)["goal_plans"] as String?; if (goalPlansJson == null) return {}; return (jsonDecode(goalPlansJson) as Map) .map((key, value) => MapEntry(key.toString(), value.toString())); } + + Future> subjectGoalAverages( + {required String userId}) async { + List userData = + await db.query("user_data", where: "id = ?", whereArgs: [userId]); + if (userData.isEmpty) return {}; + String? goalAvgsJson = userData.elementAt(0)["goal_averages"] as String?; + if (goalAvgsJson == null) return {}; + return (jsonDecode(goalAvgsJson) as Map) + .map((key, value) => MapEntry(key.toString(), value.toString())); + } + + Future> subjectGoalBefores( + {required String userId}) async { + List userData = + await db.query("user_data", where: "id = ?", whereArgs: [userId]); + if (userData.isEmpty) return {}; + String? goalBeforesJson = userData.elementAt(0)["goal_befores"] as String?; + if (goalBeforesJson == null) return {}; + return (jsonDecode(goalBeforesJson) as Map) + .map((key, value) => MapEntry(key.toString(), value.toString())); + } } diff --git a/filcnaplo/lib/database/store.dart b/filcnaplo/lib/database/store.dart index 1319286..4083bec 100644 --- a/filcnaplo/lib/database/store.dart +++ b/filcnaplo/lib/database/store.dart @@ -127,6 +127,7 @@ class UserDatabaseStore { where: "id = ?", whereArgs: [userId]); } + // renamed things Future storeRenamedSubjects(Map subjects, {required String userId}) async { String renamedSubjectsJson = jsonEncode(subjects); @@ -141,10 +142,25 @@ class UserDatabaseStore { where: "id = ?", whereArgs: [userId]); } + // goal planner Future storeSubjectGoalPlans(Map plans, {required String userId}) async { String goalPlansJson = jsonEncode(plans); await db.update("user_data", {"goal_plans": goalPlansJson}, where: "id = ?", whereArgs: [userId]); } + + Future storeSubjectGoalAverages(Map avgs, + {required String userId}) async { + String goalAvgsJson = jsonEncode(avgs); + await db.update("user_data", {"goal_averages": goalAvgsJson}, + where: "id = ?", whereArgs: [userId]); + } + + Future storeSubjectGoalBefores(Map befores, + {required String userId}) async { + String goalBeforesJson = jsonEncode(befores); + await db.update("user_data", {"goal_befores": goalBeforesJson}, + where: "id = ?", whereArgs: [userId]); + } } diff --git a/filcnaplo/pubspec.yaml b/filcnaplo/pubspec.yaml index be6afaa..751aa3e 100644 --- a/filcnaplo/pubspec.yaml +++ b/filcnaplo/pubspec.yaml @@ -86,6 +86,7 @@ flutter: - assets/icons/ic_splash.png - assets/animations/ - assets/images/ + - assets/images/subject_covers/ fonts: - family: FilcIcons diff --git a/filcnaplo_mobile_ui/lib/common/round_border_icon.dart b/filcnaplo_mobile_ui/lib/common/round_border_icon.dart index f8c9220..ac1fdf4 100644 --- a/filcnaplo_mobile_ui/lib/common/round_border_icon.dart +++ b/filcnaplo_mobile_ui/lib/common/round_border_icon.dart @@ -3,12 +3,14 @@ import 'package:flutter/material.dart'; class RoundBorderIcon extends StatelessWidget { final Color color; final double width; + final double padding; final Widget icon; const RoundBorderIcon( {Key? key, this.color = Colors.black, this.width = 1.5, + this.padding = 5.0, required this.icon}) : super(key: key); @@ -20,7 +22,7 @@ class RoundBorderIcon extends StatelessWidget { borderRadius: BorderRadius.circular(50.0), ), child: Padding( - padding: const EdgeInsets.all(5.0), + padding: EdgeInsets.all(padding), child: icon, ), ); diff --git a/filcnaplo_mobile_ui/lib/pages/grades/grade_subject_view.dart b/filcnaplo_mobile_ui/lib/pages/grades/grade_subject_view.dart index 29217c8..0c0c152 100755 --- a/filcnaplo_mobile_ui/lib/pages/grades/grade_subject_view.dart +++ b/filcnaplo_mobile_ui/lib/pages/grades/grade_subject_view.dart @@ -26,6 +26,7 @@ import 'package:filcnaplo_mobile_ui/pages/grades/subject_grades_container.dart'; import 'package:filcnaplo_premium/ui/mobile/goal_planner/goal_planner_screen.dart'; import 'package:filcnaplo_premium/models/premium_scopes.dart'; import 'package:filcnaplo_premium/providers/premium_provider.dart'; +import 'package:filcnaplo_premium/ui/mobile/goal_planner/goal_state_screen.dart'; import 'package:filcnaplo_premium/ui/mobile/premium/upsell.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -292,12 +293,11 @@ class _GradeSubjectViewState extends State { onTap: () { Navigator.of(context).push(CupertinoPageRoute( builder: (context) => - GoalPlannerScreen(subject: widget.subject))); + GoalStateScreen(subject: widget.subject))); }, child: Container( width: 54.0, - padding: const EdgeInsets.symmetric( - horizontal: 5.0, vertical: 8.0), + padding: const EdgeInsets.symmetric(vertical: 8.0), decoration: BoxDecoration( borderRadius: BorderRadius.circular(45.0), color: Theme.of(context) diff --git a/filcnaplo_premium/lib/ui/mobile/goal_planner/goal_planner_screen.dart b/filcnaplo_premium/lib/ui/mobile/goal_planner/goal_planner_screen.dart index 3db2e2d..4cf8acf 100644 --- a/filcnaplo_premium/lib/ui/mobile/goal_planner/goal_planner_screen.dart +++ b/filcnaplo_premium/lib/ui/mobile/goal_planner/goal_planner_screen.dart @@ -65,6 +65,15 @@ class _GoalPlannerScreenState extends State { return await dbProvider.userQuery.subjectGoalPlans(userId: user.id!); } + Future> fetchGoalAverages() async { + return await dbProvider.userQuery.subjectGoalAverages(userId: user.id!); + } + + // haha bees lol + Future> fetchGoalBees() async { + return await dbProvider.userQuery.subjectGoalBefores(userId: user.id!); + } + PlanResult getResult() { final currentAvg = GoalPlannerHelper.averageEvals(grades); @@ -148,7 +157,11 @@ class _GoalPlannerScreenState extends State { body: SafeArea( child: ListView( padding: const EdgeInsets.only( - left: 22.0, right: 22.0, top: 5.0, bottom: 220.0), + top: 5.0, + bottom: 220.0, + right: 15.0, + left: 2.0, + ), children: [ // Row( // mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -215,91 +228,99 @@ class _GoalPlannerScreenState extends State { ], ), const SizedBox(height: 12.0), - Text( - "set_a_goal".i18n, - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 20.0, + Padding( + padding: const EdgeInsets.only(left: 22.0, right: 22.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "set_a_goal".i18n, + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 20.0, + ), + ), + const SizedBox(height: 4.0), + Text( + goalValue.toString(), + style: TextStyle( + fontWeight: FontWeight.w900, + fontSize: 48.0, + color: gradeColor(goalValue.round(), settingsProvider), + ), + ), + // Column( + // mainAxisAlignment: MainAxisAlignment.center, + // children: [ + // Text( + // "select_subject".i18n, + // style: const TextStyle( + // fontWeight: FontWeight.bold, + // fontSize: 20.0, + // ), + // ), + // const SizedBox(height: 4.0), + // Column( + // children: [ + // Icon( + // SubjectIcon.resolveVariant( + // context: context, + // subject: widget.subject, + // ), + // size: 48.0, + // ), + // Text( + // (widget.subject.isRenamed + // ? widget.subject.renamedTo + // : widget.subject.name) ?? + // '', + // style: const TextStyle( + // fontSize: 17.0, + // fontWeight: FontWeight.w500, + // ), + // ) + // ], + // ) + // ], + // ) + const SizedBox(height: 24.0), + Text( + "pick_route".i18n, + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 20.0, + ), + ), + const SizedBox(height: 12.0), + if (recommended != null) + RouteOption( + plan: recommended!, + mark: RouteMark.recommended, + selected: selectedRoute == recommended!, + onSelected: () => setState(() { + selectedRoute = recommended; + }), + ), + if (fastest != null && fastest != recommended) + RouteOption( + plan: fastest!, + mark: RouteMark.fastest, + selected: selectedRoute == fastest!, + onSelected: () => setState(() { + selectedRoute = fastest; + }), + ), + ...otherPlans.map((e) => RouteOption( + plan: e, + selected: selectedRoute == e, + onSelected: () => setState(() { + selectedRoute = e; + }), + )), + if (result != PlanResult.available) Text(result.name), + ], ), ), - const SizedBox(height: 4.0), - Text( - goalValue.toString(), - style: TextStyle( - fontWeight: FontWeight.w900, - fontSize: 48.0, - color: gradeColor(goalValue.round(), settingsProvider), - ), - ), - // Column( - // mainAxisAlignment: MainAxisAlignment.center, - // children: [ - // Text( - // "select_subject".i18n, - // style: const TextStyle( - // fontWeight: FontWeight.bold, - // fontSize: 20.0, - // ), - // ), - // const SizedBox(height: 4.0), - // Column( - // children: [ - // Icon( - // SubjectIcon.resolveVariant( - // context: context, - // subject: widget.subject, - // ), - // size: 48.0, - // ), - // Text( - // (widget.subject.isRenamed - // ? widget.subject.renamedTo - // : widget.subject.name) ?? - // '', - // style: const TextStyle( - // fontSize: 17.0, - // fontWeight: FontWeight.w500, - // ), - // ) - // ], - // ) - // ], - // ) - const SizedBox(height: 24.0), - Text( - "pick_route".i18n, - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 20.0, - ), - ), - const SizedBox(height: 12.0), - if (recommended != null) - RouteOption( - plan: recommended!, - mark: RouteMark.recommended, - selected: selectedRoute == recommended!, - onSelected: () => setState(() { - selectedRoute = recommended; - }), - ), - if (fastest != null && fastest != recommended) - RouteOption( - plan: fastest!, - mark: RouteMark.fastest, - selected: selectedRoute == fastest!, - onSelected: () => setState(() { - selectedRoute = fastest; - }), - ), - ...otherPlans.map((e) => RouteOption( - plan: e, - selected: selectedRoute == e, - onSelected: () => setState(() { - selectedRoute = e; - }), - )), - if (result != PlanResult.available) Text(result.name), ], ), ), @@ -346,12 +367,25 @@ class _GoalPlannerScreenState extends State { } final goalPlans = await fetchGoalPlans(); + final goalAvgs = await fetchGoalAverages(); + final goalBeforeGrades = await fetchGoalBees(); + goalPlans[widget.subject.id] = selectedRoute!.dbString; + goalAvgs[widget.subject.id] = + goalValue.toStringAsFixed(1); + goalBeforeGrades[widget.subject.id] = + avg.toStringAsFixed(1); await dbProvider.userStore.storeSubjectGoalPlans( goalPlans, userId: user.id!); + await dbProvider.userStore.storeSubjectGoalAverages( + goalAvgs, + userId: user.id!); + await dbProvider.userStore.storeSubjectGoalBefores( + goalBeforeGrades, + userId: user.id!); Navigator.of(context).pop(); }, diff --git a/filcnaplo_premium/lib/ui/mobile/goal_planner/goal_state_screen.dart b/filcnaplo_premium/lib/ui/mobile/goal_planner/goal_state_screen.dart new file mode 100644 index 0000000..0397160 --- /dev/null +++ b/filcnaplo_premium/lib/ui/mobile/goal_planner/goal_state_screen.dart @@ -0,0 +1,229 @@ +import 'package:filcnaplo/api/providers/database_provider.dart'; +import 'package:filcnaplo/api/providers/user_provider.dart'; +import 'package:filcnaplo/helpers/subject.dart'; +import 'package:filcnaplo_kreta_api/models/subject.dart'; +import 'package:filcnaplo_mobile_ui/common/average_display.dart'; +import 'package:filcnaplo_mobile_ui/common/panel/panel.dart'; +import 'package:filcnaplo_mobile_ui/common/round_border_icon.dart'; +import 'package:filcnaplo_premium/ui/mobile/goal_planner/goal_state_screen.i18n.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class GoalStateScreen extends StatefulWidget { + final Subject subject; + + const GoalStateScreen({Key? key, required this.subject}) : super(key: key); + + @override + State createState() => _GoalStateScreenState(); +} + +class _GoalStateScreenState extends State { + late UserProvider user; + late DatabaseProvider db; + + double goalAvg = 0.0; + double beforeAvg = 0.0; + double avgDifference = 0; + + @override + void initState() { + super.initState(); + user = Provider.of(context, listen: false); + db = Provider.of(context, listen: false); + + WidgetsBinding.instance.addPostFrameCallback((_) { + fetchGoalAverages(); + }); + } + + void fetchGoalAverages() async { + var goalAvgRes = await db.userQuery.subjectGoalAverages(userId: user.id!); + var beforeAvgRes = await db.userQuery.subjectGoalBefores(userId: user.id!); + + String? goalAvgStr = goalAvgRes[widget.subject.id]; + String? beforeAvgStr = beforeAvgRes[widget.subject.id]; + goalAvg = double.parse(goalAvgStr ?? '0.0'); + beforeAvg = double.parse(beforeAvgStr ?? '0.0'); + + avgDifference = ((goalAvg - beforeAvg) / beforeAvg.abs()) * 100; + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Container( + decoration: const BoxDecoration( + image: DecorationImage( + image: AssetImage('assets/images/subject_covers/math_light.png'), + fit: BoxFit.fitWidth, + alignment: Alignment.topCenter, + ), + ), + child: Container( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + Theme.of(context).scaffoldBackgroundColor.withOpacity(0.2), + Theme.of(context).scaffoldBackgroundColor, + ], + stops: const [ + 0.1, + 0.22, + ], + ), + ), + child: Padding( + padding: const EdgeInsets.only(top: 10.0, left: 2.0, right: 2.0), + child: ListView( + children: [ + const Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + BackButton(), + ], + ), + const SizedBox(height: 22.0), + Column( + children: [ + RoundBorderIcon( + icon: Icon( + SubjectIcon.resolveVariant( + context: context, + subject: widget.subject, + ), + size: 26.0, + weight: 2.5, + ), + padding: 8.0, + width: 2.5, + ), + const SizedBox( + height: 10.0, + ), + Text( + (widget.subject.isRenamed + ? widget.subject.renamedTo + : widget.subject.name) ?? + 'goal_planner_title'.i18n, + style: const TextStyle( + fontSize: 30.0, + fontWeight: FontWeight.w700, + ), + ), + Text( + 'almost_there'.i18n, + style: const TextStyle( + fontSize: 22.0, + fontWeight: FontWeight.w400, + height: 1.0, + ), + ), + ], + ), + const SizedBox(height: 28.0), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 24.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Text( + 'started_with'.i18n, + style: const TextStyle( + fontWeight: FontWeight.w700, + fontSize: 20.0, + ), + ), + ], + ), + Row( + children: [ + Text( + 'current'.i18n, + style: const TextStyle( + fontWeight: FontWeight.w700, + fontSize: 20.0, + ), + ), + ], + ), + ], + ), + ), + const SizedBox(height: 10.0), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12.0), + child: Panel( + padding: const EdgeInsets.all(18.0), + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'your_goal'.i18n, + style: const TextStyle( + fontSize: 23.0, + fontWeight: FontWeight.w700, + ), + ), + RawMaterialButton( + onPressed: () async {}, + fillColor: Colors.black, + shape: const StadiumBorder(), + padding: + const EdgeInsets.symmetric(horizontal: 18.0), + child: Text( + "change_it".i18n, + style: const TextStyle( + height: 1.0, + color: Colors.white, + fontSize: 14.0, + fontWeight: FontWeight.w600, + ), + ), + ), + ], + ), + Row( + children: [ + Text( + goalAvg.toString(), + style: const TextStyle( + height: 1.1, + fontSize: 42.0, + fontWeight: FontWeight.w800, + ), + ), + Center( + child: Container( + width: 54.0, + padding: + const EdgeInsets.symmetric(vertical: 8.0), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(45.0), + color: Colors.limeAccent.shade700 + .withOpacity(.15), + ), + child: Text(avgDifference.toString()), + ), + ), + ], + ), + ], + ), + ), + ), + ], + ), + ), + ), + ), + ); + } +} diff --git a/filcnaplo_premium/lib/ui/mobile/goal_planner/goal_state_screen.i18n.dart b/filcnaplo_premium/lib/ui/mobile/goal_planner/goal_state_screen.i18n.dart new file mode 100644 index 0000000..90fabd5 --- /dev/null +++ b/filcnaplo_premium/lib/ui/mobile/goal_planner/goal_state_screen.i18n.dart @@ -0,0 +1,39 @@ +import 'package:i18n_extension/i18n_extension.dart'; + +extension Localization on String { + static final _t = Translations.byLocale("hu_hu") + + { + "en_en": { + "goal_planner_title": "Goal Planning", + "almost_there": "Almost there! Keep going!", + "select_subject": "Subject", + "pick_route": "Pick a Route", + "track_it": "Track it!", + "recommended": "Recommended", + "fastest": "Fastest", + }, + "hu_hu": { + "goal_planner_title": "Cél követés", + "set_a_goal": "Kitűzött cél", + "select_subject": "Tantárgy", + "pick_route": "Válassz egy utat", + "track_it": "Követés!", + "recommended": "Ajánlott", + "fastest": "Leggyorsabb", + }, + "de_de": { + "goal_planner_title": "Zielplanung", + "set_a_goal": "Dein Ziel", + "select_subject": "Thema", + "pick_route": "Wähle einen Weg", + "track_it": "Verfolge es!", + "recommended": "Empfohlen", + "fastest": "Am schnellsten", + }, + }; + + String get i18n => localize(this, _t); + String fill(List params) => localizeFill(this, params); + String plural(int value) => localizePlural(value, this, _t); + String version(Object modifier) => localizeVersion(modifier, this, _t); +}