diff --git a/.gitignore b/.gitignore
index 4b56298..b97fcfb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,7 @@
# See https://www.dartlang.org/guides/libraries/private-files
termek.txt
+.DS_Store
# Files and directories created by pub
.dart_tool/
diff --git a/filcnaplo/android/app/src/main/AndroidManifest.xml b/filcnaplo/android/app/src/main/AndroidManifest.xml
index ed9a9b7..ad93e0a 100644
--- a/filcnaplo/android/app/src/main/AndroidManifest.xml
+++ b/filcnaplo/android/app/src/main/AndroidManifest.xml
@@ -6,6 +6,16 @@
+
+
+
+
+
+
+
diff --git a/filcnaplo/assets/fonts/FilcIcons.ttf b/filcnaplo/assets/fonts/FilcIcons.ttf
index 9a3f33a..77d2759 100644
Binary files a/filcnaplo/assets/fonts/FilcIcons.ttf and b/filcnaplo/assets/fonts/FilcIcons.ttf differ
diff --git a/filcnaplo/ios/Runner/Runner.entitlements b/filcnaplo/ios/Runner/Runner.entitlements
index 903def2..da95ee4 100644
--- a/filcnaplo/ios/Runner/Runner.entitlements
+++ b/filcnaplo/ios/Runner/Runner.entitlements
@@ -4,5 +4,9 @@
aps-environment
development
+ com.apple.developer.associated-domains
+
+ applinks:api.filcnaplo.hu
+
diff --git a/filcnaplo/lib/api/client.dart b/filcnaplo/lib/api/client.dart
index dcab1eb..b4f9fbb 100644
--- a/filcnaplo/lib/api/client.dart
+++ b/filcnaplo/lib/api/client.dart
@@ -21,6 +21,8 @@ class FilcAPI {
// Private API
static const config = "https://api.filcnaplo.hu/config";
static const reportApi = "https://api.filcnaplo.hu/report";
+ static const premiumApi = "https://api.filcnaplo.hu/premium/activate";
+ static const premiumScopesApi = "https://api.filcnaplo.hu/premium/scopes";
// Updates
static const repo = "filc/naplo";
diff --git a/filcnaplo/lib/api/providers/news_provider.dart b/filcnaplo/lib/api/providers/news_provider.dart
index e0636b6..e1eba3b 100644
--- a/filcnaplo/lib/api/providers/news_provider.dart
+++ b/filcnaplo/lib/api/providers/news_provider.dart
@@ -41,7 +41,7 @@ class NewsProvider extends ChangeNotifier {
}
_state = state_;
- Provider.of(_context, listen: false).update(_context, newsState: _state);
+ Provider.of(_context, listen: false).update(newsState: _state);
}
Future fetch() async {
@@ -53,7 +53,7 @@ class NewsProvider extends ChangeNotifier {
if (_fresh < 0) {
_state = news_.length;
- Provider.of(_context, listen: false).update(_context, newsState: _state);
+ Provider.of(_context, listen: false).update(newsState: _state);
}
_fresh = max(_fresh, 0);
@@ -72,7 +72,7 @@ class NewsProvider extends ChangeNotifier {
_fresh--;
_state++;
- Provider.of(_context, listen: false).update(_context, newsState: _state);
+ Provider.of(_context, listen: false).update(newsState: _state);
if (_fresh > 0) {
show = true;
diff --git a/filcnaplo/lib/app.dart b/filcnaplo/lib/app.dart
index 3a9e2a3..91a823f 100644
--- a/filcnaplo/lib/app.dart
+++ b/filcnaplo/lib/app.dart
@@ -45,6 +45,7 @@ import 'package:filcnaplo/api/providers/user_provider.dart';
import 'package:filcnaplo/api/providers/update_provider.dart';
import 'package:filcnaplo_mobile_ui/pages/grades/calculator/grade_calculator_provider.dart';
import 'package:flutter_displaymode/flutter_displaymode.dart';
+import 'package:filcnaplo_premium/providers/premium_provider.dart';
class App extends StatelessWidget {
final SettingsProvider settings;
@@ -62,20 +63,23 @@ class App extends StatelessWidget {
// Set high refresh mode #28
if (Platform.isAndroid) FlutterDisplayMode.setHighRefreshRate();
- WidgetsBinding.instance.addPostFrameCallback((_) {
- FilcAPI.getConfig(settings).then((Config? config) {
- if (config != null) settings.update(context, database: database, config: config);
- });
- });
-
CorePalette? corePalette;
final status = StatusProvider();
final kreta = KretaClient(user: user, settings: settings, status: status);
final timetable = TimetableProvider(user: user, database: database, kreta: kreta);
+ final premium = PremiumProvider(settings: settings);
+
+ WidgetsBinding.instance.addPostFrameCallback((_) {
+ FilcAPI.getConfig(settings).then((Config? config) {
+ if (config != null) settings.update(config: config);
+ });
+ premium.activate();
+ });
return MultiProvider(
providers: [
+ ChangeNotifierProvider(create: (_) => premium),
ChangeNotifierProvider(create: (_) => settings),
ChangeNotifierProvider(create: (_) => user),
ChangeNotifierProvider(create: (_) => status),
diff --git a/filcnaplo/lib/database/init.dart b/filcnaplo/lib/database/init.dart
index d7bdabf..44eeba9 100644
--- a/filcnaplo/lib/database/init.dart
+++ b/filcnaplo/lib/database/init.dart
@@ -2,6 +2,7 @@
import 'dart:io';
+import 'package:filcnaplo/api/providers/database_provider.dart';
import 'package:filcnaplo/database/struct.dart';
import 'package:filcnaplo/models/settings.dart';
import 'package:sqflite/sqflite.dart';
@@ -15,7 +16,7 @@ const settingsDB = DatabaseStruct("settings", {
"vibration_strength": int, "ab_weeks": int, "swap_ab_weeks": int,
"notifications": int, "notifications_bitfield": int, "notification_poll_interval": int, // notifications
"x_filc_id": String, "graph_class_avg": int, "presentation_mode": int, "bell_delay": int, "bell_delay_enabled": int,
- "grade_opening_fun": int, "icon_pack": String,
+ "grade_opening_fun": int, "icon_pack": String, "premium_scopes": String, "premium_token": String,
});
const usersDB = DatabaseStruct("users", {
"id": String, "name": String, "username": String, "password": String, "institute_code": String, "student": String, "role": int,
@@ -30,7 +31,7 @@ const userDataDB = DatabaseStruct("user_data", {
Future createTable(Database db, DatabaseStruct struct) => db.execute("CREATE TABLE IF NOT EXISTS ${struct.table} ($struct)");
-Future initDB() async {
+Future initDB(DatabaseProvider database) async {
Database db;
if (Platform.isLinux || Platform.isWindows) {
@@ -46,7 +47,7 @@ Future initDB() async {
if ((await db.rawQuery("SELECT COUNT(*) FROM settings"))[0].values.first == 0) {
// Set default values for table Settings
- await db.insert("settings", SettingsProvider.defaultSettings().toMap());
+ await db.insert("settings", SettingsProvider.defaultSettings(database: database).toMap());
}
// Migrate Databases
@@ -54,7 +55,7 @@ Future initDB() async {
await migrateDB(
db,
struct: settingsDB,
- defaultValues: SettingsProvider.defaultSettings().toMap(),
+ defaultValues: SettingsProvider.defaultSettings(database: database).toMap(),
);
await migrateDB(
db,
diff --git a/filcnaplo/lib/database/query.dart b/filcnaplo/lib/database/query.dart
index ab19331..797d58a 100644
--- a/filcnaplo/lib/database/query.dart
+++ b/filcnaplo/lib/database/query.dart
@@ -1,4 +1,5 @@
import 'dart:convert';
+import 'package:filcnaplo/api/providers/database_provider.dart';
import 'package:filcnaplo/models/subject_lesson_count.dart';
import 'package:filcnaplo/models/user.dart';
// ignore: depend_on_referenced_packages
@@ -22,9 +23,9 @@ class DatabaseQuery {
final Database db;
- Future getSettings() async {
+ Future getSettings(DatabaseProvider database) async {
Map settingsMap = (await db.query("settings")).elementAt(0);
- SettingsProvider settings = SettingsProvider.fromMap(settingsMap);
+ SettingsProvider settings = SettingsProvider.fromMap(settingsMap, database: database);
return settings;
}
diff --git a/filcnaplo/lib/database/store.dart b/filcnaplo/lib/database/store.dart
index 1046e7e..10d455a 100644
--- a/filcnaplo/lib/database/store.dart
+++ b/filcnaplo/lib/database/store.dart
@@ -1,4 +1,5 @@
import 'dart:convert';
+import 'dart:developer';
import 'package:filcnaplo/models/subject_lesson_count.dart';
// ignore: depend_on_referenced_packages
import 'package:sqflite_common/sqlite_api.dart';
diff --git a/filcnaplo/lib/helpers/share_helper.dart b/filcnaplo/lib/helpers/share_helper.dart
index 5242980..f917e84 100644
--- a/filcnaplo/lib/helpers/share_helper.dart
+++ b/filcnaplo/lib/helpers/share_helper.dart
@@ -5,6 +5,7 @@ import 'package:share_plus/share_plus.dart';
class ShareHelper {
static Future shareText(String text, {String? subject}) => Share.share(text, subject: subject);
+ // ignore: deprecated_member_use
static Future shareFile(String path, {String? text, String? subject}) => Share.shareFiles([path], text: text, subject: subject);
static Future shareAttachment(Attachment attachment, {required BuildContext context}) async {
diff --git a/filcnaplo/lib/icons/filc_icons.dart b/filcnaplo/lib/icons/filc_icons.dart
index e0e1458..e1528fb 100644
--- a/filcnaplo/lib/icons/filc_icons.dart
+++ b/filcnaplo/lib/icons/filc_icons.dart
@@ -16,4 +16,7 @@ class FilcIcons {
/// downstairs
static const IconData downstairs = IconData(0x03, fontFamily: iconFontFamily);
+
+ /// premium
+ static const IconData premium = IconData(0x04, fontFamily: iconFontFamily);
}
diff --git a/filcnaplo/lib/main.dart b/filcnaplo/lib/main.dart
index 918eab0..3de1311 100644
--- a/filcnaplo/lib/main.dart
+++ b/filcnaplo/lib/main.dart
@@ -32,11 +32,11 @@ class Startup {
late DatabaseProvider database;
Future start() async {
- var db = await initDB();
- await db.close();
database = DatabaseProvider();
+ var db = await initDB(database);
+ await db.close();
await database.init();
- settings = await database.query.getSettings();
+ settings = await database.query.getSettings(database);
user = await database.query.getUsers();
}
}
diff --git a/filcnaplo/lib/models/settings.dart b/filcnaplo/lib/models/settings.dart
index 5985e21..48c1f59 100644
--- a/filcnaplo/lib/models/settings.dart
+++ b/filcnaplo/lib/models/settings.dart
@@ -7,7 +7,6 @@ import 'package:filcnaplo/models/icon_pack.dart';
import 'package:filcnaplo/theme/colors/accent.dart';
import 'package:filcnaplo/theme/colors/dark_mobile.dart';
import 'package:flutter/material.dart';
-import 'package:provider/provider.dart';
import 'package:uuid/uuid.dart';
enum Pages { home, grades, timetable, messages, absences }
@@ -17,6 +16,8 @@ enum UpdateChannel { stable, beta, dev }
enum VibrationStrength { off, light, medium, strong }
class SettingsProvider extends ChangeNotifier {
+ final DatabaseProvider? _database;
+
// en_en, hu_hu, de_de
String _language;
Pages _startPage;
@@ -61,8 +62,11 @@ class SettingsProvider extends ChangeNotifier {
Color _customAccentColor;
Color _customBackgroundColor;
Color _customHighlightColor;
+ List _premiumScopes;
+ String _premiumAccessToken;
SettingsProvider({
+ DatabaseProvider? database,
required String language,
required Pages startPage,
required int rounding,
@@ -91,7 +95,10 @@ class SettingsProvider extends ChangeNotifier {
required Color customAccentColor,
required Color customBackgroundColor,
required Color customHighlightColor,
- }) : _language = language,
+ required List premiumScopes,
+ required String premiumAccessToken,
+ }) : _database = database,
+ _language = language,
_startPage = startPage,
_rounding = rounding,
_theme = theme,
@@ -118,9 +125,11 @@ class SettingsProvider extends ChangeNotifier {
_iconPack = iconPack,
_customAccentColor = customAccentColor,
_customBackgroundColor = customBackgroundColor,
- _customHighlightColor = customHighlightColor;
+ _customHighlightColor = customHighlightColor,
+ _premiumScopes = premiumScopes,
+ _premiumAccessToken = premiumAccessToken;
- factory SettingsProvider.fromMap(Map map) {
+ factory SettingsProvider.fromMap(Map map, {required DatabaseProvider database}) {
Map? configMap;
try {
@@ -130,6 +139,7 @@ class SettingsProvider extends ChangeNotifier {
}
return SettingsProvider(
+ database: database,
language: map["language"],
startPage: Pages.values[map["start_page"]],
rounding: map["rounding"],
@@ -164,6 +174,8 @@ class SettingsProvider extends ChangeNotifier {
customAccentColor: Color(map["custom_accent_color"]),
customBackgroundColor: Color(map["custom_background_color"]),
customHighlightColor: Color(map["custom_highlight_color"]),
+ premiumScopes: jsonDecode(map["premium_scopes"]).cast(),
+ premiumAccessToken: map["premium_token"],
);
}
@@ -200,11 +212,14 @@ class SettingsProvider extends ChangeNotifier {
"custom_accent_color": _customAccentColor.value,
"custom_background_color": _customBackgroundColor.value,
"custom_highlight_color": _customHighlightColor.value,
+ "premium_scopes": jsonEncode(_premiumScopes),
+ "premium_token": _premiumAccessToken,
};
}
- factory SettingsProvider.defaultSettings() {
+ factory SettingsProvider.defaultSettings({DatabaseProvider? database}) {
return SettingsProvider(
+ database: database,
language: "hu",
startPage: Pages.home,
rounding: 5,
@@ -239,6 +254,8 @@ class SettingsProvider extends ChangeNotifier {
customAccentColor: const Color(0xff20AC9B),
customBackgroundColor: const Color(0xff000000),
customHighlightColor: const Color(0xff222222),
+ premiumScopes: [],
+ premiumAccessToken: "",
);
}
@@ -271,10 +288,10 @@ class SettingsProvider extends ChangeNotifier {
Color? get customAccentColor => _customAccentColor == accentColorMap[AccentColor.custom] ? null : _customAccentColor;
Color? get customBackgroundColor => _customBackgroundColor;
Color? get customHighlightColor => _customHighlightColor;
+ List get premiumScopes => _premiumScopes;
+ String get premiumAccessToken => _premiumAccessToken;
- Future update(
- BuildContext context, {
- DatabaseProvider? database,
+ Future update({
bool store = true,
String? language,
Pages? startPage,
@@ -304,6 +321,8 @@ class SettingsProvider extends ChangeNotifier {
Color? customAccentColor,
Color? customBackgroundColor,
Color? customHighlightColor,
+ List? premiumScopes,
+ String? premiumAccessToken,
}) async {
if (language != null && language != _language) _language = language;
if (startPage != null && startPage != _startPage) _startPage = startPage;
@@ -335,9 +354,10 @@ class SettingsProvider extends ChangeNotifier {
if (customAccentColor != null && customAccentColor != _customAccentColor) _customAccentColor = customAccentColor;
if (customBackgroundColor != null && customBackgroundColor != _customBackgroundColor) _customBackgroundColor = customBackgroundColor;
if (customHighlightColor != null && customHighlightColor != _customHighlightColor) _customHighlightColor = customHighlightColor;
+ if (premiumScopes != null && premiumScopes != _premiumScopes) _premiumScopes = premiumScopes;
+ if (premiumAccessToken != null && premiumAccessToken != _premiumAccessToken) _premiumAccessToken = premiumAccessToken;
- database ??= Provider.of(context, listen: false);
- if (store) await database.store.storeSettings(this);
+ if (store) await _database?.store.storeSettings(this);
notifyListeners();
}
}
diff --git a/filcnaplo/lib/ui/filter/widgets.dart b/filcnaplo/lib/ui/filter/widgets.dart
index 6e44e97..4cdb60a 100644
--- a/filcnaplo/lib/ui/filter/widgets.dart
+++ b/filcnaplo/lib/ui/filter/widgets.dart
@@ -12,6 +12,7 @@ import 'package:filcnaplo/ui/filter/widgets/events.dart' as event_filter;
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/premium.dart' as premium_filter;
import 'package:filcnaplo_kreta_api/providers/absence_provider.dart';
import 'package:filcnaplo_kreta_api/providers/event_provider.dart';
import 'package:filcnaplo_kreta_api/providers/exam_provider.dart';
@@ -20,6 +21,7 @@ import 'package:filcnaplo_kreta_api/providers/homework_provider.dart';
import 'package:filcnaplo_kreta_api/providers/message_provider.dart';
import 'package:filcnaplo_kreta_api/providers/note_provider.dart';
import 'package:filcnaplo_kreta_api/providers/timetable_provider.dart';
+import 'package:filcnaplo_premium/providers/premium_provider.dart';
import 'package:filcnaplo_mobile_ui/common/panel/panel.dart';
import 'package:flutter/material.dart';
import 'package:implicitly_animated_reorderable_list/transitions.dart';
@@ -27,7 +29,7 @@ import 'package:provider/provider.dart';
const List homeFilters = [FilterType.all, FilterType.grades, FilterType.messages, FilterType.absences];
-enum FilterType { all, grades, newGrades, messages, absences, homework, exams, notes, events, lessons, updates, certifications, missedExams }
+enum FilterType { all, grades, newGrades, messages, absences, homework, exams, notes, events, lessons, updates, certifications, missedExams, premium }
Future> getFilterWidgets(FilterType activeData, {bool absencesNoExcused = false, required BuildContext context}) async {
final gradeProvider = Provider.of(context);
@@ -40,6 +42,7 @@ Future> getFilterWidgets(FilterType activeData, {bool absencesN
final eventProvider = Provider.of(context);
final updateProvider = Provider.of(context);
final settingsProvider = Provider.of(context);
+ final premiumProvider = Provider.of(context);
List items = [];
@@ -56,6 +59,7 @@ Future> getFilterWidgets(FilterType activeData, {bool absencesN
getFilterWidgets(FilterType.updates, context: context),
getFilterWidgets(FilterType.certifications, context: context),
getFilterWidgets(FilterType.missedExams, context: context),
+ getFilterWidgets(FilterType.premium, context: context),
]);
items = all.expand((x) => x).toList();
@@ -127,6 +131,12 @@ Future> getFilterWidgets(FilterType activeData, {bool absencesN
case FilterType.missedExams:
items = missed_exam_filter.getWidgets(timetableProvider.lessons);
break;
+
+ case FilterType.premium:
+ final now = DateTime.now();
+ final isWeekend = now.weekday == DateTime.saturday || now.weekday == DateTime.sunday;
+ items = [if (!premiumProvider.hasPremium && isWeekend) premium_filter.getWidget()];
+ break;
}
return items;
}
diff --git a/filcnaplo/lib/ui/filter/widgets/premium.dart b/filcnaplo/lib/ui/filter/widgets/premium.dart
new file mode 100644
index 0000000..b1e5336
--- /dev/null
+++ b/filcnaplo/lib/ui/filter/widgets/premium.dart
@@ -0,0 +1,16 @@
+import 'package:filcnaplo/ui/date_widget.dart';
+import 'package:filcnaplo_premium/ui/mobile/premium/premium_banner_button.dart';
+import 'package:flutter/widgets.dart';
+
+DateWidget getWidget() {
+ return DateWidget(
+ date: DateTime.now().add(const Duration(minutes: 1)),
+ widget: Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 6.0),
+ child: ClipRRect(
+ borderRadius: BorderRadius.circular(14.0),
+ child: const PremiumBannerButton(),
+ ),
+ ),
+ );
+}
diff --git a/filcnaplo/pubspec.yaml b/filcnaplo/pubspec.yaml
index 92e27bb..55ddf79 100644
--- a/filcnaplo/pubspec.yaml
+++ b/filcnaplo/pubspec.yaml
@@ -57,6 +57,8 @@ dependencies:
git:
url: https://github.com/filc/flutter_expandable_fab
ref: master
+ uni_links: ^0.5.1
+ url_launcher: ^6.1.6
dev_dependencies:
flutter_lints: ^2.0.1
diff --git a/filcnaplo_mobile_ui b/filcnaplo_mobile_ui
index beac629..8dca7bf 160000
--- a/filcnaplo_mobile_ui
+++ b/filcnaplo_mobile_ui
@@ -1 +1 @@
-Subproject commit beac629f88a4d7cb9b5edf696e1fe067aef84ff0
+Subproject commit 8dca7bf10124b2eae89441f9defc506a7127755c
diff --git a/filcnaplo_premium b/filcnaplo_premium
index f659db4..ea41ee1 160000
--- a/filcnaplo_premium
+++ b/filcnaplo_premium
@@ -1 +1 @@
-Subproject commit f659db4e98390df3a46d82357b8880f2c91e379b
+Subproject commit ea41ee168fc3b1cac9d3c760edc4e5fd7c391d1f