1
0
forked from firka/firka

add warning and button to reauth

This commit is contained in:
2025-08-26 22:00:48 +02:00
parent b151f7fffd
commit 1aa54be199
9 changed files with 116 additions and 62 deletions

View File

@@ -15,6 +15,7 @@ import '../../db/models/token_model.dart';
import '../../db/util.dart';
import '../../debug_helper.dart';
import '../consts.dart';
import '../exceptions/token.dart';
import '../model/grade.dart';
import '../model/notice_board.dart';
import '../model/omission.dart';
@@ -131,7 +132,9 @@ class KretaClient {
}
}
} catch (ex) {
if (ex is! DioException || counter >= backoffCount) {
if (_isTokenExpired(ex) ||
ex is! DioException ||
counter >= backoffCount) {
rethrow;
}
@@ -296,7 +299,9 @@ class KretaClient {
}
}
} catch (ex) {
if (ex is! DioException || counter >= backoffCount) {
if (_isTokenExpired(ex) ||
ex is! DioException ||
counter >= backoffCount) {
rethrow;
}
@@ -548,3 +553,7 @@ class KretaClient {
omissionsCache = null;
}
}
bool _isTokenExpired(Object ex) =>
ex.toString() == TokenExpiredException().toString() ||
ex.toString() == InvalidGrantException().toString();

View File

@@ -0,0 +1,7 @@
class TokenExpiredException implements Exception {
TokenExpiredException();
}
class InvalidGrantException implements Exception {
InvalidGrantException();
}

View File

@@ -1,4 +1,5 @@
import 'package:dio/dio.dart';
import 'package:firka/helpers/api/exceptions/token.dart';
import 'package:firka/helpers/api/resp/token_grant.dart';
import 'package:firka/helpers/db/models/token_model.dart';
@@ -60,8 +61,10 @@ Future<TokenGrantResponse> extendToken(TokenModel model) async {
switch (response.statusCode) {
case 200:
return TokenGrantResponse.fromJson(response.data);
case 400:
throw TokenExpiredException();
case 401:
throw Exception("Invalid grant");
throw InvalidGrantException();
default:
throw Exception(
"Failed to get access token, response code: ${response.statusCode}");

View File

@@ -9,9 +9,15 @@ class FirkaCard extends StatelessWidget {
final List<Widget>? right;
final Widget? extra;
final Attach? attached;
final Color? color;
const FirkaCard(
{required this.left, this.right, this.extra, this.attached, super.key});
{required this.left,
this.right,
this.extra,
this.attached,
this.color,
super.key});
@override
Widget build(BuildContext context) {
@@ -23,30 +29,23 @@ class FirkaCard extends StatelessWidget {
if (extra != null) {
return SizedBox(
width: MediaQuery
.of(context)
.size
.width,
width: MediaQuery.of(context).size.width,
child: Card(
color: appStyle.colors.card,
color: color ?? appStyle.colors.card,
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)),
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(16.0),
@@ -67,30 +66,23 @@ class FirkaCard extends StatelessWidget {
);
} else {
return SizedBox(
width: MediaQuery
.of(context)
.size
.width,
width: MediaQuery.of(context).size.width,
child: Card(
color: appStyle.colors.card,
color: color ?? appStyle.colors.card,
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)),
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(16.0),

View File

@@ -189,6 +189,7 @@ Future<AppInitialization> initializeApp() async {
void main() async {
dio.options.connectTimeout = Duration(seconds: 5);
dio.options.receiveTimeout = Duration(seconds: 3);
dio.options.validateStatus = (status) => status != null && status < 500;
runZonedGuarded(() async {
WidgetsFlutterBinding.ensureInitialized();

View File

@@ -6,8 +6,10 @@ import 'package:flutter/material.dart';
import '../../../../helpers/firka_bundle.dart';
import '../../screens/debug/debug_screen.dart';
import '../../screens/login/login_screen.dart';
void showExtrasBottomSheet(BuildContext context, AppInitialization data) {
void showExtrasBottomSheet(
BuildContext context, bool loggedOut, AppInitialization data) {
showModalBottomSheet(
context: context,
elevation: 100,
@@ -39,6 +41,24 @@ void showExtrasBottomSheet(BuildContext context, AppInitialization data) {
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
!loggedOut
? SizedBox()
: GestureDetector(
onTap: () {
Navigator.pop(context);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DefaultAssetBundle(
bundle: FirkaBundle(),
child: LoginScreen(data))));
},
child: FirkaCard(
left: [Text(data.l10n.reauth_screen)],
right: [],
color: appStyle.colors.accent,
),
),
GestureDetector(
onTap: () => {
Navigator.pop(context),
@@ -50,7 +70,7 @@ void showExtrasBottomSheet(BuildContext context, AppInitialization data) {
child: DebugScreen(data))))
},
child: FirkaCard(
left: [Text('Debug screen')],
left: [Text(data.l10n.debug_screen)],
right: [],
),
),
@@ -66,7 +86,7 @@ void showExtrasBottomSheet(BuildContext context, AppInitialization data) {
data, data.settings.items))));
},
child: FirkaCard(
left: [Text('Settings')],
left: [Text(data.l10n.settings_screen)],
right: [],
),
)

View File

@@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:math';
import 'package:firka/helpers/api/client/kreta_client.dart';
import 'package:firka/helpers/api/exceptions/token.dart';
import 'package:firka/main.dart';
import 'package:firka/ui/model/style.dart';
import 'package:firka/ui/phone/pages/home/home_grades.dart';
@@ -61,6 +62,7 @@ class _HomeScreenState extends State<HomeScreen> {
List<ActiveHomePage> previousPages = List.empty(growable: true);
Widget? toast;
bool userLoggedOut = false;
ActiveToastType activeToast = ActiveToastType.none;
@@ -80,7 +82,20 @@ class _HomeScreenState extends State<HomeScreen> {
var random = Random();
ApiResponse<Object> res =
await widget.data.client.getGrades(forceCache: false);
await widget.data.client.getStudent(forceCache: false);
if (res.statusCode >= 400 ||
res.err == TokenExpiredException().toString()) {
setState(() {
userLoggedOut = true;
});
return;
}
if (res.err != null) {
throw "await widget.data.client.getStudent\n${res.err!}";
}
res = await widget.data.client.getGrades(forceCache: false);
if (res.err != null) {
throw "await widget.data.client.getGrades\n${res.err!}";
@@ -176,6 +191,7 @@ class _HomeScreenState extends State<HomeScreen> {
_updateSystemUI();
});
userLoggedOut = false;
prefetch();
}
@@ -334,15 +350,19 @@ class _HomeScreenState extends State<HomeScreen> {
: appStyle.colors.secondary,
appStyle.colors.textPrimary),
// More Button
BottomNavIconWidget(() {
HapticFeedback.lightImpact();
showExtrasBottomSheet(context, widget.data);
},
false,
Majesticon.globeEarthLine,
widget.data.l10n.other,
appStyle.colors.secondary,
appStyle.colors.textPrimary),
BottomNavIconWidget(
() {
HapticFeedback.lightImpact();
showExtrasBottomSheet(
context, userLoggedOut, widget.data);
},
false,
Majesticon.globeEarthLine,
widget.data.l10n.other,
appStyle.colors.secondary,
appStyle.colors.textPrimary,
warn: userLoggedOut,
),
],
),
),

View File

@@ -12,10 +12,11 @@ class BottomNavIconWidget extends StatelessWidget {
final String text;
final Color iconColor;
final Color textColor;
final bool warn;
const BottomNavIconWidget(this.onTap, this.active, this.icon, this.text,
this.iconColor, this.textColor,
{super.key});
{this.warn = false, super.key});
@override
Widget build(BuildContext context) {
@@ -31,7 +32,8 @@ class BottomNavIconWidget extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
children: [
FirkaIconWidget(FirkaIconType.majesticons, icon,
color: iconColor, size: 24)
color: warn ? appStyle.colors.errorAccent : iconColor,
size: 24)
.build(context),
const SizedBox(height: 4),
Text(