Before Width: | Height: | Size: 252 KiB After Width: | Height: | Size: 696 KiB |
Before Width: | Height: | Size: 230 KiB After Width: | Height: | Size: 616 KiB |
Before Width: | Height: | Size: 370 KiB After Width: | Height: | Size: 1009 KiB |
Before Width: | Height: | Size: 204 KiB After Width: | Height: | Size: 549 KiB |
@ -3,7 +3,7 @@ description: "Egy nem hivatalos e-KRÉTA kliens, diákoktól diákoknak."
|
||||
homepage: https://refilc.hu
|
||||
publish_to: "none"
|
||||
|
||||
version: 5.0.4+272
|
||||
version: 5.0.4+274
|
||||
|
||||
environment:
|
||||
sdk: ">=3.3.2 <=3.4.3"
|
||||
|
@ -257,26 +257,28 @@ class KretaClient {
|
||||
|
||||
refreshToken ??= loginUser.refreshToken;
|
||||
|
||||
print("REFRESH TOKEN BELOW");
|
||||
print(refreshToken);
|
||||
// print("REFRESH TOKEN BELOW");
|
||||
// print(refreshToken);
|
||||
|
||||
if (refreshToken != null) {
|
||||
print("REFRESHING LOGIN");
|
||||
// print("REFRESHING LOGIN");
|
||||
Map? res = await postAPI(KretaAPI.login,
|
||||
headers: headers,
|
||||
body: User.refreshBody(
|
||||
refreshToken: loginUser.refreshToken,
|
||||
instituteCode: loginUser.instituteCode,
|
||||
));
|
||||
print("REFRESH RESPONSE BELOW");
|
||||
print(res);
|
||||
// print("REFRESH RESPONSE BELOW");
|
||||
// print(res);
|
||||
if (res != null) {
|
||||
if (res.containsKey("error")) {
|
||||
// remove user if refresh token expired
|
||||
if (res["error"] == "invalid_grant") {
|
||||
// remove user from app
|
||||
_user.removeUser(loginUser.id);
|
||||
await _database.store.removeUser(loginUser.id);
|
||||
// _user.removeUser(loginUser.id);
|
||||
// await _database.store.removeUser(loginUser.id);
|
||||
|
||||
print("invalid refresh token (invalid_grant)");
|
||||
|
||||
// return error
|
||||
return "refresh_token_expired";
|
||||
|
@ -51,7 +51,7 @@ class ActiveSponsorCard extends StatelessWidget {
|
||||
return const SizedBox();
|
||||
}
|
||||
|
||||
Color? glow = Colors.white; //TODO: only temp fix kima (idk what but die)
|
||||
Color? glow = Colors.white;
|
||||
|
||||
switch (level) {
|
||||
case PremiumFeatureLevel.cap:
|
||||
|
@ -3,56 +3,101 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:webview_flutter/webview_flutter.dart';
|
||||
|
||||
class KretenLoginScreen extends StatefulWidget {
|
||||
const KretenLoginScreen({super.key, required this.onLogin});
|
||||
class KretenLoginWidget extends StatefulWidget {
|
||||
const KretenLoginWidget({super.key, required this.onLogin});
|
||||
|
||||
// final String selectedSchool;
|
||||
final void Function(String code) onLogin;
|
||||
|
||||
@override
|
||||
State<KretenLoginScreen> createState() => _KretenLoginScreenState();
|
||||
State<KretenLoginWidget> createState() => _KretenLoginWidgetState();
|
||||
}
|
||||
|
||||
class _KretenLoginScreenState extends State<KretenLoginScreen> {
|
||||
class _KretenLoginWidgetState extends State<KretenLoginWidget>
|
||||
with TickerProviderStateMixin {
|
||||
late final WebViewController controller;
|
||||
late AnimationController _animationController;
|
||||
var loadingPercentage = 0;
|
||||
var currentUrl = '';
|
||||
bool _hasFadedIn = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
_animationController = AnimationController(
|
||||
vsync: this, // Use the TickerProviderStateMixin
|
||||
duration: const Duration(milliseconds: 350),
|
||||
);
|
||||
|
||||
controller = WebViewController()
|
||||
..setJavaScriptMode(JavaScriptMode.unrestricted)
|
||||
..setNavigationDelegate(NavigationDelegate(
|
||||
onPageStarted: (url) async {
|
||||
setState(() {
|
||||
loadingPercentage = 0;
|
||||
currentUrl = url;
|
||||
});
|
||||
onNavigationRequest: (n) async {
|
||||
if (n.url.startsWith('https://mobil.e-kreta.hu')) {
|
||||
setState(() {
|
||||
loadingPercentage = 0;
|
||||
currentUrl = n.url;
|
||||
});
|
||||
|
||||
// final String instituteCode = widget.selectedSchool;
|
||||
if (!url.startsWith(
|
||||
'https://mobil.e-kreta.hu/ellenorzo-student/prod/oauthredirect?code=')) {
|
||||
return;
|
||||
// final String instituteCode = widget.selectedSchool;
|
||||
// if (!n.url.startsWith(
|
||||
// 'https://mobil.e-kreta.hu/ellenorzo-student/prod/oauthredirect?code=')) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
List<String> requiredThings = n.url
|
||||
.replaceAll(
|
||||
'https://mobil.e-kreta.hu/ellenorzo-student/prod/oauthredirect?code=',
|
||||
'')
|
||||
.replaceAll(
|
||||
'&scope=openid%20email%20offline_access%20kreta-ellenorzo-webapi.public%20kreta-eugyintezes-webapi.public%20kreta-fileservice-webapi.public%20kreta-mobile-global-webapi.public%20kreta-dkt-webapi.public%20kreta-ier-webapi.public&state=refilc_student_mobile&session_state=',
|
||||
':')
|
||||
.split(':');
|
||||
|
||||
String code = requiredThings[0];
|
||||
// String sessionState = requiredThings[1];
|
||||
|
||||
widget.onLogin(code);
|
||||
// Future.delayed(const Duration(milliseconds: 500), () {
|
||||
// Navigator.of(context).pop();
|
||||
// });
|
||||
// Navigator.of(context).pop();
|
||||
|
||||
return NavigationDecision.prevent;
|
||||
} else {
|
||||
return NavigationDecision.navigate;
|
||||
}
|
||||
|
||||
List<String> requiredThings = url
|
||||
.replaceAll(
|
||||
'https://mobil.e-kreta.hu/ellenorzo-student/prod/oauthredirect?code=',
|
||||
'')
|
||||
.replaceAll(
|
||||
'&scope=openid%20email%20offline_access%20kreta-ellenorzo-webapi.public%20kreta-eugyintezes-webapi.public%20kreta-fileservice-webapi.public%20kreta-mobile-global-webapi.public%20kreta-dkt-webapi.public%20kreta-ier-webapi.public&state=refilc_student_mobile&session_state=',
|
||||
':')
|
||||
.split(':');
|
||||
|
||||
String code = requiredThings[0];
|
||||
// String sessionState = requiredThings[1];
|
||||
|
||||
widget.onLogin(code);
|
||||
// Future.delayed(const Duration(milliseconds: 500), () {
|
||||
// Navigator.of(context).pop();
|
||||
},
|
||||
onPageStarted: (url) async {
|
||||
// setState(() {
|
||||
// loadingPercentage = 0;
|
||||
// currentUrl = url;
|
||||
// });
|
||||
// Navigator.of(context).pop();
|
||||
|
||||
// // final String instituteCode = widget.selectedSchool;
|
||||
// if (!url.startsWith(
|
||||
// 'https://mobil.e-kreta.hu/ellenorzo-student/prod/oauthredirect?code=')) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// List<String> requiredThings = url
|
||||
// .replaceAll(
|
||||
// 'https://mobil.e-kreta.hu/ellenorzo-student/prod/oauthredirect?code=',
|
||||
// '')
|
||||
// .replaceAll(
|
||||
// '&scope=openid%20email%20offline_access%20kreta-ellenorzo-webapi.public%20kreta-eugyintezes-webapi.public%20kreta-fileservice-webapi.public%20kreta-mobile-global-webapi.public%20kreta-dkt-webapi.public%20kreta-ier-webapi.public&state=refilc_student_mobile&session_state=',
|
||||
// ':')
|
||||
// .split(':');
|
||||
|
||||
// String code = requiredThings[0];
|
||||
// // String sessionState = requiredThings[1];
|
||||
|
||||
// widget.onLogin(code);
|
||||
// // Future.delayed(const Duration(milliseconds: 500), () {
|
||||
// // Navigator.of(context).pop();
|
||||
// // });
|
||||
// // Navigator.of(context).pop();
|
||||
},
|
||||
onProgress: (progress) {
|
||||
setState(() {
|
||||
@ -78,24 +123,57 @@ class _KretenLoginScreenState extends State<KretenLoginScreen> {
|
||||
// Nonce nonce = getNonce(nonceStr, );
|
||||
// }
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
// Step 3: Dispose of the animation controller
|
||||
_animationController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
leading: const BackButton(),
|
||||
title: const Text('e-KRÉTA Bejelentkezés'),
|
||||
),
|
||||
body: Stack(
|
||||
children: [
|
||||
WebViewWidget(
|
||||
controller: controller,
|
||||
),
|
||||
if (loadingPercentage < 100)
|
||||
LinearProgressIndicator(
|
||||
value: loadingPercentage / 100.0,
|
||||
// Trigger the fade-in animation only once when loading reaches 100%
|
||||
if (loadingPercentage == 100 && !_hasFadedIn) {
|
||||
_animationController.forward(); // Play the animation
|
||||
_hasFadedIn =
|
||||
true; // Set the flag to true, so the animation is not replayed
|
||||
}
|
||||
|
||||
return Stack(
|
||||
children: [
|
||||
// Webview that will be displayed only when the loading is 100%
|
||||
if (loadingPercentage == 100)
|
||||
FadeTransition(
|
||||
opacity: Tween<double>(begin: 0, end: 1).animate(
|
||||
CurvedAnimation(
|
||||
parent: _animationController,
|
||||
curve: Curves.easeIn,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: WebViewWidget(
|
||||
controller: controller,
|
||||
),
|
||||
),
|
||||
|
||||
// Show the CircularProgressIndicator while loading is not 100%
|
||||
if (loadingPercentage < 100)
|
||||
Center(
|
||||
child: TweenAnimationBuilder(
|
||||
tween: Tween<double>(begin: 0, end: loadingPercentage / 100.0),
|
||||
duration: const Duration(milliseconds: 300),
|
||||
builder: (context, double value, child) {
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
CircularProgressIndicator(
|
||||
value: value, // Smoothly animates the progress
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -3,14 +3,19 @@
|
||||
import 'package:refilc/api/client.dart';
|
||||
import 'package:refilc/api/login.dart';
|
||||
import 'package:refilc/theme/colors/colors.dart';
|
||||
import 'package:refilc_mobile_ui/common/bottom_sheet_menu/rounded_bottom_sheet.dart';
|
||||
import 'package:refilc_mobile_ui/common/custom_snack_bar.dart';
|
||||
import 'package:refilc_mobile_ui/common/system_chrome.dart';
|
||||
import 'package:refilc_mobile_ui/common/widgets/absence/absence_display.dart';
|
||||
import 'package:refilc_mobile_ui/screens/login/login_button.dart';
|
||||
import 'package:refilc_mobile_ui/screens/login/login_input.dart';
|
||||
import 'package:refilc_mobile_ui/screens/login/school_input/school_input.dart';
|
||||
import 'package:refilc_mobile_ui/screens/settings/privacy_view.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'login_screen.i18n.dart';
|
||||
import 'package:carousel_slider/carousel_slider.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:refilc_mobile_ui/screens/login/kreten_login.dart'; //new library for new web login
|
||||
|
||||
class LoginScreen extends StatefulWidget {
|
||||
@ -27,8 +32,8 @@ class LoginScreenState extends State<LoginScreen> {
|
||||
final passwordController = TextEditingController();
|
||||
final schoolController = SchoolInputController();
|
||||
final _scrollController = ScrollController();
|
||||
// new controllers
|
||||
final codeController = TextEditingController();
|
||||
|
||||
LoginState _loginState = LoginState.normal;
|
||||
bool showBack = false;
|
||||
|
||||
@ -80,7 +85,7 @@ class LoginScreenState extends State<LoginScreen> {
|
||||
precacheImage(const AssetImage('assets/images/showcase2.png'), context);
|
||||
precacheImage(const AssetImage('assets/images/showcase3.png'), context);
|
||||
precacheImage(const AssetImage('assets/images/showcase4.png'), context);
|
||||
// bool selected = false;
|
||||
bool selected = false;
|
||||
|
||||
return Scaffold(
|
||||
body: Container(
|
||||
@ -196,7 +201,7 @@ class LoginScreenState extends State<LoginScreen> {
|
||||
],
|
||||
),
|
||||
Container(
|
||||
height: 300,
|
||||
height: 280,
|
||||
width: double.infinity,
|
||||
decoration: const BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
@ -218,81 +223,135 @@ class LoginScreenState extends State<LoginScreen> {
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16),
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
final NavigatorState navigator =
|
||||
Navigator.of(context);
|
||||
navigator
|
||||
.push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
KretenLoginScreen(
|
||||
onLogin: (String code) {
|
||||
codeController.text = code;
|
||||
navigator.pop();
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
.then((value) {
|
||||
if (codeController.text != "") {
|
||||
_NewLoginAPI(context: context);
|
||||
}
|
||||
});
|
||||
},
|
||||
child: Container(
|
||||
width:
|
||||
MediaQuery.of(context).size.width *
|
||||
0.75,
|
||||
height: 50.0,
|
||||
decoration: BoxDecoration(
|
||||
// image: const DecorationImage(
|
||||
// image:
|
||||
// AssetImage('assets/images/btn_kreten_login.png'),
|
||||
// fit: BoxFit.scaleDown,
|
||||
// ),
|
||||
borderRadius:
|
||||
BorderRadius.circular(12.0),
|
||||
color: const Color(0xFF0097C1),
|
||||
),
|
||||
padding: const EdgeInsets.only(
|
||||
top: 5.0,
|
||||
left: 5.0,
|
||||
right: 5.0,
|
||||
bottom: 5.0),
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
children: [
|
||||
Image.asset(
|
||||
'assets/images/btn_kreten_login.png',
|
||||
),
|
||||
const SizedBox(
|
||||
width: 10.0,
|
||||
),
|
||||
Container(
|
||||
width: 1.0,
|
||||
height: 30.0,
|
||||
color: Colors.white,
|
||||
),
|
||||
const SizedBox(
|
||||
width: 10.0,
|
||||
),
|
||||
Text(
|
||||
'login_w_kreta_acc'.i18n,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 15.0,
|
||||
child: FilledButton(
|
||||
style: ButtonStyle(
|
||||
shape: WidgetStateProperty.all<
|
||||
RoundedRectangleBorder>(
|
||||
const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(12)),
|
||||
))),
|
||||
onPressed: () {
|
||||
showModalBottomSheet(
|
||||
backgroundColor: Colors.transparent,
|
||||
context: context,
|
||||
isScrollControlled:
|
||||
true, // This ensures the modal accommodates input fields properly
|
||||
builder: (BuildContext context) {
|
||||
return Container(
|
||||
height: MediaQuery.of(context)
|
||||
.size
|
||||
.height *
|
||||
0.9 +
|
||||
MediaQuery.of(context)
|
||||
.viewInsets
|
||||
.bottom,
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0xFFDAE4F7),
|
||||
borderRadius: BorderRadius.only(
|
||||
topRight:
|
||||
Radius.circular(24.0),
|
||||
topLeft:
|
||||
Radius.circular(24.0),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
)),
|
||||
child: Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.center,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets
|
||||
.symmetric(
|
||||
vertical: 18),
|
||||
child: Container(
|
||||
decoration:
|
||||
const BoxDecoration(
|
||||
color:
|
||||
Color(0xFFB9C8E5),
|
||||
borderRadius:
|
||||
BorderRadius.only(
|
||||
topRight:
|
||||
Radius.circular(
|
||||
2.0),
|
||||
topLeft:
|
||||
Radius.circular(
|
||||
2.0),
|
||||
),
|
||||
),
|
||||
width: 40,
|
||||
height: 4,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(
|
||||
right: 14,
|
||||
left: 14,
|
||||
bottom: 24),
|
||||
child: ClipRRect(
|
||||
borderRadius:
|
||||
BorderRadius
|
||||
.circular(16),
|
||||
child: Container(
|
||||
decoration:
|
||||
BoxDecoration(
|
||||
borderRadius:
|
||||
BorderRadius
|
||||
.circular(
|
||||
16),
|
||||
),
|
||||
child:
|
||||
KretenLoginWidget(
|
||||
onLogin:
|
||||
(String code) {
|
||||
codeController
|
||||
.text = code;
|
||||
Navigator.of(
|
||||
context)
|
||||
.pop();
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
).then((value) {
|
||||
// After closing the modal bottom sheet, check if the code is set
|
||||
if (codeController.text.isNotEmpty) {
|
||||
// Call your API after retrieving the code
|
||||
_NewLoginAPI(context: context);
|
||||
}
|
||||
});
|
||||
},
|
||||
child: Text(
|
||||
"login_w_kreta_acc".i18n,
|
||||
style: const TextStyle(
|
||||
fontFamily: 'Montserrat',
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w700),
|
||||
)),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 19),
|
||||
// privacy policy
|
||||
GestureDetector(
|
||||
onTap: () => PrivacyView.show(context),
|
||||
child: Text(
|
||||
'privacy'.i18n,
|
||||
style: TextStyle(
|
||||
color: AppColors.of(context).loginSecondary,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 14.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -388,13 +447,6 @@ class LoginScreenState extends State<LoginScreen> {
|
||||
// }),
|
||||
// );
|
||||
// }
|
||||
|
||||
// setState(() => _loginState = LoginState.inProgress);
|
||||
// _callAPI();
|
||||
// }
|
||||
|
||||
// new login api
|
||||
// ignore: non_constant_identifier_names
|
||||
void _NewLoginAPI({required BuildContext context}) {
|
||||
String code = codeController.text;
|
||||
|
||||
|
@ -33,7 +33,7 @@ extension Localization on String {
|
||||
"welcome_title_4": "Take as many notes as you want.",
|
||||
"welcome_text_4":
|
||||
"You can also organise your notes by lesson in the built-in notebook, so you can find everything in one app.",
|
||||
"login_w_kreta_acc": "Log in with\ne-KRÉTA account",
|
||||
"login_w_kreta_acc": "Log in with your e-KRÉTA account",
|
||||
},
|
||||
"hu_hu": {
|
||||
"username": "Felhasználónév",
|
||||
@ -65,7 +65,7 @@ extension Localization on String {
|
||||
"welcome_title_4": "Füzetelj annyit, amennyit csak szeretnél.",
|
||||
"welcome_text_4":
|
||||
"A beépített jegyzetfüzetbe órák szerint is rendezheted a jegyzeteidet, így mindent megtalálsz egy appban.",
|
||||
"login_w_kreta_acc": "Belépés e-KRÉTA\nfiókkal",
|
||||
"login_w_kreta_acc": "Bejelentkezés e-KRÉTA fiókkal",
|
||||
},
|
||||
"de_de": {
|
||||
"username": "Benutzername",
|
||||
@ -97,7 +97,7 @@ extension Localization on String {
|
||||
"welcome_title_4": "Take as many notes as you want.",
|
||||
"welcome_text_4":
|
||||
"You can also organise your notes by lesson in the built-in notebook, so you can find everything in one app.",
|
||||
"login_w_kreta_acc": "Mit e-KRÉTA-Konto\nanmelden",
|
||||
"login_w_kreta_acc": "Mit e-KRÉTA-Konto anmelden",
|
||||
},
|
||||
};
|
||||
|
||||
|