1
0
forked from firka/firka

switch to go_router

This commit is contained in:
2026-02-28 09:03:01 +01:00
parent fc9907f33d
commit e261f73c30
20 changed files with 866 additions and 1173 deletions

View File

@@ -1,6 +1,7 @@
import 'dart:typed_data';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:firka/api/client/kreta_client.dart';
import 'package:firka/data/models/token_model.dart';
import 'package:firka/core/state/update_notifier.dart';
@@ -17,12 +18,19 @@ final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
late AppInitialization initData;
bool initDone = false;
/// Set when app router is created; used for deep links and notifications.
GoRouter? appRouter;
final dio = Dio();
final isBeta = true;
final ValueNotifier<bool> isLightMode = ValueNotifier<bool>(true);
final UpdateNotifier globalUpdate = UpdateNotifier();
/// Used by home shell screens for pull-to-refresh coordination.
final UpdateNotifier homeUpdateNotifier = UpdateNotifier();
final UpdateNotifier homeUpdateFinishedNotifier = UpdateNotifier();
class DeviceInfo {
String model;

View File

@@ -6,16 +6,21 @@ import 'package:flutter_native_splash/flutter_native_splash.dart';
import 'package:firka/app/app_state.dart';
import 'package:firka/app/initialization.dart';
import 'package:firka/core/firka_bundle.dart';
import 'package:firka/routing/app_router.dart';
import 'package:firka/services/watch_sync_helper.dart';
import 'package:firka/l10n/app_localizations.dart';
import 'package:firka/ui/phone/screens/debug/debug_screen.dart';
import 'package:firka/ui/phone/screens/home/home_screen.dart';
import 'package:firka/ui/phone/screens/login/login_screen.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:go_router/go_router.dart';
class InitializationScreen extends StatelessWidget {
InitializationScreen({super.key});
class InitializationScreen extends StatefulWidget {
const InitializationScreen({super.key});
@override
State<InitializationScreen> createState() => _InitializationScreenState();
}
class _InitializationScreenState extends State<InitializationScreen> {
GoRouter? _router;
final Future<AppInitialization> _init = initializeApp().timeout(
const Duration(seconds: 20),
);
@@ -25,7 +30,6 @@ class InitializationScreen extends StatelessWidget {
return FutureBuilder<AppInitialization>(
future: _init,
builder: (context, snapshot) {
// Check if initialization is complete
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasError) {
logger.shout(
@@ -36,16 +40,15 @@ class InitializationScreen extends StatelessWidget {
FlutterNativeSplash.remove();
// Handle initialization error
return MaterialApp(
key: ValueKey('errorPage'),
key: const ValueKey('errorPage'),
home: DefaultAssetBundle(
bundle: FirkaBundle(),
child: Scaffold(
body: Center(
child: Text(
'Error initializing app: ${snapshot.error}',
style: TextStyle(color: Colors.red),
style: const TextStyle(color: Colors.red),
),
),
),
@@ -53,9 +56,6 @@ class InitializationScreen extends StatelessWidget {
);
}
// Initialization successful, determine which screen to show
Widget screen;
assert(snapshot.data != null);
initData = snapshot.data!;
initDone = true;
@@ -89,43 +89,33 @@ class InitializationScreen extends StatelessWidget {
watchChannel.invokeMethod('sendMessageToWatch', {
"id": "pong",
});
navigatorKey.currentState?.push(
MaterialPageRoute(
builder: (context) => HomeScreen(
initData,
true,
model: msg["model"] as String? ?? "unknown",
),
),
);
_router?.go('/home');
}
}
};
}
if (snapshot.data!.tokens.isEmpty) {
screen = LoginScreen(initData, key: ValueKey('loginScreen'));
} else {
screen = HomeScreen(initData, false, key: ValueKey('homeScreen'));
if (_router == null) {
_router = createAppRouter();
appRouter = _router;
}
return MaterialApp(
return MaterialApp.router(
title: 'Firka',
key: ValueKey('firkaApp'),
navigatorKey: navigatorKey,
key: const ValueKey('firkaApp'),
routerConfig: _router!,
theme: ThemeData(
primarySwatch: Colors.lightGreen,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
localizationsDelegates: [
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: AppLocalizations.supportedLocales,
home: DefaultAssetBundle(
bundle: FirkaBundle(),
child: ValueListenableBuilder<bool>(
builder: (context, child) {
return ValueListenableBuilder<bool>(
valueListenable: isLightMode,
builder: (context, isLight, _) {
final overlay = SystemUiOverlayStyle(
@@ -143,24 +133,10 @@ class InitializationScreen extends StatelessWidget {
return AnnotatedRegion<SystemUiOverlayStyle>(
value: overlay,
child: screen,
child: child ?? const SizedBox.shrink(),
);
},
),
),
routes: {
'/login': (context) => DefaultAssetBundle(
bundle: FirkaBundle(),
child: LoginScreen(initData, key: ValueKey('loginScreen')),
),
'/home': (context) => DefaultAssetBundle(
bundle: FirkaBundle(),
child: HomeScreen(initData, false, key: ValueKey('homeScreen')),
),
'/debug': (context) => DefaultAssetBundle(
bundle: FirkaBundle(),
child: DebugScreen(initData, key: ValueKey('debugScreen')),
),
);
},
);
}

View File

@@ -6,7 +6,6 @@ import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:firka/app/app_state.dart';
import 'package:firka/app/initialization.dart';
import 'package:firka/app/initialization_screen.dart';
import 'package:firka/ui/phone/pages/error/error_page.dart';
void main() async {
logger = Logger("Firka");
@@ -35,14 +34,8 @@ void main() async {
logger.shout('Caught error: $error');
logger.shout('Stack trace: $stackTrace');
navigatorKey.currentState?.push(
MaterialPageRoute(
builder: (context) => ErrorPage(
key: ValueKey('errorPage'),
exception: error.toString(),
),
),
);
final message = '$error\n$stackTrace';
appRouter?.go('/error', extra: message);
},
);
}

View File

@@ -0,0 +1,268 @@
import 'dart:collection';
import 'package:flutter/material.dart';
import 'package:firka/core/firka_bundle.dart';
import 'package:firka/app/app_state.dart';
import 'package:firka/core/settings.dart';
import 'package:firka/ui/phone/pages/home/home_grades.dart';
import 'package:firka/ui/phone/pages/home/home_grades_subject.dart';
import 'package:firka/ui/phone/pages/home/home_main.dart';
import 'package:firka/ui/phone/pages/home/home_timetable.dart';
import 'package:firka/ui/phone/pages/home/home_timetable_mo.dart';
import 'package:firka/ui/phone/screens/debug/debug_screen.dart';
import 'package:firka/ui/phone/screens/home/beta_screen.dart';
import 'package:firka/ui/phone/pages/error/error_page.dart';
import 'package:firka/ui/phone/screens/login/login_screen.dart';
import 'package:firka/ui/phone/screens/message/message_screen.dart';
import 'package:firka/ui/phone/screens/home/home_screen.dart';
import 'package:firka/ui/phone/screens/settings/settings_screen.dart';
import 'package:firka/routing/shell_with_nav_bar.dart';
import 'package:firka/routing/swipable_navigator_container.dart';
import 'package:go_router/go_router.dart';
import 'package:firka/api/model/notice_board.dart';
GoRouter createAppRouter() {
return GoRouter(
navigatorKey: navigatorKey,
initialLocation: _initialLocation,
redirect: _redirect,
routes: [
GoRoute(
path: '/error',
builder: (context, state) {
final exception = state.extra is String
? state.extra as String
: 'Unknown error';
return DefaultAssetBundle(
bundle: FirkaBundle(),
child: ErrorPage(key: state.pageKey, exception: exception),
);
},
),
GoRoute(
path: '/login',
builder: (context, state) => DefaultAssetBundle(
bundle: FirkaBundle(),
child: LoginScreen(initData, key: state.pageKey),
),
),
GoRoute(
path: '/beta',
builder: (context, state) => DefaultAssetBundle(
bundle: FirkaBundle(),
child: BetaScreen(initData, key: state.pageKey),
),
),
GoRoute(
path: '/debug',
builder: (context, state) => DefaultAssetBundle(
bundle: FirkaBundle(),
child: DebugScreen(initData, key: state.pageKey),
),
),
GoRoute(
path: '/settings',
builder: (context, state) {
final items = state.extra != null
? state.extra! as LinkedHashMap<String, SettingsItem>
: initData.settings.items;
return DefaultAssetBundle(
bundle: FirkaBundle(),
child: SettingsScreen(initData, items, key: state.pageKey),
);
},
),
GoRoute(
path: '/message',
builder: (context, state) {
final info = state.extra as InfoBoardItem?;
if (info == null) {
return const SizedBox.shrink();
}
return DefaultAssetBundle(
bundle: FirkaBundle(),
child: MessageScreen(initData, info, key: state.pageKey),
);
},
),
StatefulShellRoute(
builder: (context, state, navigationShell) => DefaultAssetBundle(
bundle: FirkaBundle(),
child: HomeScreen(
child: ShellWithNavBar(
navigationShell: navigationShell,
child: navigationShell,
),
),
),
navigatorContainerBuilder: (context, navigationShell, children) {
return SwipableNavigatorContainer(
navigationShell: navigationShell,
children: children,
);
},
branches: [
StatefulShellBranch(
routes: [
GoRoute(
path: '/home',
pageBuilder: (context, state) => NoTransitionPage(
key: state.pageKey,
child: DefaultAssetBundle(
bundle: FirkaBundle(),
child: HomeMainScreen(
initData,
homeUpdateNotifier,
homeUpdateFinishedNotifier,
),
),
),
routes: [
GoRoute(
path: 'subject/:uid',
builder: (context, state) {
final uid = state.pathParameters['uid'] ?? '';
activeSubjectUid = uid;
return DefaultAssetBundle(
bundle: FirkaBundle(),
child: HomeGradesSubjectScreen(
initData,
homeUpdateNotifier,
homeUpdateFinishedNotifier,
),
);
},
),
],
),
],
),
StatefulShellBranch(
routes: [
GoRoute(
path: '/grades',
pageBuilder: (context, state) => NoTransitionPage(
key: state.pageKey,
child: DefaultAssetBundle(
bundle: FirkaBundle(),
child: HomeGradesScreen(
initData,
homeUpdateNotifier,
homeUpdateFinishedNotifier,
),
),
),
routes: [
GoRoute(
path: 'subject/:uid',
builder: (context, state) {
final uid = state.pathParameters['uid'] ?? '';
activeSubjectUid = uid;
return DefaultAssetBundle(
bundle: FirkaBundle(),
child: HomeGradesSubjectScreen(
initData,
homeUpdateNotifier,
homeUpdateFinishedNotifier,
),
);
},
),
],
),
],
),
StatefulShellBranch(
routes: [
GoRoute(
path: '/timetable',
pageBuilder: (context, state) => NoTransitionPage(
key: state.pageKey,
child: DefaultAssetBundle(
bundle: FirkaBundle(),
child: HomeTimetableScreen(
initData,
homeUpdateNotifier,
homeUpdateFinishedNotifier,
),
),
),
routes: [
GoRoute(
path: 'monthly',
builder: (context, state) => DefaultAssetBundle(
bundle: FirkaBundle(),
child: HomeTimetableMonthlyScreen(
initData,
homeUpdateNotifier,
homeUpdateFinishedNotifier,
),
),
),
GoRoute(
path: 'subject/:uid',
builder: (context, state) {
final uid = state.pathParameters['uid'] ?? '';
activeSubjectUid = uid;
return DefaultAssetBundle(
bundle: FirkaBundle(),
child: HomeGradesSubjectScreen(
initData,
homeUpdateNotifier,
homeUpdateFinishedNotifier,
),
);
},
),
],
),
],
),
],
),
],
);
}
String get _initialLocation {
if (!initDone) return '/';
if (initData.tokens.isEmpty) return '/login';
final betaWarning = initData.settings
.group('settings')
.boolean('beta_warning');
if (!betaWarning) return '/beta';
return '/home';
}
String? _redirect(BuildContext context, GoRouterState state) {
if (!initDone) return null;
final location = state.matchedLocation;
final hasTokens = initData.tokens.isNotEmpty;
final betaWarning = initData.settings
.group('settings')
.boolean('beta_warning');
if (!hasTokens) {
if (location != '/login') return '/login';
return null;
}
if (!betaWarning && location != '/beta') {
return '/beta';
}
if (betaWarning && location == '/beta') {
return '/home';
}
if (hasTokens && location == '/login') {
return '/home';
}
if (location == '/' || location.isEmpty) {
return '/home';
}
return null;
}

View File

@@ -0,0 +1,118 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:go_router/go_router.dart';
import 'package:majesticons_flutter/majesticons_flutter.dart';
import 'package:firka/app/app_state.dart';
import 'package:firka/ui/phone/pages/extras/extras.dart';
import 'package:firka/ui/theme/style.dart';
import 'package:firka/ui/phone/widgets/bottom_nav_icon.dart';
class ShellWithNavBar extends StatelessWidget {
const ShellWithNavBar({
super.key,
required this.navigationShell,
required this.child,
});
final StatefulNavigationShell navigationShell;
final Widget child;
@override
Widget build(BuildContext context) {
final data = initData;
final currentIndex = navigationShell.currentIndex;
return Scaffold(
backgroundColor: appStyle.colors.background,
body: child,
bottomNavigationBar: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
colors: [
appStyle.colors.background,
appStyle.colors.background.withValues(alpha: 0.0),
],
stops: const [0.0, 1.0],
),
),
width: MediaQuery.sizeOf(context).width,
child: SafeArea(
top: false,
child: Padding(
padding: const EdgeInsets.fromLTRB(55, 0, 55, 12),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
BottomNavIconWidget(
() {
if (currentIndex != 0) {
navigationShell.goBranch(0);
}
},
currentIndex == 0,
currentIndex == 0
? Majesticon.homeSolid
: Majesticon.homeLine,
data.l10n.home,
currentIndex == 0
? appStyle.colors.accent
: appStyle.colors.secondary,
appStyle.colors.textPrimary,
),
BottomNavIconWidget(
() {
if (currentIndex != 1) {
navigationShell.goBranch(1);
}
},
currentIndex == 1,
currentIndex == 1
? Majesticon.bookmarkSolid
: Majesticon.bookmarkLine,
data.l10n.grades,
currentIndex == 1
? appStyle.colors.accent
: appStyle.colors.secondary,
appStyle.colors.textPrimary,
),
BottomNavIconWidget(
() {
if (currentIndex != 2) {
navigationShell.goBranch(2);
}
},
currentIndex == 2,
currentIndex == 2
? Majesticon.calendarSolid
: Majesticon.calendarLine,
data.l10n.timetable,
currentIndex == 2
? appStyle.colors.accent
: appStyle.colors.secondary,
appStyle.colors.textPrimary,
),
BottomNavIconWidget(
() {
HapticFeedback.lightImpact();
showExtrasBottomSheet(context, data);
},
false,
data.profilePicture != null
? data.profilePicture!
: Majesticon.menuLine,
data.l10n.other,
appStyle.colors.secondary,
appStyle.colors.textPrimary,
isProfilePicture: data.profilePicture != null,
),
],
),
),
),
),
);
}
}

View File

@@ -0,0 +1,92 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:go_router/go_router.dart';
class SwipableNavigatorContainer extends StatefulWidget {
const SwipableNavigatorContainer({
super.key,
required this.navigationShell,
required this.children,
});
final StatefulNavigationShell navigationShell;
final List<Widget> children;
@override
State<SwipableNavigatorContainer> createState() =>
_SwipableNavigatorContainerState();
}
class _SwipableNavigatorContainerState
extends State<SwipableNavigatorContainer> {
late PageController _pageController;
bool _isAnimating = false;
bool _isFirstBuild = true;
@override
void initState() {
super.initState();
_pageController = PageController(
initialPage: widget.navigationShell.currentIndex,
);
}
@override
void didUpdateWidget(SwipableNavigatorContainer oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.navigationShell.currentIndex !=
widget.navigationShell.currentIndex) {
_syncToShellIndex();
}
}
void _syncToShellIndex() {
if (_isFirstBuild) {
_isFirstBuild = false;
if (_pageController.hasClients &&
_pageController.page?.round() !=
widget.navigationShell.currentIndex) {
_pageController.jumpToPage(widget.navigationShell.currentIndex);
}
return;
}
if (!_pageController.hasClients) return;
if (_pageController.page?.round() == widget.navigationShell.currentIndex) {
return;
}
_isAnimating = true;
_pageController
.animateToPage(
widget.navigationShell.currentIndex,
duration: const Duration(milliseconds: 175),
curve: Curves.easeInOut,
)
.then((_) {
if (mounted) _isAnimating = false;
});
}
void _onPageChanged(int index) {
if (_isAnimating) return;
if (index != widget.navigationShell.currentIndex) {
HapticFeedback.heavyImpact();
widget.navigationShell.goBranch(index);
}
}
@override
void dispose() {
_pageController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return PageView(
controller: _pageController,
physics: const ClampingScrollPhysics(),
onPageChanged: _onPageChanged,
children: widget.children,
);
}
}

View File

@@ -16,8 +16,9 @@ import 'package:intl/intl.dart';
import 'package:firka/app/app_state.dart';
import 'package:firka/ui/theme/style.dart';
import 'package:firka/ui/phone/screens/home/home_screen.dart';
import 'package:firka/ui/phone/pages/home/home_grades.dart';
import 'package:firka/ui/phone/widgets/lesson.dart';
import 'package:go_router/go_router.dart';
import 'package:firka/ui/shared/class_icon.dart';
import 'package:firka/api/model/timetable.dart';
import 'package:firka/ui/components/firka_card.dart';
@@ -295,11 +296,14 @@ Future<void> showLessonBottomSheet(
color: appStyle.colors.buttonSecondaryFill,
),
onTap: () {
activeSubjectUid = lesson.subject!.uid;
subjectName = lesson.subject!.name;
subjectId = lesson.subject!.uid;
subjectCategory = lesson.subject!.category.name ?? "";
subjectInfo = [];
Navigator.pop(context);
pageNavNotifier.value = PageNavData(
HomePage.grades,
lesson.subject!.uid,
lesson.subject!.name,
context.push(
'/timetable/subject/${lesson.subject!.uid}',
);
},
),
@@ -728,11 +732,15 @@ Future<void> showGradeBottomSheet(
color: appStyle.colors.buttonSecondaryFill,
),
onTap: () {
activeSubjectUid = grade.subject.uid;
subjectName = grade.subject.name;
subjectId = grade.subject.uid;
subjectCategory =
grade.subject.category.name ?? "";
subjectInfo = [];
Navigator.pop(context);
pageNavNotifier.value = PageNavData(
HomePage.grades,
grade.subject.uid,
grade.subject.name,
context.go(
'/grades/subject/${grade.subject.uid}',
);
},
),
@@ -955,12 +963,13 @@ Future<void> showHomeworkBottomSheet(
color: appStyle.colors.buttonSecondaryFill,
),
onTap: () {
activeSubjectUid = homework.subject.uid;
subjectName = homework.subjectName;
subjectId = homework.subject.uid;
subjectCategory = "";
subjectInfo = [];
Navigator.pop(context);
pageNavNotifier.value = PageNavData(
HomePage.grades,
homework.subject.uid,
homework.subjectName,
);
context.push('/home/subject/${homework.subject.uid}');
},
),
),

View File

@@ -3,14 +3,11 @@ import 'package:firka/core/settings.dart';
import 'package:firka/ui/components/firka_shadow.dart';
import 'package:firka/app/app_state.dart';
import 'package:firka/ui/theme/style.dart';
import 'package:firka/ui/phone/screens/settings/settings_screen.dart';
import 'package:firka/ui/shared/firka_icon.dart';
import 'package:flutter/material.dart';
import 'package:majesticons_flutter/majesticons_flutter.dart';
import 'package:firka/core/firka_bundle.dart';
import 'package:firka/ui/phone/screens/debug/debug_screen.dart';
import 'package:firka/ui/phone/screens/home/home_screen.dart';
import 'package:go_router/go_router.dart';
void showExtrasBottomSheet(BuildContext context, AppInitialization data) {
Widget Function(double) debugBtn = (_) => const SizedBox();
@@ -20,17 +17,9 @@ void showExtrasBottomSheet(BuildContext context, AppInitialization data) {
if (isDeveloper()) {
debugBtn = (double itemWidth) => GestureDetector(
// Fejlesztői menü
onTap: () => {
Navigator.pop(context),
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DefaultAssetBundle(
bundle: FirkaBundle(),
child: DebugScreen(data),
),
),
),
onTap: () {
context.pop();
context.push('/debug');
},
child: SizedBox(
height: 60,
@@ -126,20 +115,11 @@ void showExtrasBottomSheet(BuildContext context, AppInitialization data) {
GestureDetector(
// Fiókod
onTap: () {
Navigator.pop(context);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
DefaultAssetBundle(
bundle: FirkaBundle(),
child: SettingsScreen(
data,
data.settings.items.group(
"profile_settings",
),
),
),
context.pop();
context.push(
'/settings',
extra: data.settings.items.group(
"profile_settings",
),
);
},
@@ -189,20 +169,8 @@ void showExtrasBottomSheet(BuildContext context, AppInitialization data) {
GestureDetector(
// Beállítás
onTap: () {
Navigator.pop(context);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
DefaultAssetBundle(
bundle: FirkaBundle(),
child: SettingsScreen(
data,
data.settings.items,
),
),
),
);
context.pop();
context.push('/settings');
},
child: SizedBox(
height: 60,
@@ -289,22 +257,8 @@ void showExtrasBottomSheet(BuildContext context, AppInitialization data) {
.group("settings")["developer_enabled"]!
.postUpdate();
Navigator.of(
navigatorKey.currentContext!,
).popUntil((route) => false);
Navigator.push(
navigatorKey.currentContext!,
MaterialPageRoute(
builder: (context) => DefaultAssetBundle(
bundle: FirkaBundle(),
child: HomeScreen(
data,
false,
key: ValueKey('homeScreen'),
),
),
),
);
context.pop();
context.go('/home');
} else if (debugCounter < 10) {
debugCounter++;
}

View File

@@ -6,6 +6,7 @@ import 'package:firka/ui/components/grade_helpers.dart';
import 'package:firka/ui/phone/widgets/grade_chart.dart';
import 'package:firka/ui/shared/grade_small_card.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:firka/api/consts.dart';
import 'package:firka/api/model/class_group.dart';
@@ -23,13 +24,11 @@ class HomeGradesScreen extends StatefulWidget {
final AppInitialization data;
final UpdateNotifier updateNotifier;
final UpdateNotifier finishNotifier;
final void Function(int) pageController;
const HomeGradesScreen(
this.data,
this.updateNotifier,
this.finishNotifier,
this.pageController, {
this.finishNotifier, {
super.key,
});
@@ -185,7 +184,7 @@ class _HomeGradesScreen extends FirkaState<HomeGradesScreen> {
subjectInfo = subjects
.where((s) => s.uid == subject.uid)
.toList();
widget.pageController(1);
context.go('/grades/subject/${subject.uid}');
},
),
);
@@ -201,7 +200,7 @@ class _HomeGradesScreen extends FirkaState<HomeGradesScreen> {
subjectInfo = subjects
.where((s) => s.uid == subject.uid)
.toList();
widget.pageController(1);
context.go('/grades/subject/${subject.uid}');
},
),
);

View File

@@ -7,6 +7,7 @@ import 'package:firka/ui/phone/pages/home/home_grades.dart';
import 'package:firka/ui/shared/class_icon.dart';
import 'package:firka/ui/shared/firka_icon.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:flutter_svg/svg.dart';
import 'package:majesticons_flutter/majesticons_flutter.dart';
@@ -19,13 +20,11 @@ class HomeGradesSubjectScreen extends StatefulWidget {
final AppInitialization data;
final UpdateNotifier updateNotifier;
final UpdateNotifier finishNotifier;
final void Function(int) pageController;
const HomeGradesSubjectScreen(
this.data,
this.updateNotifier,
this.finishNotifier,
this.pageController, {
this.finishNotifier, {
super.key,
});
@@ -142,235 +141,241 @@ class _HomeGradesSubjectScreen extends FirkaState<HomeGradesSubjectScreen> {
}
}
return Padding(
padding: const EdgeInsets.only(left: 16.0, right: 16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 12),
Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Transform.translate(
offset: const Offset(-4, 0),
child: GestureDetector(
child: FirkaIconWidget(
FirkaIconType.majesticons,
Majesticon.chevronLeftLine,
color: appStyle.colors.textSecondary,
),
onTap: () {
widget.pageController(0);
},
),
),
Transform.translate(
offset: const Offset(-4, 0),
child: Text(
widget.data.l10n.subjects,
style: appStyle.fonts.B_16R.apply(
color: appStyle.colors.textPrimary,
),
),
),
],
),
GestureDetector(
child: Card(
color: appStyle.colors.buttonSecondaryFill,
child: Padding(
padding: const EdgeInsets.all(4),
child: FirkaIconWidget(
FirkaIconType.majesticons,
Majesticon.menuSolid,
size: 26.0,
color: appStyle.colors.accent,
),
),
),
onTap: () {
// Navigator.push(context, Settings)
// showSubjectBottomSheetSettings(
// context,
// widget.data,
// aGrade.subject,
// );
},
),
],
),
],
),
// SizedBox(height: 16),
// GradeChart(grades: grades?.toList() ?? []),
SizedBox(
height:
MediaQuery.of(context).size.height -
MediaQuery.of(context).padding.top -
230,
child: ListView(
return Material(
color: appStyle.colors.background,
child: Padding(
padding: const EdgeInsets.only(left: 16.0, right: 16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 12),
Column(
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Card(
shadowColor: const Color.fromRGBO(0, 0, 0, 0),
color: appStyle.colors.a15p,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
child: Padding(
padding: EdgeInsetsGeometry.all(6),
child: ClassIconWidget(
uid: aGrade.subject.uid,
className: aGrade.subject.name,
category: aGrade.subject.category.name!,
color: appStyle.colors.accent,
),
),
),
SizedBox(height: 8),
Text(
aGrade.subject.name,
style: appStyle.fonts.H_H2.apply(
color: appStyle.colors.textPrimary,
),
),
SizedBox(height: 2),
Text(
aGrade.teacher,
style: appStyle.fonts.B_16R.apply(
color: appStyle.colors.textSecondary,
),
),
SizedBox(height: 15),
],
),
Padding(
padding: EdgeInsets.only(left: 4),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: gradeWidgets,
),
),
],
),
),
],
),
);
} else {
return Padding(
padding: const EdgeInsets.only(left: 16.0, right: 16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
children: [
Row(
children: [
Transform.translate(
offset: const Offset(-4, 0),
child: GestureDetector(
child: FirkaIconWidget(
FirkaIconType.majesticons,
Majesticon.chevronLeftLine,
color: appStyle.colors.textSecondary,
),
onTap: () {
widget.pageController(0);
},
),
),
Transform.translate(
offset: const Offset(-4, 1),
child: Text(
widget.data.l10n.subjects,
style: appStyle.fonts.B_16R.apply(
color: appStyle.colors.textPrimary,
),
),
),
],
),
],
),
SizedBox(height: 16),
SizedBox(
height:
MediaQuery.of(context).size.height -
MediaQuery.of(context).padding.top -
230,
child: ListView(
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Card(
shadowColor: const Color.fromRGBO(0, 0, 0, 0),
color: appStyle.colors.a15p,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
child: Padding(
padding: EdgeInsetsGeometry.all(6),
child: ClassIconWidget(
uid: subjectId,
className: subjectName,
category: subjectCategory,
color: appStyle.colors.accent,
),
),
),
SizedBox(height: 8),
Text(
subjectName,
style: appStyle.fonts.H_H2.apply(
color: appStyle.colors.textPrimary,
),
),
SizedBox(height: 2),
Text(
widget.data.l10n.unknown_teacher,
style: appStyle.fonts.B_16R.apply(
color: appStyle.colors.textSecondary,
),
),
],
),
SizedBox(
height:
MediaQuery.of(context).size.height -
MediaQuery.of(context).padding.top -
320,
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
Row(
children: [
SvgPicture.asset(
"assets/images/logos/dave.svg",
width: 48,
height: 48,
Transform.translate(
offset: const Offset(-4, 0),
child: GestureDetector(
child: FirkaIconWidget(
FirkaIconType.majesticons,
Majesticon.chevronLeftLine,
color: appStyle.colors.textSecondary,
),
onTap: () {
context.pop();
},
),
),
SizedBox(height: 12),
Text(
widget.data.l10n.no_grades,
style: appStyle.fonts.B_16R.apply(
color: appStyle.colors.textSecondary,
Transform.translate(
offset: const Offset(-4, 0),
child: Text(
widget.data.l10n.subjects,
style: appStyle.fonts.B_16R.apply(
color: appStyle.colors.textPrimary,
),
),
),
],
),
),
GestureDetector(
child: Card(
color: appStyle.colors.buttonSecondaryFill,
child: Padding(
padding: const EdgeInsets.all(4),
child: FirkaIconWidget(
FirkaIconType.majesticons,
Majesticon.menuSolid,
size: 26.0,
color: appStyle.colors.accent,
),
),
),
onTap: () {
// Navigator.push(context, Settings)
// showSubjectBottomSheetSettings(
// context,
// widget.data,
// aGrade.subject,
// );
},
),
],
),
],
),
),
],
// SizedBox(height: 16),
// GradeChart(grades: grades?.toList() ?? []),
SizedBox(
height:
MediaQuery.of(context).size.height -
MediaQuery.of(context).padding.top -
230,
child: ListView(
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Card(
shadowColor: const Color.fromRGBO(0, 0, 0, 0),
color: appStyle.colors.a15p,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
child: Padding(
padding: EdgeInsetsGeometry.all(6),
child: ClassIconWidget(
uid: aGrade.subject.uid,
className: aGrade.subject.name,
category: aGrade.subject.category.name!,
color: appStyle.colors.accent,
),
),
),
SizedBox(height: 8),
Text(
aGrade.subject.name,
style: appStyle.fonts.H_H2.apply(
color: appStyle.colors.textPrimary,
),
),
SizedBox(height: 2),
Text(
aGrade.teacher,
style: appStyle.fonts.B_16R.apply(
color: appStyle.colors.textSecondary,
),
),
SizedBox(height: 15),
],
),
Padding(
padding: EdgeInsets.only(left: 4),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: gradeWidgets,
),
),
],
),
),
],
),
),
);
} else {
return Material(
color: appStyle.colors.background,
child: Padding(
padding: const EdgeInsets.only(left: 16.0, right: 16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
children: [
Row(
children: [
Transform.translate(
offset: const Offset(-4, 0),
child: GestureDetector(
child: FirkaIconWidget(
FirkaIconType.majesticons,
Majesticon.chevronLeftLine,
color: appStyle.colors.textSecondary,
),
onTap: () {
context.pop();
},
),
),
Transform.translate(
offset: const Offset(-4, 1),
child: Text(
widget.data.l10n.subjects,
style: appStyle.fonts.B_16R.apply(
color: appStyle.colors.textPrimary,
),
),
),
],
),
],
),
SizedBox(height: 16),
SizedBox(
height:
MediaQuery.of(context).size.height -
MediaQuery.of(context).padding.top -
230,
child: ListView(
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Card(
shadowColor: const Color.fromRGBO(0, 0, 0, 0),
color: appStyle.colors.a15p,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
child: Padding(
padding: EdgeInsetsGeometry.all(6),
child: ClassIconWidget(
uid: subjectId,
className: subjectName,
category: subjectCategory,
color: appStyle.colors.accent,
),
),
),
SizedBox(height: 8),
Text(
subjectName,
style: appStyle.fonts.H_H2.apply(
color: appStyle.colors.textPrimary,
),
),
SizedBox(height: 2),
Text(
widget.data.l10n.unknown_teacher,
style: appStyle.fonts.B_16R.apply(
color: appStyle.colors.textSecondary,
),
),
],
),
SizedBox(
height:
MediaQuery.of(context).size.height -
MediaQuery.of(context).padding.top -
320,
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SvgPicture.asset(
"assets/images/logos/dave.svg",
width: 48,
height: 48,
),
SizedBox(height: 12),
Text(
widget.data.l10n.no_grades,
style: appStyle.fonts.B_16R.apply(
color: appStyle.colors.textSecondary,
),
),
],
),
),
),
],
),
),
],
),
),
);
}

View File

@@ -4,13 +4,13 @@ import 'package:firka/api/client/kreta_stream.dart';
import 'package:firka/api/model/grade.dart';
import 'package:firka/core/extensions.dart';
import 'package:firka/ui/components/common_bottom_sheets.dart';
import 'package:firka/ui/phone/screens/message/message_screen.dart';
import 'package:firka/ui/phone/widgets/home_main_starting_soon.dart';
import 'package:firka/ui/phone/widgets/homework.dart';
import 'package:firka/ui/phone/widgets/info_board_item.dart';
import 'package:firka/ui/phone/widgets/lesson_small.dart';
import 'package:firka/ui/shared/delayed_spinner.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:majesticons_flutter/majesticons_flutter.dart';
import 'package:firka/api/model/homework.dart';
@@ -326,11 +326,7 @@ class _HomeMainScreen extends FirkaState<HomeMainScreen> {
GestureDetector(
child: InfoBoardItemWidget(item),
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => MessageScreen(widget.data, item),
),
);
context.push('/message', extra: item);
},
),
item.date,

View File

@@ -1,72 +0,0 @@
import 'package:firka/ui/phone/screens/home/home_screen.dart';
import 'package:flutter/material.dart';
import 'package:firka/core/state/firka_state.dart';
import 'package:firka/core/state/update_notifier.dart';
import 'package:firka/ui/theme/style.dart';
class PageWithSubPages extends StatefulWidget {
final int pageIndex;
final List<Widget Function(void Function(int))> subPages;
final ValueNotifier<bool> subPageActive;
final UpdateNotifier back;
const PageWithSubPages(
this.subPages,
this.subPageActive,
this.back, {
super.key,
required this.pageIndex,
});
@override
PageWithSubPagesState createState() => PageWithSubPagesState();
}
class PageWithSubPagesState extends FirkaState<PageWithSubPages> {
int _currentSubPage = 0;
@override
void initState() {
super.initState();
widget.back.addListener(_backListener);
}
void _backListener() {
if (!mounted) return;
setState(() {
subPageActive.value = false;
_currentSubPage = 0;
});
}
@override
void didUpdateWidget(PageWithSubPages oldWidget) {
super.didUpdateWidget(oldWidget);
widget.back.removeListener(_backListener);
widget.back.addListener(_backListener);
}
@override
void dispose() {
super.dispose();
widget.back.removeListener(_backListener);
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: appStyle.colors.background,
body: widget.subPages[_currentSubPage]((page) {
subPageActive.value = _currentSubPage == 0;
setState(() {
_currentSubPage = page;
});
}),
);
}
}

View File

@@ -13,6 +13,7 @@ import 'package:firka/ui/phone/screens/settings/settings_screen.dart';
import 'package:firka/ui/phone/widgets/bubble_test.dart';
import 'package:firka/ui/shared/delayed_spinner.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:flutter/services.dart';
import 'package:majesticons_flutter/majesticons_flutter.dart';
import 'package:transparent_pointer/transparent_pointer.dart';
@@ -29,13 +30,11 @@ class HomeTimetableScreen extends StatefulWidget {
final AppInitialization data;
final UpdateNotifier updateNotifier;
final UpdateNotifier finishNotifier;
final void Function(int) pageController;
const HomeTimetableScreen(
this.data,
this.updateNotifier,
this.finishNotifier,
this.pageController, {
this.finishNotifier, {
super.key,
});
@@ -555,7 +554,7 @@ class _HomeTimetableScreen extends FirkaState<HomeTimetableScreen>
),
),
onTap: () {
widget.pageController(1);
context.push('/timetable/monthly');
},
),
/* TODO: 1.1.0

View File

@@ -7,6 +7,7 @@ import 'package:firka/core/settings.dart';
import 'package:firka/ui/theme/style.dart';
import 'package:firka/ui/shared/delayed_spinner.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:majesticons_flutter/majesticons_flutter.dart';
import 'package:transparent_pointer/transparent_pointer.dart';
@@ -22,13 +23,11 @@ class HomeTimetableMonthlyScreen extends StatefulWidget {
final AppInitialization data;
final UpdateNotifier updateNotifier;
final UpdateNotifier finishNotifier;
final void Function(int) pageController;
const HomeTimetableMonthlyScreen(
this.data,
this.updateNotifier,
this.finishNotifier,
this.pageController, {
this.finishNotifier, {
super.key,
});
@@ -392,7 +391,7 @@ class _HomeTimetableMonthlyScreen
),
),
onTap: () {
widget.pageController(0);
context.pop();
},
),
// Nincs elkészítve jelenleg: Dolgozat stb hozzáadása(?)

View File

@@ -7,12 +7,11 @@ import 'package:firka/core/extensions.dart';
import 'package:firka/core/icon_helper.dart';
import 'package:firka/core/profile_picture.dart';
import 'package:firka/app/app_state.dart';
import 'package:firka/ui/phone/screens/login/login_screen.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:image_picker/image_picker.dart';
import 'package:firka/core/debug_helper.dart';
import 'package:firka/core/firka_bundle.dart';
import 'package:firka/core/state/firka_state.dart';
import 'package:firka/ui/shared/firka_icon.dart';
@@ -221,15 +220,7 @@ class _DebugScreen extends FirkaState<DebugScreen> {
widget.data.tokens = List.empty(growable: true);
if (!context.mounted) return;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DefaultAssetBundle(
bundle: FirkaBundle(),
child: LoginScreen(widget.data),
),
),
);
context.go('/login');
},
child: const Text('wipe users'),
),

View File

@@ -5,8 +5,8 @@ import 'package:firka/data/models/app_settings_model.dart';
import 'package:firka/core/settings.dart';
import 'package:firka/ui/components/firka_button.dart';
import 'package:firka/ui/theme/style.dart';
import 'package:firka/ui/phone/screens/home/home_screen.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:firka/core/state/firka_state.dart';
import 'package:firka/app/app_state.dart';
@@ -123,12 +123,7 @@ class _BetaScreenState extends FirkaState<BetaScreen> {
.group("settings")["beta_warning"]!
.postUpdate();
if (!context.mounted) return;
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(
builder: (context) => HomeScreen(widget.data, false),
),
(route) => false,
);
context.go('/home');
},
),
],

File diff suppressed because it is too large Load Diff

View File

@@ -9,10 +9,10 @@ import 'package:firka/ui/components/firka_button.dart';
import 'package:firka/ui/components/firka_card.dart';
import 'package:firka/app/app_state.dart';
import 'package:firka/ui/theme/style.dart';
import 'package:firka/ui/phone/screens/login/login_screen.dart';
import 'package:firka/ui/shared/firka_icon.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:flutter/services.dart';
import 'package:isar_community/isar.dart';
import 'package:majesticons_flutter/majesticons_flutter.dart';
@@ -185,15 +185,7 @@ class _SettingsScreenState extends FirkaState<SettingsScreen> {
launchUrlString("https://firka.app/privacy");
return;
} else {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DefaultAssetBundle(
bundle: FirkaBundle(),
child: SettingsScreen(widget.data, item.children),
),
),
);
context.push('/settings', extra: item.children);
}
},
child: item.redirectTo != null
@@ -995,12 +987,7 @@ class _SettingsScreenState extends FirkaState<SettingsScreen> {
KretaClient.clearReauthFlag();
}
if (!mounted) return;
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(
builder: (context) => LoginScreen(widget.data),
),
(route) => false,
);
context.go('/login');
} else {
if (Platform.isIOS) {
final nextToken = accounts.first;

View File

@@ -13,12 +13,10 @@ import 'package:firka/services/watch_sync_helper.dart';
import 'package:firka/api/consts.dart';
import 'package:firka/api/token_grant.dart';
import 'package:firka/data/models/token_model.dart';
import 'package:firka/core/firka_bundle.dart';
import 'package:firka/app/initialization_screen.dart';
import 'package:firka/core/state/firka_state.dart';
import 'package:firka/core/settings.dart';
import 'package:firka/ui/theme/style.dart';
import '../pages/error/error_page.dart';
class LoginWebviewWidget extends StatefulWidget {
final AppInitialization data;
@@ -166,15 +164,7 @@ class _LoginWebviewWidgetState extends FirkaState<LoginWebviewWidget>
} else {
logger.shout("oauthredirect failed:", ex.toString());
}
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DefaultAssetBundle(
bundle: FirkaBundle(),
child: ErrorPage(exception: ex.toString()),
),
),
);
appRouter?.go('/error', extra: ex.toString());
}
return NavigationDecision.prevent;

View File

@@ -51,6 +51,7 @@ dependencies:
flutter_html: ^3.0.0
fl_chart: ^1.1.1
flutter_native_splash: ^2.4.7
go_router: ^17.1.0
dev_dependencies:
flutter_test: