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:
2026-03-02 23:26:59 +01:00
parent ad75a80805
commit 32936c2aa5
58 changed files with 1221 additions and 2019 deletions

View File

@@ -1,17 +1 @@
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();
}
}
export 'package:firka_common/core/debug_helper.dart';

View File

@@ -3,27 +3,10 @@ import 'package:intl/intl.dart';
import 'package:firka_wear/core/debug_helper.dart';
import 'package:firka_wear/l10n/app_localizations.dart';
import 'package:firka_common/core/extensions.dart';
import 'package:kreta_api/kreta_api.dart';
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;
}
}
export 'package:firka_common/core/extensions.dart';
extension DurationExtension on Duration {
String formatDuration() {

View File

@@ -1,152 +1 @@
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.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;
}
export 'package:firka_common/core/icon_helper.dart';

View File

@@ -1,9 +1 @@
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;
}
export 'package:firka_common/core/json_helper.dart';

View File

@@ -19,7 +19,7 @@ Future<void> resetOldHomeworkCache(Isar isar) async {
var date = getDate(week.cacheKey!);
if (date.millisecondsSinceEpoch <
now.subtract(Duration(days: 30)).millisecondsSinceEpoch) {
now.subtract(const Duration(days: 30)).millisecondsSinceEpoch) {
weeksToRemove.add(week.cacheKey!);
}
}

View File

@@ -19,7 +19,7 @@ Future<void> resetOldTimeTableCache(Isar isar) async {
var date = getDate(week.cacheKey!);
if (date.millisecondsSinceEpoch <
now.subtract(Duration(days: 30)).millisecondsSinceEpoch) {
now.subtract(const Duration(days: 30)).millisecondsSinceEpoch) {
weeksToRemove.add(week.cacheKey!);
}
}

View File

@@ -1,57 +1 @@
import 'package:flutter/material.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),
],
),
),
),
);
}
}
}
export 'package:firka_common/ui/components/firka_card.dart';

View File

@@ -1,44 +1 @@
import 'package:flutter/material.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),
);
}
}
export 'package:firka_common/ui/components/firka_shadow.dart';

View File

@@ -1,87 +1 @@
import 'package:flutter/material.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,
),
),
),
);
}
}
}
export 'package:firka_common/ui/components/grade.dart';

View File

@@ -1,75 +1 @@
import 'dart:ui';
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;
}
}
export 'package:firka_common/ui/components/grade_helpers.dart';

View File

@@ -1,36 +1 @@
import 'package:flutter/material.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,
);
}
}
export 'package:firka_common/ui/shared/class_icon.dart';

View File

@@ -1,22 +1 @@
import 'package:flutter/material.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),
),
);
}
}
export 'package:firka_common/ui/shared/counter_digit.dart';

View File

@@ -1,42 +1 @@
import 'dart:async';
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();
}
}
export 'package:firka_common/ui/shared/delayed_spinner.dart';

View File

@@ -1,39 +1 @@
// Enum values match external asset/API naming.
// 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,
);
}
}
}
export 'package:firka_common/ui/shared/firka_icon.dart';

View File

@@ -1,60 +1 @@
import 'package:flutter/material.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),
),
),
),
),
),
],
);
}
export 'package:firka_common/ui/shared/grade_small_card.dart';

View File

@@ -1,271 +1 @@
// Design token names (e.g. H_H1, B_16R) follow the design system.
// 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;
export 'package:firka_common/ui/theme/style.dart';

View File

@@ -33,6 +33,8 @@ environment:
dependencies:
flutter:
sdk: flutter
firka_common:
path: ../firka_common
kreta_api:
path: ../kreta_api