forked from firka/firka
firka: extract firka_common package with shared widgets (Isar kept separate)
- Create firka_common package with core helpers (debug, json, icon), theme, and shared widgets (FirkaCard, FirkaShadow, GradeWidget, GradeSmallCard, ClassIconWidget, FirkaIconWidget, DelayedSpinnerWidget, CounterDigitWidget) - Keep Isar models (GenericCacheModel, TimetableCacheModel, HomeworkCacheModel, DatedCacheEntry, util) in firka and firka_wear - not moved to firka_common - Update firka and firka_wear to depend on firka_common for shared UI only - Add configurable roundGrade thresholds for firka settings - Add package param to FirkaIconWidget for app asset paths
This commit is contained in:
@@ -12,8 +12,8 @@ import 'package:kreta_api/kreta_api.dart' hide KretaEndpoints;
|
|||||||
import 'package:firka/app/app_state.dart';
|
import 'package:firka/app/app_state.dart';
|
||||||
import 'package:firka/core/bloc/reauth_cubit.dart';
|
import 'package:firka/core/bloc/reauth_cubit.dart';
|
||||||
import 'package:firka/data/models/token_model.dart';
|
import 'package:firka/data/models/token_model.dart';
|
||||||
import 'package:firka/data/util.dart';
|
|
||||||
import 'package:firka/core/debug_helper.dart';
|
import 'package:firka/core/debug_helper.dart';
|
||||||
|
import 'package:firka/data/util.dart';
|
||||||
import 'package:firka/services/active_account_helper.dart';
|
import 'package:firka/services/active_account_helper.dart';
|
||||||
import 'package:firka/services/watch_sync_helper.dart';
|
import 'package:firka/services/watch_sync_helper.dart';
|
||||||
import '../consts.dart';
|
import '../consts.dart';
|
||||||
|
|||||||
@@ -1,17 +1 @@
|
|||||||
DateTime? debugFakeTime;
|
export 'package:firka_common/core/debug_helper.dart';
|
||||||
DateTime? debugSetAt;
|
|
||||||
var debugTimeAdvance = false;
|
|
||||||
|
|
||||||
DateTime timeNow() {
|
|
||||||
if (debugFakeTime != null) {
|
|
||||||
if (debugTimeAdvance && debugSetAt != null) {
|
|
||||||
var diff = DateTime.now().difference(debugSetAt!);
|
|
||||||
|
|
||||||
return debugFakeTime!.add(diff);
|
|
||||||
} else {
|
|
||||||
return debugFakeTime!;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return DateTime.now();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
import 'package:kreta_api/kreta_api.dart';
|
|
||||||
import 'package:firka/core/debug_helper.dart';
|
|
||||||
import 'package:firka/l10n/app_localizations.dart';
|
import 'package:firka/l10n/app_localizations.dart';
|
||||||
|
import 'package:firka_common/core/debug_helper.dart';
|
||||||
|
import 'package:firka_common/core/extensions.dart';
|
||||||
|
import 'package:kreta_api/kreta_api.dart';
|
||||||
|
|
||||||
|
export 'package:firka_common/core/extensions.dart';
|
||||||
|
|
||||||
extension TimetableExtension on Iterable<Lesson> {
|
extension TimetableExtension on Iterable<Lesson> {
|
||||||
List<Lesson> getAllSeqs(Lesson reference) {
|
List<Lesson> getAllSeqs(Lesson reference) {
|
||||||
@@ -59,26 +62,6 @@ extension TimetableExtension on Iterable<Lesson> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension IterableExtensionMap on Iterable<MapEntry<String, dynamic>> {
|
|
||||||
Map<String, dynamic> toMap() {
|
|
||||||
var map = <String, dynamic>{};
|
|
||||||
for (var item in this) {
|
|
||||||
map[item.key] = item.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension IterableExtension<T> on Iterable<T> {
|
|
||||||
T? firstWhereOrNull(bool Function(T element) test) {
|
|
||||||
for (var element in this) {
|
|
||||||
if (test(element)) return element;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension DurationExtension on Duration {
|
extension DurationExtension on Duration {
|
||||||
String formatDuration() {
|
String formatDuration() {
|
||||||
String hours = inHours.toString().padLeft(2, '0');
|
String hours = inHours.toString().padLeft(2, '0');
|
||||||
|
|||||||
@@ -1,152 +1 @@
|
|||||||
import 'dart:typed_data';
|
export 'package:firka_common/core/icon_helper.dart';
|
||||||
|
|
||||||
import 'package:majesticons_flutter/majesticons_flutter.dart';
|
|
||||||
|
|
||||||
enum ClassIcon {
|
|
||||||
mathematics,
|
|
||||||
grammar,
|
|
||||||
literature,
|
|
||||||
history,
|
|
||||||
geography,
|
|
||||||
art,
|
|
||||||
physics,
|
|
||||||
music,
|
|
||||||
pe,
|
|
||||||
chemistry,
|
|
||||||
biology,
|
|
||||||
env,
|
|
||||||
religion,
|
|
||||||
economics,
|
|
||||||
it,
|
|
||||||
code,
|
|
||||||
networking,
|
|
||||||
theatre,
|
|
||||||
film,
|
|
||||||
electricalEngineering,
|
|
||||||
mechanicalEngineering,
|
|
||||||
technika,
|
|
||||||
dance,
|
|
||||||
philosophy,
|
|
||||||
ofo,
|
|
||||||
diligence,
|
|
||||||
attitude,
|
|
||||||
language,
|
|
||||||
linux,
|
|
||||||
database,
|
|
||||||
applications,
|
|
||||||
project,
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<ClassIcon, RegExp> _descriptors = {
|
|
||||||
ClassIcon.mathematics: RegExp(r'mate(k|matika)'),
|
|
||||||
ClassIcon.grammar: RegExp(r'magyar nyelv|nyelvtan'),
|
|
||||||
ClassIcon.literature: RegExp(r'irodalom'),
|
|
||||||
ClassIcon.history: RegExp(r'tor(i|tenelem)'),
|
|
||||||
ClassIcon.geography: RegExp(r'foldrajz'),
|
|
||||||
ClassIcon.art: RegExp(r'rajz|muvtori|muveszet|vizualis'),
|
|
||||||
ClassIcon.physics: RegExp(r'fizika'),
|
|
||||||
ClassIcon.music: RegExp(r'^enek|zene|szolfezs|zongora|korus'),
|
|
||||||
ClassIcon.pe: RegExp(r'^tes(i|tneveles)|sport|edzeselmelet'),
|
|
||||||
ClassIcon.chemistry: RegExp(r'kemia'),
|
|
||||||
ClassIcon.biology: RegExp(r'biologia'),
|
|
||||||
ClassIcon.env: RegExp(
|
|
||||||
r'kornyezet|termeszet ?(tudomany|ismeret)|hon( es nep)?ismeret',
|
|
||||||
),
|
|
||||||
ClassIcon.religion: RegExp(r'(hit|erkolcs)tan|vallas|etika|bibliaismeret'),
|
|
||||||
ClassIcon.economics: RegExp(r'penzugy|gazdasag'),
|
|
||||||
ClassIcon.it: RegExp(r'informatika|szoftver|iroda|digitalis'),
|
|
||||||
ClassIcon.code: RegExp(r'prog|alkalmazas'),
|
|
||||||
ClassIcon.networking: RegExp(r'halozat'),
|
|
||||||
ClassIcon.theatre: RegExp(r'szinhaz'),
|
|
||||||
ClassIcon.film: RegExp(r'film|media'),
|
|
||||||
ClassIcon.electricalEngineering: RegExp(r'elektro(tech)?nika'),
|
|
||||||
ClassIcon.mechanicalEngineering: RegExp(r'gepesz|mernok|ipar'),
|
|
||||||
ClassIcon.technika: RegExp(r'technika'),
|
|
||||||
ClassIcon.dance: RegExp(r'tanc'),
|
|
||||||
ClassIcon.philosophy: RegExp(r'filozofia'),
|
|
||||||
ClassIcon.ofo: RegExp(r'osztaly(fonoki|kozosseg)|kozossegi|neveles'),
|
|
||||||
ClassIcon.diligence: RegExp(r'szorgalom'),
|
|
||||||
ClassIcon.attitude: RegExp(r'magatartas'),
|
|
||||||
ClassIcon.language: RegExp(
|
|
||||||
r'angol|nemet|francia|olasz|orosz|spanyol|latin|kinai|nyelv',
|
|
||||||
),
|
|
||||||
ClassIcon.linux: RegExp(r'linux'),
|
|
||||||
ClassIcon.database: RegExp(r'adatbazis.*'),
|
|
||||||
ClassIcon.applications: RegExp(r'asztali alkalmazasok'),
|
|
||||||
ClassIcon.project: RegExp(r'projekt'),
|
|
||||||
};
|
|
||||||
|
|
||||||
Map<ClassIcon, Uint8List> _iconMap = {
|
|
||||||
ClassIcon.mathematics: Majesticon.calculatorSolid,
|
|
||||||
ClassIcon.grammar: Majesticon.bookSolid,
|
|
||||||
ClassIcon.literature: Majesticon.bookOpenSolid,
|
|
||||||
ClassIcon.history: Majesticon.compass2Solid,
|
|
||||||
ClassIcon.geography: Majesticon.globeEarth2Solid,
|
|
||||||
ClassIcon.art: Majesticon.editPen2Solid,
|
|
||||||
// ClassIcon.physics: ,
|
|
||||||
ClassIcon.music: Majesticon.musicNoteSolid,
|
|
||||||
// ClassIcon.pe: ,
|
|
||||||
ClassIcon.chemistry: Majesticon.testTubeFilledSolid,
|
|
||||||
ClassIcon.biology: Majesticon.covidSolid,
|
|
||||||
// ClassIcon.env: ,
|
|
||||||
// ClassIcon.religion: ,
|
|
||||||
// ClassIcon.economics: ,
|
|
||||||
ClassIcon.it: Majesticon.laptopSolid,
|
|
||||||
ClassIcon.code: Majesticon.curlyBracesSolid,
|
|
||||||
ClassIcon.networking: Majesticon.cloudSolid,
|
|
||||||
// ClassIcon.theatre: ,
|
|
||||||
// ClassIcon.film: ,
|
|
||||||
// ClassIcon.electricalEngineering: ,
|
|
||||||
// ClassIcon.mechanicalEngineering: ,
|
|
||||||
ClassIcon.technika: Majesticon.ruler2Solid,
|
|
||||||
// ClassIcon.dance: ,
|
|
||||||
// ClassIcon.philosophy: ,
|
|
||||||
// ClassIcon.ofo: ,
|
|
||||||
// ClassIcon.diligence: ,
|
|
||||||
// ClassIcon.attitude: ,
|
|
||||||
ClassIcon.language: Majesticon.tooltipsSolid,
|
|
||||||
// ClassIcon.linux: ,
|
|
||||||
ClassIcon.database: Majesticon.dataSolid,
|
|
||||||
// ClassIcon.applications: ,
|
|
||||||
// ClassIcon.project: ,
|
|
||||||
};
|
|
||||||
|
|
||||||
ClassIcon? getIconType(String uid, String className, String category) {
|
|
||||||
ClassIcon? icon;
|
|
||||||
if (category.toLowerCase() == "matematika") {
|
|
||||||
icon = ClassIcon.mathematics;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (icon == null) {
|
|
||||||
for (var desc in _descriptors.entries) {
|
|
||||||
if (desc.value.hasMatch(
|
|
||||||
className
|
|
||||||
.replaceAll("ö", "o")
|
|
||||||
.replaceAll("ü", "u")
|
|
||||||
.replaceAll("ó", "o")
|
|
||||||
.replaceAll("ő", "o")
|
|
||||||
.replaceAll("ú", "u")
|
|
||||||
.replaceAll("é", "e")
|
|
||||||
.replaceAll("á", "a")
|
|
||||||
.replaceAll("ű", "u")
|
|
||||||
.replaceAll("í", "i")
|
|
||||||
.toLowerCase(),
|
|
||||||
)) {
|
|
||||||
icon = desc.key;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return icon;
|
|
||||||
}
|
|
||||||
|
|
||||||
Uint8List getIconData(ClassIcon? icon) {
|
|
||||||
if (icon == null) return Majesticon.alertCircleSolid;
|
|
||||||
|
|
||||||
var iconData = _iconMap[icon];
|
|
||||||
iconData ??= Majesticon.alertCircleSolid;
|
|
||||||
|
|
||||||
return iconData;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,9 +1 @@
|
|||||||
List<T> listToTyped<T>(List<dynamic> dynamicList) {
|
export 'package:firka_common/core/json_helper.dart';
|
||||||
var newList = List<T>.empty(growable: true);
|
|
||||||
|
|
||||||
for (var item in dynamicList) {
|
|
||||||
newList.add(item as T);
|
|
||||||
}
|
|
||||||
|
|
||||||
return newList;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import 'dart:convert';
|
|||||||
import 'package:crypto/crypto.dart';
|
import 'package:crypto/crypto.dart';
|
||||||
import 'package:dart_jsonwebtoken/dart_jsonwebtoken.dart';
|
import 'package:dart_jsonwebtoken/dart_jsonwebtoken.dart';
|
||||||
import 'package:kreta_api/kreta_api.dart';
|
import 'package:kreta_api/kreta_api.dart';
|
||||||
import 'package:firka/core/debug_helper.dart';
|
|
||||||
import 'package:firka/core/extensions.dart';
|
import 'package:firka/core/extensions.dart';
|
||||||
|
import 'package:firka_common/core/debug_helper.dart';
|
||||||
import 'package:isar_community/isar.dart';
|
import 'package:isar_community/isar.dart';
|
||||||
|
|
||||||
part 'token_model.g.dart';
|
part 'token_model.g.dart';
|
||||||
|
|||||||
@@ -1,134 +1 @@
|
|||||||
import 'package:flutter/material.dart';
|
export 'package:firka_common/ui/components/firka_card.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
|
|
||||||
import 'package:firka/core/bloc/theme_cubit.dart';
|
|
||||||
import 'package:firka/ui/components/firka_shadow.dart';
|
|
||||||
import 'package:firka/ui/theme/style.dart';
|
|
||||||
|
|
||||||
enum Attach { none, bottom, top }
|
|
||||||
|
|
||||||
class FirkaCard extends StatelessWidget {
|
|
||||||
final List<Widget> left;
|
|
||||||
final List<Widget>? center;
|
|
||||||
final double? height;
|
|
||||||
final List<Widget>? right;
|
|
||||||
final bool shadow;
|
|
||||||
final Widget? extra;
|
|
||||||
final Attach? attached;
|
|
||||||
final Color? color;
|
|
||||||
|
|
||||||
const FirkaCard({
|
|
||||||
required this.left,
|
|
||||||
this.shadow = true,
|
|
||||||
this.center,
|
|
||||||
this.right,
|
|
||||||
this.extra,
|
|
||||||
this.attached,
|
|
||||||
this.color,
|
|
||||||
this.height,
|
|
||||||
super.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
var right = this.right ?? [];
|
|
||||||
|
|
||||||
var attached = this.attached != null ? this.attached! : Attach.none;
|
|
||||||
final defaultRounding = 16.0;
|
|
||||||
final attachedRounding = 8.0;
|
|
||||||
final isLight = context.watch<ThemeCubit>().state.isLightMode;
|
|
||||||
|
|
||||||
if (extra != null) {
|
|
||||||
return SizedBox(
|
|
||||||
width: MediaQuery.of(context).size.width,
|
|
||||||
height: height,
|
|
||||||
child: FirkaShadow(
|
|
||||||
shadow: shadow,
|
|
||||||
child: Card(
|
|
||||||
color: color ?? appStyle.colors.card,
|
|
||||||
shadowColor: isLight && shadow ? null : Colors.transparent,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.only(
|
|
||||||
topLeft: Radius.circular(
|
|
||||||
attached == Attach.top ? attachedRounding : defaultRounding,
|
|
||||||
),
|
|
||||||
topRight: Radius.circular(
|
|
||||||
attached == Attach.top ? attachedRounding : defaultRounding,
|
|
||||||
),
|
|
||||||
bottomLeft: Radius.circular(
|
|
||||||
attached == Attach.bottom
|
|
||||||
? attachedRounding
|
|
||||||
: defaultRounding,
|
|
||||||
),
|
|
||||||
bottomRight: Radius.circular(
|
|
||||||
attached == Attach.bottom
|
|
||||||
? attachedRounding
|
|
||||||
: defaultRounding,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(12.0),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Row(children: left),
|
|
||||||
Row(children: center ?? []),
|
|
||||||
Row(children: right),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
extra ?? SizedBox(),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return SizedBox(
|
|
||||||
width: MediaQuery.of(context).size.width,
|
|
||||||
height: height,
|
|
||||||
child: FirkaShadow(
|
|
||||||
shadow: shadow,
|
|
||||||
child: Card(
|
|
||||||
color: color ?? appStyle.colors.card,
|
|
||||||
shadowColor: isLight && shadow ? null : Colors.transparent,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.only(
|
|
||||||
topLeft: Radius.circular(
|
|
||||||
attached == Attach.top ? attachedRounding : defaultRounding,
|
|
||||||
),
|
|
||||||
topRight: Radius.circular(
|
|
||||||
attached == Attach.top ? attachedRounding : defaultRounding,
|
|
||||||
),
|
|
||||||
bottomLeft: Radius.circular(
|
|
||||||
attached == Attach.bottom
|
|
||||||
? attachedRounding
|
|
||||||
: defaultRounding,
|
|
||||||
),
|
|
||||||
bottomRight: Radius.circular(
|
|
||||||
attached == Attach.bottom
|
|
||||||
? attachedRounding
|
|
||||||
: defaultRounding,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(12.0),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Row(children: left),
|
|
||||||
Row(children: center ?? []),
|
|
||||||
Row(children: right),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,45 +1 @@
|
|||||||
import 'package:flutter/material.dart';
|
export 'package:firka_common/ui/components/firka_shadow.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
|
|
||||||
import 'package:firka/core/bloc/theme_cubit.dart';
|
|
||||||
import 'package:firka/ui/theme/style.dart';
|
|
||||||
|
|
||||||
class FirkaShadow extends StatelessWidget {
|
|
||||||
final Widget child;
|
|
||||||
final bool shadow;
|
|
||||||
|
|
||||||
const FirkaShadow({required this.shadow, required this.child, super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final borderRadius = BorderRadius.circular(8.0);
|
|
||||||
|
|
||||||
final shadowBox = BoxDecoration(
|
|
||||||
color: Colors.transparent,
|
|
||||||
shape: BoxShape.rectangle,
|
|
||||||
boxShadow: [
|
|
||||||
BoxShadow(
|
|
||||||
color: appStyle.colors.shadowColor,
|
|
||||||
spreadRadius: -4,
|
|
||||||
blurRadius: 0,
|
|
||||||
offset: Offset(0, 2),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
borderRadius: BorderRadius.all(Radius.circular(16)),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!shadow) {
|
|
||||||
return ClipRRect(borderRadius: borderRadius, child: child);
|
|
||||||
}
|
|
||||||
|
|
||||||
final isLight = context.watch<ThemeCubit>().state.isLightMode;
|
|
||||||
if (isLight) {
|
|
||||||
return child;
|
|
||||||
} else {
|
|
||||||
return Container(
|
|
||||||
decoration: shadowBox,
|
|
||||||
child: ClipRRect(borderRadius: borderRadius, child: child),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,97 +1 @@
|
|||||||
import 'package:kreta_api/kreta_api.dart';
|
export 'package:firka_common/ui/components/grade.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
import 'package:firka/ui/theme/style.dart';
|
|
||||||
import 'package:firka/ui/components/grade_helpers.dart';
|
|
||||||
|
|
||||||
class GradeWidget extends StatelessWidget {
|
|
||||||
const GradeWidget(this.grade, {super.key})
|
|
||||||
: gradeValue = null,
|
|
||||||
_fromValue = false;
|
|
||||||
|
|
||||||
const GradeWidget.gradeValue(int value, {super.key})
|
|
||||||
: grade = null,
|
|
||||||
gradeValue = value,
|
|
||||||
_fromValue = true;
|
|
||||||
|
|
||||||
final Grade? grade;
|
|
||||||
final int? gradeValue;
|
|
||||||
final bool _fromValue;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
if (_fromValue && gradeValue != null) {
|
|
||||||
return _buildNumericCircle(
|
|
||||||
gradeValue!,
|
|
||||||
getGradeColor(gradeValue!.toDouble()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
final g = grade!;
|
|
||||||
Color gradeColor = appStyle.colors.grade1;
|
|
||||||
final gradeStr = g.numericValue?.toString() ?? '0';
|
|
||||||
|
|
||||||
if (g.valueType.name == 'Szazalekos') {
|
|
||||||
if (g.numericValue != null) {
|
|
||||||
gradeColor = getGradeColor(
|
|
||||||
percentageToGrade(g.numericValue!).toDouble(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
final str = g.strValue.replaceAll('%', '');
|
|
||||||
return Card(
|
|
||||||
shape: const CircleBorder(),
|
|
||||||
shadowColor: Colors.transparent,
|
|
||||||
color: gradeColor.withAlpha(38),
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(8),
|
|
||||||
child: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
Text(str, style: appStyle.fonts.P_14.copyWith(color: gradeColor)),
|
|
||||||
Text('%', style: appStyle.fonts.P_12.copyWith(color: gradeColor)),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (g.numericValue != null) {
|
|
||||||
gradeColor = getGradeColor(g.numericValue!.toDouble());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gradeStr == '0') {
|
|
||||||
return Card(
|
|
||||||
shadowColor: Colors.transparent,
|
|
||||||
color: gradeColor.withAlpha(38),
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.only(left: 8, right: 8, top: 2, bottom: 2),
|
|
||||||
child: Text(
|
|
||||||
g.strValue,
|
|
||||||
style: appStyle.fonts.H_H1.copyWith(
|
|
||||||
fontSize: 16,
|
|
||||||
color: gradeColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _buildNumericCircle(g.numericValue!, gradeColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildNumericCircle(int value, Color gradeColor) {
|
|
||||||
return Card(
|
|
||||||
shape: const CircleBorder(),
|
|
||||||
shadowColor: Colors.transparent,
|
|
||||||
color: gradeColor.withAlpha(38),
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.only(left: 8, right: 8),
|
|
||||||
child: Text(
|
|
||||||
value.toString(),
|
|
||||||
style: appStyle.fonts.H_H1.copyWith(fontSize: 24, color: gradeColor),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,95 +1 @@
|
|||||||
import 'dart:ui';
|
export 'package:firka_common/ui/components/grade_helpers.dart';
|
||||||
|
|
||||||
import 'package:firka/core/settings.dart';
|
|
||||||
import 'package:firka/app/app_state.dart';
|
|
||||||
|
|
||||||
import 'package:firka/ui/theme/style.dart';
|
|
||||||
import 'package:kreta_api/kreta_api.dart';
|
|
||||||
|
|
||||||
int roundGrade(double grade) {
|
|
||||||
final rounding = initData.settings
|
|
||||||
.group("settings")
|
|
||||||
.subGroup("application")
|
|
||||||
.subGroup("rounding");
|
|
||||||
if (grade < 1 + rounding.dbl("1")) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (grade < 2 + rounding.dbl("2")) {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
if (grade < 3 + rounding.dbl("3")) {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
if (grade < 4 + rounding.dbl("4")) {
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
int percentageToGrade(int grade) {
|
|
||||||
if (grade < 50) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (grade < 60) {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
if (grade < 70) {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
if (grade < 80) {
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
Color getGradeColor(double grade) {
|
|
||||||
switch (roundGrade(grade)) {
|
|
||||||
case 2:
|
|
||||||
return appStyle.colors.grade2;
|
|
||||||
case 3:
|
|
||||||
return appStyle.colors.grade3;
|
|
||||||
case 4:
|
|
||||||
return appStyle.colors.grade4;
|
|
||||||
case 5:
|
|
||||||
return appStyle.colors.grade5;
|
|
||||||
default:
|
|
||||||
return appStyle.colors.grade1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(int total, List<int> countsByGrade) getGradeDistribution(List<Grade> grades) {
|
|
||||||
final filtered = grades
|
|
||||||
.where((g) => g.type.name != "felevi_jegy_ertekeles")
|
|
||||||
.toList();
|
|
||||||
final counts = [0, 0, 0, 0, 0];
|
|
||||||
for (final g in filtered) {
|
|
||||||
if (g.numericValue == null) continue;
|
|
||||||
final value = g.valueType.name == "Szazalekos"
|
|
||||||
? percentageToGrade(g.numericValue!.round())
|
|
||||||
: g.numericValue!.round().clamp(1, 5);
|
|
||||||
counts[value - 1]++;
|
|
||||||
}
|
|
||||||
return (filtered.length, counts);
|
|
||||||
}
|
|
||||||
|
|
||||||
extension GradeListExtension on List<Grade> {
|
|
||||||
double getAverageBySubject(Subject subject) {
|
|
||||||
var weightTotal = 0.00;
|
|
||||||
var sum = 0.00;
|
|
||||||
|
|
||||||
for (var grade in this) {
|
|
||||||
if (grade.subject.uid == subject.uid) {
|
|
||||||
if (grade.numericValue != null) {
|
|
||||||
var weight = (grade.weightPercentage ?? 100) / 100.0;
|
|
||||||
weightTotal += weight;
|
|
||||||
|
|
||||||
sum += grade.numericValue! * weight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return sum / weightTotal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import 'package:firka/core/debug_helper.dart';
|
|||||||
import 'package:firka/core/state/firka_state.dart';
|
import 'package:firka/core/state/firka_state.dart';
|
||||||
import 'package:firka/app/app_state.dart';
|
import 'package:firka/app/app_state.dart';
|
||||||
import 'package:firka/core/bloc/home_refresh_cubit.dart';
|
import 'package:firka/core/bloc/home_refresh_cubit.dart';
|
||||||
|
import 'package:firka/core/settings.dart';
|
||||||
import 'package:firka/ui/theme/style.dart';
|
import 'package:firka/ui/theme/style.dart';
|
||||||
import 'package:firka/ui/shared/delayed_spinner.dart';
|
import 'package:firka/ui/shared/delayed_spinner.dart';
|
||||||
|
|
||||||
@@ -197,7 +198,17 @@ class _HomeGradesScreen extends FirkaState<HomeGradesScreen> {
|
|||||||
if (!avg.isNaN) {
|
if (!avg.isNaN) {
|
||||||
subjectCount++;
|
subjectCount++;
|
||||||
subjectAvg += avg;
|
subjectAvg += avg;
|
||||||
subjectAvgRounded += roundGrade(avg);
|
final rounding = widget.data.settings
|
||||||
|
.group("settings")
|
||||||
|
.subGroup("application")
|
||||||
|
.subGroup("rounding");
|
||||||
|
subjectAvgRounded += roundGrade(
|
||||||
|
avg,
|
||||||
|
t1: rounding.dbl("1"),
|
||||||
|
t2: rounding.dbl("2"),
|
||||||
|
t3: rounding.dbl("3"),
|
||||||
|
t4: rounding.dbl("4"),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,7 +220,17 @@ class _HomeGradesScreen extends FirkaState<HomeGradesScreen> {
|
|||||||
subjectAvgRounded = 0.00;
|
subjectAvgRounded = 0.00;
|
||||||
}
|
}
|
||||||
|
|
||||||
var subjectAvgColor = getGradeColor(subjectAvg);
|
final rounding = widget.data.settings
|
||||||
|
.group("settings")
|
||||||
|
.subGroup("application")
|
||||||
|
.subGroup("rounding");
|
||||||
|
var subjectAvgColor = getGradeColor(
|
||||||
|
subjectAvg,
|
||||||
|
t1: rounding.dbl("1"),
|
||||||
|
t2: rounding.dbl("2"),
|
||||||
|
t3: rounding.dbl("3"),
|
||||||
|
t4: rounding.dbl("4"),
|
||||||
|
);
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.only(left: 20.0, right: 20.0, top: 12.0),
|
padding: const EdgeInsets.only(left: 20.0, right: 20.0, top: 12.0),
|
||||||
|
|||||||
@@ -608,6 +608,7 @@ class _HomeTimetableScreen extends FirkaState<HomeTimetableScreen>
|
|||||||
"dropdownLeft",
|
"dropdownLeft",
|
||||||
size: 24,
|
size: 24,
|
||||||
color: appStyle.colors.accent,
|
color: appStyle.colors.accent,
|
||||||
|
package: 'firka',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
@@ -672,6 +673,7 @@ class _HomeTimetableScreen extends FirkaState<HomeTimetableScreen>
|
|||||||
"dropdownRight",
|
"dropdownRight",
|
||||||
size: 24,
|
size: 24,
|
||||||
color: appStyle.colors.accent,
|
color: appStyle.colors.accent,
|
||||||
|
package: 'firka',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
|
|||||||
@@ -438,6 +438,7 @@ class _HomeTimetableMonthlyScreen
|
|||||||
"dropdownLeft",
|
"dropdownLeft",
|
||||||
size: 24,
|
size: 24,
|
||||||
color: appStyle.colors.accent,
|
color: appStyle.colors.accent,
|
||||||
|
package: 'firka',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
@@ -467,6 +468,7 @@ class _HomeTimetableMonthlyScreen
|
|||||||
"dropdownRight",
|
"dropdownRight",
|
||||||
size: 24,
|
size: 24,
|
||||||
color: appStyle.colors.accent,
|
color: appStyle.colors.accent,
|
||||||
|
package: 'firka',
|
||||||
),
|
),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
var newNow = DateTime(now!.year, now!.month + 1);
|
var newNow = DateTime(now!.year, now!.month + 1);
|
||||||
|
|||||||
@@ -157,6 +157,11 @@ class _SettingsScreenState extends FirkaState<SettingsScreen> {
|
|||||||
item.iconType!,
|
item.iconType!,
|
||||||
item.iconData!,
|
item.iconData!,
|
||||||
color: appStyle.colors.accent,
|
color: appStyle.colors.accent,
|
||||||
|
package:
|
||||||
|
item.iconType == FirkaIconType.icons ||
|
||||||
|
item.iconType == FirkaIconType.majesticonsLocal
|
||||||
|
? 'firka'
|
||||||
|
: null,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
cardWidgets.add(SizedBox(width: 8));
|
cardWidgets.add(SizedBox(width: 8));
|
||||||
@@ -224,6 +229,12 @@ class _SettingsScreenState extends FirkaState<SettingsScreen> {
|
|||||||
item.iconType!,
|
item.iconType!,
|
||||||
item.iconData!,
|
item.iconData!,
|
||||||
color: appStyle.colors.accent,
|
color: appStyle.colors.accent,
|
||||||
|
package:
|
||||||
|
item.iconType == FirkaIconType.icons ||
|
||||||
|
item.iconType ==
|
||||||
|
FirkaIconType.majesticonsLocal
|
||||||
|
? 'firka'
|
||||||
|
: null,
|
||||||
),
|
),
|
||||||
SizedBox(width: 4),
|
SizedBox(width: 4),
|
||||||
],
|
],
|
||||||
@@ -265,6 +276,12 @@ class _SettingsScreenState extends FirkaState<SettingsScreen> {
|
|||||||
item.iconType!,
|
item.iconType!,
|
||||||
item.iconData!,
|
item.iconData!,
|
||||||
color: appStyle.colors.accent,
|
color: appStyle.colors.accent,
|
||||||
|
package:
|
||||||
|
item.iconType == FirkaIconType.icons ||
|
||||||
|
item.iconType ==
|
||||||
|
FirkaIconType.majesticonsLocal
|
||||||
|
? 'firka'
|
||||||
|
: null,
|
||||||
),
|
),
|
||||||
SizedBox(width: 4),
|
SizedBox(width: 4),
|
||||||
],
|
],
|
||||||
@@ -930,6 +947,7 @@ class _SettingsScreenState extends FirkaState<SettingsScreen> {
|
|||||||
FirkaIconType.icons,
|
FirkaIconType.icons,
|
||||||
"group",
|
"group",
|
||||||
color: appStyle.colors.accent,
|
color: appStyle.colors.accent,
|
||||||
|
package: 'firka',
|
||||||
),
|
),
|
||||||
SizedBox(width: 8),
|
SizedBox(width: 8),
|
||||||
Text(
|
Text(
|
||||||
@@ -1067,6 +1085,12 @@ class _SettingsScreenState extends FirkaState<SettingsScreen> {
|
|||||||
item.iconType!,
|
item.iconType!,
|
||||||
item.iconData!,
|
item.iconData!,
|
||||||
color: appStyle.colors.accent,
|
color: appStyle.colors.accent,
|
||||||
|
package:
|
||||||
|
item.iconType == FirkaIconType.icons ||
|
||||||
|
item.iconType ==
|
||||||
|
FirkaIconType.majesticonsLocal
|
||||||
|
? 'firka'
|
||||||
|
: null,
|
||||||
),
|
),
|
||||||
SizedBox(width: 8),
|
SizedBox(width: 8),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -56,12 +56,14 @@ class _WelcomeWidgetState extends State<WelcomeWidget> {
|
|||||||
FirkaIconType.majesticonsLocal,
|
FirkaIconType.majesticonsLocal,
|
||||||
"sunSolid",
|
"sunSolid",
|
||||||
color: appStyle.colors.accent,
|
color: appStyle.colors.accent,
|
||||||
|
package: 'firka',
|
||||||
);
|
);
|
||||||
case Cycle.day:
|
case Cycle.day:
|
||||||
return FirkaIconWidget(
|
return FirkaIconWidget(
|
||||||
FirkaIconType.majesticonsLocal,
|
FirkaIconType.majesticonsLocal,
|
||||||
"parkSolidSchool",
|
"parkSolidSchool",
|
||||||
color: appStyle.colors.accent,
|
color: appStyle.colors.accent,
|
||||||
|
package: 'firka',
|
||||||
);
|
);
|
||||||
case Cycle.afternoon:
|
case Cycle.afternoon:
|
||||||
return FirkaIconWidget(
|
return FirkaIconWidget(
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ class HomeworkWidget extends StatelessWidget {
|
|||||||
"homeWithMark",
|
"homeWithMark",
|
||||||
color: appStyle.colors.accent,
|
color: appStyle.colors.accent,
|
||||||
size: 24,
|
size: 24,
|
||||||
|
package: 'firka',
|
||||||
)
|
)
|
||||||
: FirkaIconWidget(
|
: FirkaIconWidget(
|
||||||
FirkaIconType.majesticons,
|
FirkaIconType.majesticons,
|
||||||
|
|||||||
@@ -370,6 +370,7 @@ class LessonWidget extends StatelessWidget {
|
|||||||
'cupFilled',
|
'cupFilled',
|
||||||
color: appStyle.colors.accent,
|
color: appStyle.colors.accent,
|
||||||
size: 24,
|
size: 24,
|
||||||
|
package: 'firka',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -245,6 +245,7 @@ class LessonBigWidget extends StatelessWidget {
|
|||||||
'cupFilled',
|
'cupFilled',
|
||||||
color: appStyle.colors.accent,
|
color: appStyle.colors.accent,
|
||||||
size: 24,
|
size: 24,
|
||||||
|
package: 'firka',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -487,6 +488,7 @@ class LessonBigWidget extends StatelessWidget {
|
|||||||
'cupFilled',
|
'cupFilled',
|
||||||
color: appStyle.colors.accent,
|
color: appStyle.colors.accent,
|
||||||
size: 24,
|
size: 24,
|
||||||
|
package: 'firka',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,35 +1 @@
|
|||||||
import 'package:firka/core/icon_helper.dart';
|
export 'package:firka_common/ui/shared/class_icon.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
import 'package:firka/ui/shared/firka_icon.dart';
|
|
||||||
|
|
||||||
class ClassIconWidget extends StatelessWidget {
|
|
||||||
final String _uid;
|
|
||||||
final String _className;
|
|
||||||
final String _category;
|
|
||||||
final Color color;
|
|
||||||
final double? size;
|
|
||||||
|
|
||||||
const ClassIconWidget({
|
|
||||||
super.key,
|
|
||||||
required String uid,
|
|
||||||
required String className,
|
|
||||||
required String category,
|
|
||||||
this.color = Colors.white,
|
|
||||||
this.size,
|
|
||||||
}) : _className = className,
|
|
||||||
_uid = uid,
|
|
||||||
_category = category;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
var iconCategory = getIconType(_uid, _className, _category);
|
|
||||||
|
|
||||||
return FirkaIconWidget(
|
|
||||||
FirkaIconType.majesticons,
|
|
||||||
getIconData(iconCategory),
|
|
||||||
color: color,
|
|
||||||
size: size,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,21 +1 @@
|
|||||||
import 'package:firka/ui/theme/style.dart';
|
export 'package:firka_common/ui/shared/counter_digit.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class CounterDigitWidget extends StatelessWidget {
|
|
||||||
final String c;
|
|
||||||
final TextStyle? style;
|
|
||||||
|
|
||||||
const CounterDigitWidget(this.c, this.style, {super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Card(
|
|
||||||
shadowColor: Colors.transparent,
|
|
||||||
color: appStyle.colors.buttonSecondaryFill,
|
|
||||||
child: Padding(
|
|
||||||
padding: EdgeInsets.only(left: 8, right: 8, top: 4, bottom: 4),
|
|
||||||
child: Text(c, style: style),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,45 +1 @@
|
|||||||
import 'dart:async';
|
export 'package:firka_common/ui/shared/delayed_spinner.dart';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
import 'package:firka/core/state/firka_state.dart';
|
|
||||||
import 'package:firka/ui/theme/style.dart';
|
|
||||||
|
|
||||||
class DelayedSpinnerWidget extends StatefulWidget {
|
|
||||||
const DelayedSpinnerWidget({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<DelayedSpinnerWidget> createState() => _DelayedSpinner();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _DelayedSpinner extends FirkaState<DelayedSpinnerWidget> {
|
|
||||||
Timer? timer;
|
|
||||||
bool showSpinner = false;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
|
|
||||||
timer = Timer(Duration(milliseconds: 50), () {
|
|
||||||
setState(() {
|
|
||||||
showSpinner = true;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
if (showSpinner) {
|
|
||||||
return CircularProgressIndicator(color: appStyle.colors.accent);
|
|
||||||
} else {
|
|
||||||
return SizedBox();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
super.dispose();
|
|
||||||
|
|
||||||
timer?.cancel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,42 +1 @@
|
|||||||
import 'dart:typed_data';
|
export 'package:firka_common/ui/shared/firka_icon.dart';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_svg/svg.dart';
|
|
||||||
import 'package:majesticons_flutter/majesticons_flutter.dart';
|
|
||||||
|
|
||||||
enum FirkaIconType { icons, majesticons, majesticonsLocal }
|
|
||||||
|
|
||||||
class FirkaIconWidget extends StatelessWidget {
|
|
||||||
final FirkaIconType iconType;
|
|
||||||
final Object iconData;
|
|
||||||
final Color color;
|
|
||||||
final double? size;
|
|
||||||
|
|
||||||
const FirkaIconWidget(
|
|
||||||
this.iconType,
|
|
||||||
this.iconData, {
|
|
||||||
super.key,
|
|
||||||
this.color = Colors.white,
|
|
||||||
this.size,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
switch (iconType) {
|
|
||||||
case FirkaIconType.icons:
|
|
||||||
return SvgPicture.asset(
|
|
||||||
'assets/icons/${iconData as String}.svg',
|
|
||||||
color: color,
|
|
||||||
height: size,
|
|
||||||
);
|
|
||||||
case FirkaIconType.majesticons:
|
|
||||||
return Majesticon(iconData as Uint8List, color: color, size: size);
|
|
||||||
case FirkaIconType.majesticonsLocal:
|
|
||||||
return SvgPicture.asset(
|
|
||||||
'assets/majesticons/${iconData as String}.svg',
|
|
||||||
color: color,
|
|
||||||
height: size,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,60 +1 @@
|
|||||||
import 'package:kreta_api/kreta_api.dart';
|
export 'package:firka_common/ui/shared/grade_small_card.dart';
|
||||||
import 'package:firka/ui/components/firka_card.dart';
|
|
||||||
import 'package:firka/ui/components/grade_helpers.dart';
|
|
||||||
import 'package:firka/ui/shared/class_icon.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
import 'package:firka/ui/theme/style.dart';
|
|
||||||
|
|
||||||
class GradeSmallCard extends FirkaCard {
|
|
||||||
final List<Grade> grades;
|
|
||||||
final Subject subject;
|
|
||||||
|
|
||||||
GradeSmallCard(this.grades, this.subject, {super.key})
|
|
||||||
: super(
|
|
||||||
left: [
|
|
||||||
ClassIconWidget(
|
|
||||||
uid: subject.uid,
|
|
||||||
className: subject.name,
|
|
||||||
category: subject.category.name!,
|
|
||||||
color: appStyle.colors.accent,
|
|
||||||
),
|
|
||||||
SizedBox(width: 4),
|
|
||||||
SizedBox(
|
|
||||||
width: 200,
|
|
||||||
child: Text(
|
|
||||||
subject.name,
|
|
||||||
style: appStyle.fonts.B_16SB.apply(
|
|
||||||
color: appStyle.colors.textPrimary,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
right: [
|
|
||||||
grades.getAverageBySubject(subject).isNaN
|
|
||||||
? SizedBox()
|
|
||||||
: Card(
|
|
||||||
shadowColor: Colors.transparent,
|
|
||||||
color: getGradeColor(
|
|
||||||
grades.getAverageBySubject(subject),
|
|
||||||
).withAlpha(38),
|
|
||||||
child: Padding(
|
|
||||||
padding: EdgeInsets.only(
|
|
||||||
left: 8,
|
|
||||||
right: 8,
|
|
||||||
top: 4,
|
|
||||||
bottom: 4,
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
grades.getAverageBySubject(subject).toStringAsFixed(2),
|
|
||||||
style: appStyle.fonts.B_16SB.apply(
|
|
||||||
color: getGradeColor(
|
|
||||||
grades.getAverageBySubject(subject),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,309 +1 @@
|
|||||||
import 'package:flutter/material.dart';
|
export 'package:firka_common/ui/theme/style.dart';
|
||||||
|
|
||||||
// Design system token names; ignore non_constant_identifier_names for consistency with design specs
|
|
||||||
// ignore_for_file: non_constant_identifier_names
|
|
||||||
|
|
||||||
class FirkaFonts {
|
|
||||||
TextStyle H_H1;
|
|
||||||
TextStyle H_18px;
|
|
||||||
TextStyle H_H2;
|
|
||||||
TextStyle H_16px;
|
|
||||||
TextStyle H_14px;
|
|
||||||
TextStyle H_12px;
|
|
||||||
|
|
||||||
TextStyle H_16px_trimmed;
|
|
||||||
|
|
||||||
TextStyle B_16R;
|
|
||||||
TextStyle B_16SB;
|
|
||||||
TextStyle B_15SB;
|
|
||||||
|
|
||||||
TextStyle B_14R;
|
|
||||||
TextStyle B_14SB;
|
|
||||||
|
|
||||||
TextStyle B_12R;
|
|
||||||
TextStyle B_12SB;
|
|
||||||
|
|
||||||
TextStyle P_14;
|
|
||||||
TextStyle P_12;
|
|
||||||
|
|
||||||
FirkaFonts({
|
|
||||||
required this.H_H1,
|
|
||||||
required this.H_18px,
|
|
||||||
required this.H_H2,
|
|
||||||
required this.H_16px,
|
|
||||||
required this.H_14px,
|
|
||||||
required this.H_12px,
|
|
||||||
required this.H_16px_trimmed,
|
|
||||||
required this.B_16R,
|
|
||||||
required this.B_16SB,
|
|
||||||
required this.B_15SB,
|
|
||||||
required this.B_14R,
|
|
||||||
required this.B_14SB,
|
|
||||||
required this.B_12R,
|
|
||||||
required this.B_12SB,
|
|
||||||
required this.P_14,
|
|
||||||
required this.P_12,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
class FirkaColors {
|
|
||||||
Color background;
|
|
||||||
Color backgroundAmoled;
|
|
||||||
Color background0p;
|
|
||||||
Color success;
|
|
||||||
int shadowBlur;
|
|
||||||
|
|
||||||
Color textPrimary;
|
|
||||||
Color textSecondary;
|
|
||||||
Color textTertiary;
|
|
||||||
|
|
||||||
Color textPrimaryLight;
|
|
||||||
Color textSecondaryLight;
|
|
||||||
Color textTertiaryLight;
|
|
||||||
|
|
||||||
Color card;
|
|
||||||
Color cardTranslucent;
|
|
||||||
|
|
||||||
Color buttonSecondaryFill;
|
|
||||||
|
|
||||||
Color accent;
|
|
||||||
Color secondary;
|
|
||||||
Color shadowColor;
|
|
||||||
Color a10p; // 10%
|
|
||||||
Color a15p; // 15%
|
|
||||||
|
|
||||||
Color warningAccent;
|
|
||||||
Color warningText;
|
|
||||||
Color warning15p;
|
|
||||||
Color warningCard;
|
|
||||||
|
|
||||||
Color errorAccent;
|
|
||||||
Color errorText;
|
|
||||||
Color error15p;
|
|
||||||
Color errorCard;
|
|
||||||
|
|
||||||
Color grade5;
|
|
||||||
Color grade4;
|
|
||||||
Color grade3;
|
|
||||||
Color grade2;
|
|
||||||
Color grade1;
|
|
||||||
|
|
||||||
FirkaColors({
|
|
||||||
required this.background,
|
|
||||||
required this.backgroundAmoled,
|
|
||||||
required this.background0p,
|
|
||||||
required this.success,
|
|
||||||
required this.shadowBlur,
|
|
||||||
required this.textPrimary,
|
|
||||||
required this.textSecondary,
|
|
||||||
required this.textTertiary,
|
|
||||||
required this.textPrimaryLight,
|
|
||||||
required this.textSecondaryLight,
|
|
||||||
required this.textTertiaryLight,
|
|
||||||
required this.card,
|
|
||||||
required this.cardTranslucent,
|
|
||||||
required this.buttonSecondaryFill,
|
|
||||||
required this.accent,
|
|
||||||
required this.secondary,
|
|
||||||
required this.shadowColor,
|
|
||||||
required this.a10p,
|
|
||||||
required this.a15p,
|
|
||||||
required this.warningAccent,
|
|
||||||
required this.warningText,
|
|
||||||
required this.warning15p,
|
|
||||||
required this.warningCard,
|
|
||||||
required this.errorAccent,
|
|
||||||
required this.errorText,
|
|
||||||
required this.error15p,
|
|
||||||
required this.errorCard,
|
|
||||||
required this.grade5,
|
|
||||||
required this.grade4,
|
|
||||||
required this.grade3,
|
|
||||||
required this.grade2,
|
|
||||||
required this.grade1,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
class FirkaStyle {
|
|
||||||
FirkaColors colors;
|
|
||||||
FirkaFonts fonts;
|
|
||||||
bool isLight;
|
|
||||||
|
|
||||||
FirkaStyle({
|
|
||||||
required this.isLight,
|
|
||||||
required this.colors,
|
|
||||||
required this.fonts,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
final _defaultFonts = FirkaFonts(
|
|
||||||
H_H1: TextStyle(
|
|
||||||
fontSize: 30,
|
|
||||||
fontFamily: 'Montserrat',
|
|
||||||
fontVariations: [FontVariation("wght", 700)],
|
|
||||||
),
|
|
||||||
H_18px: TextStyle(
|
|
||||||
fontSize: 18,
|
|
||||||
fontFamily: 'Montserrat',
|
|
||||||
fontVariations: [FontVariation("wght", 700)],
|
|
||||||
),
|
|
||||||
H_H2: TextStyle(
|
|
||||||
fontSize: 20,
|
|
||||||
fontFamily: 'Montserrat',
|
|
||||||
fontVariations: [FontVariation("wght", 700)],
|
|
||||||
),
|
|
||||||
H_16px: TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
fontFamily: 'Montserrat',
|
|
||||||
fontVariations: [FontVariation("wght", 600)],
|
|
||||||
),
|
|
||||||
H_14px: TextStyle(
|
|
||||||
fontSize: 14,
|
|
||||||
fontFamily: 'Montserrat',
|
|
||||||
fontVariations: [FontVariation("wght", 600)],
|
|
||||||
),
|
|
||||||
H_12px: TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
fontFamily: 'Montserrat',
|
|
||||||
fontVariations: [FontVariation("wght", 600)],
|
|
||||||
),
|
|
||||||
H_16px_trimmed: TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
fontFamily: 'Montserrat',
|
|
||||||
fontVariations: [FontVariation("wght", 600)],
|
|
||||||
height: 1.3,
|
|
||||||
),
|
|
||||||
B_16R: TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
fontFamily: 'Figtree',
|
|
||||||
fontVariations: [FontVariation("wght", 600)],
|
|
||||||
height: 1.3,
|
|
||||||
),
|
|
||||||
B_16SB: TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
fontFamily: 'Figtree',
|
|
||||||
fontVariations: [FontVariation("wght", 700)],
|
|
||||||
height: 1.3,
|
|
||||||
),
|
|
||||||
B_14R: TextStyle(
|
|
||||||
fontSize: 14,
|
|
||||||
fontFamily: 'Figtree',
|
|
||||||
fontVariations: [FontVariation("wght", 600)],
|
|
||||||
height: 1.3,
|
|
||||||
),
|
|
||||||
B_14SB: TextStyle(
|
|
||||||
fontSize: 14,
|
|
||||||
fontFamily: 'Figtree',
|
|
||||||
fontVariations: [FontVariation("wght", 700)],
|
|
||||||
height: 1.3,
|
|
||||||
),
|
|
||||||
B_15SB: TextStyle(
|
|
||||||
fontSize: 15,
|
|
||||||
fontFamily: 'Figtree',
|
|
||||||
fontVariations: [FontVariation("wght", 700)],
|
|
||||||
height: 1.3,
|
|
||||||
),
|
|
||||||
B_12R: TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
fontFamily: 'Figtree',
|
|
||||||
fontVariations: [FontVariation("wght", 600)],
|
|
||||||
height: 1.3,
|
|
||||||
),
|
|
||||||
B_12SB: TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
fontFamily: 'Figtree',
|
|
||||||
fontVariations: [FontVariation("wght", 700)],
|
|
||||||
height: 1.3,
|
|
||||||
),
|
|
||||||
P_14: TextStyle(
|
|
||||||
fontSize: 14,
|
|
||||||
fontFamily: 'RobotoMono',
|
|
||||||
fontVariations: [FontVariation("wght", 700)],
|
|
||||||
),
|
|
||||||
P_12: TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
fontFamily: 'RobotoMono',
|
|
||||||
fontVariations: [FontVariation("wght", 700)],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
final FirkaStyle lightStyle = FirkaStyle(
|
|
||||||
isLight: true,
|
|
||||||
colors: FirkaColors(
|
|
||||||
background: Color(0xFFFAFFF0),
|
|
||||||
backgroundAmoled: Colors.black,
|
|
||||||
background0p: Color(0x00fafff0),
|
|
||||||
success: Color(0xFF92EA3B),
|
|
||||||
shadowBlur: 2,
|
|
||||||
textPrimary: Color(0xFF394C0A),
|
|
||||||
textSecondary: Color(0xCC394C0A),
|
|
||||||
textTertiary: Color(0x80394C0A),
|
|
||||||
textPrimaryLight: Color(0xFF394C0A),
|
|
||||||
textSecondaryLight: Color(0xCC394C0A),
|
|
||||||
textTertiaryLight: Color(0x80394C0A),
|
|
||||||
card: Color(0xFFF3FBDE),
|
|
||||||
cardTranslucent: Color(0x80F3FBDE),
|
|
||||||
buttonSecondaryFill: Color(0xFFFEFFFD),
|
|
||||||
accent: Color(0xFFA7DC22),
|
|
||||||
secondary: Color(0xFF6E8F1B),
|
|
||||||
shadowColor: Color(0x33647e22),
|
|
||||||
a10p: Color(0x1aa7dc22),
|
|
||||||
a15p: Color(0x26a7dc22),
|
|
||||||
warningAccent: Color(0xFFFFA046),
|
|
||||||
warningText: Color(0xFF8F531B),
|
|
||||||
warning15p: Color(0x26FFA046),
|
|
||||||
warningCard: Color(0xFFFAEBDC),
|
|
||||||
errorAccent: Color(0xFFFF54A1),
|
|
||||||
errorText: Color(0xFF8F1B4F),
|
|
||||||
error15p: Color(0x26FF54A1),
|
|
||||||
errorCard: Color(0xFFFADCE9),
|
|
||||||
grade5: Color(0xFF22CCAD),
|
|
||||||
grade4: Color(0xFF92EA3B),
|
|
||||||
grade3: Color(0xFFF9CF00),
|
|
||||||
grade2: Color(0xFFFFA046),
|
|
||||||
grade1: Color(0xFFFF54A1),
|
|
||||||
),
|
|
||||||
fonts: _defaultFonts,
|
|
||||||
);
|
|
||||||
|
|
||||||
final FirkaStyle darkStyle = FirkaStyle(
|
|
||||||
isLight: false,
|
|
||||||
colors: FirkaColors(
|
|
||||||
background: Color(0xFF0D1202),
|
|
||||||
backgroundAmoled: Colors.black,
|
|
||||||
background0p: Color(0x00fafff0),
|
|
||||||
success: Color(0xFF92EA3B),
|
|
||||||
shadowBlur: 0,
|
|
||||||
textPrimary: Color(0xFFEAF7CC),
|
|
||||||
textSecondary: Color(0xB3EAF7CC),
|
|
||||||
textTertiary: Color(0x80EAF7CC),
|
|
||||||
textPrimaryLight: Color(0xFF394C0A),
|
|
||||||
textSecondaryLight: Color(0xCC394C0A),
|
|
||||||
textTertiaryLight: Color(0x80394C0A),
|
|
||||||
card: Color(0xFF141905),
|
|
||||||
cardTranslucent: Color(0x80141905),
|
|
||||||
buttonSecondaryFill: Color(0xFF20290B),
|
|
||||||
accent: Color(0xFFA7DC22),
|
|
||||||
secondary: Color(0xFFCBEE71),
|
|
||||||
shadowColor: Color(0x26CBEE71),
|
|
||||||
a10p: Color(0x1AA7DC22),
|
|
||||||
a15p: Color(0x26A7DC22),
|
|
||||||
warningAccent: Color(0xFFFFA046),
|
|
||||||
warningText: Color(0xFFF0B37A),
|
|
||||||
warning15p: Color(0x26FFA046),
|
|
||||||
warningCard: Color(0xFF201203),
|
|
||||||
errorAccent: Color(0xFFFF54A1),
|
|
||||||
errorText: Color(0xFFF59EC5),
|
|
||||||
error15p: Color(0x26FF54A1),
|
|
||||||
errorCard: Color(0xFF1E030F),
|
|
||||||
grade5: Color(0xFF22CCAD),
|
|
||||||
grade4: Color(0xFF92EA3B),
|
|
||||||
grade3: Color(0xFFF9CF00),
|
|
||||||
grade2: Color(0xFFFFA046),
|
|
||||||
grade1: Color(0xFFFF54A1),
|
|
||||||
),
|
|
||||||
fonts: _defaultFonts,
|
|
||||||
);
|
|
||||||
|
|
||||||
FirkaStyle appStyle = lightStyle;
|
|
||||||
FirkaStyle wearStyle = darkStyle;
|
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ environment:
|
|||||||
dependencies:
|
dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
firka_common:
|
||||||
|
path: ../firka_common
|
||||||
kreta_api:
|
kreta_api:
|
||||||
path: ../kreta_api
|
path: ../kreta_api
|
||||||
|
|
||||||
|
|||||||
17
firka_common/lib/core/debug_helper.dart
Normal file
17
firka_common/lib/core/debug_helper.dart
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
DateTime? debugFakeTime;
|
||||||
|
DateTime? debugSetAt;
|
||||||
|
var debugTimeAdvance = false;
|
||||||
|
|
||||||
|
DateTime timeNow() {
|
||||||
|
if (debugFakeTime != null) {
|
||||||
|
if (debugTimeAdvance && debugSetAt != null) {
|
||||||
|
var diff = DateTime.now().difference(debugSetAt!);
|
||||||
|
|
||||||
|
return debugFakeTime!.add(diff);
|
||||||
|
} else {
|
||||||
|
return debugFakeTime!;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return DateTime.now();
|
||||||
|
}
|
||||||
|
}
|
||||||
19
firka_common/lib/core/extensions.dart
Normal file
19
firka_common/lib/core/extensions.dart
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
extension IterableExtensionMap on Iterable<MapEntry<String, dynamic>> {
|
||||||
|
Map<String, dynamic> toMap() {
|
||||||
|
var map = <String, dynamic>{};
|
||||||
|
for (var item in this) {
|
||||||
|
map[item.key] = item.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension IterableExtension<T> on Iterable<T> {
|
||||||
|
T? firstWhereOrNull(bool Function(T element) test) {
|
||||||
|
for (var element in this) {
|
||||||
|
if (test(element)) return element;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
135
firka_common/lib/core/icon_helper.dart
Normal file
135
firka_common/lib/core/icon_helper.dart
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:majesticons_flutter/majesticons_flutter.dart';
|
||||||
|
|
||||||
|
enum ClassIcon {
|
||||||
|
mathematics,
|
||||||
|
grammar,
|
||||||
|
literature,
|
||||||
|
history,
|
||||||
|
geography,
|
||||||
|
art,
|
||||||
|
physics,
|
||||||
|
music,
|
||||||
|
pe,
|
||||||
|
chemistry,
|
||||||
|
biology,
|
||||||
|
env,
|
||||||
|
religion,
|
||||||
|
economics,
|
||||||
|
it,
|
||||||
|
code,
|
||||||
|
networking,
|
||||||
|
theatre,
|
||||||
|
film,
|
||||||
|
electricalEngineering,
|
||||||
|
mechanicalEngineering,
|
||||||
|
technika,
|
||||||
|
dance,
|
||||||
|
philosophy,
|
||||||
|
ofo,
|
||||||
|
diligence,
|
||||||
|
attitude,
|
||||||
|
language,
|
||||||
|
linux,
|
||||||
|
database,
|
||||||
|
applications,
|
||||||
|
project,
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<ClassIcon, RegExp> _descriptors = {
|
||||||
|
ClassIcon.mathematics: RegExp(r'mate(k|matika)'),
|
||||||
|
ClassIcon.grammar: RegExp(r'magyar nyelv|nyelvtan'),
|
||||||
|
ClassIcon.literature: RegExp(r'irodalom'),
|
||||||
|
ClassIcon.history: RegExp(r'tor(i|tenelem)'),
|
||||||
|
ClassIcon.geography: RegExp(r'foldrajz'),
|
||||||
|
ClassIcon.art: RegExp(r'rajz|muvtori|muveszet|vizualis'),
|
||||||
|
ClassIcon.physics: RegExp(r'fizika'),
|
||||||
|
ClassIcon.music: RegExp(r'^enek|zene|szolfezs|zongora|korus'),
|
||||||
|
ClassIcon.pe: RegExp(r'^tes(i|tneveles)|sport|edzeselmelet'),
|
||||||
|
ClassIcon.chemistry: RegExp(r'kemia'),
|
||||||
|
ClassIcon.biology: RegExp(r'biologia'),
|
||||||
|
ClassIcon.env: RegExp(
|
||||||
|
r'kornyezet|termeszet ?(tudomany|ismeret)|hon( es nep)?ismeret',
|
||||||
|
),
|
||||||
|
ClassIcon.religion: RegExp(r'(hit|erkolcs)tan|vallas|etika|bibliaismeret'),
|
||||||
|
ClassIcon.economics: RegExp(r'penzugy|gazdasag'),
|
||||||
|
ClassIcon.it: RegExp(r'informatika|szoftver|iroda|digitalis'),
|
||||||
|
ClassIcon.code: RegExp(r'prog|alkalmazas'),
|
||||||
|
ClassIcon.networking: RegExp(r'halozat'),
|
||||||
|
ClassIcon.theatre: RegExp(r'szinhaz'),
|
||||||
|
ClassIcon.film: RegExp(r'film|media'),
|
||||||
|
ClassIcon.electricalEngineering: RegExp(r'elektro(tech)?nika'),
|
||||||
|
ClassIcon.mechanicalEngineering: RegExp(r'gepesz|mernok|ipar'),
|
||||||
|
ClassIcon.technika: RegExp(r'technika'),
|
||||||
|
ClassIcon.dance: RegExp(r'tanc'),
|
||||||
|
ClassIcon.philosophy: RegExp(r'filozofia'),
|
||||||
|
ClassIcon.ofo: RegExp(r'osztaly(fonoki|kozosseg)|kozossegi|neveles'),
|
||||||
|
ClassIcon.diligence: RegExp(r'szorgalom'),
|
||||||
|
ClassIcon.attitude: RegExp(r'magatartas'),
|
||||||
|
ClassIcon.language: RegExp(
|
||||||
|
r'angol|nemet|francia|olasz|orosz|spanyol|latin|kinai|nyelv',
|
||||||
|
),
|
||||||
|
ClassIcon.linux: RegExp(r'linux'),
|
||||||
|
ClassIcon.database: RegExp(r'adatbazis.*'),
|
||||||
|
ClassIcon.applications: RegExp(r'asztali alkalmazasok'),
|
||||||
|
ClassIcon.project: RegExp(r'projekt'),
|
||||||
|
};
|
||||||
|
|
||||||
|
Map<ClassIcon, Uint8List> _iconMap = {
|
||||||
|
ClassIcon.mathematics: Majesticon.calculatorSolid,
|
||||||
|
ClassIcon.grammar: Majesticon.bookSolid,
|
||||||
|
ClassIcon.literature: Majesticon.bookOpenSolid,
|
||||||
|
ClassIcon.history: Majesticon.compass2Solid,
|
||||||
|
ClassIcon.geography: Majesticon.globeEarth2Solid,
|
||||||
|
ClassIcon.art: Majesticon.editPen2Solid,
|
||||||
|
ClassIcon.music: Majesticon.musicNoteSolid,
|
||||||
|
ClassIcon.chemistry: Majesticon.testTubeFilledSolid,
|
||||||
|
ClassIcon.biology: Majesticon.covidSolid,
|
||||||
|
ClassIcon.it: Majesticon.laptopSolid,
|
||||||
|
ClassIcon.code: Majesticon.curlyBracesSolid,
|
||||||
|
ClassIcon.networking: Majesticon.cloudSolid,
|
||||||
|
ClassIcon.technika: Majesticon.ruler2Solid,
|
||||||
|
ClassIcon.language: Majesticon.tooltipsSolid,
|
||||||
|
ClassIcon.database: Majesticon.dataSolid,
|
||||||
|
};
|
||||||
|
|
||||||
|
ClassIcon? getIconType(String uid, String className, String category) {
|
||||||
|
ClassIcon? icon;
|
||||||
|
if (category.toLowerCase() == "matematika") {
|
||||||
|
icon = ClassIcon.mathematics;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (icon == null) {
|
||||||
|
for (var desc in _descriptors.entries) {
|
||||||
|
if (desc.value.hasMatch(
|
||||||
|
className
|
||||||
|
.replaceAll("ö", "o")
|
||||||
|
.replaceAll("ü", "u")
|
||||||
|
.replaceAll("ó", "o")
|
||||||
|
.replaceAll("ő", "o")
|
||||||
|
.replaceAll("ú", "u")
|
||||||
|
.replaceAll("é", "e")
|
||||||
|
.replaceAll("á", "a")
|
||||||
|
.replaceAll("ű", "u")
|
||||||
|
.replaceAll("í", "i")
|
||||||
|
.toLowerCase(),
|
||||||
|
)) {
|
||||||
|
icon = desc.key;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
Uint8List getIconData(ClassIcon? icon) {
|
||||||
|
if (icon == null) return Majesticon.alertCircleSolid;
|
||||||
|
|
||||||
|
var iconData = _iconMap[icon];
|
||||||
|
iconData ??= Majesticon.alertCircleSolid;
|
||||||
|
|
||||||
|
return iconData;
|
||||||
|
}
|
||||||
9
firka_common/lib/core/json_helper.dart
Normal file
9
firka_common/lib/core/json_helper.dart
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
List<T> listToTyped<T>(List<dynamic> dynamicList) {
|
||||||
|
var newList = List<T>.empty(growable: true);
|
||||||
|
|
||||||
|
for (var item in dynamicList) {
|
||||||
|
newList.add(item as T);
|
||||||
|
}
|
||||||
|
|
||||||
|
return newList;
|
||||||
|
}
|
||||||
16
firka_common/lib/firka_common.dart
Normal file
16
firka_common/lib/firka_common.dart
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
library firka_common;
|
||||||
|
|
||||||
|
export 'core/debug_helper.dart';
|
||||||
|
export 'core/extensions.dart';
|
||||||
|
export 'core/icon_helper.dart';
|
||||||
|
export 'core/json_helper.dart';
|
||||||
|
export 'ui/components/firka_card.dart';
|
||||||
|
export 'ui/components/firka_shadow.dart';
|
||||||
|
export 'ui/components/grade.dart';
|
||||||
|
export 'ui/components/grade_helpers.dart';
|
||||||
|
export 'ui/shared/class_icon.dart';
|
||||||
|
export 'ui/shared/counter_digit.dart';
|
||||||
|
export 'ui/shared/delayed_spinner.dart';
|
||||||
|
export 'ui/shared/firka_icon.dart';
|
||||||
|
export 'ui/shared/grade_small_card.dart';
|
||||||
|
export 'ui/theme/style.dart';
|
||||||
137
firka_common/lib/ui/components/firka_card.dart
Normal file
137
firka_common/lib/ui/components/firka_card.dart
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:firka_common/ui/components/firka_shadow.dart';
|
||||||
|
import 'package:firka_common/ui/theme/style.dart';
|
||||||
|
|
||||||
|
enum Attach { none, bottom, top }
|
||||||
|
|
||||||
|
class FirkaCard extends StatelessWidget {
|
||||||
|
final List<Widget> left;
|
||||||
|
final List<Widget>? center;
|
||||||
|
final double? height;
|
||||||
|
final List<Widget>? right;
|
||||||
|
final bool shadow;
|
||||||
|
final Widget? extra;
|
||||||
|
final Attach? attached;
|
||||||
|
final Color? color;
|
||||||
|
final bool? isLightMode;
|
||||||
|
|
||||||
|
const FirkaCard({
|
||||||
|
required this.left,
|
||||||
|
this.shadow = true,
|
||||||
|
this.center,
|
||||||
|
this.right,
|
||||||
|
this.extra,
|
||||||
|
this.attached,
|
||||||
|
this.color,
|
||||||
|
this.height,
|
||||||
|
this.isLightMode,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
var right = this.right ?? [];
|
||||||
|
|
||||||
|
var attached = this.attached != null ? this.attached! : Attach.none;
|
||||||
|
final defaultRounding = 16.0;
|
||||||
|
final attachedRounding = 8.0;
|
||||||
|
final isLight =
|
||||||
|
isLightMode ?? Theme.of(context).brightness == Brightness.light;
|
||||||
|
|
||||||
|
if (extra != null) {
|
||||||
|
return SizedBox(
|
||||||
|
width: MediaQuery.of(context).size.width,
|
||||||
|
height: height,
|
||||||
|
child: FirkaShadow(
|
||||||
|
shadow: shadow,
|
||||||
|
isLightMode: isLight,
|
||||||
|
child: Card(
|
||||||
|
color: color ?? appStyle.colors.card,
|
||||||
|
shadowColor: isLight && shadow ? null : Colors.transparent,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
topLeft: Radius.circular(
|
||||||
|
attached == Attach.top ? attachedRounding : defaultRounding,
|
||||||
|
),
|
||||||
|
topRight: Radius.circular(
|
||||||
|
attached == Attach.top ? attachedRounding : defaultRounding,
|
||||||
|
),
|
||||||
|
bottomLeft: Radius.circular(
|
||||||
|
attached == Attach.bottom
|
||||||
|
? attachedRounding
|
||||||
|
: defaultRounding,
|
||||||
|
),
|
||||||
|
bottomRight: Radius.circular(
|
||||||
|
attached == Attach.bottom
|
||||||
|
? attachedRounding
|
||||||
|
: defaultRounding,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(12.0),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Row(children: left),
|
||||||
|
Row(children: center ?? []),
|
||||||
|
Row(children: right),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
extra ?? const SizedBox(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return SizedBox(
|
||||||
|
width: MediaQuery.of(context).size.width,
|
||||||
|
height: height,
|
||||||
|
child: FirkaShadow(
|
||||||
|
shadow: shadow,
|
||||||
|
isLightMode: isLight,
|
||||||
|
child: Card(
|
||||||
|
color: color ?? appStyle.colors.card,
|
||||||
|
shadowColor: isLight && shadow ? null : Colors.transparent,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
topLeft: Radius.circular(
|
||||||
|
attached == Attach.top ? attachedRounding : defaultRounding,
|
||||||
|
),
|
||||||
|
topRight: Radius.circular(
|
||||||
|
attached == Attach.top ? attachedRounding : defaultRounding,
|
||||||
|
),
|
||||||
|
bottomLeft: Radius.circular(
|
||||||
|
attached == Attach.bottom
|
||||||
|
? attachedRounding
|
||||||
|
: defaultRounding,
|
||||||
|
),
|
||||||
|
bottomRight: Radius.circular(
|
||||||
|
attached == Attach.bottom
|
||||||
|
? attachedRounding
|
||||||
|
: defaultRounding,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(12.0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Row(children: left),
|
||||||
|
Row(children: center ?? []),
|
||||||
|
Row(children: right),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
52
firka_common/lib/ui/components/firka_shadow.dart
Normal file
52
firka_common/lib/ui/components/firka_shadow.dart
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:firka_common/ui/theme/style.dart';
|
||||||
|
|
||||||
|
class FirkaShadow extends StatelessWidget {
|
||||||
|
final Widget child;
|
||||||
|
final bool shadow;
|
||||||
|
final double radius;
|
||||||
|
final bool? isLightMode;
|
||||||
|
|
||||||
|
const FirkaShadow({
|
||||||
|
required this.shadow,
|
||||||
|
required this.child,
|
||||||
|
this.radius = 16.0,
|
||||||
|
this.isLightMode,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final isLight =
|
||||||
|
isLightMode ?? Theme.of(context).brightness == Brightness.light;
|
||||||
|
final borderRadius = BorderRadius.circular(radius);
|
||||||
|
|
||||||
|
final shadowBox = BoxDecoration(
|
||||||
|
color: Colors.transparent,
|
||||||
|
shape: BoxShape.rectangle,
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: appStyle.colors.shadowColor,
|
||||||
|
spreadRadius: -4,
|
||||||
|
blurRadius: 0,
|
||||||
|
offset: const Offset(0, 2),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(radius)),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!shadow) {
|
||||||
|
return ClipRRect(borderRadius: borderRadius, child: child);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLight) {
|
||||||
|
return child;
|
||||||
|
} else {
|
||||||
|
return Container(
|
||||||
|
decoration: shadowBox,
|
||||||
|
child: ClipRRect(borderRadius: borderRadius, child: child),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
97
firka_common/lib/ui/components/grade.dart
Normal file
97
firka_common/lib/ui/components/grade.dart
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:kreta_api/kreta_api.dart';
|
||||||
|
|
||||||
|
import 'package:firka_common/ui/components/grade_helpers.dart';
|
||||||
|
import 'package:firka_common/ui/theme/style.dart';
|
||||||
|
|
||||||
|
class GradeWidget extends StatelessWidget {
|
||||||
|
const GradeWidget(this.grade, {super.key})
|
||||||
|
: gradeValue = null,
|
||||||
|
_fromValue = false;
|
||||||
|
|
||||||
|
const GradeWidget.gradeValue(int value, {super.key})
|
||||||
|
: grade = null,
|
||||||
|
gradeValue = value,
|
||||||
|
_fromValue = true;
|
||||||
|
|
||||||
|
final Grade? grade;
|
||||||
|
final int? gradeValue;
|
||||||
|
final bool _fromValue;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (_fromValue && gradeValue != null) {
|
||||||
|
return _buildNumericCircle(
|
||||||
|
gradeValue!,
|
||||||
|
getGradeColor(gradeValue!.toDouble()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final g = grade!;
|
||||||
|
Color gradeColor = appStyle.colors.grade1;
|
||||||
|
final gradeStr = g.numericValue?.toString() ?? '0';
|
||||||
|
|
||||||
|
if (g.valueType.name == 'Szazalekos') {
|
||||||
|
if (g.numericValue != null) {
|
||||||
|
gradeColor = getGradeColor(
|
||||||
|
percentageToGrade(g.numericValue!).toDouble(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final str = g.strValue.replaceAll('%', '');
|
||||||
|
return Card(
|
||||||
|
shape: const CircleBorder(),
|
||||||
|
shadowColor: Colors.transparent,
|
||||||
|
color: gradeColor.withAlpha(38),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(8),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Text(str, style: appStyle.fonts.P_14.copyWith(color: gradeColor)),
|
||||||
|
Text('%', style: appStyle.fonts.P_12.copyWith(color: gradeColor)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g.numericValue != null) {
|
||||||
|
gradeColor = getGradeColor(g.numericValue!.toDouble());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gradeStr == '0') {
|
||||||
|
return Card(
|
||||||
|
shadowColor: Colors.transparent,
|
||||||
|
color: gradeColor.withAlpha(38),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 8, right: 8, top: 2, bottom: 2),
|
||||||
|
child: Text(
|
||||||
|
g.strValue,
|
||||||
|
style: appStyle.fonts.H_H1.copyWith(
|
||||||
|
fontSize: 16,
|
||||||
|
color: gradeColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _buildNumericCircle(g.numericValue!, gradeColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildNumericCircle(int value, Color gradeColor) {
|
||||||
|
return Card(
|
||||||
|
shape: const CircleBorder(),
|
||||||
|
shadowColor: Colors.transparent,
|
||||||
|
color: gradeColor.withAlpha(38),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 8, right: 8),
|
||||||
|
child: Text(
|
||||||
|
value.toString(),
|
||||||
|
style: appStyle.fonts.H_H1.copyWith(fontSize: 24, color: gradeColor),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
100
firka_common/lib/ui/components/grade_helpers.dart
Normal file
100
firka_common/lib/ui/components/grade_helpers.dart
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
|
import 'package:firka_common/ui/theme/style.dart';
|
||||||
|
import 'package:kreta_api/kreta_api.dart';
|
||||||
|
|
||||||
|
int roundGrade(
|
||||||
|
double grade, {
|
||||||
|
double t1 = 1,
|
||||||
|
double t2 = 0.5,
|
||||||
|
double t3 = 0.5,
|
||||||
|
double t4 = 0.5,
|
||||||
|
}) {
|
||||||
|
if (grade < 1 + t1) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (grade < 2 + t2) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
if (grade < 3 + t3) {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
if (grade < 4 + t4) {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
int percentageToGrade(int grade) {
|
||||||
|
if (grade < 50) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (grade < 60) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
if (grade < 70) {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
if (grade < 80) {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
Color getGradeColor(
|
||||||
|
double grade, {
|
||||||
|
double t1 = 1,
|
||||||
|
double t2 = 0.5,
|
||||||
|
double t3 = 0.5,
|
||||||
|
double t4 = 0.5,
|
||||||
|
}) {
|
||||||
|
switch (roundGrade(grade, t1: t1, t2: t2, t3: t3, t4: t4)) {
|
||||||
|
case 2:
|
||||||
|
return appStyle.colors.grade2;
|
||||||
|
case 3:
|
||||||
|
return appStyle.colors.grade3;
|
||||||
|
case 4:
|
||||||
|
return appStyle.colors.grade4;
|
||||||
|
case 5:
|
||||||
|
return appStyle.colors.grade5;
|
||||||
|
default:
|
||||||
|
return appStyle.colors.grade1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(int total, List<int> countsByGrade) getGradeDistribution(List<Grade> grades) {
|
||||||
|
final filtered = grades
|
||||||
|
.where((g) => g.type.name != "felevi_jegy_ertekeles")
|
||||||
|
.toList();
|
||||||
|
final counts = [0, 0, 0, 0, 0];
|
||||||
|
for (final g in filtered) {
|
||||||
|
if (g.numericValue == null) continue;
|
||||||
|
final value = g.valueType.name == "Szazalekos"
|
||||||
|
? percentageToGrade(g.numericValue!.round())
|
||||||
|
: g.numericValue!.round().clamp(1, 5);
|
||||||
|
counts[value - 1]++;
|
||||||
|
}
|
||||||
|
return (filtered.length, counts);
|
||||||
|
}
|
||||||
|
|
||||||
|
extension GradeListExtension on List<Grade> {
|
||||||
|
double getAverageBySubject(Subject subject) {
|
||||||
|
var weightTotal = 0.00;
|
||||||
|
var sum = 0.00;
|
||||||
|
|
||||||
|
for (var grade in this) {
|
||||||
|
if (grade.subject.uid == subject.uid) {
|
||||||
|
if (grade.numericValue != null) {
|
||||||
|
var weight = (grade.weightPercentage ?? 100) / 100.0;
|
||||||
|
weightTotal += weight;
|
||||||
|
|
||||||
|
sum += grade.numericValue! * weight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sum / weightTotal;
|
||||||
|
}
|
||||||
|
}
|
||||||
35
firka_common/lib/ui/shared/class_icon.dart
Normal file
35
firka_common/lib/ui/shared/class_icon.dart
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:firka_common/core/icon_helper.dart';
|
||||||
|
import 'package:firka_common/ui/shared/firka_icon.dart';
|
||||||
|
|
||||||
|
class ClassIconWidget extends StatelessWidget {
|
||||||
|
final String _uid;
|
||||||
|
final String _className;
|
||||||
|
final String _category;
|
||||||
|
final Color color;
|
||||||
|
final double? size;
|
||||||
|
|
||||||
|
const ClassIconWidget({
|
||||||
|
super.key,
|
||||||
|
required String uid,
|
||||||
|
required String className,
|
||||||
|
required String category,
|
||||||
|
this.color = Colors.white,
|
||||||
|
this.size,
|
||||||
|
}) : _className = className,
|
||||||
|
_uid = uid,
|
||||||
|
_category = category;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
var iconCategory = getIconType(_uid, _className, _category);
|
||||||
|
|
||||||
|
return FirkaIconWidget(
|
||||||
|
FirkaIconType.majesticons,
|
||||||
|
getIconData(iconCategory),
|
||||||
|
color: color,
|
||||||
|
size: size,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
22
firka_common/lib/ui/shared/counter_digit.dart
Normal file
22
firka_common/lib/ui/shared/counter_digit.dart
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:firka_common/ui/theme/style.dart';
|
||||||
|
|
||||||
|
class CounterDigitWidget extends StatelessWidget {
|
||||||
|
final String c;
|
||||||
|
final TextStyle? style;
|
||||||
|
|
||||||
|
const CounterDigitWidget(this.c, this.style, {super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Card(
|
||||||
|
shadowColor: Colors.transparent,
|
||||||
|
color: appStyle.colors.buttonSecondaryFill,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 8, right: 8, top: 4, bottom: 4),
|
||||||
|
child: Text(c, style: style),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
48
firka_common/lib/ui/shared/delayed_spinner.dart
Normal file
48
firka_common/lib/ui/shared/delayed_spinner.dart
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:firka_common/ui/theme/style.dart';
|
||||||
|
|
||||||
|
class DelayedSpinnerWidget extends StatefulWidget {
|
||||||
|
final Color? color;
|
||||||
|
|
||||||
|
const DelayedSpinnerWidget({super.key, this.color});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<DelayedSpinnerWidget> createState() => _DelayedSpinner();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DelayedSpinner extends State<DelayedSpinnerWidget> {
|
||||||
|
Timer? timer;
|
||||||
|
bool showSpinner = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
timer = Timer(const Duration(milliseconds: 50), () {
|
||||||
|
setState(() {
|
||||||
|
showSpinner = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (showSpinner) {
|
||||||
|
return CircularProgressIndicator(
|
||||||
|
color: widget.color ?? appStyle.colors.accent,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return const SizedBox();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
|
||||||
|
timer?.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
46
firka_common/lib/ui/shared/firka_icon.dart
Normal file
46
firka_common/lib/ui/shared/firka_icon.dart
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
import 'package:majesticons_flutter/majesticons_flutter.dart';
|
||||||
|
|
||||||
|
enum FirkaIconType { icons, majesticons, majesticonsLocal }
|
||||||
|
|
||||||
|
class FirkaIconWidget extends StatelessWidget {
|
||||||
|
final FirkaIconType iconType;
|
||||||
|
final Object iconData;
|
||||||
|
final Color color;
|
||||||
|
final double? size;
|
||||||
|
final String? package;
|
||||||
|
|
||||||
|
const FirkaIconWidget(
|
||||||
|
this.iconType,
|
||||||
|
this.iconData, {
|
||||||
|
super.key,
|
||||||
|
this.color = Colors.white,
|
||||||
|
this.size,
|
||||||
|
this.package,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
switch (iconType) {
|
||||||
|
case FirkaIconType.icons:
|
||||||
|
return SvgPicture.asset(
|
||||||
|
'assets/icons/${iconData as String}.svg',
|
||||||
|
color: color,
|
||||||
|
height: size,
|
||||||
|
package: package,
|
||||||
|
);
|
||||||
|
case FirkaIconType.majesticons:
|
||||||
|
return Majesticon(iconData as Uint8List, color: color, size: size);
|
||||||
|
case FirkaIconType.majesticonsLocal:
|
||||||
|
return SvgPicture.asset(
|
||||||
|
'assets/majesticons/${iconData as String}.svg',
|
||||||
|
color: color,
|
||||||
|
height: size,
|
||||||
|
package: package,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
60
firka_common/lib/ui/shared/grade_small_card.dart
Normal file
60
firka_common/lib/ui/shared/grade_small_card.dart
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:kreta_api/kreta_api.dart';
|
||||||
|
|
||||||
|
import 'package:firka_common/ui/components/firka_card.dart';
|
||||||
|
import 'package:firka_common/ui/components/grade_helpers.dart';
|
||||||
|
import 'package:firka_common/ui/shared/class_icon.dart';
|
||||||
|
import 'package:firka_common/ui/theme/style.dart';
|
||||||
|
|
||||||
|
class GradeSmallCard extends FirkaCard {
|
||||||
|
final List<Grade> grades;
|
||||||
|
final Subject subject;
|
||||||
|
|
||||||
|
GradeSmallCard(this.grades, this.subject, {super.key})
|
||||||
|
: super(
|
||||||
|
left: [
|
||||||
|
ClassIconWidget(
|
||||||
|
uid: subject.uid,
|
||||||
|
className: subject.name,
|
||||||
|
category: subject.category.name!,
|
||||||
|
color: appStyle.colors.accent,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
SizedBox(
|
||||||
|
width: 200,
|
||||||
|
child: Text(
|
||||||
|
subject.name,
|
||||||
|
style: appStyle.fonts.B_16SB.apply(
|
||||||
|
color: appStyle.colors.textPrimary,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
right: [
|
||||||
|
grades.getAverageBySubject(subject).isNaN
|
||||||
|
? const SizedBox()
|
||||||
|
: Card(
|
||||||
|
shadowColor: Colors.transparent,
|
||||||
|
color: getGradeColor(
|
||||||
|
grades.getAverageBySubject(subject),
|
||||||
|
).withAlpha(38),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
left: 8,
|
||||||
|
right: 8,
|
||||||
|
top: 4,
|
||||||
|
bottom: 4,
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
grades.getAverageBySubject(subject).toStringAsFixed(2),
|
||||||
|
style: appStyle.fonts.B_16SB.apply(
|
||||||
|
color: getGradeColor(
|
||||||
|
grades.getAverageBySubject(subject),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
309
firka_common/lib/ui/theme/style.dart
Normal file
309
firka_common/lib/ui/theme/style.dart
Normal file
@@ -0,0 +1,309 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
// Design system token names; ignore non_constant_identifier_names for consistency with design specs
|
||||||
|
// ignore_for_file: non_constant_identifier_names
|
||||||
|
|
||||||
|
class FirkaFonts {
|
||||||
|
TextStyle H_H1;
|
||||||
|
TextStyle H_18px;
|
||||||
|
TextStyle H_H2;
|
||||||
|
TextStyle H_16px;
|
||||||
|
TextStyle H_14px;
|
||||||
|
TextStyle H_12px;
|
||||||
|
|
||||||
|
TextStyle H_16px_trimmed;
|
||||||
|
|
||||||
|
TextStyle B_16R;
|
||||||
|
TextStyle B_16SB;
|
||||||
|
TextStyle B_15SB;
|
||||||
|
|
||||||
|
TextStyle B_14R;
|
||||||
|
TextStyle B_14SB;
|
||||||
|
|
||||||
|
TextStyle B_12R;
|
||||||
|
TextStyle B_12SB;
|
||||||
|
|
||||||
|
TextStyle P_14;
|
||||||
|
TextStyle P_12;
|
||||||
|
|
||||||
|
FirkaFonts({
|
||||||
|
required this.H_H1,
|
||||||
|
required this.H_18px,
|
||||||
|
required this.H_H2,
|
||||||
|
required this.H_16px,
|
||||||
|
required this.H_14px,
|
||||||
|
required this.H_12px,
|
||||||
|
required this.H_16px_trimmed,
|
||||||
|
required this.B_16R,
|
||||||
|
required this.B_16SB,
|
||||||
|
required this.B_15SB,
|
||||||
|
required this.B_14R,
|
||||||
|
required this.B_14SB,
|
||||||
|
required this.B_12R,
|
||||||
|
required this.B_12SB,
|
||||||
|
required this.P_14,
|
||||||
|
required this.P_12,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class FirkaColors {
|
||||||
|
Color background;
|
||||||
|
Color backgroundAmoled;
|
||||||
|
Color background0p;
|
||||||
|
Color success;
|
||||||
|
int shadowBlur;
|
||||||
|
|
||||||
|
Color textPrimary;
|
||||||
|
Color textSecondary;
|
||||||
|
Color textTertiary;
|
||||||
|
|
||||||
|
Color textPrimaryLight;
|
||||||
|
Color textSecondaryLight;
|
||||||
|
Color textTertiaryLight;
|
||||||
|
|
||||||
|
Color card;
|
||||||
|
Color cardTranslucent;
|
||||||
|
|
||||||
|
Color buttonSecondaryFill;
|
||||||
|
|
||||||
|
Color accent;
|
||||||
|
Color secondary;
|
||||||
|
Color shadowColor;
|
||||||
|
Color a10p; // 10%
|
||||||
|
Color a15p; // 15%
|
||||||
|
|
||||||
|
Color warningAccent;
|
||||||
|
Color warningText;
|
||||||
|
Color warning15p;
|
||||||
|
Color warningCard;
|
||||||
|
|
||||||
|
Color errorAccent;
|
||||||
|
Color errorText;
|
||||||
|
Color error15p;
|
||||||
|
Color errorCard;
|
||||||
|
|
||||||
|
Color grade5;
|
||||||
|
Color grade4;
|
||||||
|
Color grade3;
|
||||||
|
Color grade2;
|
||||||
|
Color grade1;
|
||||||
|
|
||||||
|
FirkaColors({
|
||||||
|
required this.background,
|
||||||
|
required this.backgroundAmoled,
|
||||||
|
required this.background0p,
|
||||||
|
required this.success,
|
||||||
|
required this.shadowBlur,
|
||||||
|
required this.textPrimary,
|
||||||
|
required this.textSecondary,
|
||||||
|
required this.textTertiary,
|
||||||
|
required this.textPrimaryLight,
|
||||||
|
required this.textSecondaryLight,
|
||||||
|
required this.textTertiaryLight,
|
||||||
|
required this.card,
|
||||||
|
required this.cardTranslucent,
|
||||||
|
required this.buttonSecondaryFill,
|
||||||
|
required this.accent,
|
||||||
|
required this.secondary,
|
||||||
|
required this.shadowColor,
|
||||||
|
required this.a10p,
|
||||||
|
required this.a15p,
|
||||||
|
required this.warningAccent,
|
||||||
|
required this.warningText,
|
||||||
|
required this.warning15p,
|
||||||
|
required this.warningCard,
|
||||||
|
required this.errorAccent,
|
||||||
|
required this.errorText,
|
||||||
|
required this.error15p,
|
||||||
|
required this.errorCard,
|
||||||
|
required this.grade5,
|
||||||
|
required this.grade4,
|
||||||
|
required this.grade3,
|
||||||
|
required this.grade2,
|
||||||
|
required this.grade1,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class FirkaStyle {
|
||||||
|
FirkaColors colors;
|
||||||
|
FirkaFonts fonts;
|
||||||
|
bool isLight;
|
||||||
|
|
||||||
|
FirkaStyle({
|
||||||
|
required this.isLight,
|
||||||
|
required this.colors,
|
||||||
|
required this.fonts,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
final _defaultFonts = FirkaFonts(
|
||||||
|
H_H1: TextStyle(
|
||||||
|
fontSize: 30,
|
||||||
|
fontFamily: 'Montserrat',
|
||||||
|
fontVariations: [FontVariation("wght", 700)],
|
||||||
|
),
|
||||||
|
H_18px: TextStyle(
|
||||||
|
fontSize: 18,
|
||||||
|
fontFamily: 'Montserrat',
|
||||||
|
fontVariations: [FontVariation("wght", 700)],
|
||||||
|
),
|
||||||
|
H_H2: TextStyle(
|
||||||
|
fontSize: 20,
|
||||||
|
fontFamily: 'Montserrat',
|
||||||
|
fontVariations: [FontVariation("wght", 700)],
|
||||||
|
),
|
||||||
|
H_16px: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontFamily: 'Montserrat',
|
||||||
|
fontVariations: [FontVariation("wght", 600)],
|
||||||
|
),
|
||||||
|
H_14px: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
fontFamily: 'Montserrat',
|
||||||
|
fontVariations: [FontVariation("wght", 600)],
|
||||||
|
),
|
||||||
|
H_12px: TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
fontFamily: 'Montserrat',
|
||||||
|
fontVariations: [FontVariation("wght", 600)],
|
||||||
|
),
|
||||||
|
H_16px_trimmed: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontFamily: 'Montserrat',
|
||||||
|
fontVariations: [FontVariation("wght", 600)],
|
||||||
|
height: 1.3,
|
||||||
|
),
|
||||||
|
B_16R: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontFamily: 'Figtree',
|
||||||
|
fontVariations: [FontVariation("wght", 600)],
|
||||||
|
height: 1.3,
|
||||||
|
),
|
||||||
|
B_16SB: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontFamily: 'Figtree',
|
||||||
|
fontVariations: [FontVariation("wght", 700)],
|
||||||
|
height: 1.3,
|
||||||
|
),
|
||||||
|
B_14R: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
fontFamily: 'Figtree',
|
||||||
|
fontVariations: [FontVariation("wght", 600)],
|
||||||
|
height: 1.3,
|
||||||
|
),
|
||||||
|
B_14SB: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
fontFamily: 'Figtree',
|
||||||
|
fontVariations: [FontVariation("wght", 700)],
|
||||||
|
height: 1.3,
|
||||||
|
),
|
||||||
|
B_15SB: TextStyle(
|
||||||
|
fontSize: 15,
|
||||||
|
fontFamily: 'Figtree',
|
||||||
|
fontVariations: [FontVariation("wght", 700)],
|
||||||
|
height: 1.3,
|
||||||
|
),
|
||||||
|
B_12R: TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
fontFamily: 'Figtree',
|
||||||
|
fontVariations: [FontVariation("wght", 600)],
|
||||||
|
height: 1.3,
|
||||||
|
),
|
||||||
|
B_12SB: TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
fontFamily: 'Figtree',
|
||||||
|
fontVariations: [FontVariation("wght", 700)],
|
||||||
|
height: 1.3,
|
||||||
|
),
|
||||||
|
P_14: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
fontFamily: 'RobotoMono',
|
||||||
|
fontVariations: [FontVariation("wght", 700)],
|
||||||
|
),
|
||||||
|
P_12: TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
fontFamily: 'RobotoMono',
|
||||||
|
fontVariations: [FontVariation("wght", 700)],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final FirkaStyle lightStyle = FirkaStyle(
|
||||||
|
isLight: true,
|
||||||
|
colors: FirkaColors(
|
||||||
|
background: Color(0xFFFAFFF0),
|
||||||
|
backgroundAmoled: Colors.black,
|
||||||
|
background0p: Color(0x00fafff0),
|
||||||
|
success: Color(0xFF92EA3B),
|
||||||
|
shadowBlur: 2,
|
||||||
|
textPrimary: Color(0xFF394C0A),
|
||||||
|
textSecondary: Color(0xCC394C0A),
|
||||||
|
textTertiary: Color(0x80394C0A),
|
||||||
|
textPrimaryLight: Color(0xFF394C0A),
|
||||||
|
textSecondaryLight: Color(0xCC394C0A),
|
||||||
|
textTertiaryLight: Color(0x80394C0A),
|
||||||
|
card: Color(0xFFF3FBDE),
|
||||||
|
cardTranslucent: Color(0x80F3FBDE),
|
||||||
|
buttonSecondaryFill: Color(0xFFFEFFFD),
|
||||||
|
accent: Color(0xFFA7DC22),
|
||||||
|
secondary: Color(0xFF6E8F1B),
|
||||||
|
shadowColor: Color(0x33647e22),
|
||||||
|
a10p: Color(0x1aa7dc22),
|
||||||
|
a15p: Color(0x26a7dc22),
|
||||||
|
warningAccent: Color(0xFFFFA046),
|
||||||
|
warningText: Color(0xFF8F531B),
|
||||||
|
warning15p: Color(0x26FFA046),
|
||||||
|
warningCard: Color(0xFFFAEBDC),
|
||||||
|
errorAccent: Color(0xFFFF54A1),
|
||||||
|
errorText: Color(0xFF8F1B4F),
|
||||||
|
error15p: Color(0x26FF54A1),
|
||||||
|
errorCard: Color(0xFFFADCE9),
|
||||||
|
grade5: Color(0xFF22CCAD),
|
||||||
|
grade4: Color(0xFF92EA3B),
|
||||||
|
grade3: Color(0xFFF9CF00),
|
||||||
|
grade2: Color(0xFFFFA046),
|
||||||
|
grade1: Color(0xFFFF54A1),
|
||||||
|
),
|
||||||
|
fonts: _defaultFonts,
|
||||||
|
);
|
||||||
|
|
||||||
|
final FirkaStyle darkStyle = FirkaStyle(
|
||||||
|
isLight: false,
|
||||||
|
colors: FirkaColors(
|
||||||
|
background: Color(0xFF0D1202),
|
||||||
|
backgroundAmoled: Colors.black,
|
||||||
|
background0p: Color(0x00fafff0),
|
||||||
|
success: Color(0xFF92EA3B),
|
||||||
|
shadowBlur: 0,
|
||||||
|
textPrimary: Color(0xFFEAF7CC),
|
||||||
|
textSecondary: Color(0xB3EAF7CC),
|
||||||
|
textTertiary: Color(0x80EAF7CC),
|
||||||
|
textPrimaryLight: Color(0xFF394C0A),
|
||||||
|
textSecondaryLight: Color(0xCC394C0A),
|
||||||
|
textTertiaryLight: Color(0x80394C0A),
|
||||||
|
card: Color(0xFF141905),
|
||||||
|
cardTranslucent: Color(0x80141905),
|
||||||
|
buttonSecondaryFill: Color(0xFF20290B),
|
||||||
|
accent: Color(0xFFA7DC22),
|
||||||
|
secondary: Color(0xFFCBEE71),
|
||||||
|
shadowColor: Color(0x26CBEE71),
|
||||||
|
a10p: Color(0x1AA7DC22),
|
||||||
|
a15p: Color(0x26A7DC22),
|
||||||
|
warningAccent: Color(0xFFFFA046),
|
||||||
|
warningText: Color(0xFFF0B37A),
|
||||||
|
warning15p: Color(0x26FFA046),
|
||||||
|
warningCard: Color(0xFF201203),
|
||||||
|
errorAccent: Color(0xFFFF54A1),
|
||||||
|
errorText: Color(0xFFF59EC5),
|
||||||
|
error15p: Color(0x26FF54A1),
|
||||||
|
errorCard: Color(0xFF1E030F),
|
||||||
|
grade5: Color(0xFF22CCAD),
|
||||||
|
grade4: Color(0xFF92EA3B),
|
||||||
|
grade3: Color(0xFFF9CF00),
|
||||||
|
grade2: Color(0xFFFFA046),
|
||||||
|
grade1: Color(0xFFFF54A1),
|
||||||
|
),
|
||||||
|
fonts: _defaultFonts,
|
||||||
|
);
|
||||||
|
|
||||||
|
FirkaStyle appStyle = lightStyle;
|
||||||
|
FirkaStyle wearStyle = darkStyle;
|
||||||
21
firka_common/pubspec.yaml
Normal file
21
firka_common/pubspec.yaml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
name: firka_common
|
||||||
|
description: Shared widgets, data structures, and helpers for firka and firka_wear.
|
||||||
|
publish_to: "none"
|
||||||
|
version: 0.1.0
|
||||||
|
|
||||||
|
environment:
|
||||||
|
sdk: ^3.11.0
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
flutter:
|
||||||
|
sdk: flutter
|
||||||
|
kreta_api:
|
||||||
|
path: ../kreta_api
|
||||||
|
majesticons_flutter: ^0.0.1
|
||||||
|
flutter_svg: ^1.1.6
|
||||||
|
intl: any
|
||||||
|
|
||||||
|
dev_dependencies:
|
||||||
|
flutter_test:
|
||||||
|
sdk: flutter
|
||||||
|
flutter_lints: ^6.0.0
|
||||||
@@ -1,17 +1 @@
|
|||||||
DateTime? debugFakeTime;
|
export 'package:firka_common/core/debug_helper.dart';
|
||||||
DateTime? debugSetAt;
|
|
||||||
var debugTimeAdvance = false;
|
|
||||||
|
|
||||||
DateTime timeNow() {
|
|
||||||
if (debugFakeTime != null) {
|
|
||||||
if (debugTimeAdvance && debugSetAt != null) {
|
|
||||||
var diff = DateTime.now().difference(debugSetAt!);
|
|
||||||
|
|
||||||
return debugFakeTime!.add(diff);
|
|
||||||
} else {
|
|
||||||
return debugFakeTime!;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return DateTime.now();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -3,27 +3,10 @@ import 'package:intl/intl.dart';
|
|||||||
|
|
||||||
import 'package:firka_wear/core/debug_helper.dart';
|
import 'package:firka_wear/core/debug_helper.dart';
|
||||||
import 'package:firka_wear/l10n/app_localizations.dart';
|
import 'package:firka_wear/l10n/app_localizations.dart';
|
||||||
|
import 'package:firka_common/core/extensions.dart';
|
||||||
import 'package:kreta_api/kreta_api.dart';
|
import 'package:kreta_api/kreta_api.dart';
|
||||||
|
|
||||||
extension IterableExtensionMap on Iterable<MapEntry<String, dynamic>> {
|
export 'package:firka_common/core/extensions.dart';
|
||||||
Map<String, dynamic> toMap() {
|
|
||||||
var map = <String, dynamic>{};
|
|
||||||
for (var item in this) {
|
|
||||||
map[item.key] = item.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension IterableExtension<T> on Iterable<T> {
|
|
||||||
T? firstWhereOrNull(bool Function(T element) test) {
|
|
||||||
for (var element in this) {
|
|
||||||
if (test(element)) return element;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension DurationExtension on Duration {
|
extension DurationExtension on Duration {
|
||||||
String formatDuration() {
|
String formatDuration() {
|
||||||
|
|||||||
@@ -1,152 +1 @@
|
|||||||
import 'dart:typed_data';
|
export 'package:firka_common/core/icon_helper.dart';
|
||||||
|
|
||||||
import 'package:majesticons_flutter/majesticons_flutter.dart';
|
|
||||||
|
|
||||||
enum ClassIcon {
|
|
||||||
mathematics,
|
|
||||||
grammar,
|
|
||||||
literature,
|
|
||||||
history,
|
|
||||||
geography,
|
|
||||||
art,
|
|
||||||
physics,
|
|
||||||
music,
|
|
||||||
pe,
|
|
||||||
chemistry,
|
|
||||||
biology,
|
|
||||||
env,
|
|
||||||
religion,
|
|
||||||
economics,
|
|
||||||
it,
|
|
||||||
code,
|
|
||||||
networking,
|
|
||||||
theatre,
|
|
||||||
film,
|
|
||||||
electricalEngineering,
|
|
||||||
mechanicalEngineering,
|
|
||||||
technika,
|
|
||||||
dance,
|
|
||||||
philosophy,
|
|
||||||
ofo,
|
|
||||||
diligence,
|
|
||||||
attitude,
|
|
||||||
language,
|
|
||||||
linux,
|
|
||||||
database,
|
|
||||||
applications,
|
|
||||||
project,
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<ClassIcon, RegExp> _descriptors = {
|
|
||||||
ClassIcon.mathematics: RegExp(r'mate(k|matika)'),
|
|
||||||
ClassIcon.grammar: RegExp(r'magyar nyelv|nyelvtan'),
|
|
||||||
ClassIcon.literature: RegExp(r'irodalom'),
|
|
||||||
ClassIcon.history: RegExp(r'tor(i|tenelem)'),
|
|
||||||
ClassIcon.geography: RegExp(r'foldrajz'),
|
|
||||||
ClassIcon.art: RegExp(r'rajz|muvtori|muveszet|vizualis'),
|
|
||||||
ClassIcon.physics: RegExp(r'fizika'),
|
|
||||||
ClassIcon.music: RegExp(r'^enek|zene|szolfezs|zongora|korus'),
|
|
||||||
ClassIcon.pe: RegExp(r'^tes(i|tneveles)|sport|edzeselmelet'),
|
|
||||||
ClassIcon.chemistry: RegExp(r'kemia'),
|
|
||||||
ClassIcon.biology: RegExp(r'biologia'),
|
|
||||||
ClassIcon.env: RegExp(
|
|
||||||
r'kornyezet|termeszet ?(tudomany|ismeret)|hon( es nep)?ismeret',
|
|
||||||
),
|
|
||||||
ClassIcon.religion: RegExp(r'(hit|erkolcs)tan|vallas|etika|bibliaismeret'),
|
|
||||||
ClassIcon.economics: RegExp(r'penzugy|gazdasag'),
|
|
||||||
ClassIcon.it: RegExp(r'informatika|szoftver|iroda|digitalis'),
|
|
||||||
ClassIcon.code: RegExp(r'prog|alkalmazas'),
|
|
||||||
ClassIcon.networking: RegExp(r'halozat'),
|
|
||||||
ClassIcon.theatre: RegExp(r'szinhaz'),
|
|
||||||
ClassIcon.film: RegExp(r'film|media'),
|
|
||||||
ClassIcon.electricalEngineering: RegExp(r'elektro(tech)?nika'),
|
|
||||||
ClassIcon.mechanicalEngineering: RegExp(r'gepesz|mernok|ipar'),
|
|
||||||
ClassIcon.technika: RegExp(r'technika'),
|
|
||||||
ClassIcon.dance: RegExp(r'tanc'),
|
|
||||||
ClassIcon.philosophy: RegExp(r'filozofia'),
|
|
||||||
ClassIcon.ofo: RegExp(r'osztaly(fonoki|kozosseg)|kozossegi|neveles'),
|
|
||||||
ClassIcon.diligence: RegExp(r'szorgalom'),
|
|
||||||
ClassIcon.attitude: RegExp(r'magatartas'),
|
|
||||||
ClassIcon.language: RegExp(
|
|
||||||
r'angol|nemet|francia|olasz|orosz|spanyol|latin|kinai|nyelv',
|
|
||||||
),
|
|
||||||
ClassIcon.linux: RegExp(r'linux'),
|
|
||||||
ClassIcon.database: RegExp(r'adatbazis.*'),
|
|
||||||
ClassIcon.applications: RegExp(r'asztali alkalmazasok'),
|
|
||||||
ClassIcon.project: RegExp(r'projekt'),
|
|
||||||
};
|
|
||||||
|
|
||||||
Map<ClassIcon, Uint8List> _iconMap = {
|
|
||||||
ClassIcon.mathematics: Majesticon.calculatorSolid,
|
|
||||||
ClassIcon.grammar: Majesticon.bookSolid,
|
|
||||||
ClassIcon.literature: Majesticon.bookOpenSolid,
|
|
||||||
ClassIcon.history: Majesticon.compass2Solid,
|
|
||||||
ClassIcon.geography: Majesticon.globeEarth2Solid,
|
|
||||||
ClassIcon.art: Majesticon.editPen2Solid,
|
|
||||||
// ClassIcon.physics: ,
|
|
||||||
ClassIcon.music: Majesticon.musicNoteSolid,
|
|
||||||
// ClassIcon.pe: ,
|
|
||||||
ClassIcon.chemistry: Majesticon.testTubeFilledSolid,
|
|
||||||
ClassIcon.biology: Majesticon.covidSolid,
|
|
||||||
// ClassIcon.env: ,
|
|
||||||
// ClassIcon.religion: ,
|
|
||||||
// ClassIcon.economics: ,
|
|
||||||
ClassIcon.it: Majesticon.laptopSolid,
|
|
||||||
ClassIcon.code: Majesticon.curlyBracesSolid,
|
|
||||||
ClassIcon.networking: Majesticon.cloudSolid,
|
|
||||||
// ClassIcon.theatre: ,
|
|
||||||
// ClassIcon.film: ,
|
|
||||||
// ClassIcon.electricalEngineering: ,
|
|
||||||
// ClassIcon.mechanicalEngineering: ,
|
|
||||||
ClassIcon.technika: Majesticon.ruler2Solid,
|
|
||||||
// ClassIcon.dance: ,
|
|
||||||
// ClassIcon.philosophy: ,
|
|
||||||
// ClassIcon.ofo: ,
|
|
||||||
// ClassIcon.diligence: ,
|
|
||||||
// ClassIcon.attitude: ,
|
|
||||||
ClassIcon.language: Majesticon.tooltipsSolid,
|
|
||||||
// ClassIcon.linux: ,
|
|
||||||
ClassIcon.database: Majesticon.dataSolid,
|
|
||||||
// ClassIcon.applications: ,
|
|
||||||
// ClassIcon.project: ,
|
|
||||||
};
|
|
||||||
|
|
||||||
ClassIcon? getIconType(String uid, String className, String category) {
|
|
||||||
ClassIcon? icon;
|
|
||||||
if (category.toLowerCase() == "matematika") {
|
|
||||||
icon = ClassIcon.mathematics;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (icon == null) {
|
|
||||||
for (var desc in _descriptors.entries) {
|
|
||||||
if (desc.value.hasMatch(
|
|
||||||
className
|
|
||||||
.replaceAll("ö", "o")
|
|
||||||
.replaceAll("ü", "u")
|
|
||||||
.replaceAll("ó", "o")
|
|
||||||
.replaceAll("ő", "o")
|
|
||||||
.replaceAll("ú", "u")
|
|
||||||
.replaceAll("é", "e")
|
|
||||||
.replaceAll("á", "a")
|
|
||||||
.replaceAll("ű", "u")
|
|
||||||
.replaceAll("í", "i")
|
|
||||||
.toLowerCase(),
|
|
||||||
)) {
|
|
||||||
icon = desc.key;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return icon;
|
|
||||||
}
|
|
||||||
|
|
||||||
Uint8List getIconData(ClassIcon? icon) {
|
|
||||||
if (icon == null) return Majesticon.alertCircleSolid;
|
|
||||||
|
|
||||||
var iconData = _iconMap[icon];
|
|
||||||
iconData ??= Majesticon.alertCircleSolid;
|
|
||||||
|
|
||||||
return iconData;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,9 +1 @@
|
|||||||
List<T> listToTyped<T>(List<dynamic> dynamicList) {
|
export 'package:firka_common/core/json_helper.dart';
|
||||||
var newList = List<T>.empty(growable: true);
|
|
||||||
|
|
||||||
for (var item in dynamicList) {
|
|
||||||
newList.add(item as T);
|
|
||||||
}
|
|
||||||
|
|
||||||
return newList;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ Future<void> resetOldHomeworkCache(Isar isar) async {
|
|||||||
var date = getDate(week.cacheKey!);
|
var date = getDate(week.cacheKey!);
|
||||||
|
|
||||||
if (date.millisecondsSinceEpoch <
|
if (date.millisecondsSinceEpoch <
|
||||||
now.subtract(Duration(days: 30)).millisecondsSinceEpoch) {
|
now.subtract(const Duration(days: 30)).millisecondsSinceEpoch) {
|
||||||
weeksToRemove.add(week.cacheKey!);
|
weeksToRemove.add(week.cacheKey!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ Future<void> resetOldTimeTableCache(Isar isar) async {
|
|||||||
var date = getDate(week.cacheKey!);
|
var date = getDate(week.cacheKey!);
|
||||||
|
|
||||||
if (date.millisecondsSinceEpoch <
|
if (date.millisecondsSinceEpoch <
|
||||||
now.subtract(Duration(days: 30)).millisecondsSinceEpoch) {
|
now.subtract(const Duration(days: 30)).millisecondsSinceEpoch) {
|
||||||
weeksToRemove.add(week.cacheKey!);
|
weeksToRemove.add(week.cacheKey!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,57 +1 @@
|
|||||||
import 'package:flutter/material.dart';
|
export 'package:firka_common/ui/components/firka_card.dart';
|
||||||
|
|
||||||
import 'package:firka_wear/ui/theme/style.dart';
|
|
||||||
|
|
||||||
class FirkaCard extends StatelessWidget {
|
|
||||||
final List<Widget> left;
|
|
||||||
final List<Widget>? right;
|
|
||||||
final Widget? extra;
|
|
||||||
|
|
||||||
const FirkaCard({required this.left, this.right, this.extra, super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
var right = this.right ?? [];
|
|
||||||
|
|
||||||
if (extra != null) {
|
|
||||||
return SizedBox(
|
|
||||||
width: MediaQuery.of(context).size.width,
|
|
||||||
child: Card(
|
|
||||||
color: appStyle.colors.card,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Row(children: left),
|
|
||||||
Row(children: right),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
extra ?? SizedBox(),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return SizedBox(
|
|
||||||
width: MediaQuery.of(context).size.width,
|
|
||||||
child: Card(
|
|
||||||
color: appStyle.colors.card,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Row(children: left),
|
|
||||||
Row(children: right),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,44 +1 @@
|
|||||||
import 'package:flutter/material.dart';
|
export 'package:firka_common/ui/components/firka_shadow.dart';
|
||||||
|
|
||||||
import 'package:firka_wear/ui/theme/style.dart';
|
|
||||||
|
|
||||||
class FirkaShadow extends StatelessWidget {
|
|
||||||
final Widget child;
|
|
||||||
final bool shadow;
|
|
||||||
final double radius;
|
|
||||||
|
|
||||||
const FirkaShadow({
|
|
||||||
required this.shadow,
|
|
||||||
required this.child,
|
|
||||||
this.radius = 16.0,
|
|
||||||
super.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final borderRadius = BorderRadius.circular(radius);
|
|
||||||
|
|
||||||
final shadowBox = BoxDecoration(
|
|
||||||
color: Colors.transparent,
|
|
||||||
shape: BoxShape.rectangle,
|
|
||||||
boxShadow: [
|
|
||||||
BoxShadow(
|
|
||||||
color: wearStyle.colors.shadowColor,
|
|
||||||
spreadRadius: -4,
|
|
||||||
blurRadius: 0,
|
|
||||||
offset: Offset(0, 2),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
borderRadius: borderRadius,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!shadow) {
|
|
||||||
return ClipRRect(borderRadius: borderRadius, child: child);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Container(
|
|
||||||
decoration: shadowBox,
|
|
||||||
child: ClipRRect(borderRadius: borderRadius, child: child),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,87 +1 @@
|
|||||||
import 'package:flutter/material.dart';
|
export 'package:firka_common/ui/components/grade.dart';
|
||||||
import 'package:kreta_api/kreta_api.dart';
|
|
||||||
|
|
||||||
import 'package:firka_wear/ui/theme/style.dart';
|
|
||||||
import 'grade_helpers.dart';
|
|
||||||
|
|
||||||
class GradeWidget extends StatelessWidget {
|
|
||||||
final Grade grade;
|
|
||||||
|
|
||||||
const GradeWidget(this.grade, {super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
Color gradeColor = appStyle.colors.grade1;
|
|
||||||
var gradeStr = grade.numericValue?.toString() ?? "0";
|
|
||||||
double eccentricity = 0;
|
|
||||||
|
|
||||||
if (grade.valueType.name == "Szazalekos") {
|
|
||||||
gradeStr = grade.strValue.replaceAll("%", "");
|
|
||||||
if (grade.numericValue != null) {
|
|
||||||
gradeColor = getGradeColor(
|
|
||||||
percentageToGrade(grade.numericValue!).toDouble(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (grade.numericValue != null && grade.numericValue == 100) {
|
|
||||||
return Card(
|
|
||||||
shape: CircleBorder(eccentricity: eccentricity),
|
|
||||||
shadowColor: Colors.transparent,
|
|
||||||
color: gradeColor.withAlpha(38),
|
|
||||||
child: Padding(
|
|
||||||
padding: EdgeInsets.only(left: 8, right: 8),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
"100", // TODO: Make this curved
|
|
||||||
style: appStyle.fonts.P_14.copyWith(color: gradeColor),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return Card(
|
|
||||||
shape: CircleBorder(eccentricity: eccentricity),
|
|
||||||
shadowColor: Colors.transparent,
|
|
||||||
color: gradeColor.withAlpha(38),
|
|
||||||
child: Padding(
|
|
||||||
padding: EdgeInsets.only(left: 8, right: 8),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
gradeStr,
|
|
||||||
style: appStyle.fonts.P_14.copyWith(color: gradeColor),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
"%",
|
|
||||||
style: appStyle.fonts.P_12.copyWith(color: gradeColor),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (grade.numericValue != null) {
|
|
||||||
gradeColor = getGradeColor(grade.numericValue!.toDouble());
|
|
||||||
}
|
|
||||||
|
|
||||||
return Card(
|
|
||||||
shape: CircleBorder(eccentricity: eccentricity),
|
|
||||||
shadowColor: Colors.transparent,
|
|
||||||
color: gradeColor.withAlpha(38),
|
|
||||||
child: Padding(
|
|
||||||
padding: EdgeInsets.only(left: 8, right: 8),
|
|
||||||
child: Text(
|
|
||||||
gradeStr,
|
|
||||||
style: appStyle.fonts.H_H1.copyWith(
|
|
||||||
fontSize: 24,
|
|
||||||
color: gradeColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,75 +1 @@
|
|||||||
import 'dart:ui';
|
export 'package:firka_common/ui/components/grade_helpers.dart';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:kreta_api/kreta_api.dart';
|
|
||||||
|
|
||||||
import 'package:firka_wear/ui/theme/style.dart';
|
|
||||||
|
|
||||||
int roundGrade(double grade) {
|
|
||||||
if (grade < 2) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (grade < 2.5) {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
if (grade < 3.5) {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
if (grade < 4.5) {
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
int percentageToGrade(int grade) {
|
|
||||||
if (grade < 50) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (grade < 60) {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
if (grade < 70) {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
if (grade < 80) {
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
Color getGradeColor(double grade) {
|
|
||||||
switch (roundGrade(grade)) {
|
|
||||||
case 2:
|
|
||||||
return appStyle.colors.grade2;
|
|
||||||
case 3:
|
|
||||||
return appStyle.colors.grade3;
|
|
||||||
case 4:
|
|
||||||
return appStyle.colors.grade4;
|
|
||||||
case 5:
|
|
||||||
return appStyle.colors.grade5;
|
|
||||||
default:
|
|
||||||
return appStyle.colors.grade1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension GradeListExtension on List<Grade> {
|
|
||||||
double getAverageBySubject(Subject subject) {
|
|
||||||
var weightTotal = 0.00;
|
|
||||||
var sum = 0.00;
|
|
||||||
|
|
||||||
for (var grade in this) {
|
|
||||||
if (grade.subject.uid == subject.uid) {
|
|
||||||
if (grade.numericValue != null) {
|
|
||||||
var weight = (grade.weightPercentage ?? 100) / 100.0;
|
|
||||||
weightTotal += weight;
|
|
||||||
|
|
||||||
sum += grade.numericValue! * weight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return sum / weightTotal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,36 +1 @@
|
|||||||
import 'package:flutter/material.dart';
|
export 'package:firka_common/ui/shared/class_icon.dart';
|
||||||
|
|
||||||
import 'package:firka_wear/core/icon_helper.dart';
|
|
||||||
|
|
||||||
import 'firka_icon.dart';
|
|
||||||
|
|
||||||
class ClassIconWidget extends StatelessWidget {
|
|
||||||
final String _uid;
|
|
||||||
final String _className;
|
|
||||||
final String _category;
|
|
||||||
final Color color;
|
|
||||||
final double? size;
|
|
||||||
|
|
||||||
const ClassIconWidget({
|
|
||||||
super.key,
|
|
||||||
required String uid,
|
|
||||||
required String className,
|
|
||||||
required String category,
|
|
||||||
this.color = Colors.white,
|
|
||||||
this.size,
|
|
||||||
}) : _className = className,
|
|
||||||
_uid = uid,
|
|
||||||
_category = category;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
var iconCategory = getIconType(_uid, _className, _category);
|
|
||||||
|
|
||||||
return FirkaIconWidget(
|
|
||||||
FirkaIconType.Majesticons,
|
|
||||||
getIconData(iconCategory),
|
|
||||||
color: color,
|
|
||||||
size: size,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,22 +1 @@
|
|||||||
import 'package:flutter/material.dart';
|
export 'package:firka_common/ui/shared/counter_digit.dart';
|
||||||
|
|
||||||
import 'package:firka_wear/ui/theme/style.dart';
|
|
||||||
|
|
||||||
class CounterDigitWidget extends StatelessWidget {
|
|
||||||
final String c;
|
|
||||||
final TextStyle? style;
|
|
||||||
|
|
||||||
const CounterDigitWidget(this.c, this.style, {super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Card(
|
|
||||||
shadowColor: Colors.transparent,
|
|
||||||
color: appStyle.colors.buttonSecondaryFill,
|
|
||||||
child: Padding(
|
|
||||||
padding: EdgeInsets.only(left: 8, right: 8, top: 4, bottom: 4),
|
|
||||||
child: Text(c, style: style),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,42 +1 @@
|
|||||||
import 'dart:async';
|
export 'package:firka_common/ui/shared/delayed_spinner.dart';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class DelayedSpinnerWidget extends StatefulWidget {
|
|
||||||
const DelayedSpinnerWidget({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<DelayedSpinnerWidget> createState() => _DelayedSpinner();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _DelayedSpinner extends State<DelayedSpinnerWidget> {
|
|
||||||
Timer? timer;
|
|
||||||
bool showSpinner = false;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
|
|
||||||
timer = Timer(Duration(milliseconds: 50), () {
|
|
||||||
setState(() {
|
|
||||||
showSpinner = true;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
if (showSpinner) {
|
|
||||||
return CircularProgressIndicator();
|
|
||||||
} else {
|
|
||||||
return SizedBox();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
super.dispose();
|
|
||||||
|
|
||||||
timer?.cancel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,39 +1 @@
|
|||||||
// Enum values match external asset/API naming.
|
export 'package:firka_common/ui/shared/firka_icon.dart';
|
||||||
// ignore_for_file: constant_identifier_names
|
|
||||||
|
|
||||||
import 'dart:typed_data';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_svg/svg.dart';
|
|
||||||
import 'package:majesticons_flutter/majesticons_flutter.dart';
|
|
||||||
|
|
||||||
enum FirkaIconType { Majesticons, MajesticonsLocal }
|
|
||||||
|
|
||||||
class FirkaIconWidget extends StatelessWidget {
|
|
||||||
final FirkaIconType iconType;
|
|
||||||
final Object iconData;
|
|
||||||
final Color color;
|
|
||||||
final double? size;
|
|
||||||
|
|
||||||
const FirkaIconWidget(
|
|
||||||
this.iconType,
|
|
||||||
this.iconData, {
|
|
||||||
super.key,
|
|
||||||
this.color = Colors.white,
|
|
||||||
this.size,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
switch (iconType) {
|
|
||||||
case FirkaIconType.Majesticons:
|
|
||||||
return Majesticon(iconData as Uint8List, color: color, size: size);
|
|
||||||
case FirkaIconType.MajesticonsLocal:
|
|
||||||
return SvgPicture.asset(
|
|
||||||
'assets/majesticons/${iconData as String}.svg',
|
|
||||||
color: color,
|
|
||||||
height: size,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,60 +1 @@
|
|||||||
import 'package:flutter/material.dart';
|
export 'package:firka_common/ui/shared/grade_small_card.dart';
|
||||||
import 'package:kreta_api/kreta_api.dart';
|
|
||||||
|
|
||||||
import 'package:firka_wear/ui/components/firka_card.dart';
|
|
||||||
import 'package:firka_wear/ui/components/grade_helpers.dart';
|
|
||||||
import 'package:firka_wear/ui/shared/class_icon.dart';
|
|
||||||
import 'package:firka_wear/ui/theme/style.dart';
|
|
||||||
|
|
||||||
class GradeSmallCard extends FirkaCard {
|
|
||||||
final List<Grade> grades;
|
|
||||||
final Subject subject;
|
|
||||||
|
|
||||||
GradeSmallCard(this.grades, this.subject, {super.key})
|
|
||||||
: super(
|
|
||||||
left: [
|
|
||||||
ClassIconWidget(
|
|
||||||
uid: subject.uid,
|
|
||||||
className: subject.name,
|
|
||||||
category: subject.category.name!,
|
|
||||||
color: appStyle.colors.accent,
|
|
||||||
),
|
|
||||||
SizedBox(width: 4),
|
|
||||||
SizedBox(
|
|
||||||
width: 200,
|
|
||||||
child: Text(
|
|
||||||
subject.name,
|
|
||||||
style: appStyle.fonts.B_16SB.apply(
|
|
||||||
color: appStyle.colors.textPrimary,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
right: [
|
|
||||||
grades.getAverageBySubject(subject).isNaN
|
|
||||||
? SizedBox()
|
|
||||||
: Card(
|
|
||||||
shadowColor: Colors.transparent,
|
|
||||||
color: getGradeColor(
|
|
||||||
grades.getAverageBySubject(subject),
|
|
||||||
).withAlpha(38),
|
|
||||||
child: Padding(
|
|
||||||
padding: EdgeInsets.only(
|
|
||||||
left: 8,
|
|
||||||
right: 8,
|
|
||||||
top: 4,
|
|
||||||
bottom: 4,
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
grades.getAverageBySubject(subject).toStringAsFixed(2),
|
|
||||||
style: appStyle.fonts.B_16SB.apply(
|
|
||||||
color: getGradeColor(
|
|
||||||
grades.getAverageBySubject(subject),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,271 +1 @@
|
|||||||
// Design token names (e.g. H_H1, B_16R) follow the design system.
|
export 'package:firka_common/ui/theme/style.dart';
|
||||||
// ignore_for_file: non_constant_identifier_names
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class FirkaFonts {
|
|
||||||
TextStyle H_H1;
|
|
||||||
TextStyle H_18px;
|
|
||||||
TextStyle H_H2;
|
|
||||||
TextStyle H_16px;
|
|
||||||
TextStyle H_14px;
|
|
||||||
TextStyle H_12px;
|
|
||||||
|
|
||||||
TextStyle H_16px_trimmed; // TODO: somehow implement this
|
|
||||||
// the design has this trimmed to 130% line height
|
|
||||||
|
|
||||||
TextStyle B_16R;
|
|
||||||
TextStyle B_16SB;
|
|
||||||
|
|
||||||
TextStyle B_14R;
|
|
||||||
TextStyle B_14SB;
|
|
||||||
|
|
||||||
TextStyle B_12R;
|
|
||||||
TextStyle B_12SB;
|
|
||||||
|
|
||||||
TextStyle P_14;
|
|
||||||
TextStyle P_12;
|
|
||||||
|
|
||||||
FirkaFonts({
|
|
||||||
required this.H_H1,
|
|
||||||
required this.H_18px,
|
|
||||||
required this.H_H2,
|
|
||||||
required this.H_16px,
|
|
||||||
required this.H_14px,
|
|
||||||
required this.H_12px,
|
|
||||||
required this.H_16px_trimmed,
|
|
||||||
required this.B_16R,
|
|
||||||
required this.B_16SB,
|
|
||||||
required this.B_14R,
|
|
||||||
required this.B_14SB,
|
|
||||||
required this.B_12R,
|
|
||||||
required this.B_12SB,
|
|
||||||
required this.P_14,
|
|
||||||
required this.P_12,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
class FirkaColors {
|
|
||||||
Color background;
|
|
||||||
Color backgroundAmoled;
|
|
||||||
Color background0p;
|
|
||||||
Color success;
|
|
||||||
int shadowBlur;
|
|
||||||
|
|
||||||
Color textPrimary;
|
|
||||||
Color textSecondary;
|
|
||||||
Color textTertiary;
|
|
||||||
|
|
||||||
Color card;
|
|
||||||
Color cardTranslucent;
|
|
||||||
|
|
||||||
Color buttonSecondaryFill;
|
|
||||||
|
|
||||||
Color accent;
|
|
||||||
Color secondary;
|
|
||||||
Color shadowColor;
|
|
||||||
Color a15p; // 15%
|
|
||||||
|
|
||||||
Color warningAccent;
|
|
||||||
Color warningText;
|
|
||||||
Color warning15p;
|
|
||||||
Color warningCard;
|
|
||||||
|
|
||||||
Color errorAccent;
|
|
||||||
Color errorText;
|
|
||||||
Color error15p;
|
|
||||||
Color errorCard;
|
|
||||||
|
|
||||||
Color grade5;
|
|
||||||
Color grade4;
|
|
||||||
Color grade3;
|
|
||||||
Color grade2;
|
|
||||||
Color grade1;
|
|
||||||
|
|
||||||
FirkaColors({
|
|
||||||
required this.background,
|
|
||||||
required this.backgroundAmoled,
|
|
||||||
required this.background0p,
|
|
||||||
required this.success,
|
|
||||||
required this.shadowBlur,
|
|
||||||
required this.textPrimary,
|
|
||||||
required this.textSecondary,
|
|
||||||
required this.textTertiary,
|
|
||||||
required this.card,
|
|
||||||
required this.cardTranslucent,
|
|
||||||
required this.buttonSecondaryFill,
|
|
||||||
required this.accent,
|
|
||||||
required this.secondary,
|
|
||||||
required this.shadowColor,
|
|
||||||
required this.a15p,
|
|
||||||
required this.warningAccent,
|
|
||||||
required this.warningText,
|
|
||||||
required this.warning15p,
|
|
||||||
required this.warningCard,
|
|
||||||
required this.errorAccent,
|
|
||||||
required this.errorText,
|
|
||||||
required this.error15p,
|
|
||||||
required this.errorCard,
|
|
||||||
required this.grade5,
|
|
||||||
required this.grade4,
|
|
||||||
required this.grade3,
|
|
||||||
required this.grade2,
|
|
||||||
required this.grade1,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
class FirkaStyle {
|
|
||||||
FirkaColors colors;
|
|
||||||
FirkaFonts fonts;
|
|
||||||
|
|
||||||
FirkaStyle({required this.colors, required this.fonts});
|
|
||||||
}
|
|
||||||
|
|
||||||
final _defaultFonts = FirkaFonts(
|
|
||||||
H_H1: TextStyle(
|
|
||||||
fontSize: 30,
|
|
||||||
fontFamily: 'Montserrat',
|
|
||||||
fontVariations: [FontVariation("wght", 700)],
|
|
||||||
),
|
|
||||||
H_18px: TextStyle(
|
|
||||||
fontSize: 18,
|
|
||||||
fontFamily: 'Montserrat',
|
|
||||||
fontVariations: [FontVariation("wght", 700)],
|
|
||||||
),
|
|
||||||
H_H2: TextStyle(
|
|
||||||
fontSize: 20,
|
|
||||||
fontFamily: 'Montserrat',
|
|
||||||
fontVariations: [FontVariation("wght", 700)],
|
|
||||||
),
|
|
||||||
H_16px: TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
fontFamily: 'Montserrat',
|
|
||||||
fontVariations: [FontVariation("wght", 600)],
|
|
||||||
),
|
|
||||||
H_14px: TextStyle(
|
|
||||||
fontSize: 14,
|
|
||||||
fontFamily: 'Montserrat',
|
|
||||||
fontVariations: [FontVariation("wght", 600)],
|
|
||||||
),
|
|
||||||
H_12px: TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
fontFamily: 'Montserrat',
|
|
||||||
fontVariations: [FontVariation("wght", 600)],
|
|
||||||
),
|
|
||||||
H_16px_trimmed: TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
fontFamily: 'Montserrat',
|
|
||||||
fontVariations: [FontVariation("wght", 600)],
|
|
||||||
),
|
|
||||||
B_16R: TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
fontFamily: 'Figtree',
|
|
||||||
fontVariations: [FontVariation("wght", 600)],
|
|
||||||
),
|
|
||||||
B_16SB: TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
fontFamily: 'Figtree',
|
|
||||||
fontVariations: [FontVariation("wght", 700)],
|
|
||||||
),
|
|
||||||
B_14R: TextStyle(
|
|
||||||
fontSize: 14,
|
|
||||||
fontFamily: 'Figtree',
|
|
||||||
fontVariations: [FontVariation("wght", 600)],
|
|
||||||
),
|
|
||||||
B_14SB: TextStyle(
|
|
||||||
fontSize: 14,
|
|
||||||
fontFamily: 'Figtree',
|
|
||||||
fontVariations: [FontVariation("wght", 700)],
|
|
||||||
),
|
|
||||||
B_12R: TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
fontFamily: 'Figtree',
|
|
||||||
fontVariations: [FontVariation("wght", 600)],
|
|
||||||
),
|
|
||||||
B_12SB: TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
fontFamily: 'Figtree',
|
|
||||||
fontVariations: [FontVariation("wght", 700)],
|
|
||||||
),
|
|
||||||
P_14: TextStyle(
|
|
||||||
fontSize: 14,
|
|
||||||
fontFamily: 'RobotoMono',
|
|
||||||
fontVariations: [FontVariation("wght", 700)],
|
|
||||||
),
|
|
||||||
P_12: TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
fontFamily: 'RobotoMono',
|
|
||||||
fontVariations: [FontVariation("wght", 700)],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
final FirkaStyle lightStyle = FirkaStyle(
|
|
||||||
colors: FirkaColors(
|
|
||||||
background: Color(0xFFFAFFF0),
|
|
||||||
backgroundAmoled: Colors.black,
|
|
||||||
background0p: Color(0x00fafff0),
|
|
||||||
success: Color(0xFF92EA3B),
|
|
||||||
shadowBlur: 2,
|
|
||||||
textPrimary: Color(0xFF394C0A),
|
|
||||||
textSecondary: Color(0xCC394C0A),
|
|
||||||
textTertiary: Color(0x80394C0A),
|
|
||||||
card: Color(0xFFF3FBDE),
|
|
||||||
cardTranslucent: Color(0x80F3FBDE),
|
|
||||||
buttonSecondaryFill: Color(0xFFFEFFFD),
|
|
||||||
accent: Color(0xFFA7DC22),
|
|
||||||
secondary: Color(0xFF6E8F1B),
|
|
||||||
shadowColor: Color(0x33647e22),
|
|
||||||
a15p: Color(0x26a7dc22),
|
|
||||||
warningAccent: Color(0xFFFFA046),
|
|
||||||
warningText: Color(0xFF8F531B),
|
|
||||||
warning15p: Color(0x26FFA046),
|
|
||||||
warningCard: Color(0xFFFAEBDC),
|
|
||||||
errorAccent: Color(0xFFFF54A1),
|
|
||||||
errorText: Color(0xFF8F1B4F),
|
|
||||||
error15p: Color(0x26FF54A1),
|
|
||||||
errorCard: Color(0xFFFADCE9),
|
|
||||||
grade5: Color(0xFF22CCAD),
|
|
||||||
grade4: Color(0xFF92EA3B),
|
|
||||||
grade3: Color(0xFFF9CF00),
|
|
||||||
grade2: Color(0xFFFFA046),
|
|
||||||
grade1: Color(0xFFFF54A1),
|
|
||||||
),
|
|
||||||
fonts: _defaultFonts,
|
|
||||||
);
|
|
||||||
|
|
||||||
final FirkaStyle darkStyle = FirkaStyle(
|
|
||||||
colors: FirkaColors(
|
|
||||||
background: Color(0xFF0D1202),
|
|
||||||
backgroundAmoled: Colors.black,
|
|
||||||
background0p: Color(0x00fafff0),
|
|
||||||
success: Color(0xFF92EA3B),
|
|
||||||
shadowBlur: 0,
|
|
||||||
textPrimary: Color(0xFFEAF7CC),
|
|
||||||
textSecondary: Color(0xB3EAF7CC),
|
|
||||||
textTertiary: Color(0x80EAF7CC),
|
|
||||||
card: Color(0xFF141905),
|
|
||||||
cardTranslucent: Color(0x80141905),
|
|
||||||
buttonSecondaryFill: Color(0xFF20290B),
|
|
||||||
accent: Color(0xFFA7DC22),
|
|
||||||
secondary: Color(0xFFCBEE71),
|
|
||||||
shadowColor: Color(0x26CBEE71),
|
|
||||||
a15p: Color(0x26A7DC22),
|
|
||||||
warningAccent: Color(0xFFFFA046),
|
|
||||||
warningText: Color(0xFFF0B37A),
|
|
||||||
warning15p: Color(0x26FFA046),
|
|
||||||
warningCard: Color(0xFF201203),
|
|
||||||
errorAccent: Color(0xFFFF54A1),
|
|
||||||
errorText: Color(0xFFF59EC5),
|
|
||||||
error15p: Color(0x26FF54A1),
|
|
||||||
errorCard: Color(0xFF1E030F),
|
|
||||||
grade5: Color(0xFF22CCAD),
|
|
||||||
grade4: Color(0xFF92EA3B),
|
|
||||||
grade3: Color(0xFFF9CF00),
|
|
||||||
grade2: Color(0xFFFFA046),
|
|
||||||
grade1: Color(0xFFFF54A1),
|
|
||||||
),
|
|
||||||
fonts: _defaultFonts,
|
|
||||||
);
|
|
||||||
|
|
||||||
FirkaStyle appStyle = lightStyle;
|
|
||||||
FirkaStyle wearStyle = darkStyle;
|
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ environment:
|
|||||||
dependencies:
|
dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
firka_common:
|
||||||
|
path: ../firka_common
|
||||||
kreta_api:
|
kreta_api:
|
||||||
path: ../kreta_api
|
path: ../kreta_api
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user