flutter linting
This commit is contained in:
parent
79f6ef4c50
commit
339dbea1ef
29
filcnaplo/analysis_options.yaml
Normal file
29
filcnaplo/analysis_options.yaml
Normal file
@ -0,0 +1,29 @@
|
||||
# This file configures the analyzer, which statically analyzes Dart code to
|
||||
# check for errors, warnings, and lints.
|
||||
#
|
||||
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
|
||||
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
|
||||
# invoked from the command line by running `flutter analyze`.
|
||||
|
||||
# The following line activates a set of recommended lints for Flutter apps,
|
||||
# packages, and plugins designed to encourage good coding practices.
|
||||
include: package:flutter_lints/flutter.yaml
|
||||
|
||||
linter:
|
||||
# The lint rules applied to this project can be customized in the
|
||||
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
|
||||
# included above or to enable additional rules. A list of all available lints
|
||||
# and their documentation is published at
|
||||
# https://dart-lang.github.io/linter/lints/index.html.
|
||||
#
|
||||
# Instead of disabling a lint rule for the entire project in the
|
||||
# section below, it can also be suppressed for a single line of code
|
||||
# or a specific dart file by using the `// ignore: name_of_lint` and
|
||||
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
|
||||
# producing the lint.
|
||||
rules:
|
||||
# avoid_print: false # Uncomment to disable the `avoid_print` rule
|
||||
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
|
||||
|
||||
# Additional information about this file can be found at
|
||||
# https://dart.dev/guides/language/analysis-options
|
@ -1,3 +1,5 @@
|
||||
// ignore_for_file: avoid_print
|
||||
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:filcnaplo/models/config.dart';
|
||||
@ -11,23 +13,23 @@ import 'package:connectivity_plus/connectivity_plus.dart';
|
||||
|
||||
class FilcAPI {
|
||||
// Public API
|
||||
static const SCHOOL_LIST = "https://filcnaplo.hu/v2/school_list.json";
|
||||
static const NEWS = "https://filcnaplo.hu/v2/news.json";
|
||||
static const SUPPORTERS = "https://filcnaplo.hu/v2/supporters.json";
|
||||
static const schoolList = "https://filcnaplo.hu/v2/school_list.json";
|
||||
static const news = "https://filcnaplo.hu/v2/news.json";
|
||||
static const supporters = "https://filcnaplo.hu/v2/supporters.json";
|
||||
|
||||
// Private API
|
||||
static const CONFIG = "https://api.filcnaplo.hu/config";
|
||||
static const REPORT = "https://api.filcnaplo.hu/report";
|
||||
static const config = "https://api.filcnaplo.hu/config";
|
||||
static const reportApi = "https://api.filcnaplo.hu/report";
|
||||
|
||||
// Updates
|
||||
static const REPO = "filc/naplo";
|
||||
static const RELEASES = "https://api.github.com/repos/$REPO/releases";
|
||||
static const repo = "filc/naplo";
|
||||
static const releases = "https://api.github.com/repos/$repo/releases";
|
||||
|
||||
static Future<bool> checkConnectivity() async => (await Connectivity().checkConnectivity()) != ConnectivityResult.none;
|
||||
|
||||
static Future<List<School>?> getSchools() async {
|
||||
try {
|
||||
http.Response res = await http.get(Uri.parse(SCHOOL_LIST));
|
||||
http.Response res = await http.get(Uri.parse(schoolList));
|
||||
|
||||
if (res.statusCode == 200) {
|
||||
List<School> schools = (jsonDecode(res.body) as List).cast<Map>().map((json) => School.fromJson(json)).toList();
|
||||
@ -52,12 +54,12 @@ class FilcAPI {
|
||||
};
|
||||
|
||||
try {
|
||||
http.Response res = await http.get(Uri.parse(CONFIG), headers: headers);
|
||||
http.Response res = await http.get(Uri.parse(config), headers: headers);
|
||||
|
||||
if (res.statusCode == 200) {
|
||||
return Config.fromJson(jsonDecode(res.body));
|
||||
} else if (res.statusCode == 429) {
|
||||
res = await http.get(Uri.parse(CONFIG));
|
||||
res = await http.get(Uri.parse(config));
|
||||
if (res.statusCode == 200) return Config.fromJson(jsonDecode(res.body));
|
||||
}
|
||||
throw "HTTP ${res.statusCode}: ${res.body}";
|
||||
@ -68,7 +70,7 @@ class FilcAPI {
|
||||
|
||||
static Future<List<News>?> getNews() async {
|
||||
try {
|
||||
http.Response res = await http.get(Uri.parse(NEWS));
|
||||
http.Response res = await http.get(Uri.parse(news));
|
||||
|
||||
if (res.statusCode == 200) {
|
||||
return (jsonDecode(res.body) as List).cast<Map>().map((e) => News.fromJson(e)).toList();
|
||||
@ -82,7 +84,7 @@ class FilcAPI {
|
||||
|
||||
static Future<Supporters?> getSupporters() async {
|
||||
try {
|
||||
http.Response res = await http.get(Uri.parse(SUPPORTERS));
|
||||
http.Response res = await http.get(Uri.parse(supporters));
|
||||
|
||||
if (res.statusCode == 200) {
|
||||
return Supporters.fromJson(jsonDecode(res.body));
|
||||
@ -96,7 +98,7 @@ class FilcAPI {
|
||||
|
||||
static Future<List<Release>?> getReleases() async {
|
||||
try {
|
||||
http.Response res = await http.get(Uri.parse(RELEASES));
|
||||
http.Response res = await http.get(Uri.parse(releases));
|
||||
|
||||
if (res.statusCode == 200) {
|
||||
return (jsonDecode(res.body) as List).cast<Map>().map((e) => Release.fromJson(e)).toList();
|
||||
@ -109,7 +111,7 @@ class FilcAPI {
|
||||
}
|
||||
|
||||
static Future<http.StreamedResponse?> downloadRelease(Release release) {
|
||||
if (release.downloads.length > 0) {
|
||||
if (release.downloads.isNotEmpty) {
|
||||
try {
|
||||
var client = http.Client();
|
||||
var request = http.Request('GET', Uri.parse(release.downloads.first));
|
||||
@ -124,7 +126,7 @@ class FilcAPI {
|
||||
|
||||
static Future<void> sendReport(ErrorReport report) async {
|
||||
try {
|
||||
http.Response res = await http.post(Uri.parse(REPORT), body: {
|
||||
http.Response res = await http.post(Uri.parse(reportApi), body: {
|
||||
"os": report.os,
|
||||
"version": report.version,
|
||||
"error": report.error,
|
||||
|
@ -1,3 +1,5 @@
|
||||
// ignore_for_file: avoid_print
|
||||
|
||||
import 'package:filcnaplo/utils/jwt.dart';
|
||||
import 'package:filcnaplo_kreta_api/providers/absence_provider.dart';
|
||||
import 'package:filcnaplo_kreta_api/providers/event_provider.dart';
|
||||
|
@ -72,10 +72,11 @@ class NewsProvider extends ChangeNotifier {
|
||||
|
||||
Provider.of<SettingsProvider>(_context, listen: false).update(_context, newsState: _state);
|
||||
|
||||
if (_fresh > 0)
|
||||
if (_fresh > 0) {
|
||||
show = true;
|
||||
else
|
||||
} else {
|
||||
show = false;
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
@ -5,14 +5,14 @@ import 'package:http/http.dart' as http;
|
||||
enum Status { network, maintenance, syncing }
|
||||
|
||||
class StatusProvider extends ChangeNotifier {
|
||||
List<Status> _stack = [];
|
||||
final List<Status> _stack = [];
|
||||
double _progress = 0.0;
|
||||
|
||||
StatusProvider() {
|
||||
_handleNetworkChanges();
|
||||
}
|
||||
|
||||
Status? getStatus() => _stack.length > 0 ? _stack[0] : null;
|
||||
Status? getStatus() => _stack.isNotEmpty ? _stack[0] : null;
|
||||
// Status progress from 0.0 to 1.0
|
||||
double get progress => _progress;
|
||||
|
||||
@ -64,10 +64,12 @@ class StatusProvider extends ChangeNotifier {
|
||||
if (_progress == 1.0) {
|
||||
notifyListeners();
|
||||
// Wait for animation
|
||||
Future.delayed(Duration(milliseconds: 250), () {
|
||||
Future.delayed(const Duration(milliseconds: 250), () {
|
||||
_stack.remove(Status.syncing);
|
||||
notifyListeners();
|
||||
});
|
||||
} else if (progress != prev) notifyListeners();
|
||||
} else if (progress != prev) {
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ Future<void> syncAll(BuildContext context) {
|
||||
// Lock
|
||||
lock = true;
|
||||
|
||||
// ignore: avoid_print
|
||||
print("INFO Syncing all");
|
||||
|
||||
UserProvider user = Provider.of<UserProvider>(context, listen: false);
|
||||
@ -42,7 +43,7 @@ Future<void> syncAll(BuildContext context) {
|
||||
_syncStatus(Provider.of<GradeProvider>(context, listen: false).fetch()),
|
||||
_syncStatus(Provider.of<TimetableProvider>(context, listen: false).fetch(week: Week.current())),
|
||||
_syncStatus(Provider.of<ExamProvider>(context, listen: false).fetch()),
|
||||
_syncStatus(Provider.of<HomeworkProvider>(context, listen: false).fetch(from: DateTime.now().subtract(Duration(days: 30)))),
|
||||
_syncStatus(Provider.of<HomeworkProvider>(context, listen: false).fetch(from: DateTime.now().subtract(const Duration(days: 30)))),
|
||||
_syncStatus(Provider.of<MessageProvider>(context, listen: false).fetchAll()),
|
||||
_syncStatus(Provider.of<NoteProvider>(context, listen: false).fetch()),
|
||||
_syncStatus(Provider.of<EventProvider>(context, listen: false).fetch()),
|
||||
|
@ -9,7 +9,7 @@ class UpdateProvider extends ChangeNotifier {
|
||||
// Private
|
||||
late List<Release> _releases;
|
||||
bool _available = false;
|
||||
bool get available => _available && _releases.length > 0;
|
||||
bool get available => _available && _releases.isNotEmpty;
|
||||
PackageInfo? _packageInfo;
|
||||
|
||||
// Public
|
||||
@ -32,8 +32,9 @@ class UpdateProvider extends ChangeNotifier {
|
||||
_releases.sort((a, b) => -a.version.compareTo(b.version));
|
||||
|
||||
// Check for new releases
|
||||
if (_releases.length > 0) {
|
||||
if (_releases.isNotEmpty) {
|
||||
_available = _packageInfo != null && _releases.first.version.compareTo(Version.fromString(currentVersion)) == 1;
|
||||
// ignore: avoid_print
|
||||
if (_available) print("INFO: New update: ${releases.first.version}");
|
||||
notifyListeners();
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ import 'package:filcnaplo_kreta_api/models/student.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
class UserProvider with ChangeNotifier {
|
||||
Map<String, User> _users = {};
|
||||
final Map<String, User> _users = {};
|
||||
String? _selectedUserId;
|
||||
User? get user => _users[_selectedUserId];
|
||||
|
||||
@ -23,7 +23,9 @@ class UserProvider with ChangeNotifier {
|
||||
|
||||
void addUser(User user) {
|
||||
_users[user.id] = user;
|
||||
print("DEBUG: Added User: ${user.id} ${user.name}");
|
||||
if (kDebugMode) {
|
||||
print("DEBUG: Added User: ${user.id} ${user.name}");
|
||||
}
|
||||
}
|
||||
|
||||
void removeUser(String userId) {
|
||||
|
@ -41,7 +41,7 @@ class App extends StatelessWidget {
|
||||
final DatabaseProvider database;
|
||||
|
||||
App({Key? key, required this.database, required this.settings, required this.user}) : super(key: key) {
|
||||
if (user.getUsers().length > 0) user.setUser(user.getUsers().first.id);
|
||||
if (user.getUsers().isNotEmpty) user.setUser(user.getUsers().first.id);
|
||||
}
|
||||
|
||||
@override
|
||||
@ -99,18 +99,18 @@ class App extends StatelessWidget {
|
||||
theme: AppTheme.lightTheme(context),
|
||||
darkTheme: AppTheme.darkTheme(context),
|
||||
themeMode: themeMode.themeMode,
|
||||
localizationsDelegates: [
|
||||
localizationsDelegates: const [
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
supportedLocales: [
|
||||
const Locale('en', 'EN'),
|
||||
const Locale('hu', 'HU'),
|
||||
const Locale('de', 'DE'),
|
||||
supportedLocales: const [
|
||||
Locale('en', 'EN'),
|
||||
Locale('hu', 'HU'),
|
||||
Locale('de', 'DE'),
|
||||
],
|
||||
localeListResolutionCallback: (locales, supported) {
|
||||
Locale locale = Locale('hu', 'HU');
|
||||
Locale locale = const Locale('hu', 'HU');
|
||||
|
||||
for (var loc in locales ?? []) {
|
||||
if (supported.contains(loc)) {
|
||||
@ -122,7 +122,7 @@ class App extends StatelessWidget {
|
||||
return locale;
|
||||
},
|
||||
onGenerateRoute: (settings) => rootNavigator(settings),
|
||||
initialRoute: user.getUsers().length > 0 ? "navigation" : "login");
|
||||
initialRoute: user.getUsers().isNotEmpty ? "navigation" : "login");
|
||||
},
|
||||
),
|
||||
),
|
||||
@ -133,15 +133,15 @@ class App extends StatelessWidget {
|
||||
// if platform == android || platform == ios
|
||||
switch (route.name) {
|
||||
case "login_back":
|
||||
return CupertinoPageRoute(builder: (context) => LoginScreen(back: true));
|
||||
return CupertinoPageRoute(builder: (context) => const LoginScreen(back: true));
|
||||
case "login":
|
||||
return _rootRoute(LoginScreen());
|
||||
return _rootRoute(const LoginScreen());
|
||||
case "navigation":
|
||||
return _rootRoute(NavigationScreen());
|
||||
return _rootRoute(const NavigationScreen());
|
||||
case "login_to_navigation":
|
||||
return loginRoute(NavigationScreen());
|
||||
return loginRoute(const NavigationScreen());
|
||||
case "settings":
|
||||
return settingsRoute(SettingsScreen());
|
||||
return settingsRoute(const SettingsScreen());
|
||||
}
|
||||
// else if platform == windows || ...
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
// ignore_for_file: avoid_print
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:filcnaplo/database/struct.dart';
|
||||
@ -69,7 +71,7 @@ Future<void> migrateDB(
|
||||
) async {
|
||||
var originalRows = await db.query(table);
|
||||
|
||||
if (originalRows.length == 0) {
|
||||
if (originalRows.isEmpty) {
|
||||
await db.execute("drop table $table");
|
||||
await create(db);
|
||||
return;
|
||||
@ -85,7 +87,7 @@ Future<void> migrateDB(
|
||||
var copy = Map<String, dynamic>.from(original);
|
||||
|
||||
// Fill missing columns
|
||||
keys.forEach((key) {
|
||||
for (var key in keys) {
|
||||
if (!keys.contains(key)) {
|
||||
print("DEBUG: dropping $key");
|
||||
copy.remove(key);
|
||||
@ -95,13 +97,13 @@ Future<void> migrateDB(
|
||||
print("DEBUG: migrating $key");
|
||||
copy[key] = defaultValues[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
migrated.add(copy);
|
||||
}
|
||||
});
|
||||
|
||||
if (migrated.length > 0) {
|
||||
if (migrated.isNotEmpty) {
|
||||
// Delete table
|
||||
await db.execute("drop table $table");
|
||||
|
||||
|
@ -28,9 +28,9 @@ class DatabaseQuery {
|
||||
Future<UserProvider> getUsers() async {
|
||||
var userProvider = UserProvider();
|
||||
List<Map> usersMap = await db.query("users");
|
||||
usersMap.forEach((user) {
|
||||
for (var user in usersMap) {
|
||||
userProvider.addUser(User.fromMap(user));
|
||||
});
|
||||
}
|
||||
return userProvider;
|
||||
}
|
||||
}
|
||||
@ -42,7 +42,7 @@ class UserDatabaseQuery {
|
||||
|
||||
Future<List<Grade>> getGrades({required String userId}) async {
|
||||
List<Map> userData = await db.query("user_data", where: "id = ?", whereArgs: [userId]);
|
||||
if (userData.length == 0) return [];
|
||||
if (userData.isEmpty) return [];
|
||||
String? gradesJson = userData.elementAt(0)["grades"] as String?;
|
||||
if (gradesJson == null) return [];
|
||||
List<Grade> grades = (jsonDecode(gradesJson) as List).map((e) => Grade.fromJson(e)).toList();
|
||||
@ -51,7 +51,7 @@ class UserDatabaseQuery {
|
||||
|
||||
Future<List<Lesson>> getLessons({required String userId}) async {
|
||||
List<Map> userData = await db.query("user_data", where: "id = ?", whereArgs: [userId]);
|
||||
if (userData.length == 0) return [];
|
||||
if (userData.isEmpty) return [];
|
||||
String? lessonsJson = userData.elementAt(0)["timetable"] as String?;
|
||||
if (lessonsJson == null) return [];
|
||||
List<Lesson> lessons = (jsonDecode(lessonsJson) as List).map((e) => Lesson.fromJson(e)).toList();
|
||||
@ -60,7 +60,7 @@ class UserDatabaseQuery {
|
||||
|
||||
Future<List<Exam>> getExams({required String userId}) async {
|
||||
List<Map> userData = await db.query("user_data", where: "id = ?", whereArgs: [userId]);
|
||||
if (userData.length == 0) return [];
|
||||
if (userData.isEmpty) return [];
|
||||
String? examsJson = userData.elementAt(0)["exams"] as String?;
|
||||
if (examsJson == null) return [];
|
||||
List<Exam> exams = (jsonDecode(examsJson) as List).map((e) => Exam.fromJson(e)).toList();
|
||||
@ -69,7 +69,7 @@ class UserDatabaseQuery {
|
||||
|
||||
Future<List<Homework>> getHomework({required String userId}) async {
|
||||
List<Map> userData = await db.query("user_data", where: "id = ?", whereArgs: [userId]);
|
||||
if (userData.length == 0) return [];
|
||||
if (userData.isEmpty) return [];
|
||||
String? homeworkJson = userData.elementAt(0)["homework"] as String?;
|
||||
if (homeworkJson == null) return [];
|
||||
List<Homework> homework = (jsonDecode(homeworkJson) as List).map((e) => Homework.fromJson(e)).toList();
|
||||
@ -78,7 +78,7 @@ class UserDatabaseQuery {
|
||||
|
||||
Future<List<Message>> getMessages({required String userId}) async {
|
||||
List<Map> userData = await db.query("user_data", where: "id = ?", whereArgs: [userId]);
|
||||
if (userData.length == 0) return [];
|
||||
if (userData.isEmpty) return [];
|
||||
String? messagesJson = userData.elementAt(0)["messages"] as String?;
|
||||
if (messagesJson == null) return [];
|
||||
List<Message> messages = (jsonDecode(messagesJson) as List).map((e) => Message.fromJson(e)).toList();
|
||||
@ -87,7 +87,7 @@ class UserDatabaseQuery {
|
||||
|
||||
Future<List<Note>> getNotes({required String userId}) async {
|
||||
List<Map> userData = await db.query("user_data", where: "id = ?", whereArgs: [userId]);
|
||||
if (userData.length == 0) return [];
|
||||
if (userData.isEmpty) return [];
|
||||
String? notesJson = userData.elementAt(0)["notes"] as String?;
|
||||
if (notesJson == null) return [];
|
||||
List<Note> notes = (jsonDecode(notesJson) as List).map((e) => Note.fromJson(e)).toList();
|
||||
@ -96,7 +96,7 @@ class UserDatabaseQuery {
|
||||
|
||||
Future<List<Event>> getEvents({required String userId}) async {
|
||||
List<Map> userData = await db.query("user_data", where: "id = ?", whereArgs: [userId]);
|
||||
if (userData.length == 0) return [];
|
||||
if (userData.isEmpty) return [];
|
||||
String? eventsJson = userData.elementAt(0)["events"] as String?;
|
||||
if (eventsJson == null) return [];
|
||||
List<Event> events = (jsonDecode(eventsJson) as List).map((e) => Event.fromJson(e)).toList();
|
||||
@ -105,7 +105,7 @@ class UserDatabaseQuery {
|
||||
|
||||
Future<List<Absence>> getAbsences({required String userId}) async {
|
||||
List<Map> userData = await db.query("user_data", where: "id = ?", whereArgs: [userId]);
|
||||
if (userData.length == 0) return [];
|
||||
if (userData.isEmpty) return [];
|
||||
String? absebcesJson = userData.elementAt(0)["absences"] as String?;
|
||||
if (absebcesJson == null) return [];
|
||||
List<Absence> absebces = (jsonDecode(absebcesJson) as List).map((e) => Absence.fromJson(e)).toList();
|
||||
|
@ -24,7 +24,7 @@ class DatabaseStore {
|
||||
|
||||
Future<void> storeUser(User user) async {
|
||||
List userRes = await db.query("users", where: "id = ?", whereArgs: [user.id]);
|
||||
if (userRes.length > 0) {
|
||||
if (userRes.isNotEmpty) {
|
||||
await db.update("users", user.toMap(), where: "id = ?", whereArgs: [user.id]);
|
||||
} else {
|
||||
await db.insert("users", user.toMap());
|
||||
|
@ -15,7 +15,7 @@ class DatabaseStruct {
|
||||
break;
|
||||
}
|
||||
|
||||
return "${name} ${typeName.toUpperCase()} ${name == 'id' ? 'NOT NULL' : ''}";
|
||||
return "$name ${typeName.toUpperCase()} ${name == 'id' ? 'NOT NULL' : ''}";
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -6,14 +6,15 @@ class AverageHelper {
|
||||
|
||||
List<String> ignoreInFinal = ["5,SzorgalomErtek", "4,MagatartasErtek"];
|
||||
|
||||
if (finalAvg)
|
||||
if (finalAvg) {
|
||||
grades.removeWhere((e) =>
|
||||
(e.value.value == 0) ||
|
||||
(ignoreInFinal.contains(e.gradeType?.id)));
|
||||
}
|
||||
|
||||
grades.forEach((e) {
|
||||
for (var e in grades) {
|
||||
average += e.value.value * ((finalAvg ? 100 : e.value.weight) / 100);
|
||||
});
|
||||
}
|
||||
|
||||
average = average /
|
||||
grades
|
||||
|
@ -1,3 +1,5 @@
|
||||
// ignore_for_file: avoid_print
|
||||
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
|
||||
|
@ -17,7 +17,7 @@ extension UpdateHelper on Release {
|
||||
updateCallback!(-1, UpdateState.preparing);
|
||||
|
||||
String downloads = await StorageHelper.downloadsPath();
|
||||
File apk = File("$downloads/filcnaplo-${version}.apk");
|
||||
File apk = File("$downloads/filcnaplo-$version.apk");
|
||||
|
||||
if (!await apk.exists()) {
|
||||
updateCallback(-1, UpdateState.downloading);
|
||||
@ -31,6 +31,7 @@ extension UpdateHelper on Release {
|
||||
var result = await OpenFile.open(apk.path);
|
||||
|
||||
if (result.type != ResultType.done) {
|
||||
// ignore: avoid_print
|
||||
print("ERROR: installUpdate.openFile: " + result.message);
|
||||
throw result.message;
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
class FilcIcons {
|
||||
static const IconData home = const FilcIconData(0x41);
|
||||
static const IconData linux = const FilcIconData(0x42);
|
||||
static const IconData home = FilcIconData(0x41);
|
||||
static const IconData linux = FilcIconData(0x42);
|
||||
}
|
||||
|
||||
class FilcIconData extends IconData {
|
||||
|
@ -53,10 +53,11 @@ Widget errorBuilder(FlutterErrorDetails details) {
|
||||
errorShown = true;
|
||||
lastException = details.exceptionAsString();
|
||||
Navigator.of(context, rootNavigator: true).push(MaterialPageRoute(builder: (context) {
|
||||
if (kReleaseMode)
|
||||
if (kReleaseMode) {
|
||||
return ErrorReportScreen(details);
|
||||
else
|
||||
} else {
|
||||
return ErrorScreen(details);
|
||||
}
|
||||
})).then((_) => errorShown = false);
|
||||
}
|
||||
});
|
||||
|
@ -58,10 +58,11 @@ class Version {
|
||||
|
||||
// check for valid prerelease name
|
||||
if (p[0] != "") {
|
||||
if (prereleases.contains(p[0].toLowerCase().trim()))
|
||||
if (prereleases.contains(p[0].toLowerCase().trim())) {
|
||||
pre = p[0];
|
||||
else
|
||||
} else {
|
||||
throw "invalid prerelease name: ${p[0]}";
|
||||
}
|
||||
}
|
||||
|
||||
// core
|
||||
@ -74,6 +75,7 @@ class Version {
|
||||
|
||||
return Version(x, y, z, prerelease: pre, prever: prev);
|
||||
} catch (error) {
|
||||
// ignore: avoid_print
|
||||
print("WARNING: Failed to parse version ($o): $error");
|
||||
return Version.zero;
|
||||
}
|
||||
@ -126,4 +128,7 @@ class Version {
|
||||
|
||||
static const zero = Version(0, 0, 0);
|
||||
static const List<String> prereleases = ["dev", "pre", "alpha", "beta", "rc"];
|
||||
|
||||
@override
|
||||
int get hashCode => toString().hashCode;
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ class SettingsProvider extends ChangeNotifier {
|
||||
int _notificationPollInterval;
|
||||
bool _developerMode;
|
||||
VibrationStrength _vibrate;
|
||||
bool _ABweeks;
|
||||
bool _abWeeks;
|
||||
bool _swapABweeks;
|
||||
UpdateChannel _updateChannel;
|
||||
Config _config;
|
||||
@ -64,7 +64,7 @@ class SettingsProvider extends ChangeNotifier {
|
||||
required bool developerMode,
|
||||
required int notificationPollInterval,
|
||||
required VibrationStrength vibrate,
|
||||
required bool ABweeks,
|
||||
required bool abWeeks,
|
||||
required bool swapABweeks,
|
||||
required UpdateChannel updateChannel,
|
||||
required Config config,
|
||||
@ -82,7 +82,7 @@ class SettingsProvider extends ChangeNotifier {
|
||||
_developerMode = developerMode,
|
||||
_notificationPollInterval = notificationPollInterval,
|
||||
_vibrate = vibrate,
|
||||
_ABweeks = ABweeks,
|
||||
_abWeeks = abWeeks,
|
||||
_swapABweeks = swapABweeks,
|
||||
_updateChannel = updateChannel,
|
||||
_config = config,
|
||||
@ -113,7 +113,7 @@ class SettingsProvider extends ChangeNotifier {
|
||||
notificationPollInterval: map["notification_poll_interval"],
|
||||
developerMode: map["developer_mode"] == 1 ? true : false,
|
||||
vibrate: VibrationStrength.values[map["vibration_strength"]],
|
||||
ABweeks: map["ab_weeks"] == 1 ? true : false,
|
||||
abWeeks: map["ab_weeks"] == 1 ? true : false,
|
||||
swapABweeks: map["swap_ab_weeks"] == 1 ? true : false,
|
||||
updateChannel: UpdateChannel.values[map["update_channel"]],
|
||||
config: Config.fromJson(jsonDecode(map["config"] ?? "{}")),
|
||||
@ -140,7 +140,7 @@ class SettingsProvider extends ChangeNotifier {
|
||||
"grade_color5": _gradeColors[4].value,
|
||||
"update_channel": _updateChannel.index,
|
||||
"vibration_strength": _vibrate.index,
|
||||
"ab_weeks": _ABweeks ? 1 : 0,
|
||||
"ab_weeks": _abWeeks ? 1 : 0,
|
||||
"swap_ab_weeks": _swapABweeks ? 1 : 0,
|
||||
"notification_poll_interval": _notificationPollInterval,
|
||||
"config": jsonEncode(config.json),
|
||||
@ -169,11 +169,11 @@ class SettingsProvider extends ChangeNotifier {
|
||||
developerMode: false,
|
||||
notificationPollInterval: 1,
|
||||
vibrate: VibrationStrength.medium,
|
||||
ABweeks: false,
|
||||
abWeeks: false,
|
||||
swapABweeks: false,
|
||||
updateChannel: UpdateChannel.stable,
|
||||
config: Config.fromJson({}),
|
||||
xFilcId: Uuid().v4(),
|
||||
xFilcId: const Uuid().v4(),
|
||||
);
|
||||
}
|
||||
|
||||
@ -191,7 +191,7 @@ class SettingsProvider extends ChangeNotifier {
|
||||
bool get developerMode => _developerMode;
|
||||
int get notificationPollInterval => _notificationPollInterval;
|
||||
VibrationStrength get vibrate => _vibrate;
|
||||
bool get ABweeks => _ABweeks;
|
||||
bool get abWeeks => _abWeeks;
|
||||
bool get swapABweeks => _swapABweeks;
|
||||
UpdateChannel get updateChannel => _updateChannel;
|
||||
PackageInfo? get packageInfo => _packageInfo;
|
||||
@ -214,7 +214,7 @@ class SettingsProvider extends ChangeNotifier {
|
||||
bool? developerMode,
|
||||
int? notificationPollInterval,
|
||||
VibrationStrength? vibrate,
|
||||
bool? ABweeks,
|
||||
bool? abWeeks,
|
||||
bool? swapABweeks,
|
||||
UpdateChannel? updateChannel,
|
||||
Config? config,
|
||||
@ -231,16 +231,17 @@ class SettingsProvider extends ChangeNotifier {
|
||||
if (notificationsEnabled != null && notificationsEnabled != _notificationsEnabled) _notificationsEnabled = notificationsEnabled;
|
||||
if (notificationsBitfield != null && notificationsBitfield != _notificationsBitfield) _notificationsBitfield = notificationsBitfield;
|
||||
if (developerMode != null && developerMode != _developerMode) _developerMode = developerMode;
|
||||
if (notificationPollInterval != null && notificationPollInterval != _notificationPollInterval)
|
||||
if (notificationPollInterval != null && notificationPollInterval != _notificationPollInterval) {
|
||||
_notificationPollInterval = notificationPollInterval;
|
||||
}
|
||||
if (vibrate != null && vibrate != _vibrate) _vibrate = vibrate;
|
||||
if (ABweeks != null && ABweeks != _ABweeks) _ABweeks = ABweeks;
|
||||
if (abWeeks != null && abWeeks != _abWeeks) _abWeeks = abWeeks;
|
||||
if (swapABweeks != null && swapABweeks != _swapABweeks) _swapABweeks = swapABweeks;
|
||||
if (updateChannel != null && updateChannel != _updateChannel) _updateChannel = updateChannel;
|
||||
if (config != null && config != _config) _config = config;
|
||||
if (xFilcId != null && xFilcId != _xFilcId) _xFilcId = xFilcId;
|
||||
|
||||
if (database == null) database = Provider.of<DatabaseProvider>(context, listen: false);
|
||||
database ??= Provider.of<DatabaseProvider>(context, listen: false);
|
||||
await database.store.storeSettings(this);
|
||||
notifyListeners();
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ class User {
|
||||
if (id != null) {
|
||||
this.id = id;
|
||||
} else {
|
||||
this.id = Uuid().v4();
|
||||
this.id = const Uuid().v4();
|
||||
}
|
||||
}
|
||||
|
||||
@ -67,7 +67,7 @@ class User {
|
||||
"password": password,
|
||||
"institute_code": instituteCode,
|
||||
"grant_type": "password",
|
||||
"client_id": KretaAPI.CLIENT_ID,
|
||||
"client_id": KretaAPI.clientId,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -11,14 +11,14 @@ class AppTheme {
|
||||
// Light Theme
|
||||
static ThemeData lightTheme(BuildContext context) {
|
||||
var lightColors = LightAppColors();
|
||||
Color accent = accentColorMap[Provider.of<SettingsProvider>(context, listen: false).accentColor] ?? Color(0);
|
||||
Color accent = accentColorMap[Provider.of<SettingsProvider>(context, listen: false).accentColor] ?? const Color(0x00000000);
|
||||
return ThemeData(
|
||||
brightness: Brightness.light,
|
||||
fontFamily: _fontFamily,
|
||||
scaffoldBackgroundColor: lightColors.background,
|
||||
backgroundColor: lightColors.highlight,
|
||||
primaryColor: lightColors.filc,
|
||||
dividerColor: Color(0),
|
||||
dividerColor: const Color(0x00000000),
|
||||
colorScheme: ColorScheme.fromSwatch(
|
||||
accentColor: accent,
|
||||
backgroundColor: lightColors.background,
|
||||
@ -37,14 +37,14 @@ class AppTheme {
|
||||
// Dark Theme
|
||||
static ThemeData darkTheme(BuildContext context) {
|
||||
var darkColors = DarkAppColors();
|
||||
Color accent = accentColorMap[Provider.of<SettingsProvider>(context, listen: false).accentColor] ?? Color(0);
|
||||
Color accent = accentColorMap[Provider.of<SettingsProvider>(context, listen: false).accentColor] ?? const Color(0x00000000);
|
||||
return ThemeData(
|
||||
brightness: Brightness.dark,
|
||||
fontFamily: _fontFamily,
|
||||
scaffoldBackgroundColor: darkColors.background,
|
||||
backgroundColor: darkColors.highlight,
|
||||
primaryColor: darkColors.filc,
|
||||
dividerColor: Color(0),
|
||||
dividerColor: const Color(0x00000000),
|
||||
colorScheme: ColorScheme.fromSwatch(
|
||||
accentColor: accent,
|
||||
backgroundColor: darkColors.background,
|
||||
@ -70,7 +70,7 @@ class AppColors {
|
||||
enum AccentColor { filc, blue, green, lime, yellow, orange, red, pink, purple }
|
||||
|
||||
Map<AccentColor, Color> accentColorMap = {
|
||||
AccentColor.filc: Color(0xff20AC9B),
|
||||
AccentColor.filc: const Color(0xff20AC9B),
|
||||
AccentColor.blue: Colors.blue.shade300,
|
||||
AccentColor.green: Colors.green.shade300,
|
||||
AccentColor.lime: Colors.lime.shade300,
|
||||
@ -82,54 +82,82 @@ Map<AccentColor, Color> accentColorMap = {
|
||||
};
|
||||
|
||||
abstract class ThemeAppColors {
|
||||
final Color shadow = Color(0);
|
||||
final Color text = Color(0);
|
||||
final Color background = Color(0);
|
||||
final Color highlight = Color(0);
|
||||
final Color red = Color(0);
|
||||
final Color orange = Color(0);
|
||||
final Color yellow = Color(0);
|
||||
final Color green = Color(0);
|
||||
final Color filc = Color(0);
|
||||
final Color teal = Color(0);
|
||||
final Color blue = Color(0);
|
||||
final Color indigo = Color(0);
|
||||
final Color purple = Color(0);
|
||||
final Color pink = Color(0);
|
||||
final Color shadow = const Color(0x00000000);
|
||||
final Color text = const Color(0x00000000);
|
||||
final Color background = const Color(0x00000000);
|
||||
final Color highlight = const Color(0x00000000);
|
||||
final Color red = const Color(0x00000000);
|
||||
final Color orange = const Color(0x00000000);
|
||||
final Color yellow = const Color(0x00000000);
|
||||
final Color green = const Color(0x00000000);
|
||||
final Color filc = const Color(0x00000000);
|
||||
final Color teal = const Color(0x00000000);
|
||||
final Color blue = const Color(0x00000000);
|
||||
final Color indigo = const Color(0x00000000);
|
||||
final Color purple = const Color(0x00000000);
|
||||
final Color pink = const Color(0x00000000);
|
||||
}
|
||||
|
||||
class LightAppColors implements ThemeAppColors {
|
||||
final shadow = Color(0xffE8E8E8);
|
||||
@override
|
||||
final shadow = const Color(0xffE8E8E8);
|
||||
@override
|
||||
final text = Colors.black;
|
||||
final background = Color(0xffF4F9FF);
|
||||
final highlight = Color(0xffFFFFFF);
|
||||
final red = Color(0xffFF3B30);
|
||||
final orange = Color(0xffFF9500);
|
||||
final yellow = Color(0xffFFCC00);
|
||||
final green = Color(0xff34C759);
|
||||
final filc = Color(0xff247665);
|
||||
final teal = Color(0xff5AC8FA);
|
||||
final blue = Color(0xff007AFF);
|
||||
final indigo = Color(0xff5856D6);
|
||||
final purple = Color(0xffAF52DE);
|
||||
final pink = Color(0xffFF2D55);
|
||||
@override
|
||||
final background = const Color(0xffF4F9FF);
|
||||
@override
|
||||
final highlight = const Color(0xffFFFFFF);
|
||||
@override
|
||||
final red = const Color(0xffFF3B30);
|
||||
@override
|
||||
final orange = const Color(0xffFF9500);
|
||||
@override
|
||||
final yellow = const Color(0xffFFCC00);
|
||||
@override
|
||||
final green = const Color(0xff34C759);
|
||||
@override
|
||||
final filc = const Color(0xff247665);
|
||||
@override
|
||||
final teal = const Color(0xff5AC8FA);
|
||||
@override
|
||||
final blue = const Color(0xff007AFF);
|
||||
@override
|
||||
final indigo = const Color(0xff5856D6);
|
||||
@override
|
||||
final purple = const Color(0xffAF52DE);
|
||||
@override
|
||||
final pink = const Color(0xffFF2D55);
|
||||
}
|
||||
|
||||
class DarkAppColors implements ThemeAppColors {
|
||||
final shadow = Color(0);
|
||||
@override
|
||||
final shadow = const Color(0x00000000);
|
||||
@override
|
||||
final text = Colors.white;
|
||||
final background = Color(0xff000000);
|
||||
final highlight = Color(0xff141516);
|
||||
final red = Color(0xffFF453A);
|
||||
final orange = Color(0xffFF9F0A);
|
||||
final yellow = Color(0xffFFD60A);
|
||||
final green = Color(0xff32D74B);
|
||||
final filc = Color(0xff29826F);
|
||||
final teal = Color(0xff64D2FF);
|
||||
final blue = Color(0xff0A84FF);
|
||||
final indigo = Color(0xff5E5CE6);
|
||||
final purple = Color(0xffBF5AF2);
|
||||
final pink = Color(0xffFF375F);
|
||||
@override
|
||||
final background = const Color(0xff000000);
|
||||
@override
|
||||
final highlight = const Color(0xff141516);
|
||||
@override
|
||||
final red = const Color(0xffFF453A);
|
||||
@override
|
||||
final orange = const Color(0xffFF9F0A);
|
||||
@override
|
||||
final yellow = const Color(0xffFFD60A);
|
||||
@override
|
||||
final green = const Color(0xff32D74B);
|
||||
@override
|
||||
final filc = const Color(0xff29826F);
|
||||
@override
|
||||
final teal = const Color(0xff64D2FF);
|
||||
@override
|
||||
final blue = const Color(0xff0A84FF);
|
||||
@override
|
||||
final indigo = const Color(0xff5E5CE6);
|
||||
@override
|
||||
final purple = const Color(0xffBF5AF2);
|
||||
@override
|
||||
final pink = const Color(0xffFF375F);
|
||||
}
|
||||
|
||||
class ThemeModeObserver extends ChangeNotifier {
|
||||
|
@ -6,8 +6,7 @@ import 'package:html/parser.dart';
|
||||
import 'format.i18n.dart';
|
||||
|
||||
extension StringFormatUtils on String {
|
||||
String specialChars() => this
|
||||
.replaceAll("é", "e")
|
||||
String specialChars() => replaceAll("é", "e")
|
||||
.replaceAll("á", "a")
|
||||
.replaceAll("ó", "o")
|
||||
.replaceAll("ő", "o")
|
||||
@ -17,9 +16,9 @@ extension StringFormatUtils on String {
|
||||
.replaceAll("ü", "u")
|
||||
.replaceAll("í", "i");
|
||||
|
||||
String capital() => this.length > 0 ? this[0].toUpperCase() + this.substring(1) : "";
|
||||
String capital() => isNotEmpty ? this[0].toUpperCase() + substring(1) : "";
|
||||
|
||||
String capitalize() => this.split(" ").map((w) => w.capital()).join(" ");
|
||||
String capitalize() => split(" ").map((w) => w.capital()).join(" ");
|
||||
|
||||
String escapeHtml() {
|
||||
String htmlString = this;
|
||||
@ -38,23 +37,24 @@ extension DateFormatUtils on DateTime {
|
||||
if (timeOnly) return DateFormat("HH:mm").format(this);
|
||||
|
||||
DateTime now = DateTime.now();
|
||||
if (now.year == this.year && now.month == this.month && now.day == this.day) {
|
||||
if (this.hour == 0 && this.minute == 0 && this.second == 0 || forceToday) return "Today".i18n;
|
||||
if (now.year == year && now.month == month && now.day == day) {
|
||||
if (hour == 0 && minute == 0 && second == 0 || forceToday) return "Today".i18n;
|
||||
return DateFormat("HH:mm").format(this);
|
||||
}
|
||||
if (now.year == this.year && now.month == this.month && now.subtract(Duration(days: 1)).day == this.day) return "Yesterday".i18n;
|
||||
if (now.year == this.year && now.month == this.month && now.add(Duration(days: 1)).day == this.day) return "Tomorrow".i18n;
|
||||
if (now.year == year && now.month == month && now.subtract(const Duration(days: 1)).day == day) return "Yesterday".i18n;
|
||||
if (now.year == year && now.month == month && now.add(const Duration(days: 1)).day == day) return "Tomorrow".i18n;
|
||||
|
||||
String formatString;
|
||||
|
||||
// If date is current week, show only weekday
|
||||
if (Week.current().start.isBefore(this) && Week.current().end.isAfter(this))
|
||||
formatString = "EEEE"; // ex. monday
|
||||
else {
|
||||
if (this.year == now.year)
|
||||
formatString = "MMM dd."; // ex. Jan. 01.
|
||||
else
|
||||
formatString = "yy/MM/dd"; // ex. 21/01/01
|
||||
if (Week.current().start.isBefore(this) && Week.current().end.isAfter(this)) {
|
||||
formatString = "EEEE";
|
||||
} else {
|
||||
if (year == now.year) {
|
||||
formatString = "MMM dd.";
|
||||
} else {
|
||||
formatString = "yy/MM/dd";
|
||||
} // ex. 21/01/01
|
||||
|
||||
if (weekday) formatString += " (EEEE)"; // ex. (monday)
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ class JwtUtils {
|
||||
var payload = utf8.decode(base64Url.decode(parts[1]));
|
||||
return jsonDecode(payload);
|
||||
} catch (error) {
|
||||
// ignore: avoid_print
|
||||
print("ERROR: JwtUtils.decodeJwt: $error");
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ publish_to: "none"
|
||||
version: 3.1.1+139
|
||||
|
||||
environment:
|
||||
sdk: ">=2.12.0 <3.0.0"
|
||||
sdk: ">=2.16.0-80.1.beta <3.0.0"
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
@ -32,7 +32,7 @@ dependencies:
|
||||
html: ^0.15.0
|
||||
open_file: ^3.2.1
|
||||
path_provider: ^2.0.2
|
||||
permission_handler: 8.1.2
|
||||
permission_handler: ^8.3.0
|
||||
share_plus: ^3.0.4
|
||||
package_info_plus: ^1.0.6
|
||||
connectivity_plus: ^2.0.2
|
||||
@ -41,6 +41,7 @@ dependencies:
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
flutter_lints: ^1.0.0
|
||||
# flutter_launcher_icons: ^0.9.0
|
||||
# flutter_native_splash: ^1.2.0
|
||||
sqflite_common_ffi: ^2.0.0+3
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 695ca3bcf9d67c3d316f08e1585fff9896d87c25
|
||||
Subproject commit 07658366419b844fbbcb68ac5da8432c313608bb
|
Loading…
x
Reference in New Issue
Block a user