Compare commits

..

27 Commits
4.2.0 ... 4.2.2

Author SHA1 Message Date
Márton Kiss
023329f021 Merge pull request #43 from refilc/dev
Dev
2023-09-05 22:06:51 +02:00
Kima
e66fdbaeac added expire date to ads 2023-09-05 21:59:53 +02:00
Kima
bbbaea9224 fixed ad isBefore 2023-09-05 21:55:51 +02:00
Márton Kiss
c7c18cf684 Merge pull request #42 from refilc/dev
changed version number
2023-09-05 21:23:48 +02:00
Kima
4d501fed3e changed version number 2023-09-05 21:23:30 +02:00
Márton Kiss
8168ef5329 Merge pull request #41 from refilc/dev
Dev
2023-09-05 21:18:27 +02:00
Kima
608bc58771 fixed padding on ad tile 2023-09-05 21:17:54 +02:00
Kima
2cba1ec286 ads api working 2023-09-05 21:08:06 +02:00
Kima
b6eb65814f Merge branch 'dev' of github.com:refilc/naplo into dev 2023-09-05 18:49:16 +02:00
Kima
a5a43ea0b9 added ad provider 2023-09-05 18:49:14 +02:00
Márton Kiss
da356bb212 Merge pull request #40 from refilc/dev
Dev
2023-09-04 23:15:01 +02:00
Márton Kiss
c29ab3de29 Merge pull request #39 from Monke14/dev
Android widget fix
2023-09-04 23:14:38 +02:00
Kima
fceb4e050f FINALLY FIXED AUTO UPDATE 2023-09-04 23:13:54 +02:00
Kima
8feea02f68 added api endpoint and auto update fix 2023-09-04 21:45:11 +02:00
hihihaha
939e4f4d48 widget fix 2023-09-04 21:31:50 +02:00
Kima
a401ff32d9 something 2023-09-04 20:17:38 +02:00
Márton Kiss
84e7fc60c2 Merge pull request #38 from refilc/dev
dev to master
2023-09-04 18:40:16 +02:00
Kima
6821887263 Merge branch 'dev' of github.com:refilc/naplo into dev 2023-09-04 18:39:53 +02:00
Kima
8f8ceb0597 removed prints 2023-09-04 18:39:49 +02:00
Márton Kiss
deb2403c23 Merge pull request #37 from refilc/master
master readme to dev branch
2023-09-04 18:38:06 +02:00
Márton Kiss
d65c722ef0 Merge pull request #36 from refilc/dev
dev minden is master-be
2023-09-04 18:37:18 +02:00
Kima
1bdc1409e4 updated version number 2023-09-04 18:33:24 +02:00
Kima
467eca6c14 fixed that shit timetable bug 2023-09-04 18:31:47 +02:00
Kima
da3abb7fb7 fixed school select (omfg nagyon szarul csinaltak) 2023-09-04 17:10:09 +02:00
Márton Kiss
a8a818225e modified readme 2023-09-03 23:53:28 +02:00
Kima
5e650869f2 added some hint for spaces after username 2023-09-03 22:13:39 +02:00
Kima
6e06d82b1a made goal planner modal dark mode compatible 2023-09-03 21:17:22 +02:00
35 changed files with 529 additions and 225 deletions

1
.gitignore vendored
View File

@@ -48,3 +48,4 @@ filcnaplo/ios/Podfile.lock
key.properties
.flutter-plugins*
filcnaplo/ios/Flutter/flutter_export_environment 4.sh

29
.vscode/launch.json vendored
View File

@@ -10,17 +10,16 @@
"--dart-define=APPVER=$(cat pubspec.yaml | grep version: | cut -d' ' -f2 | cut -d+ -f1)"
]
},
{
"name": "filcnaplo release",
"cwd": "filcnaplo release",
"request": "launch",
"type": "dart",
"flutterMode": "release",
"program": "lib/main.dart",
"toolArgs": [
"--dart-define=APPVER=$(cat pubspec.yaml | grep version: | cut -d' ' -f2 | cut -d+ -f1)"
]
},
// {
// "name": "filcnaplo release",
// "cwd": "filcnaplo release",
// "request": "launch",
// "type": "dart",
// "program": "lib/main.dart",
// "toolArgs": [
// "--dart-define=APPVER=$(cat pubspec.yaml | grep version: | cut -d' ' -f2 | cut -d+ -f1)"
// ]
// },
{
"name": "Flutter",
"program": "lib/main.dart",
@@ -28,6 +27,14 @@
"request": "launch",
"type": "dart",
"flutterMode": "debug"
},
{
"name": "Flutter (release)",
"program": "lib/main.dart",
"cwd": "filcnaplo",
"request": "launch",
"type": "dart",
"flutterMode": "release"
}
]
}

View File

@@ -3,7 +3,7 @@
<h1 align=center><b>reFilc</b></h1>
</p>
#### Nem hivatalos e-napló alkalmazás az eKRÉTA rendszerhez - tanulóktól, tanulóknak.
#### Nem hivatalos e-napló alkalmazás az e-KRÉTA rendszerhez - tanulóktól, tanulóknak.
[![Downloads](https://img.shields.io/github/downloads-pre/refilc/naplo/total?&logo=github&label=Downloads)](https://github.com/refilc/naplo/releases) &nbsp; [![Discord](https://img.shields.io/discord/1111649116020285532?logo=discord&label=Discord)](https://dc.refilc.hu)
@@ -35,10 +35,16 @@ Az összes (ugyan azon verzióhoz tartozó) contribution meg fog jelenni a relea
-------
# Developers
# Team
**annon:** a Filc napló készítője (ez az app a Filcen alapul)
**kima:** head developer / project manager
**kima, mog, WolfY:** fő fejlesztők
**Reiner, pdf, Pearoo:** community- and project manager / developer
**Regő, Pearoo:** weboldal design és community management
**vrolandd, TMarccci:** head developer
**dwe., xou:** designer
**Péter:** social media manager / video editor
**annon:** a régi Filc Napló fejlesztője (ez az app, ha bár sokban változott, alapjaiban a Filc-re épül)

View File

@@ -26,6 +26,11 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.HashMap;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import hu.refilc.naplo.database.DBManager;
import hu.refilc.naplo.MainActivity;
@@ -247,71 +252,61 @@ public class WidgetTimetable extends HomeWidgetProvider {
}
public static List<JSONArray> genJsonDays(Context context) {
List<JSONArray> gen_days = new ArrayList<>();
List<JSONArray> genDays = new ArrayList<>();
Map<String, JSONArray> dayMap = new HashMap<>();
DBManager dbManager = new DBManager(context.getApplicationContext());
try {
dbManager.open();
Cursor ct = dbManager.fetchTimetable();
dbManager.close();
if(ct.getCount() == 0) {
return gen_days;
if (ct.getCount() == 0) {
return genDays;
}
JSONObject fecthtt = new JSONObject(ct.getString(0));
JSONObject fetchedTimetable = new JSONObject(ct.getString(0));
String currentWeek = String.valueOf(Week.current().id());
JSONArray week = fetchedTimetable.getJSONArray(currentWeek);
JSONArray dayArray = new JSONArray();
String currday = "";
String currweek = String.valueOf(Week.current().id());
JSONArray week = fecthtt.getJSONArray(currweek);
for (int i=0; i < week.length(); i++)
{
// Organize lessons into dates
for (int i = 0; i < week.length(); i++) {
try {
if(i == 0) currday = week.getJSONObject(0).getString("Datum");
JSONObject oraObj = week.getJSONObject(i);
if(!currday.equals(oraObj.getString("Datum"))) {
gen_days.add(dayArray);
currday = week.getJSONObject(i).getString("Datum");
dayArray = new JSONArray();
}
dayArray.put(oraObj);
if(i == week.length() - 1) {
gen_days.add(dayArray);
}
} catch (Exception e) {
JSONObject entry = week.getJSONObject(i);
String date = entry.getString("Datum");
dayMap.computeIfAbsent(date, k -> new JSONArray()).put(entry);
} catch (JSONException e) {
e.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
}
Collections.sort(gen_days, new Comparator<JSONArray>() {
public int compare(JSONArray a, JSONArray b) {
long valA = 0;
long valB = 0;
genDays.addAll(dayMap.values());
// Sort the 'genDays' list of JSON based on the start time of the first entry
genDays.sort((day1, day2) -> {
try {
valA = (long) new DateTime( a.getJSONObject(0).getString("Datum")).getMillis();
valB = (long) new DateTime( b.getJSONObject(0).getString("Datum")).getMillis();
}
catch (JSONException ignored) {
}
return (int) (valA - valB);
// Extract the start time of the first entry in each day's JSON
String startTime1 = day1.getJSONObject(0).getString("KezdetIdopont");
String startTime2 = day2.getJSONObject(0).getString("KezdetIdopont");
// Compare the start times and return the result for sorting
return startTime1.compareTo(startTime2);
} catch (JSONException e) {
e.printStackTrace();
return 0;
}
});
return gen_days;
} catch (Exception e) {
e.printStackTrace();
} finally {
dbManager.close();
}
return genDays;
}
public static String zeroPad(int value, int padding){
StringBuilder b = new StringBuilder();
b.append(value);

View File

@@ -335,10 +335,12 @@ public class WidgetTimetableDataProvider implements RemoteViewsService.RemoteVie
public Lesson jsonToLesson(JSONObject json) {
try {
String name = json.getString("Nev");
name = name.substring(0, 1).toUpperCase() + name.substring(1); // Capitalize name
return new Lesson(
json.getJSONObject("Allapot").getString("Nev"),
!json.getString("Oraszam").equals("null") ? json.getString("Oraszam") : "+",
json.getString("Nev"),
name,
json.getString("Tema"),
json.getString("TeremNeve"),
new DateTime(json.getString("KezdetIdopont")).getMillis(),

View File

@@ -1,15 +1,14 @@
// This is a generated file; do not edit or check into version control.
FLUTTER_ROOT=/Users/kima/development/flutter
FLUTTER_ROOT=/Users/kima/src/flutter
FLUTTER_APPLICATION_PATH=/Users/kima/Documents/refilc/app/naplo/filcnaplo
COCOAPODS_PARALLEL_CODE_SIGN=true
FLUTTER_TARGET=/Users/kima/Documents/refilc/app/naplo/filcnaplo/lib/main.dart
FLUTTER_TARGET=lib/main.dart
FLUTTER_BUILD_DIR=build
FLUTTER_BUILD_NAME=3.5.1
FLUTTER_BUILD_NUMBER=197
FLUTTER_BUILD_NAME=4.2.0
FLUTTER_BUILD_NUMBER=220
EXCLUDED_ARCHS[sdk=iphonesimulator*]=i386
EXCLUDED_ARCHS[sdk=iphoneos*]=armv7
DART_DEFINES=RkxVVFRFUl9XRUJfQVVUT19ERVRFQ1Q9dHJ1ZQ==,RkxVVFRFUl9XRUJfQ0FOVkFTS0lUX1VSTD1odHRwczovL3d3dy5nc3RhdGljLmNvbS9mbHV0dGVyLWNhbnZhc2tpdC9iNGZiMTEyMTRkZDJkZGE2Y2UwMTJkZDk4ZWE0OThlOWU4YjkxMjYyLw==
DART_OBFUSCATION=false
TRACK_WIDGET_CREATION=true
TREE_SHAKE_ICONS=false
PACKAGE_CONFIG=/Users/kima/Documents/refilc/app/naplo/filcnaplo/.dart_tool/package_config.json
PACKAGE_CONFIG=.dart_tool/package_config.json

View File

@@ -1,15 +1,14 @@
// This is a generated file; do not edit or check into version control.
FLUTTER_ROOT=/Users/kima/development/flutter
FLUTTER_ROOT=/Users/kima/src/flutter
FLUTTER_APPLICATION_PATH=/Users/kima/Documents/refilc/app/naplo/filcnaplo
COCOAPODS_PARALLEL_CODE_SIGN=true
FLUTTER_TARGET=/Users/kima/Documents/refilc/app/naplo/filcnaplo/lib/main.dart
FLUTTER_TARGET=lib/main.dart
FLUTTER_BUILD_DIR=build
FLUTTER_BUILD_NAME=4.1.0
FLUTTER_BUILD_NUMBER=213
FLUTTER_BUILD_NAME=4.2.0
FLUTTER_BUILD_NUMBER=220
EXCLUDED_ARCHS[sdk=iphonesimulator*]=i386
EXCLUDED_ARCHS[sdk=iphoneos*]=armv7
DART_DEFINES=RkxVVFRFUl9XRUJfQVVUT19ERVRFQ1Q9dHJ1ZQ==,RkxVVFRFUl9XRUJfQ0FOVkFTS0lUX1VSTD1odHRwczovL3d3dy5nc3RhdGljLmNvbS9mbHV0dGVyLWNhbnZhc2tpdC8yYTM0MDFjOWJiYjVhOWE5YWVjNzRkNGY3MzVkMThhOWRkM2ViZjJkLw==
DART_OBFUSCATION=false
TRACK_WIDGET_CREATION=true
TREE_SHAKE_ICONS=false
PACKAGE_CONFIG=/Users/kima/Documents/refilc/app/naplo/filcnaplo/.dart_tool/package_config.json
PACKAGE_CONFIG=.dart_tool/package_config.json

View File

@@ -1,14 +1,13 @@
#!/bin/sh
# This is a generated file; do not edit or check into version control.
export "FLUTTER_ROOT=/Users/kima/development/flutter"
export "FLUTTER_ROOT=/Users/kima/src/flutter"
export "FLUTTER_APPLICATION_PATH=/Users/kima/Documents/refilc/app/naplo/filcnaplo"
export "COCOAPODS_PARALLEL_CODE_SIGN=true"
export "FLUTTER_TARGET=/Users/kima/Documents/refilc/app/naplo/filcnaplo/lib/main.dart"
export "FLUTTER_TARGET=lib/main.dart"
export "FLUTTER_BUILD_DIR=build"
export "FLUTTER_BUILD_NAME=4.1.0"
export "FLUTTER_BUILD_NUMBER=213"
export "DART_DEFINES=RkxVVFRFUl9XRUJfQVVUT19ERVRFQ1Q9dHJ1ZQ==,RkxVVFRFUl9XRUJfQ0FOVkFTS0lUX1VSTD1odHRwczovL3d3dy5nc3RhdGljLmNvbS9mbHV0dGVyLWNhbnZhc2tpdC8yYTM0MDFjOWJiYjVhOWE5YWVjNzRkNGY3MzVkMThhOWRkM2ViZjJkLw=="
export "FLUTTER_BUILD_NAME=4.2.0"
export "FLUTTER_BUILD_NUMBER=220"
export "DART_OBFUSCATION=false"
export "TRACK_WIDGET_CREATION=true"
export "TREE_SHAKE_ICONS=false"
export "PACKAGE_CONFIG=/Users/kima/Documents/refilc/app/naplo/filcnaplo/.dart_tool/package_config.json"
export "PACKAGE_CONFIG=.dart_tool/package_config.json"

View File

@@ -0,0 +1,13 @@
#!/bin/sh
# This is a generated file; do not edit or check into version control.
export "FLUTTER_ROOT=/Users/kima/src/flutter"
export "FLUTTER_APPLICATION_PATH=/Users/kima/Documents/refilc/app/naplo/filcnaplo"
export "COCOAPODS_PARALLEL_CODE_SIGN=true"
export "FLUTTER_TARGET=lib/main.dart"
export "FLUTTER_BUILD_DIR=build"
export "FLUTTER_BUILD_NAME=4.2.0"
export "FLUTTER_BUILD_NUMBER=220"
export "DART_OBFUSCATION=false"
export "TRACK_WIDGET_CREATION=true"
export "TREE_SHAKE_ICONS=false"
export "PACKAGE_CONFIG=.dart_tool/package_config.json"

View File

@@ -1,6 +1,7 @@
import 'dart:convert';
import 'dart:developer';
import 'package:filcnaplo/models/ad.dart';
import 'package:filcnaplo/models/config.dart';
import 'package:filcnaplo/models/news.dart';
import 'package:filcnaplo/models/release.dart';
@@ -18,6 +19,7 @@ class FilcAPI {
static const supporters = "https://api.refilc.hu/v1/public/supporters";
// Private API
static const ads = "https://api.refilc.hu/v1/private/ads";
static const config = "https://api.refilc.hu/v1/private/config";
static const reportApi = "https://api.refilc.hu/v1/private/crash-report";
static const premiumApi = "https://api.filcnaplo.hu/premium/activate";
@@ -117,6 +119,24 @@ class FilcAPI {
return null;
}
static Future<List<Ad>?> getAds() async {
try {
http.Response res = await http.get(Uri.parse(ads));
if (res.statusCode == 200) {
return (jsonDecode(res.body) as List)
.cast<Map>()
.map((e) => Ad.fromJson(e))
.toList();
} else {
throw "HTTP ${res.statusCode}: ${res.body}";
}
} on Exception catch (error, stacktrace) {
log("ERROR: FilcAPI.getAds: $error $stacktrace");
}
return null;
}
static Future<List<Release>?> getReleases() async {
try {
http.Response res = await http.get(Uri.parse(releases));

View File

@@ -27,7 +27,7 @@ enum LoginState {
failed,
normal,
inProgress,
success
success,
}
Nonce getNonce(String nonce, String username, String instituteCode) {
@@ -39,7 +39,7 @@ Nonce getNonce(String nonce, String username, String instituteCode) {
return nonceEncoder;
}
Future loginApi({
Future loginAPI({
required String username,
required String password,
required String instituteCode,
@@ -121,7 +121,7 @@ Future loginApi({
return LoginState.success;
} catch (error) {
print("ERROR: loginApi: $error");
print("ERROR: loginAPI: $error");
// maybe check debug mode
// ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("ERROR: $error")));
return LoginState.failed;

View File

@@ -0,0 +1,29 @@
import 'package:filcnaplo/api/client.dart';
import 'package:filcnaplo/models/ad.dart';
import 'package:flutter/material.dart';
class AdProvider extends ChangeNotifier {
// private
late List<Ad> _ads;
bool get available => _ads.isNotEmpty;
// public
List<Ad> get ads => _ads;
AdProvider({
List<Ad> initialAds = const [],
required BuildContext context,
}) {
_ads = List.castFrom(initialAds);
}
Future<void> fetch() async {
_ads = await FilcAPI.getAds() ?? [];
_ads.sort((a, b) => -a.date.compareTo(b.date));
// check for new ads
if (_ads.isNotEmpty) {
notifyListeners();
}
}
}

View File

@@ -3,6 +3,7 @@ import 'dart:math';
import 'package:dynamic_color/dynamic_color.dart';
import 'package:filcnaplo/api/client.dart';
import 'package:filcnaplo/api/providers/ad_provider.dart';
import 'package:filcnaplo/api/providers/live_card_provider.dart';
import 'package:filcnaplo/api/providers/news_provider.dart';
import 'package:filcnaplo/api/providers/database_provider.dart';
@@ -104,6 +105,8 @@ class App extends StatelessWidget {
create: (context) => NewsProvider(context: context)),
ChangeNotifierProvider<UpdateProvider>(
create: (context) => UpdateProvider(context: context)),
ChangeNotifierProvider<AdProvider>(
create: (context) => AdProvider(context: context)),
// user data (kreten) providers
ChangeNotifierProvider<GradeProvider>(

View File

@@ -9,7 +9,7 @@ import 'package:permission_handler/permission_handler.dart';
class StorageHelper {
static Future<bool> write(String path, Uint8List data) async {
try {
if (await Permission.storage.request().isGranted) {
if (await Permission.manageExternalStorage.request().isGranted) {
await File(path).writeAsBytes(data);
return true;
} else {
@@ -34,5 +34,6 @@ class StorageHelper {
}
return downloads;
// return (await getTemporaryDirectory()).path;
}
}

View File

@@ -33,10 +33,10 @@ extension UpdateHelper on Release {
updateCallback(-1, UpdateState.installing);
var permStatus =
var installPerms =
(await Permission.manageExternalStorage.request().isGranted &&
await Permission.requestInstallPackages.request().isGranted);
if (permStatus) {
if (installPerms) {
var result = await OpenFile.open(apk.path);
if (result.type != ResultType.done) {

View File

@@ -0,0 +1,38 @@
class Ad {
String title;
String description;
String author;
Uri? logoUrl;
bool overridePremium;
DateTime date;
DateTime expireDate;
Uri launchUrl;
Ad({
required this.title,
required this.description,
required this.author,
this.logoUrl,
this.overridePremium = false,
required this.date,
required this.expireDate,
required this.launchUrl,
});
factory Ad.fromJson(Map json) {
print(json);
return Ad(
title: json['title'] ?? 'Ad',
description: json['description'] ?? '',
author: json['author'] ?? 'reFilc',
logoUrl: json['logo_url'] != null ? Uri.parse(json['logo_url']) : null,
overridePremium: json['override_premium'] ?? false,
date:
json['date'] != null ? DateTime.parse(json['date']) : DateTime.now(),
expireDate: json['expire_date'] != null
? DateTime.parse(json['expire_date'])
: DateTime.now(),
launchUrl: Uri.parse(json['launch_url'] ?? 'https://refilc.hu'),
);
}
}

View File

@@ -1,3 +1,4 @@
import 'package:filcnaplo/api/providers/ad_provider.dart';
import 'package:filcnaplo/api/providers/update_provider.dart';
import 'package:filcnaplo/models/settings.dart';
import 'package:filcnaplo/ui/date_widget.dart';
@@ -14,6 +15,7 @@ import 'package:filcnaplo/ui/filter/widgets/lessons.dart' as lesson_filter;
import 'package:filcnaplo/ui/filter/widgets/update.dart' as update_filter;
import 'package:filcnaplo/ui/filter/widgets/missed_exams.dart'
as missed_exam_filter;
import 'package:filcnaplo/ui/filter/widgets/ads.dart' as ad_filter;
import 'package:filcnaplo_kreta_api/models/week.dart';
import 'package:filcnaplo_kreta_api/providers/absence_provider.dart';
import 'package:filcnaplo_kreta_api/providers/event_provider.dart';
@@ -50,7 +52,8 @@ enum FilterType {
lessons,
updates,
certifications,
missedExams
missedExams,
ads,
}
Future<List<DateWidget>> getFilterWidgets(FilterType activeData,
@@ -65,6 +68,7 @@ Future<List<DateWidget>> getFilterWidgets(FilterType activeData,
final eventProvider = Provider.of<EventProvider>(context);
final updateProvider = Provider.of<UpdateProvider>(context);
final settingsProvider = Provider.of<SettingsProvider>(context);
final adProvider = Provider.of<AdProvider>(context);
List<DateWidget> items = [];
@@ -82,6 +86,7 @@ Future<List<DateWidget>> getFilterWidgets(FilterType activeData,
getFilterWidgets(FilterType.updates, context: context),
getFilterWidgets(FilterType.certifications, context: context),
getFilterWidgets(FilterType.missedExams, context: context),
getFilterWidgets(FilterType.ads, context: context),
]);
items = all.expand((x) => x).toList();
@@ -89,7 +94,7 @@ Future<List<DateWidget>> getFilterWidgets(FilterType activeData,
// Grades
case FilterType.grades:
if(!settingsProvider.gradeOpeningFun) {
if (!settingsProvider.gradeOpeningFun) {
gradeProvider.seenAll();
}
items = grade_filter.getWidgets(
@@ -164,6 +169,13 @@ Future<List<DateWidget>> getFilterWidgets(FilterType activeData,
items = missed_exam_filter
.getWidgets(timetableProvider.getWeek(Week.current()) ?? []);
break;
// Ads
case FilterType.ads:
if (adProvider.available) {
items = ad_filter.getWidgets(adProvider.ads);
}
break;
}
return items;
}

View File

@@ -0,0 +1,25 @@
import 'package:filcnaplo/models/ad.dart';
import 'package:filcnaplo/ui/date_widget.dart';
import 'package:filcnaplo_mobile_ui/common/widgets/ad/ad_viewable.dart'
as mobile;
List<DateWidget> getWidgets(List<Ad> providerAds) {
List<DateWidget> items = [];
if (providerAds.isNotEmpty) {
for (var ad in providerAds) {
if (ad.date.isBefore(DateTime.now()) &&
ad.expireDate.isAfter(DateTime.now())) {
providerAds.sort((a, b) => -a.date.compareTo(b.date));
items.add(DateWidget(
key: ad.description,
date: ad.date,
widget: mobile.AdViewable(ad),
));
}
}
}
return items;
}

View File

@@ -44,7 +44,8 @@ class LessonTile extends StatelessWidget {
fillLeading = true;
}
if (lesson.substituteTeacher?.name != "") {
if (lesson.substituteTeacher != null &&
lesson.substituteTeacher?.name != "") {
fill = true;
accent = AppColors.of(context).yellow;
}

View File

@@ -3,7 +3,7 @@ description: "Nem hivatalos e-napló alkalmazás az e-Kréta rendszerhez"
homepage: https://refilc.hu
publish_to: "none"
version: 4.2.0+220
version: 4.2.2+222
environment:
sdk: ">=2.17.0 <3.0.0"

View File

@@ -235,7 +235,7 @@ class _LoginScreenState extends State<LoginScreen> {
fontWeight: FontWeight.w600,
fontSize: 15.0,
)),
onPressed: () => _loginApi(context: context),
onPressed: () => _loginAPI(context: context),
),
visible: _loginState != LoginState.inProgress,
replacement: const Padding(
@@ -279,7 +279,7 @@ class _LoginScreenState extends State<LoginScreen> {
);
}
void _loginApi({required BuildContext context}) {
void _loginAPI({required BuildContext context}) {
String username = usernameController.text;
String password = passwordController.text;
@@ -289,7 +289,7 @@ class _LoginScreenState extends State<LoginScreen> {
setState(() => _loginState = LoginState.inProgress);
loginApi(
loginAPI(
username: username,
password: password,
instituteCode: schoolController.selectedSchool!.instituteCode,

View File

@@ -24,6 +24,11 @@ class KretaAPI {
KretaApiEndpoints.groupAverages +
"?oktatasiNevelesiFeladatUid=" +
uid;
static String averages(String iss, String uid) =>
BaseKreta.kreta(iss) +
KretaApiEndpoints.averages +
"?oktatasiNevelesiFeladatUid=" +
uid;
static String timetable(String iss, {DateTime? start, DateTime? end}) =>
BaseKreta.kreta(iss) +
KretaApiEndpoints.timetable +
@@ -90,6 +95,7 @@ class KretaApiEndpoints {
static const groups = "/ellenorzo/V3/Sajat/OsztalyCsoportok";
static const groupAverages =
"/ellenorzo/V3/Sajat/Ertekelesek/Atlagok/OsztalyAtlagok";
static const averages = "/ellenorzo/V3/idk";
static const timetable = "/ellenorzo/V3/Sajat/OrarendElemek";
static const exams = "/ellenorzo/V3/Sajat/BejelentettSzamonkeresek";
static const homework = "/ellenorzo/V3/Sajat/HaziFeladatok";

View File

@@ -71,8 +71,9 @@ class Lesson {
subject: Subject.fromJson(json["Tantargy"] ?? {}),
lessonIndex: json["Oraszam"] != null ? json["Oraszam"].toString() : "+",
lessonYearIndex: json["OraEvesSorszama"],
substituteTeacher:
Teacher.fromString((json["HelyettesTanarNeve"] ?? "").trim()),
substituteTeacher: json["HelyettesTanarNeve"] != null
? Teacher.fromString((json["HelyettesTanarNeve"]).trim())
: null,
teacher: Teacher.fromString((json["TanarNeve"] ?? "").trim()),
homeworkEnabled: json["IsTanuloHaziFeladatEnabled"] ?? false,
start: json["KezdetIdopont"] != null
@@ -99,8 +100,7 @@ class Lesson {
online: json["IsDigitalisOra"] ?? false,
isEmpty: json['isEmpty'] ?? false,
json: json,
isSeen: false
);
isSeen: false);
}
int? getFloor() {

View File

@@ -73,8 +73,16 @@ class HomeworkProvider with ChangeNotifier {
if (user == null) throw "Cannot fetch Homework for User null";
String iss = user.instituteCode;
List? homeworkJson = await Provider.of<KretaClient>(_context, listen: false)
List? homeworkJson = [];
try {
homeworkJson = await Provider.of<KretaClient>(_context, listen: false)
.getAPI(KretaAPI.homework(iss, start: from));
} catch (e) {
// error fetcing homework (unknown error)
}
if (homeworkJson == null) throw "Cannot fetch Homework for User ${user.id}";
List<Homework> homework = [];

View File

@@ -0,0 +1,53 @@
import 'package:filcnaplo/models/ad.dart';
import 'package:filcnaplo/theme/colors/colors.dart';
import 'package:flutter/material.dart';
import 'package:filcnaplo_mobile_ui/common/panel/panel_button.dart';
import 'package:flutter_feather_icons/flutter_feather_icons.dart';
class AdTile extends StatelessWidget {
const AdTile(this.ad, {Key? key, this.onTap, this.padding}) : super(key: key);
final Ad ad;
final Function()? onTap;
final EdgeInsetsGeometry? padding;
@override
Widget build(BuildContext context) {
print('geic');
print(ad);
return Padding(
padding: padding ?? const EdgeInsets.symmetric(horizontal: 8.0),
child: PanelButton(
padding: const EdgeInsets.only(left: 8.0, right: 16.0),
onPressed: onTap,
title: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
ad.title,
),
Text(
ad.description,
style: TextStyle(
fontWeight: FontWeight.w500,
color: AppColors.of(context).text.withOpacity(0.7),
),
),
],
),
leading: ad.logoUrl != null
? Image.network(
ad.logoUrl.toString(),
errorBuilder: (context, error, stackTrace) {
ad.logoUrl = null;
return const SizedBox();
},
)
: null,
trailing: const Icon(FeatherIcons.externalLink),
),
);
}
}

View File

@@ -0,0 +1,22 @@
import 'package:filcnaplo/models/ad.dart';
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
import 'ad_tile.dart';
class AdViewable extends StatelessWidget {
const AdViewable(this.ad, {Key? key}) : super(key: key);
final Ad ad;
@override
Widget build(BuildContext context) {
return AdTile(
ad,
onTap: () => launchUrl(
ad.launchUrl,
mode: LaunchMode.externalApplication,
),
);
}
}

View File

@@ -22,7 +22,8 @@ class LessonView extends StatelessWidget {
if (RegExp(r'\d').hasMatch(lesson.lessonIndex)) lessonIndexTrailing = ".";
if (lesson.substituteTeacher?.name != "") {
if (lesson.substituteTeacher != null &&
lesson.substituteTeacher?.name != "") {
accent = AppColors.of(context).yellow;
}

View File

@@ -18,7 +18,8 @@ class UpdateView extends StatefulWidget {
final Release release;
static void show(Release release, {required BuildContext context}) => showBottomCard(context: context, child: UpdateView(release));
static void show(Release release, {required BuildContext context}) =>
showBottomCard(context: context, child: UpdateView(release));
@override
_UpdateViewState createState() => _UpdateViewState();
@@ -45,7 +46,8 @@ class _UpdateViewState extends State<UpdateView> {
children: [
Text(
"new_update".i18n,
style: const TextStyle(fontWeight: FontWeight.w700, fontSize: 18.0),
style: const TextStyle(
fontWeight: FontWeight.w700, fontSize: 18.0),
),
Text(
"${widget.release.version}",
@@ -75,7 +77,7 @@ class _UpdateViewState extends State<UpdateView> {
borderRadius: BorderRadius.circular(12.0),
),
child: SizedBox(
height: 125.0,
height: 200.0,
child: Markdown(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
physics: const BouncingScrollPhysics(),
@@ -91,21 +93,30 @@ class _UpdateViewState extends State<UpdateView> {
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (state == UpdateState.downloading || state == UpdateState.preparing)
if (state == UpdateState.downloading ||
state == UpdateState.preparing)
Container(
height: 18.0,
width: 18.0,
margin: const EdgeInsets.only(right: 8.0),
child: CircularProgressIndicator(
value: progress > 0.05 ? progress : null,
color: ColorUtils.foregroundColor(AppColors.of(context).filc),
color: ColorUtils.foregroundColor(
AppColors.of(context).filc),
),
),
Text(["download".i18n, "downloading".i18n, "downloading".i18n, "installing".i18n][state.index].toUpperCase()),
Text([
"download".i18n,
"downloading".i18n,
"downloading".i18n,
"installing".i18n
][state.index]
.toUpperCase()),
],
),
backgroundColor: AppColors.of(context).filc,
onPressed: state == UpdateState.none ? () => downloadPrecheck() : null,
onPressed:
state == UpdateState.none ? () => downloadPrecheck() : null,
),
),
],
@@ -113,7 +124,8 @@ class _UpdateViewState extends State<UpdateView> {
);
}
String fmtSize() => "${(widget.release.downloads.first.size / 1024 / 1024).toStringAsFixed(1)} MB";
String fmtSize() =>
"${(widget.release.downloads.first.size / 1024 / 1024).toStringAsFixed(1)} MB";
void downloadPrecheck() {
final status = Provider.of<StatusProvider>(context, listen: false);
@@ -157,6 +169,7 @@ class _UpdateViewState extends State<UpdateView> {
.then((_) => Navigator.of(context).maybePop())
.catchError((error, stackTrace) {
if (mounted) {
Navigator.of(context).maybePop();
ScaffoldMessenger.of(context).showSnackBar(CustomSnackBar(
context: context,
content: Text("error".i18n),

View File

@@ -5,6 +5,8 @@ import 'package:filcnaplo/api/providers/database_provider.dart';
import 'package:filcnaplo/api/providers/user_provider.dart';
import 'package:filcnaplo/models/settings.dart';
import 'package:filcnaplo/utils/format.dart';
// import 'package:filcnaplo_kreta_api/client/api.dart';
// import 'package:filcnaplo_kreta_api/client/client.dart';
import 'package:filcnaplo_kreta_api/providers/grade_provider.dart';
import 'package:filcnaplo/helpers/average_helper.dart';
import 'package:filcnaplo/helpers/subject.dart';

View File

@@ -2,6 +2,8 @@ import 'dart:math';
import 'package:auto_size_text/auto_size_text.dart';
import 'package:filcnaplo/api/providers/update_provider.dart';
// import 'package:filcnaplo_kreta_api/client/api.dart';
// import 'package:filcnaplo_kreta_api/client/client.dart';
import 'package:filcnaplo_kreta_api/providers/grade_provider.dart';
import 'package:filcnaplo/api/providers/user_provider.dart';
import 'package:filcnaplo/theme/colors/colors.dart';
@@ -112,6 +114,18 @@ class _GradesPageState extends State<GradesPage> {
} else {
tiles.insert(
0,
// TextButton(
// onPressed: () async {
// var url = KretaAPI.averages(
// user.instituteCode!,
// user.id!,
// );
// print(url);
// var res = await Provider.of<KretaClient>(context, listen: false)
// .getAPI(url);
// print(res);
// },
// child: Text('test')),
Padding(
padding: const EdgeInsets.only(top: 24.0),
child: Empty(subtitle: "empty".i18n),

View File

@@ -1,3 +1,4 @@
// import 'dart:async';
import 'dart:ui';
import 'package:filcnaplo/api/client.dart';
@@ -42,6 +43,8 @@ class _LoginScreenState extends State<LoginScreen> {
stops: [-1.0, 0.0, 1.0],
);
late String tempUsername = '';
@override
void initState() {
super.initState();
@@ -250,7 +253,7 @@ class _LoginScreenState extends State<LoginScreen> {
fontWeight: FontWeight.w600,
fontSize: 15.0,
)),
onPressed: () => _loginApi(context: context),
onPressed: () => _loginAPI(context: context),
),
visible: _loginState != LoginState.inProgress,
replacement: const Padding(
@@ -275,7 +278,10 @@ class _LoginScreenState extends State<LoginScreen> {
][_loginState.index]
.i18n,
style: const TextStyle(
color: Colors.red, fontWeight: FontWeight.w500),
color: Colors.red,
fontWeight: FontWeight.w500,
),
textAlign: TextAlign.center,
),
),
const Spacer()
@@ -288,19 +294,20 @@ class _LoginScreenState extends State<LoginScreen> {
);
}
void _loginApi({required BuildContext context}) {
void _loginAPI({required BuildContext context}) {
String username = usernameController.text;
String password = passwordController.text;
tempUsername = username;
if (username == "" ||
password == "" ||
schoolController.selectedSchool == null) {
return setState(() => _loginState = LoginState.missingFields);
}
setState(() => _loginState = LoginState.inProgress);
loginApi(
void _callAPI() {
loginAPI(
username: username,
password: password,
instituteCode: schoolController.selectedSchool!.instituteCode,
@@ -317,6 +324,24 @@ class _LoginScreenState extends State<LoginScreen> {
ScaffoldMessenger.of(context).hideCurrentSnackBar();
setSystemChrome(context);
Navigator.of(context).pushReplacementNamed("login_to_navigation");
}).then((res) => setState(() => _loginState = res));
}).then(
(res) => setState(() {
// if (res == LoginState.invalidGrant &&
// tempUsername.replaceAll(username, '').length <= 3) {
// tempUsername = username + ' ';
// Timer(
// const Duration(milliseconds: 500),
// () => _loginAPI(context: context),
// );
// // _loginAPI(context: context);
// } else {
_loginState = res;
// }
}),
);
}
setState(() => _loginState = LoginState.inProgress);
_callAPI();
}
}

View File

@@ -12,7 +12,8 @@ extension Localization on String {
"login": "Log in",
"welcome": "Welcome, %s!",
"missing_fields": "Missing Fields!",
"invalid_grant": "Invalid Username/Password!",
"invalid_grant":
"Invalid Username/Password! (Try adding spaces after Username)",
"error": "Failed to log in.",
"schools_error": "Failed to get schools."
},
@@ -25,7 +26,8 @@ extension Localization on String {
"login": "Belépés",
"welcome": "Üdv, %s!",
"missing_fields": "Hiányzó adatok!",
"invalid_grant": "Helytelen Felhasználónév/Jelszó!",
"invalid_grant":
"Helytelen Felhasználónév/Jelszó! (Próbálj szóközöket írni a Felhasználónév után)",
"error": "Sikertelen bejelentkezés.",
"schools_error": "Nem sikerült lekérni az iskolákat."
},

View File

@@ -12,12 +12,10 @@ class SchoolInputTile extends StatelessWidget {
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(4.0),
child: GestureDetector(
onPanDown: (e) {
child: InkWell(
onTap: () {
onTap!();
},
child: InkWell(
onTapDown: (e) {},
borderRadius: BorderRadius.circular(6.0),
child: Padding(
padding: const EdgeInsets.all(6.0),
@@ -59,7 +57,6 @@ class SchoolInputTile extends StatelessWidget {
),
),
),
),
);
}
}

View File

@@ -26,6 +26,7 @@ import 'package:home_widget/home_widget.dart';
import 'package:wtf_sliding_sheet/wtf_sliding_sheet.dart';
import 'package:background_fetch/background_fetch.dart';
import 'package:filcnaplo_premium/providers/goal_provider.dart';
import 'package:filcnaplo/api/providers/ad_provider.dart';
class NavigationScreen extends StatefulWidget {
const NavigationScreen({Key? key}) : super(key: key);
@@ -48,6 +49,7 @@ class NavigationScreenState extends State<NavigationScreen>
late GoalProvider goalProvider;
late UpdateProvider updateProvider;
late GradeProvider gradeProvicer;
late AdProvider adProvider;
NavigatorState? get navigator => _navigatorState.currentState;
@@ -176,6 +178,10 @@ class NavigationScreenState extends State<NavigationScreen>
updateProvider = Provider.of<UpdateProvider>(context, listen: false);
updateProvider.fetch();
// get advertisements
adProvider = Provider.of<AdProvider>(context, listen: false);
adProvider.fetch();
// initial sync
syncAll(context);
setupQuickActions();

View File

@@ -1,5 +1,6 @@
import 'package:filcnaplo/api/providers/database_provider.dart';
import 'package:filcnaplo/api/providers/user_provider.dart';
import 'package:filcnaplo/theme/colors/colors.dart';
import 'package:filcnaplo_kreta_api/models/subject.dart';
import 'package:filcnaplo_mobile_ui/common/average_display.dart';
import 'package:filcnaplo_premium/ui/mobile/goal_planner/goal_state_screen.i18n.dart';
@@ -33,7 +34,7 @@ class GoalCompleteModal extends StatelessWidget {
child: Container(
padding: const EdgeInsets.all(16.0),
decoration: BoxDecoration(
color: Colors.white,
color: Theme.of(context).colorScheme.background,
borderRadius: BorderRadius.circular(20.0),
),
child: Column(
@@ -79,19 +80,21 @@ class GoalCompleteModal extends StatelessWidget {
Text(
'congrats_title'.i18n,
textAlign: TextAlign.center,
style: const TextStyle(
style: TextStyle(
fontSize: 27.0,
fontWeight: FontWeight.w700,
height: 1.1,
height: 1.2,
color: AppColors.of(context).text,
),
),
Text(
'goal_reached'.i18n.fill(['20']),
textAlign: TextAlign.center,
style: const TextStyle(
style: TextStyle(
fontSize: 15.0,
fontWeight: FontWeight.w500,
height: 1.1,
color: AppColors.of(context).text,
),
),
const SizedBox(height: 18.0),
@@ -103,9 +106,10 @@ class GoalCompleteModal extends StatelessWidget {
Text(
'started_at'.i18n,
textAlign: TextAlign.center,
style: const TextStyle(
style: TextStyle(
fontSize: 17.0,
fontWeight: FontWeight.w500,
color: AppColors.of(context).text,
),
),
const SizedBox(width: 5.0),
@@ -119,9 +123,10 @@ class GoalCompleteModal extends StatelessWidget {
averageDifference.toStringAsFixed(2) + '%',
]),
textAlign: TextAlign.center,
style: const TextStyle(
style: TextStyle(
fontSize: 17.0,
fontWeight: FontWeight.w500,
color: AppColors.of(context).text,
),
),
],
@@ -173,17 +178,17 @@ class GoalCompleteModal extends StatelessWidget {
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
color: const Color(0xFFF5FAF9),
color: const Color.fromARGB(38, 131, 131, 131),
),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Text(
'later'.i18n,
textAlign: TextAlign.center,
style: const TextStyle(
style: TextStyle(
fontSize: 18.0,
fontWeight: FontWeight.w700,
color: Color(0xFF01342D),
color: AppColors.of(context).text,
),
),
),