forked from firka/firka
add warning and button to reauth
This commit is contained in:
@@ -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();
|
||||
|
||||
7
firka/lib/helpers/api/exceptions/token.dart
Normal file
7
firka/lib/helpers/api/exceptions/token.dart
Normal file
@@ -0,0 +1,7 @@
|
||||
class TokenExpiredException implements Exception {
|
||||
TokenExpiredException();
|
||||
}
|
||||
|
||||
class InvalidGrantException implements Exception {
|
||||
InvalidGrantException();
|
||||
}
|
||||
@@ -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}");
|
||||
|
||||
@@ -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),
|
||||
|
||||
Submodule firka/lib/l10n updated: f69c2d2fe2...e62275ae5d
@@ -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();
|
||||
|
||||
@@ -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: [],
|
||||
),
|
||||
)
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user