forked from firka/student-legacy
add premium backend
This commit is contained in:
parent
ac18cf62c3
commit
75b03b95bc
1
.gitignore
vendored
1
.gitignore
vendored
@ -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/
|
||||
|
@ -6,6 +6,16 @@
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
<intent-filter android:autoVerify="true">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<!-- Accepts URIs that begin with https://api.filcnaplo.hu -->
|
||||
<data
|
||||
android:scheme="https"
|
||||
android:host="api.filcnaplo.hu"
|
||||
android:pathPrefix="/callback" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<meta-data android:name="flutterEmbedding" android:value="2" />
|
||||
</application>
|
||||
|
Binary file not shown.
@ -4,5 +4,9 @@
|
||||
<dict>
|
||||
<key>aps-environment</key>
|
||||
<string>development</string>
|
||||
<key>com.apple.developer.associated-domains</key>
|
||||
<array>
|
||||
<string>applinks:api.filcnaplo.hu</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
@ -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";
|
||||
|
@ -41,7 +41,7 @@ class NewsProvider extends ChangeNotifier {
|
||||
}
|
||||
|
||||
_state = state_;
|
||||
Provider.of<SettingsProvider>(_context, listen: false).update(_context, newsState: _state);
|
||||
Provider.of<SettingsProvider>(_context, listen: false).update(newsState: _state);
|
||||
}
|
||||
|
||||
Future<void> fetch() async {
|
||||
@ -53,7 +53,7 @@ class NewsProvider extends ChangeNotifier {
|
||||
|
||||
if (_fresh < 0) {
|
||||
_state = news_.length;
|
||||
Provider.of<SettingsProvider>(_context, listen: false).update(_context, newsState: _state);
|
||||
Provider.of<SettingsProvider>(_context, listen: false).update(newsState: _state);
|
||||
}
|
||||
|
||||
_fresh = max(_fresh, 0);
|
||||
@ -72,7 +72,7 @@ class NewsProvider extends ChangeNotifier {
|
||||
_fresh--;
|
||||
_state++;
|
||||
|
||||
Provider.of<SettingsProvider>(_context, listen: false).update(_context, newsState: _state);
|
||||
Provider.of<SettingsProvider>(_context, listen: false).update(newsState: _state);
|
||||
|
||||
if (_fresh > 0) {
|
||||
show = true;
|
||||
|
@ -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<PremiumProvider>(create: (_) => premium),
|
||||
ChangeNotifierProvider<SettingsProvider>(create: (_) => settings),
|
||||
ChangeNotifierProvider<UserProvider>(create: (_) => user),
|
||||
ChangeNotifierProvider<StatusProvider>(create: (_) => status),
|
||||
|
@ -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<void> createTable(Database db, DatabaseStruct struct) => db.execute("CREATE TABLE IF NOT EXISTS ${struct.table} ($struct)");
|
||||
|
||||
Future<Database> initDB() async {
|
||||
Future<Database> initDB(DatabaseProvider database) async {
|
||||
Database db;
|
||||
|
||||
if (Platform.isLinux || Platform.isWindows) {
|
||||
@ -46,7 +47,7 @@ Future<Database> 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<Database> initDB() async {
|
||||
await migrateDB(
|
||||
db,
|
||||
struct: settingsDB,
|
||||
defaultValues: SettingsProvider.defaultSettings().toMap(),
|
||||
defaultValues: SettingsProvider.defaultSettings(database: database).toMap(),
|
||||
);
|
||||
await migrateDB(
|
||||
db,
|
||||
|
@ -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<SettingsProvider> getSettings() async {
|
||||
Future<SettingsProvider> 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;
|
||||
}
|
||||
|
||||
|
@ -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';
|
||||
|
@ -5,6 +5,7 @@ import 'package:share_plus/share_plus.dart';
|
||||
|
||||
class ShareHelper {
|
||||
static Future<void> shareText(String text, {String? subject}) => Share.share(text, subject: subject);
|
||||
// ignore: deprecated_member_use
|
||||
static Future<void> shareFile(String path, {String? text, String? subject}) => Share.shareFiles([path], text: text, subject: subject);
|
||||
|
||||
static Future<void> shareAttachment(Attachment attachment, {required BuildContext context}) async {
|
||||
|
@ -16,4 +16,7 @@ class FilcIcons {
|
||||
|
||||
/// downstairs
|
||||
static const IconData downstairs = IconData(0x03, fontFamily: iconFontFamily);
|
||||
|
||||
/// premium
|
||||
static const IconData premium = IconData(0x04, fontFamily: iconFontFamily);
|
||||
}
|
||||
|
@ -32,11 +32,11 @@ class Startup {
|
||||
late DatabaseProvider database;
|
||||
|
||||
Future<void> 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();
|
||||
}
|
||||
}
|
||||
|
@ -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<String> _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<String> 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<String, Object?>? 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<String>(),
|
||||
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<String> get premiumScopes => _premiumScopes;
|
||||
String get premiumAccessToken => _premiumAccessToken;
|
||||
|
||||
Future<void> update(
|
||||
BuildContext context, {
|
||||
DatabaseProvider? database,
|
||||
Future<void> update({
|
||||
bool store = true,
|
||||
String? language,
|
||||
Pages? startPage,
|
||||
@ -304,6 +321,8 @@ class SettingsProvider extends ChangeNotifier {
|
||||
Color? customAccentColor,
|
||||
Color? customBackgroundColor,
|
||||
Color? customHighlightColor,
|
||||
List<String>? 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<DatabaseProvider>(context, listen: false);
|
||||
if (store) await database.store.storeSettings(this);
|
||||
if (store) await _database?.store.storeSettings(this);
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
@ -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<FilterType> 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<List<DateWidget>> getFilterWidgets(FilterType activeData, {bool absencesNoExcused = false, required BuildContext context}) async {
|
||||
final gradeProvider = Provider.of<GradeProvider>(context);
|
||||
@ -40,6 +42,7 @@ Future<List<DateWidget>> getFilterWidgets(FilterType activeData, {bool absencesN
|
||||
final eventProvider = Provider.of<EventProvider>(context);
|
||||
final updateProvider = Provider.of<UpdateProvider>(context);
|
||||
final settingsProvider = Provider.of<SettingsProvider>(context);
|
||||
final premiumProvider = Provider.of<PremiumProvider>(context);
|
||||
|
||||
List<DateWidget> items = [];
|
||||
|
||||
@ -56,6 +59,7 @@ Future<List<DateWidget>> 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<List<DateWidget>> 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;
|
||||
}
|
||||
|
16
filcnaplo/lib/ui/filter/widgets/premium.dart
Normal file
16
filcnaplo/lib/ui/filter/widgets/premium.dart
Normal file
@ -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(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
@ -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
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit beac629f88a4d7cb9b5edf696e1fe067aef84ff0
|
||||
Subproject commit 8dca7bf10124b2eae89441f9defc506a7127755c
|
@ -1 +1 @@
|
||||
Subproject commit f659db4e98390df3a46d82357b8880f2c91e379b
|
||||
Subproject commit ea41ee168fc3b1cac9d3c760edc4e5fd7c391d1f
|
Loading…
x
Reference in New Issue
Block a user