diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index 5316cb2..5927722 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -15,10 +15,10 @@ jobs: encodedString: ${{ secrets.KEYSTORE_BASE64 }} - name: Create key.properties run: | - echo "storeFile=${{ steps.android_keystore.outputs.filePath }}" > filcnaplo/android/key.properties - echo "storePassword=${{ secrets.STORE_PASSWORD }}" >> filcnaplo/android/key.properties - echo "keyPassword=${{ secrets.KEY_PASSWORD }}" >> filcnaplo/android/key.properties - echo "keyAlias=${{ secrets.KEY_ALIAS }}" >> filcnaplo/android/key.properties + echo "storeFile=${{ steps.android_keystore.outputs.filePath }}" > refilc/android/key.properties + echo "storePassword=${{ secrets.STORE_PASSWORD }}" >> refilc/android/key.properties + echo "keyPassword=${{ secrets.KEY_PASSWORD }}" >> refilc/android/key.properties + echo "keyAlias=${{ secrets.KEY_ALIAS }}" >> refilc/android/key.properties - uses: actions/setup-java@v3 with: distribution: "zulu" @@ -32,7 +32,7 @@ jobs: - name: Install dependencies run: ./fix-pub.sh - name: Build - run: cd filcnaplo && ./build.sh + run: cd refilc && ./build.sh - name: Upload Android Release uses: actions/upload-artifact@v2 with: diff --git a/.github/workflows/ios.yml b/.github/workflows/ios.yml index 604d8ea..c456926 100644 --- a/.github/workflows/ios.yml +++ b/.github/workflows/ios.yml @@ -46,7 +46,7 @@ jobs: # Build and sign the ipa using a single flutter command - name: Building IPA - working-directory: filcnaplo + working-directory: refilc run: bash build-ipa.sh # Collect the file and upload as artifact @@ -55,7 +55,7 @@ jobs: with: name: release-ipa # Path to the release files - path: filcnaplo/build/ios/ipa/*.ipa + path: refilc/build/ios/ipa/*.ipa # Important! Cleanup: remove the certificate and provisioning profile from the runner! - name: Clean up keychain and provisioning profile diff --git a/.gitignore b/.gitignore index eb2131f..b4db4b1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,39 +1,56 @@ -filcnaplo/.flutter-plugins -filcnaplo/.flutter-plugins-dependencies -filcnaplo/pubspec.lock -filcnaplo/.dart_tool/ -filcnaplo/android/ -filcnaplo/ios/ -filcnaplo/windows/ -filcnaplo/linux/ -filcnaplo/macos/ -filcnaplo/build/ +refilc/.flutter-plugins +refilc/.flutter-plugins-dependencies +refilc/pubspec.lock +refilc/.dart_tool/ +# refilc/android/ +# refilc/ios/ +# refilc/windows/ +# refilc/linux/ +# refilc/macos/ +refilc/build/ +refilc/android/key.properties +refilc/android/debug.keystore -filcnaplo_desktop_ui/.flutter-plugins -filcnaplo_desktop_ui/.flutter-plugins-dependencies -filcnaplo_desktop_ui/pubspec.lock -filcnaplo_desktop_ui/.dart_tool/ +refilc_desktop_ui/.flutter-plugins +refilc_desktop_ui/.flutter-plugins-dependencies +refilc_desktop_ui/pubspec.lock +refilc_desktop_ui/.dart_tool/ -filcnaplo_kreta_api/.flutter-plugins -filcnaplo_kreta_api/.flutter-plugins-dependencies -filcnaplo_kreta_api/pubspec.lock -filcnaplo_kreta_api/.dart_tool/ +refilc_kreta_api/.flutter-plugins +refilc_kreta_api/.flutter-plugins-dependencies +refilc_kreta_api/pubspec.lock +refilc_kreta_api/.dart_tool/ -filcnaplo_mobile_ui/.flutter-plugins -filcnaplo_mobile_ui/.flutter-plugins-dependencies -filcnaplo_mobile_ui/pubspec.lock -filcnaplo_mobile_ui/.dart_tool/ +refilc_mobile_ui/.flutter-plugins +refilc_mobile_ui/.flutter-plugins-dependencies +refilc_mobile_ui/pubspec.lock +refilc_mobile_ui/.dart_tool/ -filcnaplo_premium/.flutter-plugins -filcnaplo_premium/.flutter-plugins-dependencies -filcnaplo_premium/pubspec.lock -filcnaplo_premium/.dart_tool/ +# filcnaplo_premium/.flutter-plugins +# filcnaplo_premium/.flutter-plugins-dependencies +# filcnaplo_premium/pubspec.lock +# filcnaplo_premium/.dart_tool/ .vscode .github .idea .gitmodules +.gradle -filcnaplo/.DS_Store +refilc/.DS_Store .DS_Store +refilc/linux/flutter/ +.plugin_symlinks/ +refilc/macos/Flutter/ +refilc/ios/Flutter/ +refilc/ios/Runner/GeneratedPluginRegistrant.h +refilc/ios/Runner/GeneratedPluginRegistrant.m +refilc/android/local.properties +refilc/android/debugkey.properties +refilc/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java + +tool_logs/build/*.log +tool_logs/d8dx_fix/*.log +tool_logs/pub_fix/*.log +refilc_mobile_ui/android/local.properties diff --git a/.gitmodules b/.gitmodules index 5253922..8cd5c43 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "naplo-plus"] - path = filcnaplo_premium + path = refilc_plus url = git@github.com:refilc/naplo-plus.git diff --git a/README.md b/README.md index a297d87..7650e26 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,10 @@ ### Clone the project +A teljes source eléréséhez szükséged lesz a naplo-plus repo-ra is, mely biztonsági okokból privát. Írj Discord szerverünkön, hogy kaphass hozzáférést. + ```sh -git clone https://github.com/refilc/naplo +git clone --branch dev https://github.com/refilc/naplo --recursive cd naplo ``` @@ -23,8 +25,8 @@ Run `fix-pub.sh` ### Run the app ```sh -cd filcnaplo -flutter run +cd refilc +flutter run (--release) ``` ### Contribution @@ -47,6 +49,4 @@ Az összes (ugyan azon verzióhoz tartozó) contribution meg fog jelenni a relea **Péter:** 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) - -Ez a projekt egy fork; az eredeti projektet megtaláljátok itt: [filc/naplo-archive](https://github.com/filc/naplo-archive) (köszi, annon) +**annon:** a régi Filc Napló fejlesztője (ez az app, ha bár sokban változott, alapjaiban a Filc-re épül) diff --git a/changelog.md b/changelog.md deleted file mode 100644 index f01585f..0000000 --- a/changelog.md +++ /dev/null @@ -1,13 +0,0 @@ -What's new: - -- design tweak -- new premium ui -- premium fix -- rounding fix -- graph percentage fix -- fail warning -- Widget -- fix sent messages -- fix ios live activities -- Hibajavítások 🐛 -- **Megérkezett a Filc Premium!** ✨ diff --git a/filcnaplo/.gitignore b/filcnaplo/.gitignore deleted file mode 100644 index 24476c5..0000000 --- a/filcnaplo/.gitignore +++ /dev/null @@ -1,44 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ -migrate_working_dir/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -**/ios/Flutter/.last_build_id -.dart_tool/ -.flutter-plugins -.flutter-plugins-dependencies -.packages -.pub-cache/ -.pub/ -/build/ - -# Symbolication related -app.*.symbols - -# Obfuscation related -app.*.map.json - -# Android Studio will place build artifacts here -/android/app/debug -/android/app/profile -/android/app/release diff --git a/filcnaplo/android/app/proguard-rules.pro b/filcnaplo/android/app/proguard-rules.pro deleted file mode 100644 index 56fe627..0000000 --- a/filcnaplo/android/app/proguard-rules.pro +++ /dev/null @@ -1,5 +0,0 @@ --keep class io.flutter.plugin.editing.** { *; } --keep class androidx.lifecycle.DefaultLifecycleObserver --keep class com.pauldemarco.flutter_blue.** { *; } --keep class com.mr.flutter.plugin.filepicker.** { *; } --keep class com.shockwave.** \ No newline at end of file diff --git a/filcnaplo/android/app/src/main/java/hu/refilc/naplo/MainActivity.java b/filcnaplo/android/app/src/main/java/hu/refilc/naplo/MainActivity.java deleted file mode 100644 index ff22fb7..0000000 --- a/filcnaplo/android/app/src/main/java/hu/refilc/naplo/MainActivity.java +++ /dev/null @@ -1,7 +0,0 @@ -package hu.refilc.naplo; - -import io.flutter.embedding.android.FlutterActivity; - -public class MainActivity extends FlutterActivity { - -} diff --git a/filcnaplo/android/app/src/main/java/hu/refilc/naplo/database/DBManager.java b/filcnaplo/android/app/src/main/java/hu/refilc/naplo/database/DBManager.java deleted file mode 100644 index b39409d..0000000 --- a/filcnaplo/android/app/src/main/java/hu/refilc/naplo/database/DBManager.java +++ /dev/null @@ -1,119 +0,0 @@ -package hu.refilc.naplo.database; - -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; - -import java.sql.SQLException; - -import hu.refilc.naplo.database.SQLiteHelper; - -public class DBManager { - private Context context; - private SQLiteDatabase database; - private SQLiteHelper dbHelper; - - public DBManager(Context c) { - this.context = c; - } - - public DBManager open() throws SQLException { - this.dbHelper = new SQLiteHelper(this.context); - this.database = this.dbHelper.getWritableDatabase(); - return this; - } - - public void close() { - this.dbHelper.close(); - } - - public Cursor fetchWidget(int wid) { - Cursor cursor = this.database.query(SQLiteHelper.TABLE_NAME_WIDGETS, new String[]{SQLiteHelper._ID, SQLiteHelper.DAY_SEL}, SQLiteHelper._ID + " = " + wid, null, null, null, null); - if (cursor != null) { - cursor.moveToFirst(); - } - return cursor; - } - - public Cursor fetchTimetable() { - Cursor cursor = this.database.query(SQLiteHelper.TABLE_NAME_USER_DATA, new String[]{SQLiteHelper.TIMETABLE}, null, null, null, null, null); - if (cursor != null) { - cursor.moveToFirst(); - } - return cursor; - } - - public Cursor fetchLastUser() { - Cursor cursor = this.database.query(SQLiteHelper.TABLE_NAME_SETTINGS, new String[]{SQLiteHelper.LAST_ACCOUNT_ID}, null, null, null, null, null); - if (cursor != null) { - cursor.moveToFirst(); - } - return cursor; - } - - public Cursor fetchTheme() { - Cursor cursor = this.database.query(SQLiteHelper.TABLE_NAME_SETTINGS, new String[]{SQLiteHelper.THEME, SQLiteHelper.ACCENT_COLOR}, null, null, null, null, null); - if (cursor != null) { - cursor.moveToFirst(); - } - return cursor; - } - - public Cursor fetchPremiumToken() { - Cursor cursor = this.database.query(SQLiteHelper.TABLE_NAME_SETTINGS, new String[]{SQLiteHelper.PREMIUM_TOKEN}, null, null, null, null, null); - if (cursor != null) { - cursor.moveToFirst(); - } - return cursor; - } - - public Cursor fetchPremiumScopes() { - Cursor cursor = this.database.query(SQLiteHelper.TABLE_NAME_SETTINGS, new String[]{SQLiteHelper.PREMIUM_SCOPES}, null, null, null, null, null); - if (cursor != null) { - cursor.moveToFirst(); - } - return cursor; - } - - public Cursor fetchLocale() { - Cursor cursor = this.database.query(SQLiteHelper.TABLE_NAME_SETTINGS, new String[]{SQLiteHelper.LOCALE}, null, null, null, null, null); - if (cursor != null) { - cursor.moveToFirst(); - } - return cursor; - } - - public void deleteWidget(int _id) { - this.database.delete(SQLiteHelper.TABLE_NAME_WIDGETS, "_id=" + _id, null); - } - - /*public void changeSettings(int _id, Map map) { - ContentValues con = new ContentValues(); - for(Map.Entry e: map.entrySet()){ - con.put(e.getKey(), e.getValue()); - } - this.database.update(SQLiteHelper.TABLE_NAME_WIDGETS, con, "_id = " + _id, null); - } - public void insertSettings(int _id, Map map) { - ContentValues con = new ContentValues(); - for(Map.Entry e: map.entrySet()){ - con.put(e.getKey(), e.getValue()); - //Log.d("Settings added", e.getKey() + " - " + e.getValue()); - } - this.database.insert(SQLiteHelper.TABLE_NAME_WIDGETS, null, con); - }*/ - - public void insertSelDay(int _id, int day_sel) { - ContentValues con = new ContentValues(); - con.put(SQLiteHelper._ID, _id); - con.put(SQLiteHelper.DAY_SEL, day_sel); - this.database.insert(SQLiteHelper.TABLE_NAME_WIDGETS, null, con); - } - - public int update(int _id, int day_sel) { - ContentValues con = new ContentValues(); - con.put(SQLiteHelper.DAY_SEL, day_sel); - return this.database.update(SQLiteHelper.TABLE_NAME_WIDGETS, con, SQLiteHelper._ID + " = " + _id, null); - } -} \ No newline at end of file diff --git a/filcnaplo/android/app/src/main/java/hu/refilc/naplo/database/SQLiteHelper.java b/filcnaplo/android/app/src/main/java/hu/refilc/naplo/database/SQLiteHelper.java deleted file mode 100644 index 5944408..0000000 --- a/filcnaplo/android/app/src/main/java/hu/refilc/naplo/database/SQLiteHelper.java +++ /dev/null @@ -1,36 +0,0 @@ -package hu.refilc.naplo.database; - -import android.content.Context; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteOpenHelper; - -public class SQLiteHelper extends SQLiteOpenHelper { - private static final String CREATE_TABLE_WIDGET = " create table widgets ( _id INTEGER NOT NULL, day_sel INTEGER NOT NULL);"; - private static final String DB_NAME = "app.db"; - private static final int DB_VERSION = 1; - public static final String _ID = "_id"; - public static final String DAY_SEL = "day_sel"; - public static final String TIMETABLE = "timetable"; - public static final String LAST_ACCOUNT_ID = "last_account_id"; - public static final String THEME = "theme"; - public static final String PREMIUM_TOKEN = "premium_token"; - public static final String PREMIUM_SCOPES = "premium_scopes"; - public static final String LOCALE = "language"; - public static final String ACCENT_COLOR = "accent_color"; - public static final String TABLE_NAME_WIDGETS = "widgets"; - public static final String TABLE_NAME_USER_DATA = "user_data"; - public static final String TABLE_NAME_SETTINGS = "settings"; - - public SQLiteHelper(Context context) { - super(context, DB_NAME, null, 7); - } - - public void onCreate(SQLiteDatabase db) { - db.execSQL(CREATE_TABLE_WIDGET); - } - - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - db.execSQL("DROP TABLE IF EXISTS widgets"); - onCreate(db); - } -} \ No newline at end of file diff --git a/filcnaplo/android/app/src/main/java/hu/refilc/naplo/utils/Utils.java b/filcnaplo/android/app/src/main/java/hu/refilc/naplo/utils/Utils.java deleted file mode 100644 index 30f2a62..0000000 --- a/filcnaplo/android/app/src/main/java/hu/refilc/naplo/utils/Utils.java +++ /dev/null @@ -1,36 +0,0 @@ -package hu.refilc.naplo.utils; - -import android.content.Context; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; - -import java.util.Calendar; -import java.util.Date; - -public class Utils { - public static boolean hasNetwork(Context context) { - ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkInfo netInfo = cm.getActiveNetworkInfo(); - if (netInfo != null && netInfo.isConnectedOrConnecting()) { - return true; - } - return false; - } - - public static Date getWeekStartDate() { - Calendar calendar = Calendar.getInstance(); - while (calendar.get(Calendar.DAY_OF_WEEK) != Calendar.MONDAY) { - calendar.add(Calendar.DATE, -1); - } - return calendar.getTime(); - } - - public static Date getWeekEndDate() { - Calendar calendar = Calendar.getInstance(); - while (calendar.get(Calendar.DAY_OF_WEEK) != Calendar.MONDAY) { - calendar.add(Calendar.DATE, 1); - } - calendar.add(Calendar.DATE, -1); - return calendar.getTime(); - } -} \ No newline at end of file diff --git a/filcnaplo/android/app/src/main/java/hu/refilc/naplo/utils/Week.java b/filcnaplo/android/app/src/main/java/hu/refilc/naplo/utils/Week.java deleted file mode 100644 index 9f62c3e..0000000 --- a/filcnaplo/android/app/src/main/java/hu/refilc/naplo/utils/Week.java +++ /dev/null @@ -1,65 +0,0 @@ -package hu.refilc.naplo.utils; - -import java.time.DayOfWeek; -import java.time.Duration; -import java.time.LocalDate; - -public class Week { - private final LocalDate start; - private final LocalDate end; - - private Week(LocalDate start, LocalDate end) { - this.start = start; - this.end = end; - } - - public static Week current() { - return fromDate(LocalDate.now()); - } - - public static Week fromId(int id) { - LocalDate _now = getYearStart().plusDays(id * 7L); - return new Week(_now.minusDays(_now.getDayOfWeek().getValue() - 1), _now.plusDays(7 - _now.getDayOfWeek().getValue())); - } - - public static Week fromDate(LocalDate date) { - - return new Week(date.minusDays(date.getDayOfWeek().getValue() - 1), date.plusDays(7 - date.getDayOfWeek().getValue())); - } - - public Week next() { - return Week.fromDate(start.plusDays(8)); - } - - public int id() { - return (int) Math.ceil(Duration.between(getYearStart().atStartOfDay(), start.atStartOfDay()).toDays() / 7f); - } - - private static LocalDate getYearStart() { - LocalDate now = LocalDate.now(); - LocalDate start = getYearStart(now.getYear()); - return start.isBefore(now) ? start : getYearStart(now.getYear() -1); - } - - private static LocalDate getYearStart(int year) { - LocalDate time = LocalDate.of(year, 9, 1); - if (time.getDayOfWeek() == DayOfWeek.SATURDAY) - return time.plusDays(2); - else if (time.getDayOfWeek() == DayOfWeek.SUNDAY) - return time.plusDays(1); - return time; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Week week = (Week) o; - return this.id() == week.id(); - } - - @Override - public int hashCode() { - return id(); - } -} \ No newline at end of file diff --git a/filcnaplo/android/app/src/main/java/hu/refilc/naplo/widget_timetable/WidgetTimetable.java b/filcnaplo/android/app/src/main/java/hu/refilc/naplo/widget_timetable/WidgetTimetable.java deleted file mode 100644 index b433ec7..0000000 --- a/filcnaplo/android/app/src/main/java/hu/refilc/naplo/widget_timetable/WidgetTimetable.java +++ /dev/null @@ -1,392 +0,0 @@ -package hu.refilc.naplo.widget_timetable; - -import android.app.PendingIntent; -import android.appwidget.AppWidgetManager; -import android.appwidget.AppWidgetProvider; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.database.Cursor; -import android.net.Uri; -import android.os.Build; -import android.util.Log; -import android.view.View; -import android.widget.RemoteViews; -import android.widget.Toast; - -import org.joda.time.DateTime; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.time.DayOfWeek; -import java.time.format.TextStyle; -import java.util.ArrayList; -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; -import hu.refilc.naplo.R; - -import hu.refilc.naplo.utils.Week; - -import static android.app.PendingIntent.FLAG_UPDATE_CURRENT; - -import es.antonborri.home_widget.HomeWidgetBackgroundIntent; -import es.antonborri.home_widget.HomeWidgetLaunchIntent; -import es.antonborri.home_widget.HomeWidgetProvider; - -public class WidgetTimetable extends HomeWidgetProvider { - - private static final String ACTION_WIDGET_CLICK_NAV_LEFT = "list_widget.ACTION_WIDGET_CLICK_NAV_LEFT"; - private static final String ACTION_WIDGET_CLICK_NAV_RIGHT = "list_widget.ACTION_WIDGET_CLICK_NAV_RIGHT"; - private static final String ACTION_WIDGET_CLICK_NAV_TODAY = "list_widget.ACTION_WIDGET_CLICK_NAV_TODAY"; - private static final String ACTION_WIDGET_CLICK_NAV_REFRESH = "list_widget.ACTION_WIDGET_CLICK_NAV_REFRESH"; - private static final String ACTION_WIDGET_CLICK_BUY_PREMIUM = "list_widget.ACTION_WIDGET_CLICK_BUY_PREMIUM"; - - @Override - public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds, SharedPreferences widgetData) { - for (int i = 0; i < appWidgetIds.length; i++) { - RemoteViews views = generateView(context, appWidgetIds[i]); - - if(premiumEnabled(context) && userLoggedIn(context)) { - int rday = selectDay(context, appWidgetIds[i], 0, true); - views.setTextViewText(R.id.nav_current, convertDayOfWeek(context, rday)); - } - - pushUpdate(context, views, appWidgetIds[i]); - } - } - - public static void pushUpdate(Context context, RemoteViews remoteViews, int appWidgetSingleId) { - AppWidgetManager manager = AppWidgetManager.getInstance(context); - - manager.updateAppWidget(appWidgetSingleId, remoteViews); - manager.notifyAppWidgetViewDataChanged(appWidgetSingleId, R.id.widget_list); - } - - public static RemoteViews generateView(Context context, int appId) { - Intent serviceIntent = new Intent(context, WidgetTimetableService.class); - serviceIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appId); - serviceIntent.setData(Uri.parse(serviceIntent.toUri(Intent.URI_INTENT_SCHEME))); - - RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_timetable); - - views.setViewVisibility(R.id.need_premium, View.GONE); - views.setViewVisibility(R.id.need_login, View.GONE); - views.setViewVisibility(R.id.tt_grid_cont, View.GONE); - - if(!userLoggedIn(context)) { - views.setViewVisibility(R.id.need_login, View.VISIBLE); - views.setOnClickPendingIntent(R.id.open_login, makePending(context, ACTION_WIDGET_CLICK_BUY_PREMIUM, appId)); - } else if(premiumEnabled(context)) { - views.setViewVisibility(R.id.tt_grid_cont, View.VISIBLE); - views.setOnClickPendingIntent(R.id.nav_to_left, makePending(context, ACTION_WIDGET_CLICK_NAV_LEFT, appId)); - views.setOnClickPendingIntent(R.id.nav_to_right, makePending(context, ACTION_WIDGET_CLICK_NAV_RIGHT, appId)); - views.setOnClickPendingIntent(R.id.nav_current, makePending(context, ACTION_WIDGET_CLICK_NAV_TODAY, appId)); - views.setOnClickPendingIntent(R.id.nav_refresh, makePending(context, ACTION_WIDGET_CLICK_NAV_REFRESH, appId)); - views.setRemoteAdapter(R.id.widget_list, serviceIntent); - views.setEmptyView(R.id.widget_list, R.id.empty_view); - } else { - views.setViewVisibility(R.id.need_premium, View.VISIBLE); - views.setOnClickPendingIntent(R.id.buy_premium, makePending(context, ACTION_WIDGET_CLICK_BUY_PREMIUM, appId)); - } - - return views; - } - - static PendingIntent makePending(Context context, String action, int appWidgetId) { - Intent activebtnnext = new Intent(context, WidgetTimetable.class); - activebtnnext.setAction(action); - activebtnnext.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); - return PendingIntent.getBroadcast(context, appWidgetId, activebtnnext , PendingIntent.FLAG_IMMUTABLE); - } - - @Override - public void onReceive(Context context, Intent intent) { - super.onReceive(context, intent); - - if(intent.hasExtra(AppWidgetManager.EXTRA_APPWIDGET_ID)) { - int appId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); - RemoteViews views = generateView(context, appId); - - try { - if(premiumEnabled(context) && userLoggedIn(context)) { - if (intent.getAction().equals(ACTION_WIDGET_CLICK_NAV_LEFT)) { - int rday = selectDay(context, appId, -1, false); - views.setTextViewText(R.id.nav_current, convertDayOfWeek(context, rday)); - - pushUpdate(context, views, appId); - } else if (intent.getAction().equals(ACTION_WIDGET_CLICK_NAV_RIGHT)) { - int rday = selectDay(context, appId, 1, false); - views.setTextViewText(R.id.nav_current, convertDayOfWeek(context, rday)); - - pushUpdate(context, views, appId); - } else if (intent.getAction().equals(ACTION_WIDGET_CLICK_NAV_TODAY)) { - int rday = getToday(context); - setSelectedDay(context, appId, rday); - - views.setTextViewText(R.id.nav_current, convertDayOfWeek(context, rday)); - - pushUpdate(context, views, appId); - } else if (intent.getAction().equals(ACTION_WIDGET_CLICK_NAV_REFRESH)) { - PendingIntent pendingIntent = HomeWidgetLaunchIntent.INSTANCE.getActivity(context, MainActivity.class, Uri.parse("timetable://refresh")); - pendingIntent.send(); - } else if (intent.getAction().equals("android.appwidget.action.APPWIDGET_DELETED")) { - DBManager dbManager = new DBManager(context.getApplicationContext()); - - try { - dbManager.open(); - dbManager.deleteWidget(appId); - dbManager.close(); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - - if(intent.getAction().equals(ACTION_WIDGET_CLICK_BUY_PREMIUM)) { - PendingIntent pendingIntent = HomeWidgetLaunchIntent.INSTANCE.getActivity(context, MainActivity.class, Uri.parse("settings://premium")); - pendingIntent.send(); - } - } - catch (Exception e) { - e.printStackTrace(); - } - } - } - - public static String convertDayOfWeek(Context context, int rday) { - - /*if(rday == -1) return DayOfWeek.of(1).getDisplayName(TextStyle.FULL, new Locale("hu", "HU")); - - String dayOfWeek = DayOfWeek.of(rday + 1).getDisplayName(TextStyle.FULL, new Locale("hu", "HU"));*/ - - String dayOfWeek = "Unknown"; - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - Locale loc = getLocale(context); - - if (rday == -1) - return DayOfWeek.of(1).getDisplayName(TextStyle.FULL, loc); - - dayOfWeek = DayOfWeek.of(rday + 1).getDisplayName(TextStyle.FULL, loc); - } - - return dayOfWeek.substring(0, 1).toUpperCase() + dayOfWeek.substring(1).toLowerCase(); - } - - public static void setSelectedDay(Context context, int wid, int day) { - DBManager dbManager = new DBManager(context.getApplicationContext()); - - try { - dbManager.open(); - dbManager.update(wid, day); - dbManager.close(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - public static int getToday(Context context) { - int rday = new DateTime().getDayOfWeek() - 1; - List s = genJsonDays(context); - - try { - if(checkIsAfter(s, rday)) rday += 1; - } catch (Exception e) { - e.printStackTrace(); - } - return retDay(rday, s.size()); - } - - public static int selectDay(Context context, int wid, int add, Boolean afterSubjects) { - DBManager dbManager = new DBManager(context.getApplicationContext()); - - try { - dbManager.open(); - Cursor cursor = dbManager.fetchWidget(wid); - - List s = genJsonDays(context); - int retday = new DateTime().getDayOfWeek() - 1; - - if(cursor.getCount() != 0) retday = retDay(cursor.getInt(1) + add, s.size()); - - if(afterSubjects) if(checkIsAfter(s, retday)) retday += 1; - retday = retDay(retday, s.size()); - - if(cursor.getCount() == 0) dbManager.insertSelDay(wid, retday); - else dbManager.update(wid, retday); - - dbManager.close(); - - return retday; - } catch (Exception e) { - e.printStackTrace(); - } - - return 0; - } - - public static Boolean checkIsAfter(List s, int retday) throws Exception { - retday = retDay(retday, s.size()); - - String vegIdopont = s.get(retday).getJSONObject(s.get(retday).length() - 1).getString("VegIdopont"); - - return new DateTime().isAfter(new DateTime(vegIdopont)); - } - - public static int retDay(int retday, int size) { - if (retday < 0) retday = size - 1; - else if (retday > size - 1) retday = 0; - - return retday; - } - - public static List genJsonDays(Context context) { - List genDays = new ArrayList<>(); - Map dayMap = new HashMap<>(); - - DBManager dbManager = new DBManager(context.getApplicationContext()); - - try { - dbManager.open(); - Cursor ct = dbManager.fetchTimetable(); - - if (ct.getCount() == 0) { - return genDays; - } - - JSONObject fetchedTimetable = new JSONObject(ct.getString(0)); - String currentWeek = String.valueOf(Week.current().id()); - JSONArray week = fetchedTimetable.getJSONArray(currentWeek); - - // Organize lessons into dates - for (int i = 0; i < week.length(); i++) { - try { - JSONObject entry = week.getJSONObject(i); - String date = entry.getString("Datum"); - dayMap.computeIfAbsent(date, k -> new JSONArray()).put(entry); - } catch (JSONException e) { - e.printStackTrace(); - } - } - - genDays.addAll(dayMap.values()); - - // Sort the 'genDays' list of JSON based on the start time of the first entry - genDays.sort((day1, day2) -> { - try { - // 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; - } - }); - - } 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); - while(b.length() < padding){ - b.insert(0,"0"); - } - return b.toString(); - } - - public static Locale getLocale(Context context) { - DBManager dbManager = new DBManager(context.getApplicationContext()); - - try { - dbManager.open(); - String loc = dbManager.fetchLocale().getString(0); - dbManager.close(); - - if(loc.equals("hu") || loc.equals("de")) { - return new Locale(loc, loc.toUpperCase()); - } - } catch (Exception e) { - e.printStackTrace(); - } - - return new Locale("en", "GB"); - } - - public static boolean premiumEnabled(Context context) { - DBManager dbManager = new DBManager(context.getApplicationContext()); - - try { - dbManager.open(); - String premium_token = dbManager.fetchPremiumToken().getString(0); - String premium_scopes_raw = dbManager.fetchPremiumScopes().getString(0); - dbManager.close(); - - JSONArray arr = new JSONArray(premium_scopes_raw); - List premium_scopes = new ArrayList<>(); - for(int i = 0; i < arr.length(); i++){ - String scope = arr.getString(i); - premium_scopes.add(scope.substring(scope.lastIndexOf('.') + 1)); - } - - if(!premium_token.equals("") && (premium_scopes.contains("*") || premium_scopes.contains("TIMETALBE_WIDGET"))) { - return true; - } - } catch (Exception e) { - e.printStackTrace(); - } - - return false; - } - - public static boolean userLoggedIn(Context context) { - return !lastUserId(context).equals(""); - } - - public static String lastUserId(Context context) { - DBManager dbManager = new DBManager(context.getApplicationContext()); - try { - dbManager.open(); - Cursor cursor = dbManager.fetchLastUser(); - dbManager.close(); - - if(cursor != null && !cursor.getString(0).equals("")) { - String last_user = cursor.getString(0); - return last_user; - } - } catch (Exception e) { - e.printStackTrace(); - } - - return ""; - } - - @Override - public void onEnabled(Context context) { - } - - @Override - public void onDisabled(Context context) { - } -} \ No newline at end of file diff --git a/filcnaplo/android/app/src/main/java/hu/refilc/naplo/widget_timetable/WidgetTimetableDataProvider.java b/filcnaplo/android/app/src/main/java/hu/refilc/naplo/widget_timetable/WidgetTimetableDataProvider.java deleted file mode 100644 index 55eaa98..0000000 --- a/filcnaplo/android/app/src/main/java/hu/refilc/naplo/widget_timetable/WidgetTimetableDataProvider.java +++ /dev/null @@ -1,356 +0,0 @@ -package hu.refilc.naplo.widget_timetable; - -import android.appwidget.AppWidgetManager; -import android.content.Context; -import android.content.Intent; -import android.database.Cursor; -import android.os.Build; -import android.util.Log; -import android.view.View; -import android.widget.RemoteViews; -import android.widget.RemoteViewsService; - -import org.joda.time.DateTime; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - -import hu.refilc.naplo.database.DBManager; -import hu.refilc.naplo.R; - -public class WidgetTimetableDataProvider implements RemoteViewsService.RemoteViewsFactory { - - private Context context; - private int appWidgetId; - - private int rday = 0; - - private int theme; - - private Integer[] colorValues; - - List day_subjects = new ArrayList<>(); - List lessonIndexes = new ArrayList<>(); - - Item witem; - - /* Default values */ - - static class Item { - int Layout; - - int NumVisibility; - int NameVisibility; - int NameNodescVisibility; - int DescVisibility; - int RoomVisibility; - int TimeVisibility; - - int NumColor; - int NameColor; - int NameNodescColor; - int DescColor; - - Integer[] NameNodescPadding = {0, 0, 0, 0}; - - public Item(int Layout, int NumVisibility,int NameVisibility,int NameNodescVisibility,int DescVisibility,int RoomVisibility,int TimeVisibility,int NumColor,int NameColor,int NameNodescColor,int DescColor) { - this.Layout = Layout; - this.NumVisibility = NumVisibility; - this.NameVisibility = NameVisibility; - this.NameNodescVisibility = NameNodescVisibility; - this.DescVisibility = DescVisibility; - this.RoomVisibility = RoomVisibility; - this.TimeVisibility = TimeVisibility; - - this.NumColor = NumColor; - this.NameColor = NameColor; - this.NameNodescColor = NameNodescColor; - this.DescColor = DescColor; - } - } - - static class Lesson { - String status; - String lessonIndex; - String lessonName; - String lessonTopic; - String lessonRoom; - long lessonStart; - long lessonEnd; - String substituteTeacher; - - public Lesson(String status, String lessonIndex,String lessonName,String lessonTopic, String lessonRoom,long lessonStart,long lessonEnd,String substituteTeacher) { - this.status = status; - this.lessonIndex = lessonIndex; - this.lessonName = lessonName; - this.lessonTopic = lessonTopic; - this.lessonRoom = lessonRoom; - this.lessonStart = lessonStart; - this.lessonEnd = lessonEnd; - this.substituteTeacher = substituteTeacher; - } - } - - Integer[] itemNameNodescPadding = {0, 0, 0, 0}; - - public WidgetTimetableDataProvider(Context context, Intent intent) { - this.context = context; - this.appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); - - this.theme = getThemeAccent(context); - - this.colorValues = new Integer[]{R.color.filc, - R.color.blue_shade300, - R.color.green_shade300, - R.color.lime_shade300, - R.color.yellow_shade300, - R.color.orange_shade300, - R.color.red_shade300, - R.color.pink_shade300, - R.color.purple_shade300}; - - } - - @Override - public void onCreate() { - initData(); - } - - @Override - public void onDataSetChanged() { - initData(); - } - - @Override - public void onDestroy() { - - } - - @Override - public int getCount() { - - return day_subjects.size(); - } - - public void setLayout(final RemoteViews view) { - /* Visibilities */ - view.setViewVisibility(R.id.tt_item_num, witem.NumVisibility); - view.setViewVisibility(R.id.tt_item_name, witem.NameVisibility); - view.setViewVisibility(R.id.tt_item_name_nodesc, witem.NameNodescVisibility); - view.setViewVisibility(R.id.tt_item_desc, witem.DescVisibility); - view.setViewVisibility(R.id.tt_item_room, witem.RoomVisibility); - view.setViewVisibility(R.id.tt_item_time, witem.TimeVisibility); - - /* backgroundResources */ - view.setInt(R.id.main_lay, "setBackgroundResource", witem.Layout); - - /* Paddings */ - view.setViewPadding(R.id.tt_item_name_nodesc, witem.NameNodescPadding[0], witem.NameNodescPadding[1], witem.NameNodescPadding[2], witem.NameNodescPadding[3]); - - /* Text Colors */ - view.setInt(R.id.tt_item_num, "setTextColor", getColor(context, witem.NumColor)); - view.setInt(R.id.tt_item_name, "setTextColor", getColor(context, witem.NameColor)); - view.setInt(R.id.tt_item_name_nodesc, "setTextColor", getColor(context, witem.NameNodescColor)); - view.setInt(R.id.tt_item_desc, "setTextColor", getColor(context, witem.DescColor)); - } - - public int getColor(Context context, int color) { - return context.getResources().getColor(color); - } - - @Override - public RemoteViews getViewAt(int position) { - RemoteViews view = new RemoteViews(context.getPackageName(), R.layout.timetable_item); - - witem = defaultItem(theme); - - Lesson curr_subject = day_subjects.get(position); - - if (curr_subject.status.equals("empty")) { - witem.NumColor = R.color.text_miss_num; - - witem.TimeVisibility = View.GONE; - witem.RoomVisibility = View.GONE; - - witem.NameNodescColor = R.color.text_miss; - } - - if (!curr_subject.substituteTeacher.equals("null")) { - witem.NumColor = R.color.yellow; - witem.Layout = R.drawable.card_layout_tile_helyetesitett; - } - - if (curr_subject.status.equals("Elmaradt")) { - witem.NumColor = R.color.red; - witem.Layout = R.drawable.card_layout_tile_elmarad; - } else if (curr_subject.status.equals("TanevRendjeEsemeny")) { - witem.NumVisibility = View.GONE; - witem.TimeVisibility = View.GONE; - witem.RoomVisibility = View.GONE; - - witem.NameNodescPadding[0] = 50; - witem.NameNodescPadding[2] = 50; - - witem.NameNodescColor = R.color.text_miss; - } - - if (curr_subject.lessonTopic.equals("null")) { - witem.DescVisibility = View.GONE; - witem.NameVisibility = View.GONE; - - witem.NameNodescVisibility = View.VISIBLE; - } - - setLayout(view); - - String lessonIndexTrailing = curr_subject.lessonIndex.equals("+") ? "" : "."; - - view.setTextViewText(R.id.tt_item_num, curr_subject.lessonIndex + lessonIndexTrailing); - view.setTextViewText(R.id.tt_item_name, curr_subject.lessonName); - view.setTextViewText(R.id.tt_item_name_nodesc, curr_subject.lessonName); - view.setTextViewText(R.id.tt_item_desc, curr_subject.lessonTopic); - view.setTextViewText(R.id.tt_item_room, curr_subject.lessonRoom); - if(curr_subject.lessonStart != 0 && curr_subject.lessonEnd != 0) - view.setTextViewText(R.id.tt_item_time, WidgetTimetable.zeroPad(new DateTime(curr_subject.lessonStart).getHourOfDay(), 2) + ":" + WidgetTimetable.zeroPad(new DateTime(curr_subject.lessonStart).getMinuteOfHour(), 2) + - "\n" + WidgetTimetable.zeroPad(new DateTime(curr_subject.lessonEnd).getHourOfDay(), 2) + ":" + WidgetTimetable.zeroPad(new DateTime(curr_subject.lessonEnd).getMinuteOfHour(),2)); - - return view; - } - - @Override - public RemoteViews getLoadingView() { - return null; - } - - @Override - public int getViewTypeCount() { - return 1; - } - - @Override - public long getItemId(int position) { - return position; - } - - @Override - public boolean hasStableIds() { - return true; - } - - private void initData() { - - theme = getThemeAccent(context); - - rday = WidgetTimetable.selectDay(context, appWidgetId, 0, false); - - day_subjects.clear(); - lessonIndexes.clear(); - - try { - List arr = WidgetTimetable.genJsonDays(context); - - if(arr.isEmpty()) { - return; - } - JSONArray arr_lessons = WidgetTimetable.genJsonDays(context).get(rday); - - for (int i = 0; i < arr_lessons.length(); i++) { - JSONObject obj_lessons = arr_lessons.getJSONObject(i); - - day_subjects.add(jsonToLesson(obj_lessons)); - } - } catch (JSONException e) { - e.printStackTrace(); - } - - if(day_subjects.size() > 0) { - Collections.sort(day_subjects, new Comparator() { - public int compare(Lesson o1, Lesson o2) { - return new DateTime(o1.lessonStart).compareTo(new DateTime(o2.lessonStart)); - } - }); - - for (int i = 0; i < day_subjects.size(); i++) { - if(!day_subjects.get(i).lessonIndex.equals("+")) { - lessonIndexes.add(Integer.valueOf(day_subjects.get(i).lessonIndex)); - } - } - - if(lessonIndexes.size() > 0) { - - int lessonsChecked = Collections.min(lessonIndexes); - int i = 0; - - while(lessonsChecked < Collections.max(lessonIndexes)) { - if(!lessonIndexes.contains(lessonsChecked)) { - day_subjects.add(i, emptyLesson(lessonsChecked)); - } - lessonsChecked++; - i++; - } - } - } - } - - public static Integer getThemeAccent(Context context) { - DBManager dbManager = new DBManager(context.getApplicationContext()); - - try { - dbManager.open(); - Cursor cursor = dbManager.fetchTheme(); - dbManager.close(); - - return cursor.getInt(1); - } catch (Exception e) { - e.printStackTrace(); - } - - return 0; - } - - public Item defaultItem(int theme) { - return new Item( - R.drawable.card_layout_tile, - View.VISIBLE, - View.VISIBLE, - View.INVISIBLE, - View.VISIBLE, - View.VISIBLE, - View.VISIBLE, - colorValues[theme >= colorValues.length ? 0 : theme], - R.color.text, - R.color.text, - R.color.text_desc - ); - } - - public Lesson emptyLesson(int lessonIndex) { - return new Lesson("empty", String.valueOf(lessonIndex), "Lyukasóra", "null", "null", 0, 0, "null"); - } - - 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") : "+", - name, - json.getString("Tema"), - json.getString("TeremNeve"), - new DateTime(json.getString("KezdetIdopont")).getMillis(), - new DateTime(json.getString("VegIdopont")).getMillis(), - json.getString("HelyettesTanarNeve") - ); - }catch (Exception e) { - Log.d("Filc", "exception: " + e); - }; - - return null; - } -} \ No newline at end of file diff --git a/filcnaplo/android/app/src/main/java/hu/refilc/naplo/widget_timetable/WidgetTimetableService.java b/filcnaplo/android/app/src/main/java/hu/refilc/naplo/widget_timetable/WidgetTimetableService.java deleted file mode 100644 index 1864174..0000000 --- a/filcnaplo/android/app/src/main/java/hu/refilc/naplo/widget_timetable/WidgetTimetableService.java +++ /dev/null @@ -1,12 +0,0 @@ -package hu.refilc.naplo.widget_timetable; - -import android.content.Intent; -import android.os.Build; -import android.widget.RemoteViewsService; - -public class WidgetTimetableService extends RemoteViewsService { - @Override - public RemoteViewsFactory onGetViewFactory(Intent intent) { - return new WidgetTimetableDataProvider(getApplicationContext(), intent); - } -} \ No newline at end of file diff --git a/filcnaplo/android/app/src/main/res/drawable-hdpi/android12splash.png b/filcnaplo/android/app/src/main/res/drawable-hdpi/android12splash.png deleted file mode 100644 index 42f64fb..0000000 Binary files a/filcnaplo/android/app/src/main/res/drawable-hdpi/android12splash.png and /dev/null differ diff --git a/filcnaplo/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png b/filcnaplo/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png deleted file mode 100644 index 314c878..0000000 Binary files a/filcnaplo/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/filcnaplo/android/app/src/main/res/drawable-hdpi/splash.png b/filcnaplo/android/app/src/main/res/drawable-hdpi/splash.png deleted file mode 100644 index 42f64fb..0000000 Binary files a/filcnaplo/android/app/src/main/res/drawable-hdpi/splash.png and /dev/null differ diff --git a/filcnaplo/android/app/src/main/res/drawable-mdpi/android12splash.png b/filcnaplo/android/app/src/main/res/drawable-mdpi/android12splash.png deleted file mode 100644 index 65928ee..0000000 Binary files a/filcnaplo/android/app/src/main/res/drawable-mdpi/android12splash.png and /dev/null differ diff --git a/filcnaplo/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png b/filcnaplo/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png deleted file mode 100644 index aa13b85..0000000 Binary files a/filcnaplo/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/filcnaplo/android/app/src/main/res/drawable-mdpi/splash.png b/filcnaplo/android/app/src/main/res/drawable-mdpi/splash.png deleted file mode 100644 index 65928ee..0000000 Binary files a/filcnaplo/android/app/src/main/res/drawable-mdpi/splash.png and /dev/null differ diff --git a/filcnaplo/android/app/src/main/res/drawable-night-hdpi/android12splash.png b/filcnaplo/android/app/src/main/res/drawable-night-hdpi/android12splash.png deleted file mode 100644 index 42f64fb..0000000 Binary files a/filcnaplo/android/app/src/main/res/drawable-night-hdpi/android12splash.png and /dev/null differ diff --git a/filcnaplo/android/app/src/main/res/drawable-night-mdpi/android12splash.png b/filcnaplo/android/app/src/main/res/drawable-night-mdpi/android12splash.png deleted file mode 100644 index 65928ee..0000000 Binary files a/filcnaplo/android/app/src/main/res/drawable-night-mdpi/android12splash.png and /dev/null differ diff --git a/filcnaplo/android/app/src/main/res/drawable-night-xhdpi/android12splash.png b/filcnaplo/android/app/src/main/res/drawable-night-xhdpi/android12splash.png deleted file mode 100644 index 8147fe6..0000000 Binary files a/filcnaplo/android/app/src/main/res/drawable-night-xhdpi/android12splash.png and /dev/null differ diff --git a/filcnaplo/android/app/src/main/res/drawable-night-xxhdpi/android12splash.png b/filcnaplo/android/app/src/main/res/drawable-night-xxhdpi/android12splash.png deleted file mode 100644 index 80a42fb..0000000 Binary files a/filcnaplo/android/app/src/main/res/drawable-night-xxhdpi/android12splash.png and /dev/null differ diff --git a/filcnaplo/android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png b/filcnaplo/android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png deleted file mode 100644 index 2148f7f..0000000 Binary files a/filcnaplo/android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png and /dev/null differ diff --git a/filcnaplo/android/app/src/main/res/drawable-v21/background.png b/filcnaplo/android/app/src/main/res/drawable-v21/background.png deleted file mode 100644 index d90316e..0000000 Binary files a/filcnaplo/android/app/src/main/res/drawable-v21/background.png and /dev/null differ diff --git a/filcnaplo/android/app/src/main/res/drawable-xhdpi/android12splash.png b/filcnaplo/android/app/src/main/res/drawable-xhdpi/android12splash.png deleted file mode 100644 index 8147fe6..0000000 Binary files a/filcnaplo/android/app/src/main/res/drawable-xhdpi/android12splash.png and /dev/null differ diff --git a/filcnaplo/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png b/filcnaplo/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png deleted file mode 100644 index a83f396..0000000 Binary files a/filcnaplo/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/filcnaplo/android/app/src/main/res/drawable-xhdpi/splash.png b/filcnaplo/android/app/src/main/res/drawable-xhdpi/splash.png deleted file mode 100644 index 8147fe6..0000000 Binary files a/filcnaplo/android/app/src/main/res/drawable-xhdpi/splash.png and /dev/null differ diff --git a/filcnaplo/android/app/src/main/res/drawable-xxhdpi/android12splash.png b/filcnaplo/android/app/src/main/res/drawable-xxhdpi/android12splash.png deleted file mode 100644 index 80a42fb..0000000 Binary files a/filcnaplo/android/app/src/main/res/drawable-xxhdpi/android12splash.png and /dev/null differ diff --git a/filcnaplo/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png b/filcnaplo/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png deleted file mode 100644 index 1de7a46..0000000 Binary files a/filcnaplo/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/filcnaplo/android/app/src/main/res/drawable-xxhdpi/splash.png b/filcnaplo/android/app/src/main/res/drawable-xxhdpi/splash.png deleted file mode 100644 index 80a42fb..0000000 Binary files a/filcnaplo/android/app/src/main/res/drawable-xxhdpi/splash.png and /dev/null differ diff --git a/filcnaplo/android/app/src/main/res/drawable-xxxhdpi/android12splash.png b/filcnaplo/android/app/src/main/res/drawable-xxxhdpi/android12splash.png deleted file mode 100644 index 2148f7f..0000000 Binary files a/filcnaplo/android/app/src/main/res/drawable-xxxhdpi/android12splash.png and /dev/null differ diff --git a/filcnaplo/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png b/filcnaplo/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png deleted file mode 100644 index beeae31..0000000 Binary files a/filcnaplo/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/filcnaplo/android/app/src/main/res/drawable-xxxhdpi/splash.png b/filcnaplo/android/app/src/main/res/drawable-xxxhdpi/splash.png deleted file mode 100644 index 2148f7f..0000000 Binary files a/filcnaplo/android/app/src/main/res/drawable-xxxhdpi/splash.png and /dev/null differ diff --git a/filcnaplo/android/app/src/main/res/drawable/background.png b/filcnaplo/android/app/src/main/res/drawable/background.png deleted file mode 100644 index d90316e..0000000 Binary files a/filcnaplo/android/app/src/main/res/drawable/background.png and /dev/null differ diff --git a/filcnaplo/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/filcnaplo/android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index 7144abf..0000000 Binary files a/filcnaplo/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/filcnaplo/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/filcnaplo/android/app/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 0e55b88..0000000 Binary files a/filcnaplo/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/filcnaplo/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/filcnaplo/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 83ad190..0000000 Binary files a/filcnaplo/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/filcnaplo/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/filcnaplo/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index 26c3c81..0000000 Binary files a/filcnaplo/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/filcnaplo/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/filcnaplo/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 9ef3354..0000000 Binary files a/filcnaplo/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/filcnaplo/android/settings.gradle b/filcnaplo/android/settings.gradle deleted file mode 100644 index 33f0745..0000000 --- a/filcnaplo/android/settings.gradle +++ /dev/null @@ -1,11 +0,0 @@ -include ':app' - -def localPropertiesFile = new File(rootProject.projectDir, "local.properties") -def properties = new Properties() - -assert localPropertiesFile.exists() -localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } - -def flutterSdkPath = properties.getProperty("flutter.sdk") -assert flutterSdkPath != null, "flutter.sdk not set in local.properties" -apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/filcnaplo/assets/icons/ic_android.png b/filcnaplo/assets/icons/ic_android.png deleted file mode 100644 index f274933..0000000 Binary files a/filcnaplo/assets/icons/ic_android.png and /dev/null differ diff --git a/filcnaplo/assets/icons/ic_launcher.png b/filcnaplo/assets/icons/ic_launcher.png deleted file mode 100644 index 154065b..0000000 Binary files a/filcnaplo/assets/icons/ic_launcher.png and /dev/null differ diff --git a/filcnaplo/assets/icons/ic_launcher_foreground.png b/filcnaplo/assets/icons/ic_launcher_foreground.png deleted file mode 100644 index a6d9eab..0000000 Binary files a/filcnaplo/assets/icons/ic_launcher_foreground.png and /dev/null differ diff --git a/filcnaplo/assets/icons/ic_launcher_monochrome.png b/filcnaplo/assets/icons/ic_launcher_monochrome.png deleted file mode 100644 index 29efac3..0000000 Binary files a/filcnaplo/assets/icons/ic_launcher_monochrome.png and /dev/null differ diff --git a/filcnaplo/assets/icons/ic_splash.png b/filcnaplo/assets/icons/ic_splash.png deleted file mode 100644 index 6fdfa13..0000000 Binary files a/filcnaplo/assets/icons/ic_splash.png and /dev/null differ diff --git a/filcnaplo/assets/images/card_border.png b/filcnaplo/assets/images/card_border.png deleted file mode 100644 index 5df72be..0000000 Binary files a/filcnaplo/assets/images/card_border.png and /dev/null differ diff --git a/filcnaplo/assets/images/heart.png b/filcnaplo/assets/images/heart.png deleted file mode 100644 index a219089..0000000 Binary files a/filcnaplo/assets/images/heart.png and /dev/null differ diff --git a/filcnaplo/assets/images/logo.png b/filcnaplo/assets/images/logo.png deleted file mode 100644 index 20b717e..0000000 Binary files a/filcnaplo/assets/images/logo.png and /dev/null differ diff --git a/filcnaplo/assets/images/static_confetti.png b/filcnaplo/assets/images/static_confetti.png deleted file mode 100644 index a9450ed..0000000 Binary files a/filcnaplo/assets/images/static_confetti.png and /dev/null differ diff --git a/filcnaplo/assets/images/subject_covers/math_light.png b/filcnaplo/assets/images/subject_covers/math_light.png deleted file mode 100644 index eb3e2f5..0000000 Binary files a/filcnaplo/assets/images/subject_covers/math_light.png and /dev/null differ diff --git a/filcnaplo/assets/launch_icons/refilc_concept.png b/filcnaplo/assets/launch_icons/refilc_concept.png deleted file mode 100644 index bc031ab..0000000 Binary files a/filcnaplo/assets/launch_icons/refilc_concept.png and /dev/null differ diff --git a/filcnaplo/assets/launch_icons/refilc_default.png b/filcnaplo/assets/launch_icons/refilc_default.png deleted file mode 100644 index ab54f58..0000000 Binary files a/filcnaplo/assets/launch_icons/refilc_default.png and /dev/null differ diff --git a/filcnaplo/assets/launch_icons/refilc_overcomplicated.png b/filcnaplo/assets/launch_icons/refilc_overcomplicated.png deleted file mode 100644 index de1f125..0000000 Binary files a/filcnaplo/assets/launch_icons/refilc_overcomplicated.png and /dev/null differ diff --git a/filcnaplo/assets/launch_icons/refilc_pride.png b/filcnaplo/assets/launch_icons/refilc_pride.png deleted file mode 100644 index 2b1a305..0000000 Binary files a/filcnaplo/assets/launch_icons/refilc_pride.png and /dev/null differ diff --git a/filcnaplo/ios/Runner/AppDelegate.swift b/filcnaplo/ios/Runner/AppDelegate.swift deleted file mode 100644 index 028b1bd..0000000 --- a/filcnaplo/ios/Runner/AppDelegate.swift +++ /dev/null @@ -1,25 +0,0 @@ -import UIKit -import Flutter - -@UIApplicationMain -@objc class AppDelegate: FlutterAppDelegate { - override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - GeneratedPluginRegistrant.register(with: self) - - // here, Without this code the task will not work. - //SwiftFlutterForegroundTaskPlugin.setPluginRegistrantCallback(registerPlugins) - if #available(iOS 10.0, *) { - UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate - } - - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } -} - -// here -func registerPlugins(registry: FlutterPluginRegistry) { - GeneratedPluginRegistrant.register(with: registry) -} diff --git a/filcnaplo/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png b/filcnaplo/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png deleted file mode 100644 index d90316e..0000000 Binary files a/filcnaplo/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png and /dev/null differ diff --git a/filcnaplo/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/filcnaplo/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png deleted file mode 100644 index 65928ee..0000000 Binary files a/filcnaplo/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png and /dev/null differ diff --git a/filcnaplo/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/filcnaplo/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png deleted file mode 100644 index 8147fe6..0000000 Binary files a/filcnaplo/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png and /dev/null differ diff --git a/filcnaplo/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/filcnaplo/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png deleted file mode 100644 index 80a42fb..0000000 Binary files a/filcnaplo/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png and /dev/null differ diff --git a/filcnaplo/ios/livecard/lesson_model.swift b/filcnaplo/ios/livecard/lesson_model.swift deleted file mode 100644 index 3f9e2d0..0000000 --- a/filcnaplo/ios/livecard/lesson_model.swift +++ /dev/null @@ -1,31 +0,0 @@ -import Foundation - -class LessonData { - var color: String - var icon: String - var index: String - var title: String - var subtitle: String - var description: String - var startDate: Date - var endDate: Date - var date: ClosedRange - var nextSubject: String - var nextRoom: String - - init?() { - let sharedDefault = UserDefaults(suiteName: "group.refilc2.livecard")! - - self.color = sharedDefault.string(forKey: "color")! - self.icon = sharedDefault.string(forKey: "icon")! - self.index = sharedDefault.string(forKey: "index")! - self.title = sharedDefault.string(forKey: "title")! - self.subtitle = sharedDefault.string(forKey: "subtitle")! - self.description = sharedDefault.string(forKey: "description")! - self.startDate = Date(timeIntervalSince1970: Double(sharedDefault.string(forKey: "startDate")!)! / 1000) - self.endDate = Date(timeIntervalSince1970: Double(sharedDefault.string(forKey: "endDate")!)! / 1000) - date = self.startDate...self.endDate - self.nextSubject = sharedDefault.string(forKey: "nextSubject")! - self.nextRoom = sharedDefault.string(forKey: "nextRoom")! - } -} diff --git a/filcnaplo/ios/livecard/livecard.swift b/filcnaplo/ios/livecard/livecard.swift deleted file mode 100644 index f873311..0000000 --- a/filcnaplo/ios/livecard/livecard.swift +++ /dev/null @@ -1,205 +0,0 @@ -import ActivityKit -import WidgetKit -import SwiftUI - -@main -struct Widgets: WidgetBundle { - var body: some Widget { - if #available(iOS 16.1, *) { - LiveCardWidget() - } - } -} - -// Color Converter -extension Color { - init(hex: String, alpha: Double = 1.0) { - var hexValue = hex.trimmingCharacters(in: .whitespacesAndNewlines).uppercased() - - if hexValue.hasPrefix("#") { - hexValue.remove(at: hexValue.startIndex) - } - - var rgbValue: UInt64 = 0 - Scanner(string: hexValue).scanHexInt64(&rgbValue) - - let red = Double((rgbValue & 0xFF0000) >> 16) / 255.0 - let green = Double((rgbValue & 0x00FF00) >> 8) / 255.0 - let blue = Double(rgbValue & 0x0000FF) / 255.0 - - self.init( - .sRGB, - red: red, - green: green, - blue: blue, - opacity: alpha - ) - } -} - - -// We need to redefined live activities pipe -struct LiveActivitiesAppAttributes: ActivityAttributes, Identifiable { - public struct ContentState: Codable, Hashable { } - - var id = UUID() -} - -struct LockScreenLiveActivityView: View { - let context: ActivityViewContext - - let lesson = LessonData() - - var body: some View { - HStack(alignment: .center) { - Image(systemName: lesson!.icon) - .resizable() - .aspectRatio(contentMode: .fit) - .frame(width: CGFloat(30), height: CGFloat(30)) - .padding(.leading, CGFloat(24)) - - VStack(alignment: .leading) { - HStack(alignment: .center) { - Text(lesson!.index + lesson!.title) - .font(.title3) - .bold() - - Text(lesson!.subtitle) - .font(.subheadline) - .padding(.trailing, 12) - } - - if (lesson!.description != "") { - Text(lesson!.description) - .font(.subheadline) - } - - HStack { - Image(systemName: "arrow.right") - .resizable() - .aspectRatio(contentMode: .fit) - .frame(width: CGFloat(8), height: CGFloat(8)) - Text(lesson!.nextSubject) - .font(.caption) - Text(lesson!.nextRoom) - .font(.caption2) - } - }.padding(15) - - Spacer() - - Text(timerInterval: lesson!.date, countsDown: true) - .multilineTextAlignment(.center) - .frame(width: 85) - .font(.title2) - .monospacedDigit() - .padding(.trailing, CGFloat(24)) - } - .activityBackgroundTint( - lesson!.color != "#676767" - ? Color(hex: lesson!.color) - // Ha nem megy hat nem megy - : Color.clear - ) - } -} - -@available(iOSApplicationExtension 16.1, *) -struct LiveCardWidget: Widget { - var body: some WidgetConfiguration { - /// Live Activity Notification - ActivityConfiguration(for: LiveActivitiesAppAttributes.self) { context in - LockScreenLiveActivityView(context: context) - /// Dynamic Island - } dynamicIsland: { context in - let lesson = LessonData() - - /// Expanded - return DynamicIsland { - DynamicIslandExpandedRegion(.leading) { - VStack { - Spacer() - ProgressView( - timerInterval: lesson!.date, - countsDown: true, - label: { - Image(systemName: lesson!.icon) - .resizable() - .aspectRatio(contentMode: .fit) - .frame(width: CGFloat(32), height: CGFloat(32)) - }, - currentValueLabel: { - Image(systemName: lesson!.icon) - .resizable() - .aspectRatio(contentMode: .fit) - .frame(width: CGFloat(32), height: CGFloat(32)) - } - ).progressViewStyle(.circular) - } - } - DynamicIslandExpandedRegion(.center) { - VStack(alignment: .leading) { - Text(lesson!.index + lesson!.title) - .lineLimit(1) - .font(.title3) - .bold() - - Text(lesson!.description) - .lineLimit(2) - .font(.caption) - }.padding(EdgeInsets(top: 0.0, leading: 5.0, bottom: 0.0, trailing: 0.0)) - } - DynamicIslandExpandedRegion(.trailing) { - VStack { - Spacer() - Text(lesson!.subtitle) - .lineLimit(1) - .font(.subheadline) - Spacer() - } - } - - /// Compact - } compactLeading: { - Label { - Text(lesson!.title) - } icon: { - Image(systemName: lesson!.icon) - } - .font(.caption2) - } - compactTrailing: { - Text(timerInterval: lesson!.date, countsDown: true) - .multilineTextAlignment(.center) - .frame(width: 40) - .font(.caption2) - - /// Collapsed - } minimal: { - VStack(alignment: .center, content: { - ProgressView( - timerInterval: lesson!.date, - countsDown: true, - label: { - Image(systemName: lesson!.icon) - .resizable() - .aspectRatio(contentMode: .fit) - .frame(width: CGFloat(12), height: CGFloat(12)) - }, - currentValueLabel: { - Image(systemName: lesson!.icon) - .resizable() - .aspectRatio(contentMode: .fit) - .frame(width: CGFloat(12), height: CGFloat(12)) - } - ).progressViewStyle(.circular) - }) - } - .keylineTint( - lesson!.color != "#676767" - ? Color(hex: lesson!.color) - : Color.clear - ) - } - } -} diff --git a/filcnaplo/lib/api/login.dart b/filcnaplo/lib/api/login.dart deleted file mode 100644 index 0d2f1cc..0000000 --- a/filcnaplo/lib/api/login.dart +++ /dev/null @@ -1,191 +0,0 @@ -// ignore_for_file: avoid_print, use_build_context_synchronously - -import 'package:filcnaplo/utils/jwt.dart'; -import 'package:filcnaplo_kreta_api/models/school.dart'; -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'; -import 'package:filcnaplo_kreta_api/providers/grade_provider.dart'; -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/api/providers/user_provider.dart'; -import 'package:filcnaplo/api/providers/database_provider.dart'; -import 'package:filcnaplo/models/settings.dart'; -import 'package:filcnaplo/models/user.dart'; -import 'package:filcnaplo_kreta_api/client/api.dart'; -import 'package:filcnaplo_kreta_api/client/client.dart'; -import 'package:filcnaplo_kreta_api/models/student.dart'; -import 'package:filcnaplo_kreta_api/models/week.dart'; -import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; -import 'package:filcnaplo/api/nonce.dart'; -import 'package:uuid/uuid.dart'; - -enum LoginState { - missingFields, - invalidGrant, - failed, - normal, - inProgress, - success, -} - -Nonce getNonce(String nonce, String username, String instituteCode) { - Nonce nonceEncoder = Nonce( - key: [98, 97, 83, 115, 120, 79, 119, 108, 85, 49, 106, 77], nonce: nonce); - nonceEncoder - .encode(instituteCode.toUpperCase() + nonce + username.toUpperCase()); - - return nonceEncoder; -} - -Future loginAPI({ - required String username, - required String password, - required String instituteCode, - required BuildContext context, - void Function(User)? onLogin, - void Function()? onSuccess, -}) async { - Future testLogin(School school) async { - var user = User( - username: username, - password: password, - instituteCode: instituteCode, - name: 'Teszt Lajos', - student: Student( - birth: DateTime.now(), - id: const Uuid().v4(), - name: 'Teszt Lajos', - school: school, - yearId: '1', - parents: ['Teszt András', 'Teszt Linda'], - json: {"a": "b"}, - address: '1117 Budapest, Gábor Dénes utca 4.', - ), - role: Role.parent, - ); - - if (onLogin != null) onLogin(user); - - // store test user in db - await Provider.of(context, listen: false) - .store - .storeUser(user); - Provider.of(context, listen: false).addUser(user); - Provider.of(context, listen: false).setUser(user.id); - - if (onSuccess != null) onSuccess(); - - return LoginState.success; - } - - // if institute matches one of test things do test login - if (instituteCode == 'refilc-test-sweden') { - School school = School( - city: "Stockholm", - instituteCode: "refilc-test-sweden", - name: "reFilc Test SE - Leo Ekström High School", - ); - - await testLogin(school); - } else if (instituteCode == 'refilc-test-spain') { - School school = School( - city: "Madrid", - instituteCode: "refilc-test-spain", - name: "reFilc Test ES - Emilio Obrero University", - ); - - await testLogin(school); - } else { - // normal login from here - Provider.of(context, listen: false).userAgent = - Provider.of(context, listen: false).config.userAgent; - - Map headers = { - "content-type": "application/x-www-form-urlencoded", - }; - - String nonceStr = await Provider.of(context, listen: false) - .getAPI(KretaAPI.nonce, json: false); - - Nonce nonce = getNonce(nonceStr, username, instituteCode); - headers.addAll(nonce.header()); - - Map? res = await Provider.of(context, listen: false) - .postAPI(KretaAPI.login, - headers: headers, - body: User.loginBody( - username: username, - password: password, - instituteCode: instituteCode, - )); - if (res != null) { - if (res.containsKey("error")) { - if (res["error"] == "invalid_grant") { - return LoginState.invalidGrant; - } - } else { - if (res.containsKey("access_token")) { - try { - Provider.of(context, listen: false).accessToken = - res["access_token"]; - Map? studentJson = - await Provider.of(context, listen: false) - .getAPI(KretaAPI.student(instituteCode)); - Student student = Student.fromJson(studentJson!); - var user = User( - username: username, - password: password, - instituteCode: instituteCode, - name: student.name, - student: student, - role: JwtUtils.getRoleFromJWT(res["access_token"])!, - ); - - if (onLogin != null) onLogin(user); - - // Store User in the database - await Provider.of(context, listen: false) - .store - .storeUser(user); - Provider.of(context, listen: false).addUser(user); - Provider.of(context, listen: false).setUser(user.id); - - // Get user data - try { - await Future.wait([ - Provider.of(context, listen: false).fetch(), - Provider.of(context, listen: false) - .fetch(week: Week.current()), - Provider.of(context, listen: false).fetch(), - Provider.of(context, listen: false).fetch(), - Provider.of(context, listen: false).fetchAll(), - Provider.of(context, listen: false) - .fetchAllRecipients(), - Provider.of(context, listen: false).fetch(), - Provider.of(context, listen: false).fetch(), - Provider.of(context, listen: false).fetch(), - ]); - } catch (error) { - print("WARNING: failed to fetch user data: $error"); - } - - if (onSuccess != null) onSuccess(); - - return LoginState.success; - } catch (error) { - print("ERROR: loginAPI: $error"); - // maybe check debug mode - // ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("ERROR: $error"))); - return LoginState.failed; - } - } - } - } - } - - return LoginState.failed; -} diff --git a/filcnaplo/lib/api/providers/live_card_provider.dart b/filcnaplo/lib/api/providers/live_card_provider.dart deleted file mode 100644 index ccb278c..0000000 --- a/filcnaplo/lib/api/providers/live_card_provider.dart +++ /dev/null @@ -1,294 +0,0 @@ -// ignore_for_file: no_leading_underscores_for_local_identifiers - -import 'dart:async'; -import 'dart:io'; - -import 'package:filcnaplo/helpers/subject.dart'; -import 'package:filcnaplo/models/settings.dart'; -import 'package:filcnaplo_kreta_api/models/lesson.dart'; -import 'package:filcnaplo_kreta_api/models/week.dart'; -import 'package:filcnaplo/utils/format.dart'; -import 'package:filcnaplo_kreta_api/providers/timetable_provider.dart'; -import 'package:flutter/foundation.dart'; -import 'package:live_activities/live_activities.dart'; -import 'package:filcnaplo_mobile_ui/pages/home/live_card/live_card.i18n.dart'; - -enum LiveCardState { - empty, - duringLesson, - duringBreak, - morning, - afternoon, - night, - summary -} - -class LiveCardProvider extends ChangeNotifier { - Lesson? currentLesson; - Lesson? nextLesson; - Lesson? prevLesson; - List? nextLessons; - - LiveCardState currentState = LiveCardState.empty; - late Timer _timer; - late final TimetableProvider _timetable; - late final SettingsProvider _settings; - - late Duration _delay; - - final _liveActivitiesPlugin = LiveActivities(); - String? _latestActivityId; - Map _lastActivity = {}; - - bool _hasCheckedTimetable = false; - - LiveCardProvider({ - required TimetableProvider timetable, - required SettingsProvider settings, - }) : _timetable = timetable, - _settings = settings { - if (Platform.isIOS) { - _liveActivitiesPlugin.areActivitiesEnabled().then((value) { - // Console log - if (kDebugMode) { - print("iOS LiveActivity enabled: $value"); - } - - if (value) { - _liveActivitiesPlugin.init(appGroupId: "group.refilc2.livecard"); - - _liveActivitiesPlugin.getAllActivitiesIds().then((value) { - _latestActivityId = value.isNotEmpty ? value.first : null; - }); - } - }); - } - - _timer = Timer.periodic(const Duration(seconds: 1), (timer) => update()); - _delay = settings.bellDelayEnabled - ? Duration(seconds: settings.bellDelay) - : Duration.zero; - update(); - } - - @override - void dispose() { - _timer.cancel(); - if (Platform.isIOS) { - _liveActivitiesPlugin.areActivitiesEnabled().then((value) { - if (value) { - if (_latestActivityId != null) { - _liveActivitiesPlugin.endActivity(_latestActivityId!); - } - } - }); - } - super.dispose(); - } - - // Debugging - static DateTime _now() { - // return DateTime(2023, 9, 27, 9, 30); - return DateTime.now(); - } - - String getFloorDifference() { - final prevFloor = prevLesson!.getFloor(); - final nextFloor = nextLesson!.getFloor(); - if (prevFloor == null || nextFloor == null || prevFloor == nextFloor) { - return "to room"; - } - if (nextFloor == 0) { - return "ground floor"; - } - if (nextFloor > prevFloor) { - return "up floor"; - } else { - return "down floor"; - } - } - - Map toMap() { - switch (currentState) { - case LiveCardState.duringLesson: - return { - "color": - '#${_settings.liveActivityColor.toString().substring(10, 16)}', - "icon": currentLesson != null - ? SubjectIcon.resolveName(subject: currentLesson?.subject) - : "book", - "index": - currentLesson != null ? '${currentLesson!.lessonIndex}. ' : "", - "title": currentLesson != null - ? currentLesson?.subject.renamedTo ?? ShortSubject.resolve(subject: currentLesson?.subject).capital() - : "", - "subtitle": currentLesson?.room.replaceAll("_", " ") ?? "", - "description": currentLesson?.description ?? "", - "startDate": ((currentLesson?.start.millisecondsSinceEpoch ?? 0) - - _delay.inMilliseconds) - .toString(), - "endDate": ((currentLesson?.end.millisecondsSinceEpoch ?? 0) - - _delay.inMilliseconds) - .toString(), - "nextSubject": nextLesson != null - ? nextLesson?.subject.renamedTo ?? ShortSubject.resolve(subject: nextLesson?.subject).capital() - : "", - "nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "", - }; - case LiveCardState.duringBreak: - final iconFloorMap = { - "to room": "chevron.right.2", - "up floor": "arrow.up.right", - "down floor": "arrow.down.left", - "ground floor": "arrow.down.left", - }; - - final diff = getFloorDifference(); - - return { - "color": - '#${_settings.liveActivityColor.toString().substring(10, 16)}', - "icon": iconFloorMap[diff] ?? "cup.and.saucer", - "title": "Szünet", - "description": "go $diff".i18n.fill([ - diff != "to room" ? (nextLesson!.getFloor() ?? 0) : nextLesson!.room - ]), - "startDate": ((prevLesson?.end.millisecondsSinceEpoch ?? 0) - - _delay.inMilliseconds) - .toString(), - "endDate": ((nextLesson?.start.millisecondsSinceEpoch ?? 0) - - _delay.inMilliseconds) - .toString(), - "nextSubject": (nextLesson != null - ? nextLesson?.subject.renamedTo ?? ShortSubject.resolve(subject: nextLesson?.subject).capital() - : "") - .capital(), - "nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "", - "index": "", - "subtitle": "", - }; - default: - return {}; - } - } - - void update() async { - if (Platform.isIOS) { - _liveActivitiesPlugin.areActivitiesEnabled().then((value) { - if (value) { - final cmap = toMap(); - if (!mapEquals(cmap, _lastActivity)) { - _lastActivity = cmap; - try { - if (_lastActivity.isNotEmpty) { - if (_latestActivityId == null) { - _liveActivitiesPlugin - .createActivity(_lastActivity) - .then((value) => _latestActivityId = value); - } else { - _liveActivitiesPlugin.updateActivity( - _latestActivityId!, _lastActivity); - } - } else { - if (_latestActivityId != null) { - _liveActivitiesPlugin.endActivity(_latestActivityId!); - } - } - } catch (e) { - if (kDebugMode) { - print('ERROR: Unable to create or update iOS LiveActivity!'); - } - } - } - } - }); - } - - List today = _today(_timetable); - - if (today.isEmpty && !_hasCheckedTimetable) { - _hasCheckedTimetable = true; - await _timetable.fetch(week: Week.current()); - today = _today(_timetable); - } - - _delay = _settings.bellDelayEnabled - ? Duration(seconds: _settings.bellDelay) - : Duration.zero; - - final now = _now().add(_delay); - - // Filter cancelled lessons #20 - // Filter label lessons #128 - today = today - .where((lesson) => - lesson.status?.name != "Elmaradt" && - lesson.subject.id != '' && - !lesson.isEmpty) - .toList(); - - if (today.isNotEmpty) { - // sort - today.sort((a, b) => a.start.compareTo(b.start)); - - final _lesson = today.firstWhere( - (l) => l.start.isBefore(now) && l.end.isAfter(now), - orElse: () => Lesson.fromJson({})); - - if (_lesson.start.year != 0) { - currentLesson = _lesson; - } else { - currentLesson = null; - } - - final _next = today.firstWhere((l) => l.start.isAfter(now), - orElse: () => Lesson.fromJson({})); - nextLessons = today.where((l) => l.start.isAfter(now)).toList(); - - if (_next.start.year != 0) { - nextLesson = _next; - } else { - nextLesson = null; - } - - final _prev = today.lastWhere((l) => l.end.isBefore(now), - orElse: () => Lesson.fromJson({})); - - if (_prev.start.year != 0) { - prevLesson = _prev; - } else { - prevLesson = null; - } - } - - if (now.isBefore(DateTime(now.year, DateTime.august, 31)) && - now.isAfter(DateTime(now.year, DateTime.june, 14))) { - currentState = LiveCardState.summary; - } else if (currentLesson != null) { - currentState = LiveCardState.duringLesson; - } else if (nextLesson != null && prevLesson != null) { - currentState = LiveCardState.duringBreak; - } else if (now.hour >= 12 && now.hour < 20) { - currentState = LiveCardState.afternoon; - } else if (now.hour >= 20) { - currentState = LiveCardState.night; - } else if (now.hour >= 5 && now.hour <= 10) { - currentState = LiveCardState.morning; - } else { - currentState = LiveCardState.empty; - } - - notifyListeners(); - } - - bool get show => currentState != LiveCardState.empty; - - Duration get delay => _delay; - - bool _sameDate(DateTime a, DateTime b) => - (a.year == b.year && a.month == b.month && a.day == b.day); - - List _today(TimetableProvider p) => (p.getWeek(Week.current()) ?? []) - .where((l) => _sameDate(l.date, _now())) - .toList(); -} diff --git a/filcnaplo/lib/helpers/notification_helper.dart b/filcnaplo/lib/helpers/notification_helper.dart deleted file mode 100644 index 6f6f9a4..0000000 --- a/filcnaplo/lib/helpers/notification_helper.dart +++ /dev/null @@ -1,601 +0,0 @@ -import 'package:filcnaplo/api/providers/database_provider.dart'; -import 'package:filcnaplo/api/providers/status_provider.dart'; -import 'package:filcnaplo/api/providers/user_provider.dart'; -import 'package:filcnaplo/models/settings.dart'; -import 'package:filcnaplo/helpers/notification_helper.i18n.dart'; -import 'package:filcnaplo_kreta_api/client/api.dart'; -import 'package:filcnaplo_kreta_api/client/client.dart'; -import 'package:filcnaplo_kreta_api/models/absence.dart'; -import 'package:filcnaplo_kreta_api/models/grade.dart'; -import 'package:filcnaplo_kreta_api/models/lesson.dart'; -import 'package:filcnaplo_kreta_api/models/week.dart'; -import 'package:filcnaplo_kreta_api/providers/grade_provider.dart'; -import 'package:filcnaplo_kreta_api/providers/timetable_provider.dart'; -import 'package:flutter_local_notifications/flutter_local_notifications.dart' - hide Message; -import 'package:i18n_extension/i18n_widget.dart'; -import 'package:intl/intl.dart'; -import 'package:filcnaplo_kreta_api/models/message.dart'; - -class NotificationsHelper { - late DatabaseProvider database; - late SettingsProvider settingsProvider; - late UserProvider userProvider; - late KretaClient kretaClient; - FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = - FlutterLocalNotificationsPlugin(); - - List combineLists( - List list1, - List list2, - K Function(T) keyExtractor, - ) { - Set uniqueKeys = {}; - List combinedList = []; - - for (T item in list1) { - K key = keyExtractor(item); - if (!uniqueKeys.contains(key)) { - uniqueKeys.add(key); - combinedList.add(item); - } - } - - for (T item in list2) { - K key = keyExtractor(item); - if (!uniqueKeys.contains(key)) { - uniqueKeys.add(key); - combinedList.add(item); - } - } - - return combinedList; - } - - String dayTitle(DateTime date) { - try { - return DateFormat("EEEE", I18n.locale.languageCode).format(date); - } catch (e) { - return "Unknown"; - } - } - - @pragma('vm:entry-point') - void backgroundJob() async { - // initialize providers - database = DatabaseProvider(); - await database.init(); - settingsProvider = await database.query.getSettings(database); - userProvider = await database.query.getUsers(settingsProvider); - - if (userProvider.id != null && settingsProvider.notificationsEnabled) { - // refresh kreta login - final status = StatusProvider(); - kretaClient = KretaClient( - user: userProvider, settings: settingsProvider, status: status); - kretaClient.refreshLogin(); - if (settingsProvider.notificationsGradesEnabled) gradeNotification(); - if (settingsProvider.notificationsAbsencesEnabled) absenceNotification(); - if (settingsProvider.notificationsMessagesEnabled) messageNotification(); - if (settingsProvider.notificationsLessonsEnabled) lessonNotification(); - } - } - - void gradeNotification() async { - // fetch grades - GradeProvider gradeProvider = GradeProvider( - settings: settingsProvider, - user: userProvider, - database: database, - kreta: kretaClient); - gradeProvider.fetch(); - List grades = - await database.userQuery.getGrades(userId: userProvider.id ?? ""); - DateTime lastSeenGrade = - await database.userQuery.lastSeenGrade(userId: userProvider.id ?? ""); - - // loop through grades and see which hasn't been seen yet - for (Grade grade in grades) { - // if grade is not a normal grade (1-5), don't show it - if ([1, 2, 3, 4, 5].contains(grade.value.value)) { - // if the grade was added over a week ago, don't show it to avoid notification spam - if (grade.seenDate.isAfter(lastSeenGrade) && - grade.date.difference(DateTime.now()).inDays * -1 < 7) { - // send notificiation about new grade - AndroidNotificationDetails androidNotificationDetails = - AndroidNotificationDetails( - 'GRADES', - 'Jegyek', - channelDescription: 'Értesítés jegyek beírásakor', - importance: Importance.max, - priority: Priority.max, - color: settingsProvider.customAccentColor, - ticker: 'Jegyek', - ); - NotificationDetails notificationDetails = - NotificationDetails(android: androidNotificationDetails); - if (userProvider.getUsers().length == 1) { - await flutterLocalNotificationsPlugin.show( - grade.id.hashCode, - "title_grade".i18n, - "body_grade".i18n.fill( - [ - grade.value.value.toString(), - grade.subject.isRenamed && - settingsProvider.renamedSubjectsEnabled - ? grade.subject.renamedTo! - : grade.subject.name - ], - ), - notificationDetails, - ); - } else { - // multiple users are added, also display student name - await flutterLocalNotificationsPlugin.show( - grade.id.hashCode, - "title_grade".i18n, - "body_grade_multiuser".i18n.fill( - [ - userProvider.displayName!, - grade.value.value.toString(), - grade.subject.isRenamed && - settingsProvider.renamedSubjectsEnabled - ? grade.subject.renamedTo! - : grade.subject.name - ], - ), - notificationDetails, - ); - } - } - } - } - // set grade seen status - gradeProvider.seenAll(); - } - - void absenceNotification() async { - // get absences from api - List? absenceJson = await kretaClient - .getAPI(KretaAPI.absences(userProvider.instituteCode ?? "")); - List storedAbsences = - await database.userQuery.getAbsences(userId: userProvider.id!); - if (absenceJson == null) { - return; - } - // format api absences to correct format while preserving isSeen value - List absences = absenceJson.map((e) { - Absence apiAbsence = Absence.fromJson(e); - Absence storedAbsence = storedAbsences.firstWhere( - (stored) => stored.id == apiAbsence.id, - orElse: () => apiAbsence); - apiAbsence.isSeen = storedAbsence.isSeen; - return apiAbsence; - }).toList(); - List modifiedAbsences = []; - if (absences != storedAbsences) { - // remove absences that are not new - absences.removeWhere((element) => storedAbsences.contains(element)); - for (Absence absence in absences) { - if (!absence.isSeen) { - absence.isSeen = true; - modifiedAbsences.add(absence); - AndroidNotificationDetails androidNotificationDetails = - AndroidNotificationDetails( - 'ABSENCES', - 'Hiányzások', - channelDescription: 'Értesítés hiányzások beírásakor', - importance: Importance.max, - priority: Priority.max, - color: settingsProvider.customAccentColor, - ticker: 'Hiányzások', - ); - NotificationDetails notificationDetails = - NotificationDetails(android: androidNotificationDetails); - if (userProvider.getUsers().length == 1) { - await flutterLocalNotificationsPlugin.show( - absence.id.hashCode, - "title_absence".i18n, // https://discord.com/channels/1111649116020285532/1153273625206591528 - "body_absence".i18n.fill( - [ - DateFormat("yyyy-MM-dd").format(absence.date), - absence.subject.isRenamed && - settingsProvider.renamedSubjectsEnabled - ? absence.subject.renamedTo! - : absence.subject.name - ], - ), - notificationDetails, - ); - } else { - await flutterLocalNotificationsPlugin.show( - absence.id.hashCode, - "title_absence".i18n, // https://discord.com/channels/1111649116020285532/1153273625206591528 - "body_absence_multiuser".i18n.fill( - [ - userProvider.displayName!, - DateFormat("yyyy-MM-dd").format(absence.date), - absence.subject.isRenamed && - settingsProvider.renamedSubjectsEnabled - ? absence.subject.renamedTo! - : absence.subject.name - ], - ), - notificationDetails, - ); - } - } - } - } - // combine modified absences and storedabsences list and save them to the database - List combinedAbsences = combineLists( - modifiedAbsences, - storedAbsences, - (Absence absence) => absence.id, - ); - await database.userStore - .storeAbsences(combinedAbsences, userId: userProvider.id!); - } - - void messageNotification() async { - // get messages from api - List? messageJson = - await kretaClient.getAPI(KretaAPI.messages("beerkezett")); - List storedmessages = - await database.userQuery.getMessages(userId: userProvider.id!); - if (messageJson == null) { - return; - } - // format api messages to correct format while preserving isSeen value - // Parse messages - List messages = []; - await Future.wait(List.generate(messageJson.length, (index) { - return () async { - Map message = messageJson.cast()[index]; - Map? innerMessageJson = await kretaClient - .getAPI(KretaAPI.message(message["azonosito"].toString())); - if (innerMessageJson != null) { - messages.add( - Message.fromJson(innerMessageJson, forceType: MessageType.inbox)); - } - }(); - })); - - for (Message message in messages) { - for (Message storedMessage in storedmessages) { - if (message.id == storedMessage.id) { - message.isSeen = storedMessage.isSeen; - } - } - } - List modifiedmessages = []; - if (messages != storedmessages) { - // remove messages that are not new - messages.removeWhere((element) => storedmessages.contains(element)); - for (Message message in messages) { - if (!message.isSeen) { - message.isSeen = true; - modifiedmessages.add(message); - AndroidNotificationDetails androidNotificationDetails = - AndroidNotificationDetails( - 'MESSAGES', - 'Üzenetek', - channelDescription: 'Értesítés kapott üzenetekkor', - importance: Importance.max, - priority: Priority.max, - color: settingsProvider.customAccentColor, - ticker: 'Üzenetek', - ); - NotificationDetails notificationDetails = - NotificationDetails(android: androidNotificationDetails); - if (userProvider.getUsers().length == 1) { - await flutterLocalNotificationsPlugin.show( - message.id.hashCode, - message.author, - message.content.replaceAll(RegExp(r'<[^>]*>'), ''), - notificationDetails, - ); - } else { - await flutterLocalNotificationsPlugin.show( - message.id.hashCode, - "(${userProvider.displayName!}) ${message.author}", - message.content.replaceAll(RegExp(r'<[^>]*>'), ''), - notificationDetails, - ); - } - } - } - } - // combine modified messages and storedmessages list and save them to the database - List combinedmessages = combineLists( - modifiedmessages, - storedmessages, - (Message message) => message.id, - ); - await database.userStore - .storeMessages(combinedmessages, userId: userProvider.id!); - } - - void lessonNotification() async { - // get lesson from api - TimetableProvider timetableProvider = TimetableProvider( - user: userProvider, database: database, kreta: kretaClient); - List storedlessons = - timetableProvider.lessons[Week.current()] ?? []; - List? apilessons = timetableProvider.getWeek(Week.current()) ?? []; - for (Lesson lesson in apilessons) { - for (Lesson storedLesson in storedlessons) { - if (lesson.id == storedLesson.id) { - lesson.isSeen = storedLesson.isSeen; - } - } - } - List modifiedlessons = []; - if (apilessons != storedlessons) { - // remove lessons that are not new - apilessons.removeWhere((element) => storedlessons.contains(element)); - for (Lesson lesson in apilessons) { - if (!lesson.isSeen && lesson.isChanged) { - lesson.isSeen = true; - modifiedlessons.add(lesson); - AndroidNotificationDetails androidNotificationDetails = - AndroidNotificationDetails( - 'LESSONS', - 'Órák', - channelDescription: - 'Értesítés órák elmaradásáról, helyettesítésről', - importance: Importance.max, - priority: Priority.max, - color: settingsProvider.customAccentColor, - ticker: 'Órák', - ); - NotificationDetails notificationDetails = - NotificationDetails(android: androidNotificationDetails); - if (userProvider.getUsers().length == 1) { - if (lesson.status?.name == "Elmaradt") { - switch (I18n.localeStr) { - case "en_en": - { - await flutterLocalNotificationsPlugin.show( - lesson.id.hashCode, - "title_lesson".i18n, - "body_lesson_canceled".i18n.fill( - [ - lesson.lessonIndex, - lesson.name, - dayTitle(lesson.date) - ], - ), - notificationDetails, - ); - break; - } - case "hu_hu": - { - await flutterLocalNotificationsPlugin.show( - lesson.id.hashCode, - "title_lesson".i18n, - "body_lesson_canceled".i18n.fill( - [ - dayTitle(lesson.date), - lesson.lessonIndex, - lesson.name - ], - ), - notificationDetails, - ); - break; - } - default: - { - await flutterLocalNotificationsPlugin.show( - lesson.id.hashCode, - "title_lesson".i18n, - "body_lesson_canceled".i18n.fill( - [ - lesson.lessonIndex, - lesson.name, - dayTitle(lesson.date) - ], - ), - notificationDetails, - ); - break; - } - } - } else if (lesson.substituteTeacher?.name != "") { - switch (I18n.localeStr) { - case "en_en": - { - await flutterLocalNotificationsPlugin.show( - lesson.id.hashCode, - "title_lesson".i18n, - "body_lesson_substituted".i18n.fill( - [ - lesson.lessonIndex, - lesson.name, - dayTitle(lesson.date), - lesson.substituteTeacher!.isRenamed - ? lesson.substituteTeacher!.renamedTo! - : lesson.substituteTeacher!.name - ], - ), - notificationDetails, - ); - break; - } - case "hu_hu": - { - await flutterLocalNotificationsPlugin.show( - lesson.id.hashCode, - "title_lesson".i18n, - "body_lesson_substituted".i18n.fill( - [ - dayTitle(lesson.date), - lesson.lessonIndex, - lesson.name, - lesson.substituteTeacher!.isRenamed - ? lesson.substituteTeacher!.renamedTo! - : lesson.substituteTeacher!.name - ], - ), - notificationDetails, - ); - break; - } - default: - { - await flutterLocalNotificationsPlugin.show( - lesson.id.hashCode, - "title_lesson".i18n, - "body_lesson_substituted".i18n.fill( - [ - lesson.lessonIndex, - lesson.name, - dayTitle(lesson.date), - lesson.substituteTeacher!.isRenamed - ? lesson.substituteTeacher!.renamedTo! - : lesson.substituteTeacher!.name - ], - ), - notificationDetails, - ); - break; - } - } - } - } else { - if (lesson.status?.name == "Elmaradt") { - switch (I18n.localeStr) { - case "en_en": - { - await flutterLocalNotificationsPlugin.show( - lesson.id.hashCode, - "title_lesson".i18n, - "body_lesson_canceled".i18n.fill( - [ - userProvider.displayName!, - lesson.lessonIndex, - lesson.name, - dayTitle(lesson.date) - ], - ), - notificationDetails, - ); - break; - } - case "hu_hu": - { - await flutterLocalNotificationsPlugin.show( - lesson.id.hashCode, - "title_lesson".i18n, - "body_lesson_canceled".i18n.fill( - [ - userProvider.displayName!, - dayTitle(lesson.date), - lesson.lessonIndex, - lesson.name - ], - ), - notificationDetails, - ); - break; - } - default: - { - await flutterLocalNotificationsPlugin.show( - lesson.id.hashCode, - "title_lesson".i18n, - "body_lesson_canceled".i18n.fill( - [ - userProvider.displayName!, - lesson.lessonIndex, - lesson.name, - dayTitle(lesson.date) - ], - ), - notificationDetails, - ); - break; - } - } - } else if (lesson.substituteTeacher?.name != "") { - switch (I18n.localeStr) { - case "en_en": - { - await flutterLocalNotificationsPlugin.show( - lesson.id.hashCode, - "title_lesson".i18n, - "body_lesson_substituted".i18n.fill( - [ - userProvider.displayName!, - lesson.lessonIndex, - lesson.name, - dayTitle(lesson.date), - lesson.substituteTeacher!.isRenamed - ? lesson.substituteTeacher!.renamedTo! - : lesson.substituteTeacher!.name - ], - ), - notificationDetails, - ); - break; - } - case "hu_hu": - { - await flutterLocalNotificationsPlugin.show( - lesson.id.hashCode, - "title_lesson".i18n, - "body_lesson_substituted".i18n.fill( - [ - userProvider.displayName!, - dayTitle(lesson.date), - lesson.lessonIndex, - lesson.name, - lesson.substituteTeacher!.isRenamed - ? lesson.substituteTeacher!.renamedTo! - : lesson.substituteTeacher!.name - ], - ), - notificationDetails, - ); - break; - } - default: - { - await flutterLocalNotificationsPlugin.show( - lesson.id.hashCode, - "title_lesson".i18n, - "body_lesson_substituted".i18n.fill( - [ - userProvider.displayName!, - lesson.lessonIndex, - lesson.name, - dayTitle(lesson.date), - lesson.substituteTeacher!.isRenamed - ? lesson.substituteTeacher!.renamedTo! - : lesson.substituteTeacher!.name - ], - ), - notificationDetails, - ); - break; - } - } - } - } - } - } - // combine modified lesson and storedlesson list and save them to the database - List combinedlessons = combineLists( - modifiedlessons, - storedlessons, - (Lesson message) => message.id, - ); - Map> timetableLessons = timetableProvider.lessons; - timetableLessons[Week.current()] = combinedlessons; - await database.userStore - .storeLessons(timetableLessons, userId: userProvider.id!); - } - } -} diff --git a/filcnaplo/lib/helpers/share_helper.dart b/filcnaplo/lib/helpers/share_helper.dart deleted file mode 100644 index 9b27793..0000000 --- a/filcnaplo/lib/helpers/share_helper.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:filcnaplo/helpers/attachment_helper.dart'; -import 'package:filcnaplo_kreta_api/models/attachment.dart'; -import 'package:flutter/widgets.dart'; -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 { - String path = await attachment.download(context); - await shareFile(path); - } -} diff --git a/filcnaplo/lib/theme/colors/accent.dart b/filcnaplo/lib/theme/colors/accent.dart deleted file mode 100644 index 779e82c..0000000 --- a/filcnaplo/lib/theme/colors/accent.dart +++ /dev/null @@ -1,33 +0,0 @@ -import 'package:flutter/material.dart'; - -enum AccentColor { - filc, - blue, - green, - lime, - yellow, - orange, - red, - pink, - purple, - none, - ogfilc, - adaptive, - custom -} - -Map accentColorMap = { - AccentColor.filc: const Color(0xFF3D7BF4), - AccentColor.blue: Colors.blue.shade300, - AccentColor.green: Colors.green.shade400, - AccentColor.lime: Colors.lightGreen.shade400, - AccentColor.yellow: Colors.orange.shade300, - AccentColor.orange: Colors.deepOrange.shade300, - AccentColor.red: Colors.red.shade300, - AccentColor.pink: Colors.pink.shade300, - AccentColor.purple: Colors.purple.shade300, - //AccentColor.none: Colors.black, - AccentColor.ogfilc: const Color(0xff20AC9B), - AccentColor.adaptive: const Color(0xFF3D7BF4), - AccentColor.custom: const Color(0xFF3D7BF4), -}; diff --git a/filcnaplo/lib/theme/theme.dart b/filcnaplo/lib/theme/theme.dart deleted file mode 100644 index e6e7a0f..0000000 --- a/filcnaplo/lib/theme/theme.dart +++ /dev/null @@ -1,160 +0,0 @@ -import 'package:filcnaplo/models/settings.dart'; -import 'package:filcnaplo/theme/colors/accent.dart'; -import 'package:filcnaplo/theme/colors/colors.dart'; -import 'package:filcnaplo/theme/observer.dart'; -import 'package:flutter/material.dart'; -import 'package:material_color_utilities/material_color_utilities.dart'; -import 'package:provider/provider.dart'; - -class AppTheme { - // Dev note: All of these could be constant variables, but this is better for - // development (you don't have to hot-restart) - - static const String _fontFamily = "Montserrat"; - - static Color? _paletteAccentLight(CorePalette? palette) => palette != null ? Color(palette.primary.get(70)) : null; - static Color? _paletteHighlightLight(CorePalette? palette) => palette != null ? Color(palette.neutral.get(100)) : null; - static Color? _paletteBackgroundLight(CorePalette? palette) => palette != null ? Color(palette.neutral.get(95)) : null; - - static Color? _paletteAccentDark(CorePalette? palette) => palette != null ? Color(palette.primary.get(80)) : null; - static Color? _paletteBackgroundDark(CorePalette? palette) => palette != null ? Color(palette.neutralVariant.get(10)) : null; - static Color? _paletteHighlightDark(CorePalette? palette) => palette != null ? Color(palette.neutralVariant.get(20)) : null; - - // Light Theme - static ThemeData lightTheme(BuildContext context, {CorePalette? palette}) { - var lightColors = AppColors.fromBrightness(Brightness.light); - final settings = Provider.of(context, listen: false); - AccentColor accentColor = settings.accentColor; - final customAccentColor = accentColor == AccentColor.custom ? settings.customAccentColor : null; - Color accent = customAccentColor ?? accentColorMap[accentColor] ?? const Color(0x00000000); - - if (accentColor == AccentColor.adaptive) { - if (palette != null) accent = _paletteAccentLight(palette)!; - } else { - palette = null; - } - - Color backgroundColor = - (accentColor == AccentColor.custom ? settings.customBackgroundColor : _paletteBackgroundLight(palette)) ?? lightColors.background; - Color highlightColor = - (accentColor == AccentColor.custom ? settings.customHighlightColor : _paletteHighlightLight(palette)) ?? lightColors.highlight; - - return ThemeData( - brightness: Brightness.light, - useMaterial3: true, - fontFamily: _fontFamily, - scaffoldBackgroundColor: backgroundColor, - primaryColor: lightColors.filc, - dividerColor: const Color(0x00000000), - colorScheme: ColorScheme( - primary: accent, - onPrimary: (accent.computeLuminance() > 0.5 ? Colors.black : Colors.white).withOpacity(.9), - secondary: accent, - onSecondary: (accent.computeLuminance() > 0.5 ? Colors.black : Colors.white).withOpacity(.9), - background: highlightColor, - onBackground: Colors.black.withOpacity(.9), - brightness: Brightness.light, - error: lightColors.red, - onError: Colors.white.withOpacity(.9), - surface: highlightColor, - onSurface: Colors.black.withOpacity(.9), - ), - shadowColor: lightColors.shadow.withOpacity(.5), - appBarTheme: AppBarTheme(backgroundColor: backgroundColor), - indicatorColor: accent, - iconTheme: IconThemeData(color: lightColors.text.withOpacity(.75)), - navigationBarTheme: NavigationBarThemeData( - indicatorColor: accent.withOpacity(accentColor == AccentColor.adaptive ? 0.4 : 0.8), - iconTheme: MaterialStateProperty.all(IconThemeData(color: lightColors.text)), - backgroundColor: highlightColor, - labelTextStyle: MaterialStateProperty.all(TextStyle( - fontSize: 13.0, - fontWeight: FontWeight.w500, - color: lightColors.text.withOpacity(0.8), - )), - labelBehavior: NavigationDestinationLabelBehavior.alwaysShow, - height: 76.0, - ), - sliderTheme: SliderThemeData( - inactiveTrackColor: accent.withOpacity(.3), - ), - progressIndicatorTheme: ProgressIndicatorThemeData(color: accent), - expansionTileTheme: ExpansionTileThemeData(iconColor: accent), - cardColor: highlightColor, - bottomNavigationBarTheme: BottomNavigationBarThemeData( - backgroundColor: Provider.of(context, listen: false).updateNavbarColor ? backgroundColor : null, - ), - ); - } - - // Dark Theme - static ThemeData darkTheme(BuildContext context, {CorePalette? palette}) { - var darkColors = AppColors.fromBrightness(Brightness.dark); - final settings = Provider.of(context, listen: false); - AccentColor accentColor = settings.accentColor; - final customAccentColor = accentColor == AccentColor.custom ? settings.customAccentColor : null; - Color accent = customAccentColor ?? accentColorMap[accentColor] ?? const Color(0x00000000); - - if (accentColor == AccentColor.adaptive) { - if (palette != null) accent = _paletteAccentDark(palette)!; - } else { - palette = null; - } - - Color backgroundColor = - (accentColor == AccentColor.custom ? settings.customBackgroundColor : _paletteBackgroundDark(palette)) ?? darkColors.background; - Color highlightColor = - (accentColor == AccentColor.custom ? settings.customHighlightColor : _paletteHighlightDark(palette)) ?? darkColors.highlight; - - return ThemeData( - brightness: Brightness.dark, - useMaterial3: true, - fontFamily: _fontFamily, - scaffoldBackgroundColor: backgroundColor, - primaryColor: darkColors.filc, - dividerColor: const Color(0x00000000), - colorScheme: ColorScheme( - primary: accent, - onPrimary: (accent.computeLuminance() > 0.5 ? Colors.black : Colors.white).withOpacity(.9), - secondary: accent, - onSecondary: (accent.computeLuminance() > 0.5 ? Colors.black : Colors.white).withOpacity(.9), - background: highlightColor, - onBackground: Colors.white.withOpacity(.9), - brightness: Brightness.dark, - error: darkColors.red, - onError: Colors.black.withOpacity(.9), - surface: highlightColor, - onSurface: Colors.white.withOpacity(.9), - ), - shadowColor: highlightColor.withOpacity(.5), //darkColors.shadow, - appBarTheme: AppBarTheme(backgroundColor: backgroundColor), - indicatorColor: accent, - iconTheme: IconThemeData(color: darkColors.text.withOpacity(.75)), - navigationBarTheme: NavigationBarThemeData( - indicatorColor: accent.withOpacity(accentColor == AccentColor.adaptive ? 0.4 : 0.8), - iconTheme: MaterialStateProperty.all(IconThemeData(color: darkColors.text)), - backgroundColor: highlightColor, - labelTextStyle: MaterialStateProperty.all(TextStyle( - fontSize: 13.0, - fontWeight: FontWeight.w500, - color: darkColors.text.withOpacity(0.8), - )), - labelBehavior: NavigationDestinationLabelBehavior.alwaysShow, - height: 76.0, - ), - sliderTheme: SliderThemeData( - inactiveTrackColor: accent.withOpacity(.3), - ), - progressIndicatorTheme: ProgressIndicatorThemeData(color: accent), - expansionTileTheme: ExpansionTileThemeData(iconColor: accent), - cardColor: highlightColor, - chipTheme: ChipThemeData( - backgroundColor: accent.withOpacity(.2), - elevation: 1, - ), - bottomNavigationBarTheme: BottomNavigationBarThemeData( - backgroundColor: Provider.of(context, listen: false).updateNavbarColor ? backgroundColor : null, - ), - ); - } -} diff --git a/filcnaplo/lib/ui/filter/widgets/absences.dart b/filcnaplo/lib/ui/filter/widgets/absences.dart deleted file mode 100644 index 4e4748d..0000000 --- a/filcnaplo/lib/ui/filter/widgets/absences.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:filcnaplo/ui/date_widget.dart'; -import 'package:filcnaplo_kreta_api/models/absence.dart'; -import 'package:filcnaplo_mobile_ui/common/widgets/absence/absence_viewable.dart' as mobile; - -List getWidgets(List providerAbsences, {bool noExcused = false}) { - List items = []; - providerAbsences.where((a) => !noExcused || a.state != Justification.excused).forEach((absence) { - items.add(DateWidget( - key: absence.id, - date: absence.date, - widget: mobile.AbsenceViewable(absence), - )); - }); - return items; -} diff --git a/filcnaplo/lib/ui/filter/widgets/grades.dart b/filcnaplo/lib/ui/filter/widgets/grades.dart deleted file mode 100644 index 667e58a..0000000 --- a/filcnaplo/lib/ui/filter/widgets/grades.dart +++ /dev/null @@ -1,41 +0,0 @@ -import 'package:filcnaplo/ui/date_widget.dart'; -import 'package:filcnaplo/utils/platform.dart'; -import 'package:filcnaplo_kreta_api/models/grade.dart'; -import 'package:filcnaplo_mobile_ui/common/widgets/grade/grade_viewable.dart' as mobile; -import 'package:filcnaplo_mobile_ui/common/widgets/grade/new_grades.dart' as mobile; -import 'package:filcnaplo_desktop_ui/common/widgets/grade/grade_viewable.dart' as desktop; - -List getWidgets(List providerGrades, DateTime? lastSeenDate) { - List items = []; - for (var grade in providerGrades) { - final surprise = (!(lastSeenDate != null && grade.date.isAfter(lastSeenDate)) || grade.value.value == 0); - if (grade.type == GradeType.midYear && surprise) { - items.add(DateWidget( - key: grade.id, - date: grade.date, - widget: PlatformUtils.isMobile ? mobile.GradeViewable(grade) : desktop.GradeViewable(grade), - )); - } - } - return items; -} - -List getNewWidgets(List providerGrades, DateTime? lastSeenDate) { - List items = []; - List newGrades = []; - for (var grade in providerGrades) { - final surprise = !(lastSeenDate != null && !grade.date.isAfter(lastSeenDate)) && grade.value.value != 0; - if (grade.type == GradeType.midYear && surprise) { - newGrades.add(grade); - } - } - newGrades.sort((a, b) => a.date.compareTo(b.date)); - if (newGrades.isNotEmpty) { - items.add(DateWidget( - key: newGrades.last.id, - date: newGrades.last.date, - widget: mobile.NewGradesSurprise(newGrades), - )); - } - return items; -} diff --git a/filcnaplo/lib/ui/filter/widgets/homework.dart b/filcnaplo/lib/ui/filter/widgets/homework.dart deleted file mode 100644 index 5698666..0000000 --- a/filcnaplo/lib/ui/filter/widgets/homework.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:filcnaplo/ui/date_widget.dart'; -import 'package:filcnaplo_kreta_api/models/homework.dart'; -import 'package:filcnaplo_mobile_ui/common/widgets/homework/homework_viewable.dart' as mobile; - -List getWidgets(List providerHomework) { - List items = []; - for (var homework in providerHomework) { - items.add(DateWidget( - key: homework.id, - date: homework.deadline.year != 0 ? homework.deadline : homework.date, - widget: mobile.HomeworkViewable(homework), - )); - } - return items; -} diff --git a/filcnaplo/lib/ui/filter/widgets/lessons.dart b/filcnaplo/lib/ui/filter/widgets/lessons.dart deleted file mode 100644 index 676126a..0000000 --- a/filcnaplo/lib/ui/filter/widgets/lessons.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:filcnaplo/ui/date_widget.dart'; -import 'package:filcnaplo_kreta_api/models/lesson.dart'; -import 'package:filcnaplo_mobile_ui/common/widgets/lesson/changed_lesson_viewable.dart' as mobile; - -List getWidgets(List providerLessons) { - List items = []; - providerLessons.where((l) => l.isChanged && l.start.isAfter(DateTime.now())).forEach((lesson) { - items.add(DateWidget( - key: lesson.id, - date: DateTime(lesson.date.year, lesson.date.month, lesson.date.day, lesson.start.hour, lesson.start.minute), - widget: mobile.ChangedLessonViewable(lesson), - )); - }); - return items; -} diff --git a/filcnaplo/lib/ui/filter/widgets/messages.dart b/filcnaplo/lib/ui/filter/widgets/messages.dart deleted file mode 100644 index 4181ce7..0000000 --- a/filcnaplo/lib/ui/filter/widgets/messages.dart +++ /dev/null @@ -1,23 +0,0 @@ -import 'package:filcnaplo/ui/date_widget.dart'; -import 'package:filcnaplo/ui/filter/widgets/notes.dart' as note_filter; -import 'package:filcnaplo/ui/filter/widgets/events.dart' as event_filter; -import 'package:filcnaplo_kreta_api/models/event.dart'; -import 'package:filcnaplo_kreta_api/models/message.dart'; -import 'package:filcnaplo_kreta_api/models/note.dart'; -import 'package:filcnaplo_mobile_ui/common/widgets/message/message_viewable.dart' as mobile; - -List getWidgets(List providerMessages, List providerNotes, List providerEvents) { - List items = []; - for (var message in providerMessages) { - if (message.type == MessageType.inbox) { - items.add(DateWidget( - key: "${message.id}", - date: message.date, - widget: mobile.MessageViewable(message), - )); - } - } - items.addAll(note_filter.getWidgets(providerNotes)); - items.addAll(event_filter.getWidgets(providerEvents)); - return items; -} diff --git a/filcnaplo/lib/ui/filter/widgets/update.dart b/filcnaplo/lib/ui/filter/widgets/update.dart deleted file mode 100644 index 6b35e63..0000000 --- a/filcnaplo/lib/ui/filter/widgets/update.dart +++ /dev/null @@ -1,10 +0,0 @@ -import 'package:filcnaplo/models/release.dart'; -import 'package:filcnaplo/ui/date_widget.dart'; -import 'package:filcnaplo_mobile_ui/common/widgets/update/update_viewable.dart' as mobile; - -DateWidget getWidget(Release providerRelease) { - return DateWidget( - date: DateTime.now(), - widget: mobile.UpdateViewable(providerRelease), - ); -} diff --git a/filcnaplo/lib/ui/widgets/lesson/lesson_tile.dart b/filcnaplo/lib/ui/widgets/lesson/lesson_tile.dart deleted file mode 100644 index 59e7547..0000000 --- a/filcnaplo/lib/ui/widgets/lesson/lesson_tile.dart +++ /dev/null @@ -1,348 +0,0 @@ -import 'package:filcnaplo/models/settings.dart'; -import 'package:filcnaplo_kreta_api/providers/exam_provider.dart'; -import 'package:filcnaplo_kreta_api/providers/homework_provider.dart'; -import 'package:filcnaplo/theme/colors/colors.dart'; -import 'package:filcnaplo_kreta_api/models/exam.dart'; -import 'package:filcnaplo_kreta_api/models/homework.dart'; -import 'package:filcnaplo_kreta_api/models/lesson.dart'; -import 'package:filcnaplo/utils/format.dart'; -import 'package:filcnaplo_mobile_ui/common/panel/panel.dart'; -import 'package:filcnaplo_mobile_ui/common/widgets/exam/exam_view.dart'; -import 'package:filcnaplo_mobile_ui/common/widgets/homework/homework_view.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_feather_icons/flutter_feather_icons.dart'; -import 'package:intl/intl.dart'; -import 'package:provider/provider.dart'; -import 'lesson_tile.i18n.dart'; - -class LessonTile extends StatelessWidget { - const LessonTile(this.lesson, {super.key, this.onTap, this.swapDesc = false}); - - final Lesson lesson; - final bool swapDesc; - final void Function()? onTap; - - @override - Widget build(BuildContext context) { - List subtiles = []; - - Color accent = Theme.of(context).colorScheme.secondary; - bool fill = false; - bool fillLeading = false; - String lessonIndexTrailing = ""; - - SettingsProvider settingsProvider = Provider.of(context); - - // Only put a trailing . if its a digit - if (RegExp(r'\d').hasMatch(lesson.lessonIndex)) lessonIndexTrailing = "."; - - var now = DateTime.now(); - if (lesson.start.isBefore(now) && - lesson.end.isAfter(now) && - lesson.status?.name != "Elmaradt") { - fillLeading = true; - } - - if (lesson.substituteTeacher != null && - lesson.substituteTeacher?.name != "") { - fill = true; - accent = AppColors.of(context).yellow; - } - - if (lesson.status?.name == "Elmaradt") { - fill = true; - accent = AppColors.of(context).red; - } - - if (lesson.isEmpty) { - accent = AppColors.of(context).text.withOpacity(0.6); - } - - if (!lesson.studentPresence) { - subtiles.add(LessonSubtile( - type: LessonSubtileType.absence, - title: "absence".i18n, - )); - } - - if (lesson.homeworkId != "") { - Homework homework = Provider.of(context, listen: false) - .homework - .firstWhere((h) => h.id == lesson.homeworkId, - orElse: () => Homework.fromJson({})); - - if (homework.id != "") { - subtiles.add(LessonSubtile( - type: LessonSubtileType.homework, - title: homework.content, - onPressed: () => HomeworkView.show(homework, context: context), - )); - } - } - - if (lesson.exam != "") { - Exam exam = Provider.of(context, listen: false) - .exams - .firstWhere((t) => t.id == lesson.exam, - orElse: () => Exam.fromJson({})); - if (exam.id != "") { - subtiles.add(LessonSubtile( - type: LessonSubtileType.exam, - title: exam.description != "" - ? exam.description - : exam.mode?.description ?? "exam".i18n, - onPressed: () => ExamView.show(exam, context: context), - )); - } - } - - String description = ''; - String room = ''; - - final cleanDesc = lesson.description - .specialChars() - .toLowerCase() - .replaceAll(lesson.subject.name.specialChars().toLowerCase(), ''); - - if (!swapDesc) { - if (cleanDesc != "") { - description = lesson.description; - } - - // Changed lesson Description - if (lesson.isChanged) { - if (lesson.status?.name == "Elmaradt") { - description = 'cancelled'.i18n; - } else if (lesson.substituteTeacher?.name != "") { - description = 'substitution'.i18n; - } - } - - room = lesson.room.replaceAll("_", " "); - } else { - description = lesson.room.replaceAll("_", " "); - } - - return Padding( - padding: const EdgeInsets.only(bottom: 2.0), - child: Material( - color: fill ? accent.withOpacity(.25) : Colors.transparent, - borderRadius: BorderRadius.circular(12.0), - child: Visibility( - visible: lesson.subject.id != '' || lesson.isEmpty, - replacement: Padding( - padding: const EdgeInsets.only(top: 6.0), - child: PanelTitle(title: Text(lesson.name)), - ), - child: Padding( - padding: EdgeInsets.only(bottom: subtiles.isEmpty ? 0.0 : 12.0), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - ListTile( - minVerticalPadding: 12.0, - dense: true, - onTap: onTap, - // onLongPress: kDebugMode ? () => log(jsonEncode(lesson.json)) : null, - visualDensity: VisualDensity.compact, - contentPadding: const EdgeInsets.symmetric(horizontal: 4.0), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12.0)), - title: Text( - !lesson.isEmpty - ? lesson.subject.renamedTo ?? - lesson.subject.name.capital() - : "empty".i18n, - maxLines: 2, - overflow: TextOverflow.ellipsis, - style: TextStyle( - fontWeight: FontWeight.w600, - fontSize: 15.5, - color: AppColors.of(context) - .text - .withOpacity(!lesson.isEmpty ? 1.0 : 0.5), - fontStyle: lesson.subject.isRenamed && - settingsProvider.renamedSubjectsItalics - ? FontStyle.italic - : null), - ), - subtitle: description != "" - ? Text( - description, - style: const TextStyle( - fontWeight: FontWeight.w500, - fontSize: 14.0, - ), - maxLines: 1, - softWrap: false, - overflow: TextOverflow.ellipsis, - ) - : null, - minLeadingWidth: 34.0, - leading: AspectRatio( - aspectRatio: 1, - child: Center( - child: Stack( - children: [ - Text( - lesson.lessonIndex + lessonIndexTrailing, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 30.0, - fontWeight: FontWeight.w600, - color: accent, - ), - ), - - // Current lesson indicator - Transform.translate( - offset: const Offset(-12.0, -2.0), - child: Container( - decoration: BoxDecoration( - color: fillLeading - ? Theme.of(context) - .colorScheme - .secondary - .withOpacity(.3) - : const Color(0x00000000), - borderRadius: BorderRadius.circular(12.0), - boxShadow: [ - if (fillLeading) - BoxShadow( - color: Theme.of(context) - .colorScheme - .secondary - .withOpacity(.25), - blurRadius: 6.0, - ) - ], - ), - margin: const EdgeInsets.symmetric(vertical: 4.0), - width: 4.0, - height: double.infinity, - ), - ) - ], - ), - ), - ), - trailing: !lesson.isEmpty - ? Row( - mainAxisSize: MainAxisSize.min, - children: [ - if (!swapDesc) - SizedBox( - width: 52.0, - child: Padding( - padding: const EdgeInsets.only(right: 6.0), - child: Text( - room, - textAlign: TextAlign.center, - overflow: TextOverflow.ellipsis, - maxLines: 2, - style: TextStyle( - fontWeight: FontWeight.w500, - color: AppColors.of(context) - .text - .withOpacity(.75), - ), - ), - ), - ), - Stack( - alignment: Alignment.center, - children: [ - // Fix alignment hack - const Opacity(opacity: 0, child: Text("EE:EE")), - Text( - "${DateFormat("H:mm").format(lesson.start)}\n${DateFormat("H:mm").format(lesson.end)}", - textAlign: TextAlign.center, - style: TextStyle( - fontWeight: FontWeight.w500, - color: AppColors.of(context) - .text - .withOpacity(.9), - ), - ), - ], - ), - ], - ) - : null, - ), - - // Homework & Exams - ...subtiles, - ], - ), - ), - ), - ), - ); - } -} - -enum LessonSubtileType { homework, exam, absence } - -class LessonSubtile extends StatelessWidget { - const LessonSubtile( - {super.key, this.onPressed, required this.title, required this.type}); - - final Function()? onPressed; - final String title; - final LessonSubtileType type; - - @override - Widget build(BuildContext context) { - IconData icon; - Color iconColor = AppColors.of(context).text; - - switch (type) { - case LessonSubtileType.absence: - icon = FeatherIcons.slash; - iconColor = AppColors.of(context).red; - break; - case LessonSubtileType.exam: - icon = FeatherIcons.file; - break; - case LessonSubtileType.homework: - icon = FeatherIcons.home; - break; - } - - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: InkWell( - onTap: onPressed, - borderRadius: BorderRadius.circular(8.0), - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 4.0), - child: Row( - children: [ - Center( - child: SizedBox( - width: 30.0, - child: - Icon(icon, color: iconColor.withOpacity(.75), size: 20.0), - ), - ), - Expanded( - child: Padding( - padding: const EdgeInsets.only(left: 20.0), - child: Text( - title.escapeHtml(), - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: TextStyle( - fontWeight: FontWeight.w500, - color: AppColors.of(context).text.withOpacity(.65)), - ), - ), - ), - ], - ), - ), - ), - ); - } -} diff --git a/filcnaplo/lib/utils/reverse_search.dart b/filcnaplo/lib/utils/reverse_search.dart deleted file mode 100644 index e313937..0000000 --- a/filcnaplo/lib/utils/reverse_search.dart +++ /dev/null @@ -1,38 +0,0 @@ -import 'dart:developer'; - -import 'package:filcnaplo_kreta_api/models/absence.dart'; -import 'package:filcnaplo_kreta_api/models/lesson.dart'; -import 'package:filcnaplo_kreta_api/models/week.dart'; -import 'package:filcnaplo_kreta_api/providers/timetable_provider.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:provider/provider.dart'; - -class ReverseSearch { - static Future getLessonByAbsence(Absence absence, BuildContext context) async { - final timetableProvider = Provider.of(context, listen: false); - - List lessons = []; - final week = Week.fromDate(absence.date); - try { - await timetableProvider.fetch(week: week); - } catch (e) { - log("[ERROR] getLessonByAbsence: $e"); - } - lessons = timetableProvider.getWeek(week) ?? []; - - // Find absence lesson in timetable - Lesson lesson = lessons.firstWhere( - (l) => _sameDate(l.date, absence.date) && l.subject.id == absence.subject.id && l.lessonIndex == absence.lessonIndex.toString(), - orElse: () => Lesson.fromJson({'isEmpty': true}), - ); - - if (lesson.isEmpty) { - return null; - } else { - return lesson; - } - } - - // difference.inDays is not reliable - static bool _sameDate(DateTime a, DateTime b) => (a.year == b.year && a.month == b.month && a.day == b.day); -} diff --git a/filcnaplo_desktop_ui/lib/common/widgets/grade/grade_viewable.dart b/filcnaplo_desktop_ui/lib/common/widgets/grade/grade_viewable.dart deleted file mode 100644 index f3f1ffa..0000000 --- a/filcnaplo_desktop_ui/lib/common/widgets/grade/grade_viewable.dart +++ /dev/null @@ -1,14 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:filcnaplo_kreta_api/models/grade.dart'; -import 'package:filcnaplo/ui/widgets/grade/grade_tile.dart'; - -class GradeViewable extends StatelessWidget { - const GradeViewable(this.grade, {Key? key}) : super(key: key); - - final Grade grade; - - @override - Widget build(BuildContext context) { - return GradeTile(grade); - } -} \ No newline at end of file diff --git a/filcnaplo_desktop_ui/lib/pages/grades/grades_count.dart b/filcnaplo_desktop_ui/lib/pages/grades/grades_count.dart deleted file mode 100644 index c3c75f6..0000000 --- a/filcnaplo_desktop_ui/lib/pages/grades/grades_count.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:filcnaplo_kreta_api/models/grade.dart'; -import 'package:filcnaplo_desktop_ui/pages/grades/grades_count_item.dart'; -import 'package:collection/collection.dart'; - -class GradesCount extends StatelessWidget { - const GradesCount({Key? key, required this.grades}) : super(key: key); - - final List grades; - - @override - Widget build(BuildContext context) { - List gradesCount = List.generate(5, (int index) => grades.where((e) => e.value.value == index + 1).length); - - return Container( - width: 75, - padding: const EdgeInsets.only(bottom: 6.0, top: 6.0, left: 12.0, right: 0.0), - margin: const EdgeInsets.symmetric(horizontal: 12.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: gradesCount.mapIndexed((index, e) => GradesCountItem(count: e, value: index + 1)).toList(), - ), - ); - } -} diff --git a/filcnaplo_desktop_ui/pubspec.yaml b/filcnaplo_desktop_ui/pubspec.yaml deleted file mode 100644 index 2a1645a..0000000 --- a/filcnaplo_desktop_ui/pubspec.yaml +++ /dev/null @@ -1,34 +0,0 @@ -name: filcnaplo_desktop_ui -publish_to: "none" - -environment: - sdk: ">=2.17.0 <3.0.0" - -dependencies: - flutter: - sdk: flutter - - # Filcnaplo main dep - filcnaplo: - path: ../filcnaplo/ - filcnaplo_kreta_api: - path: ../filcnaplo_kreta_api/ - - cupertino_icons: ^1.0.2 - flutter_feather_icons: ^2.0.0+1 - provider: ^5.0.0 - url_launcher: ^6.0.9 - flutter_linkify: ^5.0.2 - flutter_markdown: ^0.6.5 - animations: ^2.0.1 - confetti: ^0.6.0 - auto_size_text: ^3.0.0 - flutter_acrylic: ^1.1.3 - elegant_notification: ^1.6.1 - flutter_staggered_grid_view: ^0.7.0 - -dev_dependencies: - flutter_lints: ^1.0.0 - -flutter: - uses-material-design: true diff --git a/filcnaplo_kreta_api/.github/dependabot.yml b/filcnaplo_kreta_api/.github/dependabot.yml deleted file mode 100644 index 9fc48a7..0000000 --- a/filcnaplo_kreta_api/.github/dependabot.yml +++ /dev/null @@ -1,11 +0,0 @@ -# To get started with Dependabot version updates, you'll need to specify which -# package ecosystems to update and where the package manifests are located. -# Please see the documentation for all configuration options: -# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates - -version: 2 -updates: - - package-ecosystem: "pub" # See documentation for possible values - directory: "/" # Location of package manifests - schedule: - interval: "daily" diff --git a/filcnaplo_kreta_api/pubspec.yaml b/filcnaplo_kreta_api/pubspec.yaml deleted file mode 100644 index 6b3d5e4..0000000 --- a/filcnaplo_kreta_api/pubspec.yaml +++ /dev/null @@ -1,20 +0,0 @@ -name: filcnaplo_kreta_api -publish_to: "none" - -environment: - sdk: ">=2.17.0 <3.0.0" - -dependencies: - flutter: - sdk: flutter - filcnaplo: - path: ../filcnaplo/ - http: ^0.13.3 - provider: ^5.0.0 - file_picker: ^6.1.1 - intl: ^0.18.1 - i18n_extension: ^10.0.1 - uuid: ^4.2.1 - -dev_dependencies: - flutter_lints: ^3.0.1 diff --git a/filcnaplo_mobile_ui/.github/dependabot.yml b/filcnaplo_mobile_ui/.github/dependabot.yml deleted file mode 100644 index 9fc48a7..0000000 --- a/filcnaplo_mobile_ui/.github/dependabot.yml +++ /dev/null @@ -1,11 +0,0 @@ -# To get started with Dependabot version updates, you'll need to specify which -# package ecosystems to update and where the package manifests are located. -# Please see the documentation for all configuration options: -# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates - -version: 2 -updates: - - package-ecosystem: "pub" # See documentation for possible values - directory: "/" # Location of package manifests - schedule: - interval: "daily" diff --git a/filcnaplo_mobile_ui/lib/common/bottom_sheet_menu/rounded_bottom_sheet.dart b/filcnaplo_mobile_ui/lib/common/bottom_sheet_menu/rounded_bottom_sheet.dart deleted file mode 100755 index a22bbe5..0000000 --- a/filcnaplo_mobile_ui/lib/common/bottom_sheet_menu/rounded_bottom_sheet.dart +++ /dev/null @@ -1,70 +0,0 @@ -import 'package:filcnaplo/theme/colors/colors.dart'; -import 'package:flutter/material.dart'; - -class RoundedBottomSheet extends StatelessWidget { - const RoundedBottomSheet({super.key, this.child, this.borderRadius = 12.0, this.shrink = true, this.showHandle = true}); - - final Widget? child; - final double borderRadius; - final bool shrink; - final bool showHandle; - - @override - Widget build(BuildContext context) { - return AnimatedContainer( - duration: const Duration(milliseconds: 500), - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.background, - borderRadius: BorderRadius.only( - topLeft: Radius.circular(borderRadius), - topRight: Radius.circular(borderRadius), - ), - ), - child: SafeArea( - child: Column( - mainAxisSize: shrink ? MainAxisSize.min : MainAxisSize.max, - children: [ - if (showHandle) - Container( - width: 42.0, - height: 4.0, - margin: const EdgeInsets.only(top: 12.0, bottom: 4.0), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(45.0), - color: AppColors.of(context).text.withOpacity(0.10), - ), - ), - if (child != null) child!, - SizedBox(height: MediaQuery.of(context).padding.bottom), - ], - ), - ), - ); - } -} - -Future showRoundedModalBottomSheet( - BuildContext context, { - required Widget child, - bool rootNavigator = true, -}) async { - return await showModalBottomSheet( - context: context, - backgroundColor: const Color(0x00000000), - elevation: 0, - isDismissible: true, - useRootNavigator: rootNavigator, - builder: (context) => RoundedBottomSheet(child: child)); -} - -PersistentBottomSheetController showRoundedBottomSheet( - BuildContext context, { - required Widget child, -}) { - return showBottomSheet( - context: context, - backgroundColor: const Color(0x00000000), - elevation: 12.0, - builder: (context) => RoundedBottomSheet(child: child), - ); -} diff --git a/filcnaplo_mobile_ui/lib/common/hero_scrollview.dart b/filcnaplo_mobile_ui/lib/common/hero_scrollview.dart deleted file mode 100755 index af3174d..0000000 --- a/filcnaplo_mobile_ui/lib/common/hero_scrollview.dart +++ /dev/null @@ -1,136 +0,0 @@ -import 'package:filcnaplo/theme/colors/colors.dart'; -import 'package:flutter/material.dart'; -import 'package:filcnaplo/utils/format.dart'; - -class HeroScrollView extends StatefulWidget { - const HeroScrollView( - {super.key, - required this.child, - required this.title, - required this.icon, - this.italic = false, - this.navBarItems = const [], - this.onClose, - this.iconSize = 64.0, - this.scrollController}); - - final Widget child; - final String title; - final IconData? icon; - final List navBarItems; - final VoidCallback? onClose; - final double iconSize; - final ScrollController? scrollController; - final bool italic; - - @override - HeroScrollViewState createState() => HeroScrollViewState(); -} - -class HeroScrollViewState extends State { - late ScrollController _scrollController; - - bool showBarTitle = false; - - @override - void initState() { - super.initState(); - _scrollController = widget.scrollController ?? ScrollController(); - - _scrollController.addListener(() { - if (_scrollController.offset > 42.0) { - if (showBarTitle == false) setState(() => showBarTitle = true); - } else { - if (showBarTitle == true) setState(() => showBarTitle = false); - } - }); - } - - @override - void dispose() { - super.dispose(); - _scrollController.dispose(); - } - - @override - Widget build(BuildContext context) { - return NestedScrollView( - controller: _scrollController, - physics: - const BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()), - headerSliverBuilder: (context, _) => [ - SliverAppBar( - pinned: true, - floating: false, - snap: false, - centerTitle: false, - titleSpacing: 0, - surfaceTintColor: Theme.of(context).scaffoldBackgroundColor, - title: AnimatedOpacity( - opacity: showBarTitle ? 1.0 : 0.0, - duration: const Duration(milliseconds: 200), - child: Row( - children: [ - Icon(widget.icon, - color: AppColors.of(context).text.withOpacity(.8)), - const SizedBox(width: 8.0), - Expanded( - child: Text( - widget.title.capital(), - overflow: TextOverflow.ellipsis, - maxLines: 2, - style: TextStyle( - color: AppColors.of(context).text, - fontWeight: FontWeight.w500, - fontStyle: widget.italic ? FontStyle.italic : null), - ), - ), - ], - )), - leading: BackButton( - color: AppColors.of(context).text, - onPressed: () { - if (widget.onClose != null) { - widget.onClose!(); - } else { - Navigator.of(context).pop(); - } - }), - actions: widget.navBarItems, - expandedHeight: 145.69, - stretch: true, - flexibleSpace: FlexibleSpaceBar( - background: Stack( - children: [ - Center( - child: Icon( - widget.icon, - size: widget.iconSize, - color: AppColors.of(context).text.withOpacity(.15), - ), - ), - Container( - alignment: Alignment.center, - margin: const EdgeInsets.only(top: 82), - padding: const EdgeInsets.symmetric(horizontal: 12.0), - child: Text( - widget.title.capital(), - maxLines: 2, - overflow: TextOverflow.ellipsis, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 36.0, - color: AppColors.of(context).text.withOpacity(.9), - fontStyle: widget.italic ? FontStyle.italic : null, - fontWeight: FontWeight.bold), - ), - ), - ], - ), - ), - ), - ], - body: widget.child, - ); - } -} diff --git a/filcnaplo_mobile_ui/lib/common/widgets/absence/absence_subject_tile.dart b/filcnaplo_mobile_ui/lib/common/widgets/absence/absence_subject_tile.dart deleted file mode 100755 index 9a3e0c3..0000000 --- a/filcnaplo_mobile_ui/lib/common/widgets/absence/absence_subject_tile.dart +++ /dev/null @@ -1,99 +0,0 @@ -import 'package:filcnaplo/helpers/subject.dart'; -import 'package:filcnaplo/models/settings.dart'; -import 'package:filcnaplo/theme/colors/colors.dart'; -import 'package:filcnaplo/utils/format.dart'; -import 'package:filcnaplo_kreta_api/models/subject.dart'; -import 'package:filcnaplo_mobile_ui/common/widgets/absence/absence_display.dart'; -import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; - -class AbsenceSubjectTile extends StatelessWidget { - const AbsenceSubjectTile(this.subject, - {super.key, - this.percentage = 0.0, - this.excused = 0, - this.unexcused = 0, - this.pending = 0, - this.onTap}); - - final GradeSubject subject; - final void Function()? onTap; - final double percentage; - - final int excused; - final int unexcused; - final int pending; - - @override - Widget build(BuildContext context) { - SettingsProvider settingsProvider = Provider.of(context); - return Material( - type: MaterialType.transparency, - child: ListTile( - // minLeadingWidth: 32.0, - dense: true, - contentPadding: const EdgeInsets.only(left: 8.0, right: 6.0), - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.0)), - visualDensity: VisualDensity.compact, - onTap: onTap, - leading: Icon( - SubjectIcon.resolveVariant(subject: subject, context: context), - size: 32.0), - title: Text( - subject.renamedTo ?? subject.name.capital(), - maxLines: 2, - overflow: TextOverflow.ellipsis, - style: TextStyle( - fontWeight: FontWeight.w600, - fontSize: 15.0, - fontStyle: - subject.isRenamed && settingsProvider.renamedSubjectsItalics - ? FontStyle.italic - : null), - ), - subtitle: AbsenceDisplay(excused, unexcused, pending), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: [ - const SizedBox(width: 8.0), - if (percentage >= 0) - Stack( - alignment: Alignment.centerRight, - children: [ - const Opacity( - opacity: 0, - child: Text("100%", - style: TextStyle(fontFamily: "monospace"))), - Text( - "${percentage.round()}%", - style: TextStyle( - // fontFamily: "monospace", - color: getColorByPercentage(percentage, context: context), - fontWeight: FontWeight.w700, - fontSize: 24.0, - ), - ), - ], - ), - ], - ), - ), - ); - } -} - -Color getColorByPercentage(double percentage, {required BuildContext context}) { - Color color = AppColors.of(context).text; - - percentage = percentage.round().toDouble(); - - if (percentage > 35) { - color = AppColors.of(context).red; - } else if (percentage > 25) { - color = AppColors.of(context).orange; - } else if (percentage > 15) { - color = AppColors.of(context).yellow; - } - - return color.withOpacity(.8); -} diff --git a/filcnaplo_mobile_ui/lib/common/widgets/event/event_tile.dart b/filcnaplo_mobile_ui/lib/common/widgets/event/event_tile.dart deleted file mode 100755 index 807c17e..0000000 --- a/filcnaplo_mobile_ui/lib/common/widgets/event/event_tile.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'package:filcnaplo_kreta_api/models/event.dart'; -import 'package:filcnaplo/utils/format.dart'; -import 'package:filcnaplo_mobile_ui/common/profile_image/profile_image.dart'; -import 'package:flutter/material.dart'; - -class EventTile extends StatelessWidget { - const EventTile(this.event, {super.key, this.onTap, this.padding}); - - final Event event; - final void Function()? onTap; - final EdgeInsetsGeometry? padding; - - @override - Widget build(BuildContext context) { - return Material( - color: Theme.of(context).colorScheme.background, - borderRadius: BorderRadius.circular(14.0), - child: Padding( - padding: padding ?? const EdgeInsets.symmetric(horizontal: 8.0), - child: ListTile( - visualDensity: VisualDensity.compact, - contentPadding: const EdgeInsets.only(left: 8.0, right: 12.0), - onTap: onTap, - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(14.0)), - leading: const ProfileImage( - name: "!", - radius: 22.0, - ), - title: Text( - event.title, - maxLines: 2, - overflow: TextOverflow.ellipsis, - style: const TextStyle(fontWeight: FontWeight.w600), - ), - subtitle: Text( - event.content.escapeHtml().replaceAll('\n', ' '), - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: const TextStyle(fontWeight: FontWeight.w500), - ), - minLeadingWidth: 0, - ), - ), - ); - } -} diff --git a/filcnaplo_mobile_ui/lib/common/widgets/exam/exam_tile.dart b/filcnaplo_mobile_ui/lib/common/widgets/exam/exam_tile.dart deleted file mode 100755 index 3f9076e..0000000 --- a/filcnaplo_mobile_ui/lib/common/widgets/exam/exam_tile.dart +++ /dev/null @@ -1,64 +0,0 @@ -import 'package:filcnaplo/helpers/subject.dart'; -import 'package:filcnaplo/theme/colors/colors.dart'; -import 'package:filcnaplo_kreta_api/models/exam.dart'; -import 'package:flutter/material.dart'; -import 'package:filcnaplo/utils/format.dart'; -import 'package:flutter_feather_icons/flutter_feather_icons.dart'; - -class ExamTile extends StatelessWidget { - const ExamTile(this.exam, {super.key, this.onTap, this.padding}); - - final Exam exam; - final void Function()? onTap; - final EdgeInsetsGeometry? padding; - - @override - Widget build(BuildContext context) { - return Material( - type: MaterialType.transparency, - child: Padding( - padding: padding ?? const EdgeInsets.symmetric(horizontal: 8.0), - child: ListTile( - visualDensity: VisualDensity.compact, - contentPadding: const EdgeInsets.only(left: 8.0, right: 12.0), - onTap: onTap, - shape: - RoundedRectangleBorder(borderRadius: BorderRadius.circular(14.0)), - leading: SizedBox( - width: 44, - height: 44, - child: Padding( - padding: const EdgeInsets.only(top: 2.0), - child: Icon( - SubjectIcon.resolveVariant( - subject: exam.subject, context: context), - size: 28.0, - color: AppColors.of(context).text.withOpacity(.75), - ), - )), - title: Text( - exam.description != "" - ? exam.description - : (exam.mode?.description ?? "Számonkérés"), - maxLines: 2, - overflow: TextOverflow.ellipsis, - style: const TextStyle(fontWeight: FontWeight.w600), - ), - subtitle: Text( - exam.subject.isRenamed - ? exam.subject.renamedTo! - : exam.subject.name.capital(), - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: const TextStyle(fontWeight: FontWeight.w500), - ), - trailing: Icon( - FeatherIcons.edit, - color: AppColors.of(context).text.withOpacity(.75), - ), - minLeadingWidth: 0, - ), - ), - ); - } -} diff --git a/filcnaplo_mobile_ui/lib/common/widgets/exam/exam_viewable.dart b/filcnaplo_mobile_ui/lib/common/widgets/exam/exam_viewable.dart deleted file mode 100755 index 7eab3b6..0000000 --- a/filcnaplo_mobile_ui/lib/common/widgets/exam/exam_viewable.dart +++ /dev/null @@ -1,20 +0,0 @@ -import 'package:filcnaplo_kreta_api/models/exam.dart'; -import 'package:filcnaplo_mobile_ui/common/viewable.dart'; -import 'package:filcnaplo_mobile_ui/common/widgets/card_handle.dart'; -import 'package:filcnaplo_mobile_ui/common/widgets/exam/exam_tile.dart'; -import 'package:filcnaplo_mobile_ui/common/widgets/exam/exam_view.dart'; -import 'package:flutter/material.dart'; - -class ExamViewable extends StatelessWidget { - const ExamViewable(this.exam, {super.key}); - - final Exam exam; - - @override - Widget build(BuildContext context) { - return Viewable( - tile: ExamTile(exam), - view: CardHandle(child: ExamView(exam)), - ); - } -} diff --git a/filcnaplo_mobile_ui/lib/common/widgets/homework/homework_tile.dart b/filcnaplo_mobile_ui/lib/common/widgets/homework/homework_tile.dart deleted file mode 100755 index dd8050a..0000000 --- a/filcnaplo_mobile_ui/lib/common/widgets/homework/homework_tile.dart +++ /dev/null @@ -1,115 +0,0 @@ -import 'package:filcnaplo/helpers/subject.dart'; -import 'package:filcnaplo/models/settings.dart'; -import 'package:filcnaplo/theme/colors/colors.dart'; -import 'package:filcnaplo_kreta_api/models/homework.dart'; -import 'package:filcnaplo/utils/format.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_feather_icons/flutter_feather_icons.dart'; -import 'package:provider/provider.dart'; - -class HomeworkTile extends StatelessWidget { - const HomeworkTile(this.homework, - {super.key, this.onTap, this.padding, this.censored = false}); - - final Homework homework; - final void Function()? onTap; - final EdgeInsetsGeometry? padding; - final bool censored; - - @override - Widget build(BuildContext context) { - SettingsProvider settingsProvider = Provider.of(context); - - return Material( - color: Theme.of(context).colorScheme.background, - borderRadius: BorderRadius.circular(8.0), - child: Padding( - padding: padding ?? const EdgeInsets.symmetric(horizontal: 8.0), - child: ListTile( - visualDensity: VisualDensity.compact, - contentPadding: const EdgeInsets.only(left: 8.0, right: 12.0), - onTap: onTap, - shape: - RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.0)), - leading: SizedBox( - width: 44, - height: 44, - child: censored - ? Container( - decoration: BoxDecoration( - color: AppColors.of(context).text.withOpacity(.55), - borderRadius: BorderRadius.circular(60.0), - ), - ) - : Padding( - padding: const EdgeInsets.only(top: 2.0), - child: Icon( - SubjectIcon.resolveVariant( - subject: homework.subject, context: context), - size: 28.0, - color: AppColors.of(context).text.withOpacity(.75), - ), - ), - ), - title: censored - ? Wrap( - children: [ - Container( - width: 160, - height: 15, - decoration: BoxDecoration( - color: AppColors.of(context).text.withOpacity(.85), - borderRadius: BorderRadius.circular(8.0), - ), - ), - ], - ) - : Text( - homework.subject.renamedTo ?? homework.subject.name.capital(), - maxLines: 2, - overflow: TextOverflow.ellipsis, - style: TextStyle( - fontWeight: FontWeight.w600, - fontStyle: homework.subject.isRenamed && - settingsProvider.renamedSubjectsItalics - ? FontStyle.italic - : null), - ), - subtitle: censored - ? Wrap( - children: [ - Container( - width: 100, - height: 10, - decoration: BoxDecoration( - color: AppColors.of(context).text.withOpacity(.45), - borderRadius: BorderRadius.circular(8.0), - ), - ), - ], - ) - : Text( - homework.content.escapeHtml().replaceAll('\n', ' '), - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: const TextStyle(fontWeight: FontWeight.w500), - ), - trailing: censored - ? Container( - width: 15, - height: 15, - decoration: BoxDecoration( - color: AppColors.of(context).text.withOpacity(.45), - borderRadius: BorderRadius.circular(8.0), - ), - ) - : Icon( - FeatherIcons.home, - color: AppColors.of(context).text.withOpacity(.75), - ), - minLeadingWidth: 0, - ), - ), - ); - } -} diff --git a/filcnaplo_mobile_ui/lib/common/widgets/lesson/lesson_viewable.dart b/filcnaplo_mobile_ui/lib/common/widgets/lesson/lesson_viewable.dart deleted file mode 100755 index 2a26ded..0000000 --- a/filcnaplo_mobile_ui/lib/common/widgets/lesson/lesson_viewable.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'package:filcnaplo_kreta_api/models/lesson.dart'; -import 'package:filcnaplo_mobile_ui/common/viewable.dart'; -import 'package:filcnaplo_mobile_ui/common/widgets/card_handle.dart'; -import 'package:filcnaplo/ui/widgets/lesson/lesson_tile.dart'; -import 'package:filcnaplo_mobile_ui/common/widgets/lesson/lesson_view.dart'; -import 'package:flutter/material.dart'; - -class LessonViewable extends StatelessWidget { - const LessonViewable(this.lesson, {super.key, this.swapDesc = false}); - - final Lesson lesson; - final bool swapDesc; - - @override - Widget build(BuildContext context) { - final tile = LessonTile(lesson, swapDesc: swapDesc); - - if (lesson.subject.id == '' || tile.lesson.isEmpty) return tile; - - return Viewable( - tile: tile, - view: CardHandle(child: LessonView(lesson)), - ); - } -} diff --git a/filcnaplo_mobile_ui/lib/common/widgets/message/message_view_tile.dart b/filcnaplo_mobile_ui/lib/common/widgets/message/message_view_tile.dart deleted file mode 100755 index 535f772..0000000 --- a/filcnaplo_mobile_ui/lib/common/widgets/message/message_view_tile.dart +++ /dev/null @@ -1,128 +0,0 @@ -import 'package:filcnaplo/api/providers/user_provider.dart'; -import 'package:filcnaplo/utils/color.dart'; -import 'package:filcnaplo_kreta_api/models/message.dart'; -import 'package:filcnaplo_mobile_ui/common/panel/panel.dart'; -import 'package:filcnaplo_mobile_ui/common/profile_image/profile_image.dart'; -import 'package:filcnaplo_mobile_ui/common/widgets/message/attachment_tile.dart'; -import 'package:flutter/material.dart'; -import 'package:filcnaplo/utils/format.dart'; -import 'package:flutter_custom_tabs/flutter_custom_tabs.dart'; -// import 'package:flutter_feather_icons/flutter_feather_icons.dart'; -import 'package:flutter_linkify/flutter_linkify.dart'; -import 'package:provider/provider.dart'; -import 'message_view_tile.i18n.dart'; - -class MessageViewTile extends StatelessWidget { - const MessageViewTile(this.message, {super.key}); - - final Message message; - - @override - Widget build(BuildContext context) { - UserProvider user = Provider.of(context, listen: false); - String recipientLabel = ""; - - if (message.recipients.any((r) => r.name == user.student?.name)) { - recipientLabel = "me".i18n; - } - - if (recipientLabel != "" && message.recipients.length > 1) { - recipientLabel += " +"; - recipientLabel += message.recipients - .where((r) => r.name != user.student?.name) - .length - .toString(); - } - - if (recipientLabel == "") { - // note: convertint to set to remove duplicates - recipientLabel += - message.recipients.map((r) => r.name).toSet().join(", "); - } - - List attachments = []; - for (var a in message.attachments) { - attachments.add(AttachmentTile(a)); - } - - return Padding( - padding: const EdgeInsets.symmetric(vertical: 12.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Subject - Text( - message.subject, - softWrap: true, - maxLines: 10, - style: const TextStyle( - fontWeight: FontWeight.w600, - fontSize: 24.0, - ), - ), - - // Author - ListTile( - visualDensity: VisualDensity.compact, - contentPadding: EdgeInsets.zero, - leading: ProfileImage( - name: message.author, - backgroundColor: ColorUtils.stringToColor(message.author), - ), - title: Text( - message.author, - style: const TextStyle(fontWeight: FontWeight.w600), - overflow: TextOverflow.ellipsis, - maxLines: 2, - ), - subtitle: Text( - "${"to".i18n} $recipientLabel", - style: const TextStyle(fontWeight: FontWeight.w500), - overflow: TextOverflow.ellipsis, - maxLines: 1, - ), - trailing: const Row( - mainAxisSize: MainAxisSize.min, - children: [ - // IconButton( - // onPressed: () {}, - // icon: Icon(FeatherIcons.cornerUpLeft, color: AppColors.of(context).text), - // splashRadius: 24.0, - // padding: EdgeInsets.zero, - // visualDensity: VisualDensity.compact, - // ), - // IconButton( - // onPressed: () {}, - // icon: Icon(FeatherIcons.share2, color: AppColors.of(context).text), - // splashRadius: 24.0, - // padding: EdgeInsets.zero, - // visualDensity: VisualDensity.compact, - // ), - ], - ), - ), - - // Content - Panel( - padding: const EdgeInsets.all(12.0), - child: SelectableLinkify( - text: message.content.escapeHtml(), - options: const LinkifyOptions(looseUrl: true, removeWww: true), - onOpen: (link) { - launch(link.url, - customTabsOption: CustomTabsOption( - toolbarColor: Theme.of(context).scaffoldBackgroundColor, - showPageTitle: true, - )); - }, - style: const TextStyle(fontWeight: FontWeight.w400), - ), - ), - - // Attachments - ...attachments, - ], - ), - ); - } -} diff --git a/filcnaplo_mobile_ui/lib/common/widgets/note/note_tile.dart b/filcnaplo_mobile_ui/lib/common/widgets/note/note_tile.dart deleted file mode 100755 index 276d7c8..0000000 --- a/filcnaplo_mobile_ui/lib/common/widgets/note/note_tile.dart +++ /dev/null @@ -1,55 +0,0 @@ -import 'package:filcnaplo/utils/color.dart'; -import 'package:filcnaplo_kreta_api/models/note.dart'; -import 'package:filcnaplo_mobile_ui/common/profile_image/profile_image.dart'; -import 'package:flutter/material.dart'; - -class NoteTile extends StatelessWidget { - const NoteTile(this.note, {super.key, this.onTap, this.padding}); - - final Note note; - final void Function()? onTap; - final EdgeInsetsGeometry? padding; - - @override - Widget build(BuildContext context) { - return Material( - type: MaterialType.transparency, - child: Padding( - padding: padding ?? const EdgeInsets.symmetric(horizontal: 8.0), - child: ListTile( - visualDensity: VisualDensity.compact, - contentPadding: const EdgeInsets.only(left: 8.0, right: 12.0), - onTap: onTap, - shape: - RoundedRectangleBorder(borderRadius: BorderRadius.circular(14.0)), - leading: ProfileImage( - name: (note.teacher.isRenamed - ? note.teacher.renamedTo - : note.teacher.name) ?? - '', - radius: 22.0, - backgroundColor: ColorUtils.stringToColor( - (note.teacher.isRenamed - ? note.teacher.renamedTo - : note.teacher.name) ?? - '', - ), - ), - title: Text( - note.title, - maxLines: 2, - overflow: TextOverflow.ellipsis, - style: const TextStyle(fontWeight: FontWeight.w600), - ), - subtitle: Text( - note.content.replaceAll('\n', ' '), - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: const TextStyle(fontWeight: FontWeight.w500), - ), - minLeadingWidth: 0, - ), - ), - ); - } -} diff --git a/filcnaplo_mobile_ui/lib/pages/absences/absences_page.dart b/filcnaplo_mobile_ui/lib/pages/absences/absences_page.dart deleted file mode 100755 index 7d3120a..0000000 --- a/filcnaplo_mobile_ui/lib/pages/absences/absences_page.dart +++ /dev/null @@ -1,431 +0,0 @@ -// ignore_for_file: no_leading_underscores_for_local_identifiers - -import 'dart:math'; - -import 'package:animations/animations.dart'; -import 'package:auto_size_text/auto_size_text.dart'; -import 'package:filcnaplo/api/providers/update_provider.dart'; -import 'package:filcnaplo/ui/date_widget.dart'; -import 'package:filcnaplo_kreta_api/models/absence.dart'; -import 'package:filcnaplo_kreta_api/models/lesson.dart'; -import 'package:filcnaplo_kreta_api/models/subject.dart'; -import 'package:filcnaplo_kreta_api/models/week.dart'; -import 'package:filcnaplo_kreta_api/providers/absence_provider.dart'; -import 'package:filcnaplo_kreta_api/providers/note_provider.dart'; -import 'package:filcnaplo/api/providers/user_provider.dart'; -import 'package:filcnaplo/theme/colors/colors.dart'; -import 'package:filcnaplo_kreta_api/providers/timetable_provider.dart'; -import 'package:filcnaplo_mobile_ui/common/action_button.dart'; -import 'package:filcnaplo_mobile_ui/common/empty.dart'; -import 'package:filcnaplo_mobile_ui/common/filter_bar.dart'; -import 'package:filcnaplo_mobile_ui/common/panel/panel.dart'; -import 'package:filcnaplo_mobile_ui/common/profile_image/profile_button.dart'; -import 'package:filcnaplo_mobile_ui/common/profile_image/profile_image.dart'; -import 'package:filcnaplo_mobile_ui/common/widgets/absence/absence_subject_tile.dart'; -import 'package:filcnaplo_mobile_ui/common/widgets/absence/absence_viewable.dart'; -import 'package:filcnaplo_mobile_ui/common/widgets/statistics_tile.dart'; -import 'package:filcnaplo_mobile_ui/common/widgets/miss_tile.dart'; -import 'package:filcnaplo_mobile_ui/pages/absences/absence_subject_view.dart'; -import 'package:filcnaplo/ui/filter/sort.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_feather_icons/flutter_feather_icons.dart'; -import 'package:provider/provider.dart'; -import 'absences_page.i18n.dart'; - -enum AbsenceFilter { absences, delays, misses } - -class SubjectAbsence { - GradeSubject subject; - List absences; - double percentage; - - SubjectAbsence( - {required this.subject, this.absences = const [], this.percentage = 0.0}); -} - -class AbsencesPage extends StatefulWidget { - const AbsencesPage({super.key}); - - @override - AbsencesPageState createState() => AbsencesPageState(); -} - -class AbsencesPageState extends State - with TickerProviderStateMixin { - late UserProvider user; - late AbsenceProvider absenceProvider; - late TimetableProvider timetableProvider; - late NoteProvider noteProvider; - late UpdateProvider updateProvider; - late String firstName; - late TabController _tabController; - late List absences = []; - final Map _lessonCount = {}; - - @override - void initState() { - super.initState(); - - _tabController = TabController(length: 3, vsync: this); - timetableProvider = Provider.of(context, listen: false); - - WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { - for (final lesson in timetableProvider.getWeek(Week.current()) ?? []) { - if (!lesson.isEmpty && - lesson.subject.id != '' && - lesson.lessonYearIndex != null) { - _lessonCount.update( - lesson.subject, - (value) { - if (lesson.lessonYearIndex! > value.lessonYearIndex!) { - return lesson; - } else { - return value; - } - }, - ifAbsent: () => lesson, - ); - } - } - setState(() {}); - }); - } - - void buildSubjectAbsences() { - Map _absences = {}; - - for (final absence in absenceProvider.absences) { - if (absence.delay != 0) continue; - - if (!_absences.containsKey(absence.subject)) { - _absences[absence.subject] = - SubjectAbsence(subject: absence.subject, absences: [absence]); - } else { - _absences[absence.subject]?.absences.add(absence); - } - } - - _absences.forEach((subject, absence) { - final absentLessonsOfSubject = absenceProvider.absences - .where((e) => e.subject == subject && e.delay == 0) - .length; - final totalLessonsOfSubject = _lessonCount[subject]?.lessonYearIndex ?? 0; - - double absentLessonsOfSubjectPercentage; - - if (absentLessonsOfSubject <= totalLessonsOfSubject) { - absentLessonsOfSubjectPercentage = - absentLessonsOfSubject / totalLessonsOfSubject * 100; - } else { - absentLessonsOfSubjectPercentage = -1; - } - - _absences[subject]?.percentage = - absentLessonsOfSubjectPercentage.clamp(-1, 100.0); - }); - - absences = _absences.values.toList(); - absences.sort((a, b) => -a.percentage.compareTo(b.percentage)); - } - - @override - Widget build(BuildContext context) { - user = Provider.of(context); - absenceProvider = Provider.of(context); - noteProvider = Provider.of(context); - updateProvider = Provider.of(context); - timetableProvider = Provider.of(context); - - List nameParts = user.displayName?.split(" ") ?? ["?"]; - firstName = nameParts.length > 1 ? nameParts[1] : nameParts[0]; - - buildSubjectAbsences(); - - return Scaffold( - body: Padding( - padding: const EdgeInsets.only(top: 12.0), - child: NestedScrollView( - physics: const BouncingScrollPhysics( - parent: AlwaysScrollableScrollPhysics()), - headerSliverBuilder: (context, _) => [ - SliverAppBar( - pinned: true, - floating: false, - snap: false, - centerTitle: false, - surfaceTintColor: Theme.of(context).scaffoldBackgroundColor, - actions: [ - // Profile Icon - Padding( - padding: const EdgeInsets.only(right: 24.0), - child: ProfileButton( - child: ProfileImage( - heroTag: "profile", - name: firstName, - backgroundColor: Theme.of(context) - .colorScheme - .primary, //ColorUtils.stringToColor(user.displayName ?? "?"), - badge: updateProvider.available, - role: user.role, - profilePictureString: user.picture, - ), - ), - ), - ], - automaticallyImplyLeading: false, - shadowColor: Theme.of(context).shadowColor, - title: Padding( - padding: const EdgeInsets.only(left: 8.0), - child: Text( - "Absences".i18n, - style: TextStyle( - color: AppColors.of(context).text, - fontSize: 32.0, - fontWeight: FontWeight.bold), - ), - ), - bottom: FilterBar( - items: [ - Tab(text: "Absences".i18n), - Tab(text: "Delays".i18n), - Tab(text: "Misses".i18n), - ], - controller: _tabController, - disableFading: true, - ), - ), - ], - body: TabBarView( - physics: const BouncingScrollPhysics(), - controller: _tabController, - children: List.generate( - 3, (index) => filterViewBuilder(context, index))), - ), - ), - ); - } - - List getFilterWidgets(AbsenceFilter activeData) { - List items = []; - switch (activeData) { - case AbsenceFilter.absences: - for (var a in absences) { - items.add(DateWidget( - date: DateTime.fromMillisecondsSinceEpoch(0), - widget: AbsenceSubjectTile( - a.subject, - percentage: a.percentage, - excused: a.absences - .where((a) => a.state == Justification.excused) - .length, - unexcused: a.absences - .where((a) => a.state == Justification.unexcused) - .length, - pending: a.absences - .where((a) => a.state == Justification.pending) - .length, - onTap: () => AbsenceSubjectView.show(a.subject, a.absences, - context: context), - ), - )); - } - break; - case AbsenceFilter.delays: - for (var absence in absenceProvider.absences) { - if (absence.delay != 0) { - items.add(DateWidget( - date: absence.date, - widget: AbsenceViewable(absence, padding: EdgeInsets.zero), - )); - } - } - break; - case AbsenceFilter.misses: - for (var note in noteProvider.notes) { - if (note.type?.name == "HaziFeladatHiany" || - note.type?.name == "Felszereleshiany") { - items.add(DateWidget( - date: note.date, - widget: MissTile(note), - )); - } - } - break; - } - return items; - } - - Widget filterViewBuilder(context, int activeData) { - List filterWidgets = []; - - if (activeData > 0) { - filterWidgets = sortDateWidgets( - context, - dateWidgets: getFilterWidgets(AbsenceFilter.values[activeData]), - padding: EdgeInsets.zero, - hasShadow: true, - ); - } else { - filterWidgets = [ - Padding( - padding: const EdgeInsets.only(bottom: 24.0), - child: Panel( - title: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text("Subjects".i18n), - Padding( - padding: const EdgeInsets.only(right: 4.0), - child: IconButton( - onPressed: () { - showDialog( - context: context, - builder: (context) => AlertDialog( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12.0)), - title: Text("attention".i18n), - content: Text("attention_body".i18n), - actions: [ - ActionButton( - label: "Ok", - onTap: () => Navigator.of(context).pop(), - ), - ], - ), - ); - }, - padding: EdgeInsets.zero, - splashRadius: 24.0, - visualDensity: VisualDensity.compact, - constraints: BoxConstraints.tight(const Size(42.0, 42.0)), - icon: const Icon(FeatherIcons.info), - ), - ), - ], - ), - child: PageTransitionSwitcher( - transitionBuilder: ( - Widget child, - Animation primaryAnimation, - Animation secondaryAnimation, - ) { - return FadeThroughTransition( - animation: primaryAnimation, - secondaryAnimation: secondaryAnimation, - fillColor: Theme.of(context).colorScheme.background, - child: child, - ); - }, - child: Column( - children: getFilterWidgets(AbsenceFilter.values[activeData]) - .map((e) => e.widget) - .cast() - .toList(), - ), - ), - ), - ) - ]; - } - - return Padding( - padding: const EdgeInsets.only(top: 12.0), - child: RefreshIndicator( - color: Theme.of(context).colorScheme.secondary, - onRefresh: () async { - await absenceProvider.fetch(); - await noteProvider.fetch(); - }, - child: ListView.builder( - padding: EdgeInsets.zero, - physics: const BouncingScrollPhysics(), - itemCount: max(filterWidgets.length + (activeData <= 1 ? 1 : 0), 1), - itemBuilder: (context, index) { - if (filterWidgets.isNotEmpty) { - if ((index == 0 && activeData == 1) || - (index == 0 && activeData == 0)) { - int value1 = 0; - int value2 = 0; - String title1 = ""; - String title2 = ""; - String suffix = ""; - - if (activeData == AbsenceFilter.absences.index) { - value1 = absenceProvider.absences - .where((e) => - e.delay == 0 && e.state == Justification.excused) - .length; - value2 = absenceProvider.absences - .where((e) => - e.delay == 0 && e.state == Justification.unexcused) - .length; - title1 = "stat_1".i18n; - title2 = "stat_2".i18n; - suffix = " ${"hr".i18n}"; - } else if (activeData == AbsenceFilter.delays.index) { - value1 = absenceProvider.absences - .where((e) => - e.delay != 0 && e.state == Justification.excused) - .map((e) => e.delay) - .fold(0, (a, b) => a + b); - value2 = absenceProvider.absences - .where((e) => - e.delay != 0 && e.state == Justification.unexcused) - .map((e) => e.delay) - .fold(0, (a, b) => a + b); - title1 = "stat_3".i18n; - title2 = "stat_4".i18n; - suffix = " ${"min".i18n}"; - } - - return Padding( - padding: const EdgeInsets.only( - bottom: 24.0, left: 24.0, right: 24.0), - child: Row(children: [ - Expanded( - child: StatisticsTile( - title: AutoSizeText( - title1, - textAlign: TextAlign.center, - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - valueSuffix: suffix, - value: value1.toDouble(), - decimal: false, - color: AppColors.of(context).green, - ), - ), - const SizedBox(width: 24.0), - Expanded( - child: StatisticsTile( - title: AutoSizeText( - title2, - textAlign: TextAlign.center, - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - valueSuffix: suffix, - value: value2.toDouble(), - decimal: false, - color: AppColors.of(context).red, - ), - ), - ]), - ); - } - - return Padding( - padding: - const EdgeInsets.symmetric(horizontal: 24.0, vertical: 6.0), - child: filterWidgets[index - (activeData <= 1 ? 1 : 0)], - ); - } else { - return Empty(subtitle: "empty".i18n); - } - }, - ), - ), - ); - } -} diff --git a/filcnaplo_mobile_ui/lib/pages/absences/absences_page.i18n.dart b/filcnaplo_mobile_ui/lib/pages/absences/absences_page.i18n.dart deleted file mode 100755 index 61c971a..0000000 --- a/filcnaplo_mobile_ui/lib/pages/absences/absences_page.i18n.dart +++ /dev/null @@ -1,60 +0,0 @@ -import 'package:i18n_extension/i18n_extension.dart'; - -extension ScreensLocalization on String { - static final _t = Translations.byLocale("hu_hu") + - { - "en_en": { - "Absences": "Absences", - "Delays": "Delays", - "Misses": "Misses", - "empty": "You have no absences.", - "stat_1": "Excused Absences", - "stat_2": "Unexcused Absences", - "stat_3": "Excused Delay", - "stat_4": "Unexcused Delay", - "min": "min", - "hr": "hrs", - "Subjects": "Subjects", - "attention": "Attention!", - "attention_body": "Percentage calculations are only an approximation so they may not be accurate.", - "lesson_not_found": "Cannot find lesson", - }, - "hu_hu": { - "Absences": "Hiányzások", - "Delays": "Késések", - "Misses": "Hiányok", - "empty": "Nincsenek hiányaid.", - "stat_1": "Igazolt hiányzások", - "stat_2": "Igazolatlan hiányzások", - "stat_3": "Igazolt Késés", - "stat_4": "Igazolatlan Késés", - "min": "perc", - "hr": "óra", - "Subjects": "Tantárgyak", - "attention": "Figyelem!", - "attention_body": "A százalékos számítások csak közelítések, ezért előfordulhat, hogy nem pontosak.", - "lesson_not_found": "Nem található óra", - }, - "de_de": { - "Absences": "Fehlen", - "Delays": "Verspätung", - "Misses": "Fehlt", - "empty": "Sie haben keine Fehlen.", - "stat_1": "Entschuldigte Fehlen", - "stat_2": "Unentschuldigte Fehlen", - "stat_3": "Entschuldigte Verspätung", - "stat_4": "Unentschuldigte Verspätung", - "min": "min", - "hr": "hrs", - "Subjects": "Fächer", - "attention": "Achtung!", - "attention_body": "Prozentberechnungen sind nur eine Annäherung und können daher ungenau sein.", - "lesson_not_found": "Lektion kann nicht gefunden werden", - }, - }; - - String get i18n => localize(this, _t); - String fill(List params) => localizeFill(this, params); - String plural(int value) => localizePlural(value, this, _t); - String version(Object modifier) => localizeVersion(modifier, this, _t); -} diff --git a/filcnaplo_mobile_ui/lib/pages/grades/grade_subject_view.dart b/filcnaplo_mobile_ui/lib/pages/grades/grade_subject_view.dart deleted file mode 100755 index b3e93f5..0000000 --- a/filcnaplo_mobile_ui/lib/pages/grades/grade_subject_view.dart +++ /dev/null @@ -1,367 +0,0 @@ -import 'dart:math'; - -import 'package:animations/animations.dart'; -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'; -import 'package:filcnaplo_kreta_api/models/grade.dart'; -import 'package:filcnaplo_kreta_api/models/subject.dart'; -import 'package:filcnaplo_mobile_ui/common/average_display.dart'; -import 'package:filcnaplo_mobile_ui/common/bottom_sheet_menu/rounded_bottom_sheet.dart'; -import 'package:filcnaplo_mobile_ui/common/panel/panel.dart'; -import 'package:filcnaplo_mobile_ui/common/trend_display.dart'; -import 'package:filcnaplo_mobile_ui/common/widgets/cretification/certification_tile.dart'; -import 'package:filcnaplo/ui/widgets/grade/grade_tile.dart'; -import 'package:filcnaplo_mobile_ui/common/widgets/grade/grade_viewable.dart'; -import 'package:filcnaplo_mobile_ui/common/hero_scrollview.dart'; -import 'package:filcnaplo_mobile_ui/pages/grades/calculator/grade_calculator.dart'; -import 'package:filcnaplo_mobile_ui/pages/grades/calculator/grade_calculator_provider.dart'; -import 'package:filcnaplo_mobile_ui/pages/grades/grades_count.dart'; -import 'package:filcnaplo_mobile_ui/pages/grades/graph.dart'; -import 'package:filcnaplo_mobile_ui/pages/grades/subject_grades_container.dart'; -import 'package:filcnaplo_premium/ui/mobile/goal_planner/goal_planner_screen.dart'; -import 'package:filcnaplo_premium/models/premium_scopes.dart'; -import 'package:filcnaplo_premium/providers/premium_provider.dart'; -import 'package:filcnaplo_premium/ui/mobile/goal_planner/goal_state_screen.dart'; -import 'package:filcnaplo_premium/ui/mobile/premium/upsell.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_expandable_fab/flutter_expandable_fab.dart'; -import 'package:flutter_feather_icons/flutter_feather_icons.dart'; -import 'package:provider/provider.dart'; -import 'grades_page.i18n.dart'; -// import 'package:filcnaplo_premium/ui/mobile/goal_planner/new_goal.dart'; - -class GradeSubjectView extends StatefulWidget { - const GradeSubjectView(this.subject, {super.key, this.groupAverage = 0.0}); - - final GradeSubject subject; - final double groupAverage; - - void push(BuildContext context, {bool root = false}) { - Navigator.of(context, rootNavigator: root) - .push(CupertinoPageRoute(builder: (context) => this)); - } - - @override - State createState() => _GradeSubjectViewState(); -} - -class _GradeSubjectViewState extends State { - final GlobalKey _scaffoldKey = GlobalKey(); - - // Controllers - PersistentBottomSheetController? _sheetController; - final ScrollController _scrollController = ScrollController(); - - List gradeTiles = []; - - // Providers - late GradeProvider gradeProvider; - late GradeCalculatorProvider calculatorProvider; - late SettingsProvider settingsProvider; - late DatabaseProvider dbProvider; - late UserProvider user; - - late double average; - late Widget gradeGraph; - - bool gradeCalcMode = false; - - String plan = ''; - - List getSubjectGrades(GradeSubject subject) => !gradeCalcMode - ? gradeProvider.grades.where((e) => e.subject == subject).toList() - : calculatorProvider.grades.where((e) => e.subject == subject).toList(); - - bool showGraph(List subjectGrades) { - if (gradeCalcMode) return true; - - final gradeDates = subjectGrades.map((e) => e.date.millisecondsSinceEpoch); - final maxGradeDate = gradeDates.fold(0, max); - final minGradeDate = gradeDates.fold(0, min); - if (maxGradeDate - minGradeDate < const Duration(days: 5).inMilliseconds) { - return false; // naplo/#78 - } - - return subjectGrades.where((e) => e.type == GradeType.midYear).length > 1; - } - - void buildTiles(List subjectGrades) { - List tiles = []; - - if (showGraph(subjectGrades)) { - tiles.add(gradeGraph); - } else { - tiles.add(Container(height: 24.0)); - } - - tiles.add(Padding( - padding: const EdgeInsets.only(bottom: 24.0), - child: Panel( - child: GradesCount(grades: getSubjectGrades(widget.subject).toList()), - ), - )); - - // ignore: no_leading_underscores_for_local_identifiers - List _gradeTiles = []; - - if (!gradeCalcMode) { - subjectGrades.sort((a, b) => -a.date.compareTo(b.date)); - for (var grade in subjectGrades) { - if (grade.type == GradeType.midYear) { - _gradeTiles.add(GradeViewable(grade)); - } else { - _gradeTiles.add(CertificationTile(grade, padding: EdgeInsets.zero)); - } - } - } else if (subjectGrades.isNotEmpty) { - subjectGrades.sort((a, b) => -a.date.compareTo(b.date)); - for (var grade in subjectGrades) { - _gradeTiles.add(GradeTile(grade)); - } - } - tiles.add( - PageTransitionSwitcher( - transitionBuilder: ( - Widget child, - Animation primaryAnimation, - Animation secondaryAnimation, - ) { - return SharedAxisTransition( - animation: primaryAnimation, - secondaryAnimation: secondaryAnimation, - transitionType: SharedAxisTransitionType.vertical, - fillColor: Colors.transparent, - child: child, - ); - }, - child: _gradeTiles.isNotEmpty - ? Panel( - key: ValueKey(gradeCalcMode), - title: Text( - gradeCalcMode ? "Ghost Grades".i18n : "Grades".i18n, - ), - child: Column( - children: _gradeTiles, - )) - : const SizedBox(), - ), - ); - - tiles.add(Padding( - padding: EdgeInsets.only(bottom: !gradeCalcMode ? 24.0 : 250.0))); - gradeTiles = List.castFrom(tiles); - } - - @override - void initState() { - super.initState(); - user = Provider.of(context, listen: false); - dbProvider = Provider.of(context, listen: false); - } - - void fetchGoalPlans() async { - plan = (await dbProvider.userQuery - .subjectGoalPlans(userId: user.id!))[widget.subject.id] ?? - ''; - setState(() {}); - } - - @override - Widget build(BuildContext context) { - gradeProvider = Provider.of(context); - calculatorProvider = Provider.of(context); - settingsProvider = Provider.of(context); - - List subjectGrades = getSubjectGrades(widget.subject).toList(); - average = AverageHelper.averageEvals(subjectGrades); - final prevAvg = subjectGrades.isNotEmpty - ? AverageHelper.averageEvals(subjectGrades - .where((e) => e.date.isBefore(subjectGrades - .reduce((v, e) => e.date.isAfter(v.date) ? e : v) - .date - .subtract(const Duration(days: 30)))) - .toList()) - : 0.0; - - gradeGraph = Padding( - padding: const EdgeInsets.only(top: 16.0, bottom: 8.0), - child: Panel( - title: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text("annual_average".i18n), - if (average != prevAvg) - TrendDisplay(current: average, previous: prevAvg), - ], - ), - child: Container( - padding: const EdgeInsets.only(top: 16.0, right: 12.0), - child: GradeGraph(subjectGrades, - dayThreshold: 5, classAvg: widget.groupAverage), - ), - ), - ); - - if (!gradeCalcMode) { - buildTiles(subjectGrades); - } else { - List ghostGrades = calculatorProvider.ghosts - .where((e) => e.subject == widget.subject) - .toList(); - buildTiles(ghostGrades); - } - - fetchGoalPlans(); - - return Scaffold( - key: _scaffoldKey, - floatingActionButtonLocation: ExpandableFab.location, - floatingActionButton: Visibility( - visible: !gradeCalcMode && - subjectGrades - .where((e) => e.type == GradeType.midYear) - .isNotEmpty, - child: ExpandableFab( - type: ExpandableFabType.up, - distance: 50, - childrenOffset: const Offset(-3.8, 0.0), - children: [ - FloatingActionButton.small( - heroTag: "btn_ghost_grades", - backgroundColor: Theme.of(context).colorScheme.secondary, - onPressed: () { - gradeCalc(context); - }, - child: const Icon(FeatherIcons.plus), - ), - FloatingActionButton.small( - heroTag: "btn_goal_planner", - backgroundColor: Theme.of(context).colorScheme.secondary, - onPressed: () { - if (!Provider.of(context, listen: false) - .hasScope(PremiumScopes.goalPlanner)) { - PremiumLockedFeatureUpsell.show( - context: context, feature: PremiumFeature.goalplanner); - return; - } - - // ScaffoldMessenger.of(context).showSnackBar( - // const SnackBar(content: Text("Hamarosan..."))); - - Navigator.of(context).push(CupertinoPageRoute( - builder: (context) => - GoalPlannerScreen(subject: widget.subject))); - }, - child: const Icon(FeatherIcons.flag, size: 20.0), - ), - ], - ), - ), - body: RefreshIndicator( - onRefresh: () async {}, - color: Theme.of(context).colorScheme.secondary, - child: HeroScrollView( - onClose: () { - if (_sheetController != null && gradeCalcMode) { - _sheetController!.close(); - } else { - Navigator.of(context).pop(); - } - }, - navBarItems: [ - const SizedBox(width: 6.0), - if (widget.groupAverage != 0) - Center( - child: AverageDisplay( - average: widget.groupAverage, border: true)), - const SizedBox(width: 6.0), - if (average != 0) - Center(child: AverageDisplay(average: average)), - const SizedBox(width: 6.0), - if (plan != '') - Center( - child: GestureDetector( - onTap: () { - Navigator.of(context).push(CupertinoPageRoute( - builder: (context) => - GoalStateScreen(subject: widget.subject))); - }, - child: Container( - width: 54.0, - padding: const EdgeInsets.symmetric(vertical: 8.0), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(45.0), - color: Theme.of(context) - .colorScheme - .primary - .withOpacity(.15), - ), - child: Icon( - FeatherIcons.flag, - size: 17.0, - weight: 2.5, - color: Theme.of(context).colorScheme.primary, - ), - ), - ), - ), - const SizedBox(width: 12.0), - ], - icon: SubjectIcon.resolveVariant( - subject: widget.subject, context: context), - scrollController: _scrollController, - title: widget.subject.renamedTo ?? widget.subject.name.capital(), - italic: settingsProvider.renamedSubjectsItalics && - widget.subject.isRenamed, - child: SubjectGradesContainer( - child: CupertinoScrollbar( - child: ListView.builder( - physics: const BouncingScrollPhysics(), - padding: const EdgeInsets.symmetric(horizontal: 24.0), - shrinkWrap: true, - itemBuilder: (context, index) => gradeTiles[index], - itemCount: gradeTiles.length, - ), - ), - )), - )); - } - - void gradeCalc(BuildContext context) { - // Scroll to the top of the page - _scrollController.animateTo(100, - duration: const Duration(milliseconds: 500), curve: Curves.ease); - - calculatorProvider.clear(); - calculatorProvider.addAllGrades(gradeProvider.grades); - - _sheetController = _scaffoldKey.currentState?.showBottomSheet( - (context) => RoundedBottomSheet( - borderRadius: 14.0, child: GradeCalculator(widget.subject)), - backgroundColor: const Color(0x00000000), - elevation: 12.0, - ); - - // Hide the fab and grades - setState(() { - gradeCalcMode = true; - }); - - _sheetController!.closed.then((value) { - // Show fab and grades - if (mounted) { - setState(() { - gradeCalcMode = false; - }); - } - }); - } -} diff --git a/filcnaplo_mobile_ui/lib/pages/grades/grades_count_item.dart b/filcnaplo_mobile_ui/lib/pages/grades/grades_count_item.dart deleted file mode 100755 index c5b1e3e..0000000 --- a/filcnaplo_mobile_ui/lib/pages/grades/grades_count_item.dart +++ /dev/null @@ -1,34 +0,0 @@ -import 'package:filcnaplo/ui/widgets/grade/grade_tile.dart'; -import 'package:filcnaplo_kreta_api/models/grade.dart'; -import 'package:flutter/material.dart'; - -class GradesCountItem extends StatelessWidget { - const GradesCountItem({super.key, required this.count, required this.value}); - - final int count; - final int value; - - @override - Widget build(BuildContext context) { - return Row( - children: [ - Text.rich( - TextSpan(children: [ - TextSpan( - text: count.toString(), - style: const TextStyle(fontWeight: FontWeight.w600), - ), - const TextSpan( - text: "x", - style: TextStyle(fontSize: 13.0), - ), - ]), - style: const TextStyle(fontSize: 15.0), - ), - const SizedBox(width: 5.0), - GradeValueWidget(GradeValue(value, "Value", "Value", 100), - size: 19.0, fill: true, shadow: false), - ], - ); - } -} diff --git a/filcnaplo_mobile_ui/lib/pages/home/live_card/live_card.dart b/filcnaplo_mobile_ui/lib/pages/home/live_card/live_card.dart deleted file mode 100755 index 76026b9..0000000 --- a/filcnaplo_mobile_ui/lib/pages/home/live_card/live_card.dart +++ /dev/null @@ -1,297 +0,0 @@ -import 'package:animations/animations.dart'; -import 'package:filcnaplo/api/providers/user_provider.dart'; -import 'package:filcnaplo/helpers/subject.dart'; -import 'package:filcnaplo/icons/filc_icons.dart'; -import 'package:filcnaplo/models/settings.dart'; -import 'package:filcnaplo_mobile_ui/pages/home/live_card/heads_up_countdown.dart'; -import 'package:filcnaplo_mobile_ui/screens/summary/summary_screen.dart'; -import 'package:flutter/material.dart'; -import 'package:filcnaplo/utils/format.dart'; -import 'package:filcnaplo/api/providers/live_card_provider.dart'; -import 'package:filcnaplo_mobile_ui/pages/home/live_card/live_card_widget.dart'; -import 'package:flutter_feather_icons/flutter_feather_icons.dart'; -import 'package:i18n_extension/i18n_widget.dart'; -import 'package:intl/intl.dart'; -import 'package:provider/provider.dart'; -import 'live_card.i18n.dart'; - -class LiveCard extends StatefulWidget { - const LiveCard({super.key}); - - @override - LiveCardStateA createState() => LiveCardStateA(); -} - -class LiveCardStateA extends State { - late void Function() listener; - late UserProvider _userProvider; - late LiveCardProvider liveCard; - - @override - void initState() { - super.initState(); - listener = () => setState(() {}); - _userProvider = Provider.of(context, listen: false); - liveCard = Provider.of(context, listen: false); - _userProvider.addListener(liveCard.update); - } - - @override - void dispose() { - _userProvider.removeListener(liveCard.update); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - liveCard = Provider.of(context); - SettingsProvider settingsProvider = Provider.of(context); - - if (!liveCard.show) return Container(); - - Widget child; - Duration bellDelay = liveCard.delay; - - switch (liveCard.currentState) { - case LiveCardState.summary: - child = LiveCardWidget( - key: const Key('livecard.summary'), - title: 'Vége a tanévnek! 🥳', - icon: FeatherIcons.arrowRight, - description: Text( - 'Irány az összefoglaláshoz', - style: TextStyle( - fontWeight: FontWeight.w500, - fontSize: 18.0, - color: Theme.of(context).textTheme.bodyMedium?.color, - ), - ), - onTap: () { - // showSlidingBottomSheet( - // context, - // useRootNavigator: true, - // builder: (context) => SlidingSheetDialog( - // color: Colors.black.withOpacity(0.99), - // duration: const Duration(milliseconds: 400), - // scrollSpec: const ScrollSpec.bouncingScroll(), - // snapSpec: const SnapSpec( - // snap: true, - // snappings: [1.0], - // initialSnap: 1.0, - // positioning: SnapPositioning.relativeToAvailableSpace, - // ), - // minHeight: MediaQuery.of(context).size.height, - // cornerRadius: 16, - // cornerRadiusOnFullscreen: 0, - // builder: (context, state) => const Material( - // color: Colors.black, - // child: SummaryScreen( - // currentPage: 'start', - // ), - // ), - // ), - // ); - SummaryScreen.show(context: context, currentPage: 'start'); - }, - ); - break; - case LiveCardState.morning: - child = LiveCardWidget( - key: const Key('livecard.morning'), - title: DateFormat("EEEE", I18n.of(context).locale.toString()) - .format(DateTime.now()) - .capital(), - icon: FeatherIcons.sun, - description: liveCard.nextLesson != null - ? Text.rich( - TextSpan( - children: [ - TextSpan(text: "first_lesson_1".i18n), - TextSpan( - text: liveCard.nextLesson!.subject.renamedTo ?? - liveCard.nextLesson!.subject.name.capital(), - style: TextStyle( - fontWeight: FontWeight.w600, - color: Theme.of(context) - .colorScheme - .secondary - .withOpacity(.85), - fontStyle: liveCard.nextLesson!.subject.isRenamed && - settingsProvider.renamedSubjectsItalics - ? FontStyle.italic - : null), - ), - TextSpan(text: "first_lesson_2".i18n), - TextSpan( - text: liveCard.nextLesson!.room.capital(), - style: TextStyle( - fontWeight: FontWeight.w600, - color: Theme.of(context) - .colorScheme - .secondary - .withOpacity(.85), - ), - ), - TextSpan(text: "first_lesson_3".i18n), - TextSpan( - text: DateFormat('H:mm') - .format(liveCard.nextLesson!.start), - style: TextStyle( - fontWeight: FontWeight.w600, - color: Theme.of(context) - .colorScheme - .secondary - .withOpacity(.85), - ), - ), - TextSpan(text: "first_lesson_4".i18n), - ], - ), - ) - : null, - ); - break; - case LiveCardState.duringLesson: - final elapsedTime = DateTime.now() - .difference(liveCard.currentLesson!.start) - .inSeconds - .toDouble() + - bellDelay.inSeconds; - final maxTime = liveCard.currentLesson!.end - .difference(liveCard.currentLesson!.start) - .inSeconds - .toDouble(); - - final showMinutes = maxTime - elapsedTime > 60; - - child = LiveCardWidget( - key: const Key('livecard.duringLesson'), - leading: liveCard.currentLesson!.lessonIndex + - (RegExp(r'\d').hasMatch(liveCard.currentLesson!.lessonIndex) - ? "." - : ""), - title: liveCard.currentLesson!.subject.renamedTo ?? - liveCard.currentLesson!.subject.name.capital(), - titleItalic: liveCard.currentLesson!.subject.isRenamed && - settingsProvider.renamedSubjectsEnabled && - settingsProvider.renamedSubjectsItalics, - subtitle: liveCard.currentLesson!.room, - icon: SubjectIcon.resolveVariant( - subject: liveCard.currentLesson!.subject, context: context), - description: liveCard.currentLesson!.description != "" - ? Text(liveCard.currentLesson!.description) - : null, - nextSubject: liveCard.nextLesson?.subject.renamedTo ?? - liveCard.nextLesson?.subject.name.capital(), - nextSubjectItalic: liveCard.nextLesson?.subject.isRenamed == true && - settingsProvider.renamedSubjectsEnabled && - settingsProvider.renamedSubjectsItalics, - nextRoom: liveCard.nextLesson?.room, - progressMax: showMinutes ? maxTime / 60 : maxTime, - progressCurrent: showMinutes ? elapsedTime / 60 : elapsedTime, - progressAccuracy: - showMinutes ? ProgressAccuracy.minutes : ProgressAccuracy.seconds, - onProgressTap: () { - showDialog( - barrierColor: Colors.black, - context: context, - builder: (context) => - HeadsUpCountdown(maxTime: maxTime, elapsedTime: elapsedTime), - ); - }, - ); - break; - case LiveCardState.duringBreak: - final iconFloorMap = { - "to room": FeatherIcons.chevronsRight, - "up floor": FilcIcons.upstairs, - "down floor": FilcIcons.downstairs, - "ground floor": FilcIcons.downstairs, - }; - - final diff = liveCard.getFloorDifference(); - - final maxTime = liveCard.nextLesson!.start - .difference(liveCard.prevLesson!.end) - .inSeconds - .toDouble(); - final elapsedTime = DateTime.now() - .difference(liveCard.prevLesson!.end) - .inSeconds - .toDouble() + - bellDelay.inSeconds.toDouble(); - - final showMinutes = maxTime - elapsedTime > 60; - - child = LiveCardWidget( - key: const Key('livecard.duringBreak'), - title: "break".i18n, - icon: iconFloorMap[diff], - description: liveCard.nextLesson!.room != liveCard.prevLesson!.room - ? Text("go $diff".i18n.fill([ - diff != "to room" - ? (liveCard.nextLesson!.getFloor() ?? 0) - : liveCard.nextLesson!.room - ])) - : Text("stay".i18n), - nextSubject: liveCard.nextLesson?.subject.renamedTo ?? - liveCard.nextLesson?.subject.name.capital(), - nextSubjectItalic: liveCard.nextLesson?.subject.isRenamed == true && - settingsProvider.renamedSubjectsItalics, - nextRoom: diff != "to room" ? liveCard.nextLesson?.room : null, - progressMax: showMinutes ? maxTime / 60 : maxTime, - progressCurrent: showMinutes ? elapsedTime / 60 : elapsedTime, - progressAccuracy: - showMinutes ? ProgressAccuracy.minutes : ProgressAccuracy.seconds, - onProgressTap: () { - showDialog( - barrierColor: Colors.black, - context: context, - builder: (context) => HeadsUpCountdown( - maxTime: maxTime, - elapsedTime: elapsedTime, - ), - ); - }, - ); - break; - case LiveCardState.afternoon: - child = LiveCardWidget( - key: const Key('livecard.afternoon'), - title: DateFormat("EEEE", I18n.of(context).locale.toString()) - .format(DateTime.now()) - .capital(), - icon: FeatherIcons.coffee, - ); - break; - case LiveCardState.night: - child = LiveCardWidget( - key: const Key('livecard.night'), - title: DateFormat("EEEE", I18n.of(context).locale.toString()) - .format(DateTime.now()) - .capital(), - icon: FeatherIcons.moon, - ); - break; - default: - child = Container(); - } - - return PageTransitionSwitcher( - transitionBuilder: ( - Widget child, - Animation primaryAnimation, - Animation secondaryAnimation, - ) { - return SharedAxisTransition( - animation: primaryAnimation, - secondaryAnimation: secondaryAnimation, - transitionType: SharedAxisTransitionType.horizontal, - fillColor: Theme.of(context).scaffoldBackgroundColor, - child: child, - ); - }, - child: child, - ); - } -} diff --git a/filcnaplo_mobile_ui/lib/pages/home/live_card/live_card_widget.dart b/filcnaplo_mobile_ui/lib/pages/home/live_card/live_card_widget.dart deleted file mode 100755 index 6b439b1..0000000 --- a/filcnaplo_mobile_ui/lib/pages/home/live_card/live_card_widget.dart +++ /dev/null @@ -1,390 +0,0 @@ -import 'package:filcnaplo/models/settings.dart'; -import 'package:filcnaplo/theme/colors/colors.dart'; -import 'package:filcnaplo_mobile_ui/common/progress_bar.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_feather_icons/flutter_feather_icons.dart'; -import 'package:provider/provider.dart'; -import 'live_card.i18n.dart'; - -enum ProgressAccuracy { minutes, seconds } - -class LiveCardWidget extends StatefulWidget { - const LiveCardWidget({ - super.key, - this.isEvent = false, - this.leading, - this.title, - this.titleItalic = false, - this.subtitle, - this.icon, - this.description, - this.nextRoom, - this.nextSubject, - this.nextSubjectItalic = false, - this.progressCurrent, - this.progressMax, - this.progressAccuracy = ProgressAccuracy.minutes, - this.onProgressTap, - this.onTap, - }); - - final bool isEvent; - final String? leading; - final String? title; - final bool titleItalic; - final String? subtitle; - final IconData? icon; - final Widget? description; - final String? nextSubject; - final bool nextSubjectItalic; - final String? nextRoom; - final double? progressCurrent; - final double? progressMax; - final ProgressAccuracy? progressAccuracy; - final Function()? onProgressTap; - final Function()? onTap; - - @override - State createState() => _LiveCardWidgetState(); -} - -class _LiveCardWidgetState extends State { - bool hold = false; - - @override - Widget build(BuildContext context) { - return GestureDetector( - onLongPressDown: (_) => setState(() => hold = true), - onLongPressEnd: (_) => setState(() => hold = false), - onLongPressCancel: () => setState(() => hold = false), - onTap: widget.onTap, - child: AnimatedScale( - scale: hold ? 1.03 : 1.0, - curve: Curves.easeInOutBack, - duration: const Duration(milliseconds: 300), - child: Container( - margin: const EdgeInsets.symmetric(vertical: 2.0), - padding: const EdgeInsets.all(12.0), - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.background, - borderRadius: BorderRadius.circular(16.0), - boxShadow: [ - if (Provider.of(context, listen: false) - .shadowEffect) - BoxShadow( - offset: const Offset(0, 21), - blurRadius: 23.0, - color: Theme.of(context).shadowColor, - ) - ], - ), - child: Container( - padding: const EdgeInsets.symmetric(horizontal: 6.0), - child: OverflowBox( - maxHeight: 96.0, - child: widget.isEvent - ? Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - widget.title ?? 'Esemény', - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 24.0, - color: - Theme.of(context).textTheme.bodyMedium?.color, - fontStyle: - widget.titleItalic ? FontStyle.italic : null, - ), - ), - Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - widget.description ?? - Text( - 'Nincs leírás megadva.', - style: TextStyle( - fontWeight: FontWeight.w500, - fontSize: 18.0, - color: Theme.of(context) - .textTheme - .bodyMedium - ?.color, - ), - ), - SizedBox( - height: 15, - child: Container( - decoration: BoxDecoration( - color: Theme.of(context) - .colorScheme - .secondary - .withOpacity(0.5), - borderRadius: const BorderRadius.all( - Radius.circular(10), - ), - ), - child: Padding( - padding: const EdgeInsets.all(4), - child: Icon(widget.icon), - ), - ), - ), - ], - ), - ], - ) - : Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - Expanded( - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (widget.leading != null) - Padding( - padding: const EdgeInsets.only( - right: 12.0, top: 8.0), - child: Text( - widget.leading!, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 32.0, - fontWeight: FontWeight.w600, - color: Theme.of(context) - .colorScheme - .secondary, - ), - ), - ), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: - MainAxisAlignment.spaceAround, - children: [ - Row( - children: [ - if (widget.title != null) - Expanded( - child: Text.rich( - TextSpan( - children: [ - TextSpan( - text: widget.title!, - style: TextStyle( - fontStyle: widget - .titleItalic - ? FontStyle.italic - : null)), - if (widget.subtitle != null) - WidgetSpan( - child: Container( - margin: const EdgeInsets - .only( - left: 6.0, - bottom: 3.0), - padding: - const EdgeInsets - .symmetric( - horizontal: 4.0, - vertical: 2.0), - decoration: - BoxDecoration( - color: Theme.of( - context) - .colorScheme - .secondary - .withOpacity(.3), - borderRadius: - BorderRadius - .circular( - 4.0), - ), - child: Text( - widget.subtitle!, - style: TextStyle( - height: 1.2, - fontSize: 14.0, - fontWeight: - FontWeight.w600, - color: Theme.of( - context) - .colorScheme - .secondary, - ), - ), - ), - ), - ], - ), - style: const TextStyle( - fontWeight: FontWeight.w600, - fontSize: 22.0), - maxLines: 1, - softWrap: false, - overflow: TextOverflow.ellipsis, - ), - ), - if (widget.title != null) - const SizedBox(width: 6.0), - if (widget.icon != null) - Padding( - padding: const EdgeInsets.symmetric( - vertical: 4.0), - child: Icon( - widget.icon, - size: 26.0, - color: AppColors.of(context) - .text - .withOpacity(.75), - ), - ), - ], - ), - if (widget.description != null) - DefaultTextStyle( - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith( - fontWeight: FontWeight.w500, - fontSize: 16.0, - height: 1.0, - color: AppColors.of(context) - .text - .withOpacity(.75), - ), - maxLines: - !(widget.nextSubject == null && - widget.progressCurrent == - null && - widget.progressMax == null) - ? 1 - : 2, - softWrap: false, - overflow: TextOverflow.ellipsis, - child: widget.description!, - ), - ], - ), - ), - ], - ), - ), - if (!(widget.nextSubject == null && - widget.progressCurrent == null && - widget.progressMax == null)) - Padding( - padding: const EdgeInsets.only(top: 8.0), - child: Row( - children: [ - if (widget.nextSubject != null) - const Icon(FeatherIcons.arrowRight, - size: 12.0), - if (widget.nextSubject != null) - const SizedBox(width: 4.0), - if (widget.nextSubject != null) - Expanded( - child: Text.rich( - TextSpan( - children: [ - TextSpan( - text: widget.nextSubject!, - style: TextStyle( - fontStyle: - widget.nextSubjectItalic - ? FontStyle.italic - : null)), - if (widget.nextRoom != null) - WidgetSpan( - child: Container( - margin: const EdgeInsets.only( - left: 4.0), - padding: - const EdgeInsets.symmetric( - horizontal: 3.0, - vertical: 1.5), - decoration: BoxDecoration( - color: Theme.of(context) - .colorScheme - .secondary - .withOpacity(.25), - borderRadius: - BorderRadius.circular( - 4.0), - ), - child: Text( - widget.nextRoom!, - style: TextStyle( - height: 1.1, - fontSize: 12.0, - fontWeight: FontWeight.w600, - color: Theme.of(context) - .colorScheme - .secondary - .withOpacity(.9), - ), - ), - ), - ), - ], - ), - style: TextStyle( - color: AppColors.of(context) - .text - .withOpacity(.8), - fontWeight: FontWeight.w600, - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - softWrap: false, - ), - ), - if (widget.nextRoom == null && - widget.nextSubject == null) - const Spacer(), - if (widget.progressCurrent != null && - widget.progressMax != null) - GestureDetector( - onTap: widget.onProgressTap, - child: Container( - color: Colors.transparent, - child: Text( - "remaining ${widget.progressAccuracy == ProgressAccuracy.minutes ? 'min' : 'sec'}" - .plural((widget.progressMax! - - widget.progressCurrent!) - .round()), - maxLines: 1, - style: TextStyle( - fontWeight: FontWeight.w500, - color: AppColors.of(context) - .text - .withOpacity(.75), - ), - ), - ), - ) - ], - ), - ), - if (widget.progressCurrent != null && - widget.progressMax != null) - Padding( - padding: const EdgeInsets.symmetric(vertical: 4.0), - child: ProgressBar( - value: widget.progressCurrent! / - widget.progressMax!), - ) - ], - ), - ), - ), - ), - ), - ); - } -} diff --git a/filcnaplo_mobile_ui/lib/pages/timetable/timetable_page.dart b/filcnaplo_mobile_ui/lib/pages/timetable/timetable_page.dart deleted file mode 100755 index a556498..0000000 --- a/filcnaplo_mobile_ui/lib/pages/timetable/timetable_page.dart +++ /dev/null @@ -1,560 +0,0 @@ -import 'dart:math'; -import 'package:animations/animations.dart'; -import 'package:filcnaplo/api/providers/update_provider.dart'; -import 'package:filcnaplo_kreta_api/client/client.dart'; -import 'package:filcnaplo_kreta_api/models/week.dart'; -import 'package:filcnaplo_kreta_api/providers/timetable_provider.dart'; -import 'package:filcnaplo/api/providers/user_provider.dart'; -import 'package:filcnaplo/theme/colors/colors.dart'; -import 'package:filcnaplo_kreta_api/models/lesson.dart'; -import 'package:filcnaplo_mobile_ui/common/dot.dart'; -import 'package:filcnaplo_mobile_ui/common/empty.dart'; -import 'package:filcnaplo_mobile_ui/common/panel/panel.dart'; -import 'package:filcnaplo_mobile_ui/common/profile_image/profile_button.dart'; -import 'package:filcnaplo_mobile_ui/common/profile_image/profile_image.dart'; -import 'package:filcnaplo_mobile_ui/common/system_chrome.dart'; -import 'package:filcnaplo_mobile_ui/common/widgets/lesson/lesson_view.dart'; -import 'package:filcnaplo_kreta_api/controllers/timetable_controller.dart'; -import 'package:filcnaplo_mobile_ui/common/widgets/lesson/lesson_viewable.dart'; -import 'package:filcnaplo_mobile_ui/pages/timetable/day_title.dart'; -import 'package:filcnaplo_mobile_ui/pages/timetable/fs_timetable.dart'; -import 'package:filcnaplo_mobile_ui/screens/navigation/navigation_route_handler.dart'; -import 'package:filcnaplo_mobile_ui/screens/navigation/navigation_screen.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_feather_icons/flutter_feather_icons.dart'; -import 'package:provider/provider.dart'; -import 'package:intl/intl.dart'; -import 'package:i18n_extension/i18n_widget.dart'; -import 'timetable_page.i18n.dart'; - -// todo: "fix" overflow (priority: -1) - -class TimetablePage extends StatefulWidget { - const TimetablePage({super.key, this.initialDay, this.initialWeek}); - - final DateTime? initialDay; - final Week? initialWeek; - - static void jump(BuildContext context, - {Week? week, DateTime? day, Lesson? lesson}) { - // Go to timetable page with arguments - NavigationScreen.of(context) - ?.customRoute(navigationPageRoute((context) => TimetablePage( - initialDay: lesson?.date ?? day, - initialWeek: lesson?.date != null - ? Week.fromDate(lesson!.date) - : day != null - ? Week.fromDate(day) - : week, - ))); - - NavigationScreen.of(context)?.setPage("timetable"); - - // Show initial Lesson - if (lesson != null) LessonView.show(lesson, context: context); - } - - @override - TimetablePageState createState() => TimetablePageState(); -} - -class TimetablePageState extends State - with TickerProviderStateMixin, WidgetsBindingObserver { - late UserProvider user; - late TimetableProvider timetableProvider; - late UpdateProvider updateProvider; - late String firstName; - late TimetableController _controller; - late TabController _tabController; - late Widget empty; - - int _getDayIndex(DateTime date) { - int index = 0; - if (_controller.days == null || (_controller.days?.isEmpty ?? true)) { - return index; - } - - // find the first day with upcoming lessons - index = _controller.days!.indexWhere((day) => day.last.end.isAfter(date)); - if (index == -1) index = 0; // fallback - - return index; - } - - // Update timetable on user change - Future _userListener() async { - await Provider.of(context, listen: false).refreshLogin(); - if (mounted) _controller.jump(_controller.currentWeek, context: context); - } - - // When the app comes to foreground, refresh the timetable - @override - void didChangeAppLifecycleState(AppLifecycleState state) { - if (state == AppLifecycleState.resumed) { - if (mounted) _controller.jump(_controller.currentWeek, context: context); - } - } - - @override - void initState() { - super.initState(); - - // Initalize controllers - _controller = TimetableController(); - _tabController = TabController(length: 0, vsync: this, initialIndex: 0); - - empty = Empty(subtitle: "empty".i18n); - - bool initial = true; - - // Only update the TabController on week changes - _controller.addListener(() { - if (_controller.days == null) return; - setState(() { - _tabController = TabController( - length: _controller.days!.length, - vsync: this, - initialIndex: - min(_tabController.index, max(_controller.days!.length - 1, 0)), - ); - - if (initial || - _controller.previousWeekId != _controller.currentWeekId) { - _tabController - .animateTo(_getDayIndex(widget.initialDay ?? DateTime.now())); - } - initial = false; - - // Empty is updated once every week change - empty = Empty(subtitle: "empty".i18n); - }); - }); - - if (mounted) { - if (widget.initialWeek != null) { - _controller.jump(widget.initialWeek!, context: context, initial: true); - } else { - _controller.jump(_controller.currentWeek, - context: context, initial: true, skip: true); - } - } - - // Listen for user changes - user = Provider.of(context, listen: false); - user.addListener(_userListener); - - // Register listening for app state changes to refresh the timetable - WidgetsBinding.instance.addObserver(this); - } - - @override - void dispose() { - _tabController.dispose(); - _controller.dispose(); - user.removeListener(_userListener); - WidgetsBinding.instance.removeObserver(this); - super.dispose(); - } - - String dayTitle(int index) { - // Sometimes when changing weeks really fast, - // controller.days might be null or won't include index - try { - return DateFormat("EEEE", I18n.of(context).locale.languageCode) - .format(_controller.days![index].first.date); - } catch (e) { - return "timetable".i18n; - } - } - - @override - Widget build(BuildContext context) { - user = Provider.of(context); - timetableProvider = Provider.of(context); - updateProvider = Provider.of(context); - - // First name - List nameParts = user.displayName?.split(" ") ?? ["?"]; - firstName = nameParts.length > 1 ? nameParts[1] : nameParts[0]; - - return Scaffold( - body: Padding( - padding: const EdgeInsets.only(top: 9.0), - child: RefreshIndicator( - onRefresh: () => mounted - ? _controller.jump(_controller.currentWeek, - context: context, loader: false) - : Future.value(null), - color: Theme.of(context).colorScheme.secondary, - edgeOffset: 132.0, - child: NestedScrollView( - physics: const BouncingScrollPhysics( - parent: AlwaysScrollableScrollPhysics()), - headerSliverBuilder: (context, _) => [ - SliverAppBar( - centerTitle: false, - pinned: true, - floating: false, - snap: false, - surfaceTintColor: Theme.of(context).scaffoldBackgroundColor, - actions: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: IconButton( - splashRadius: 24.0, - onPressed: () { - // If timetable empty, show empty - if (_tabController.length == 0) { - ScaffoldMessenger.of(context).showSnackBar(SnackBar( - content: Text("empty_timetable".i18n), - duration: const Duration(seconds: 2), - )); - return; - } - - Navigator.of(context, rootNavigator: true) - .push(PageRouteBuilder( - pageBuilder: - (context, animation, secondaryAnimation) => - FSTimetable( - controller: _controller, - ), - )) - .then((_) { - SystemChrome.setPreferredOrientations( - [DeviceOrientation.portraitUp]); - setSystemChrome(context); - }); - }, - icon: Icon(FeatherIcons.trello, - color: AppColors.of(context).text), - ), - ), - - // Profile Icon - Padding( - padding: const EdgeInsets.only(right: 24.0), - child: ProfileButton( - child: ProfileImage( - heroTag: "profile", - name: firstName, - backgroundColor: Theme.of(context) - .colorScheme - .primary, //ColorUtils.stringToColor(user.displayName ?? "?"), - badge: updateProvider.available, - role: user.role, - profilePictureString: user.picture, - ), - ), - ), - ], - automaticallyImplyLeading: false, - // Current day text - title: PageTransitionSwitcher( - reverse: - _controller.currentWeekId < _controller.previousWeekId, - transitionBuilder: ( - Widget child, - Animation primaryAnimation, - Animation secondaryAnimation, - ) { - return SharedAxisTransition( - animation: primaryAnimation, - secondaryAnimation: secondaryAnimation, - transitionType: SharedAxisTransitionType.horizontal, - fillColor: Theme.of(context).scaffoldBackgroundColor, - child: child, - ); - }, - layoutBuilder: (List entries) { - return Stack( - children: entries, - ); - }, - child: Padding( - padding: const EdgeInsets.only(left: 8.0), - child: Row( - children: [ - () { - final show = _controller.days == null || - (_controller.loadType != LoadType.offline && - _controller.loadType != LoadType.online); - const duration = Duration(milliseconds: 150); - return AnimatedOpacity( - opacity: show ? 1.0 : 0.0, - duration: duration, - curve: Curves.easeInOut, - child: AnimatedContainer( - duration: duration, - width: show ? 24.0 : 0.0, - curve: Curves.easeInOut, - child: const Padding( - padding: EdgeInsets.only(right: 12.0), - child: CupertinoActivityIndicator(), - ), - ), - ); - }(), - () { - if ((_controller.days?.length ?? 0) > 0) { - return DayTitle( - controller: _tabController, dayTitle: dayTitle); - } else { - return Text( - "timetable".i18n, - style: TextStyle( - fontSize: 32.0, - fontWeight: FontWeight.bold, - color: AppColors.of(context).text, - ), - ); - } - }(), - ], - ), - ), - ), - shadowColor: Theme.of(context).shadowColor, - bottom: PreferredSize( - preferredSize: const Size.fromHeight(50.0), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 12.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - // Previous week - IconButton( - onPressed: _controller.currentWeekId == 0 - ? null - : () => setState(() { - _controller.previous(context); - }), - splashRadius: 24.0, - icon: const Icon(FeatherIcons.chevronLeft), - color: Theme.of(context).colorScheme.secondary), - - // Week selector - InkWell( - borderRadius: BorderRadius.circular(6.0), - onTap: () => setState(() { - _controller.current(); - if (mounted) { - _controller.jump( - _controller.currentWeek, - context: context, - loader: _controller.currentWeekId != - _controller.previousWeekId, - ); - } - _tabController - .animateTo(_getDayIndex(DateTime.now())); - }), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - "${_controller.currentWeekId + 1}. ${"week".i18n} (${DateFormat("${_controller.currentWeek.start.year != DateTime.now().year ? "yy. " : ""}MMM d.", I18n.of(context).locale.languageCode).format(_controller.currentWeek.start)} - ${DateFormat("${_controller.currentWeek.start.year != DateTime.now().year ? "yy. " : ""}MMM d.", I18n.of(context).locale.languageCode).format(_controller.currentWeek.end)})", - style: const TextStyle( - fontWeight: FontWeight.w500, - fontSize: 14.0, - ), - ), - ), - ), - - // Next week - IconButton( - onPressed: _controller.currentWeekId == 51 - ? null - : () => setState(() { - _controller.next(context); - }), - splashRadius: 24.0, - icon: const Icon(FeatherIcons.chevronRight), - color: Theme.of(context).colorScheme.secondary), - ], - ), - ), - ), - ), - ], - body: PageTransitionSwitcher( - transitionBuilder: ( - Widget child, - Animation primaryAnimation, - Animation secondaryAnimation, - ) { - return FadeThroughTransition( - animation: primaryAnimation, - secondaryAnimation: secondaryAnimation, - fillColor: Theme.of(context).scaffoldBackgroundColor, - child: child, - ); - }, - child: _controller.days != null - ? Column( - key: Key(_controller.currentWeek.toString()), - children: [ - // Week view - _tabController.length > 0 - ? Expanded( - child: TabBarView( - physics: const BouncingScrollPhysics(), - controller: _tabController, - // days - children: List.generate( - _controller.days!.length, - (tab) => RefreshIndicator( - onRefresh: () => mounted - ? _controller.jump( - _controller.currentWeek, - context: context, - loader: false) - : Future.value(null), - color: Theme.of(context) - .colorScheme - .secondary, - child: ListView.builder( - padding: EdgeInsets.zero, - physics: const BouncingScrollPhysics(), - itemCount: - _controller.days![tab].length + 2, - itemBuilder: (context, index) { - if (_controller.days == null) { - return Container(); - } - - // Header - if (index == 0) { - return const Padding( - padding: EdgeInsets.only( - top: 8.0, - left: 24.0, - right: 24.0), - child: PanelHeader( - padding: EdgeInsets.only( - top: 12.0)), - ); - } - - // Footer - if (index == - _controller.days![tab].length + - 1) { - return const Padding( - padding: EdgeInsets.only( - bottom: 8.0, - left: 24.0, - right: 24.0), - child: PanelFooter( - padding: EdgeInsets.only( - top: 12.0)), - ); - } - - // Body - final Lesson lesson = - _controller.days![tab][index - 1]; - final bool swapDescDay = _controller - .days![tab] - .map( - (l) => l.swapDesc ? 1 : 0) - .reduce((a, b) => a + b) >= - _controller.days![tab].length * - .5; - - return Padding( - padding: const EdgeInsets.symmetric( - horizontal: 24.0), - child: PanelBody( - padding: - const EdgeInsets.symmetric( - horizontal: 10.0), - child: LessonViewable( - lesson, - swapDesc: swapDescDay, - ), - ), - ); - }, - ), - ), - ), - ), - ) - - // Empty week - : Expanded( - child: Center(child: empty), - ), - - // Day selector - TabBar( - dividerColor: Colors.transparent, - controller: _tabController, - // Label - labelPadding: EdgeInsets.zero, - labelColor: Theme.of(context).colorScheme.secondary, - unselectedLabelColor: - AppColors.of(context).text.withOpacity(0.9), - // Indicator - indicatorSize: TabBarIndicatorSize.tab, - indicatorPadding: EdgeInsets.zero, - indicator: BoxDecoration( - color: Theme.of(context) - .colorScheme - .secondary - .withOpacity(0.25), - borderRadius: BorderRadius.circular(45.0), - ), - overlayColor: MaterialStateProperty.all( - const Color(0x00000000)), - // Tabs - padding: const EdgeInsets.symmetric( - vertical: 6.0, horizontal: 8.0), - tabs: List.generate(_tabController.length, (index) { - String label = DateFormat( - "E", I18n.of(context).locale.languageCode) - .format(_controller.days![index].first.date); - return Tab( - height: 46.0, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - if (_sameDate( - _controller.days![index].first.date, - DateTime.now())) - Padding( - padding: const EdgeInsets.only(top: 4.0), - child: Dot( - size: 4.0, - color: Theme.of(context) - .colorScheme - .secondary), - ), - Text( - label.substring(0, min(2, label.length)), - style: const TextStyle( - fontSize: 26.0, - fontWeight: FontWeight.w600), - ), - ], - ), - ); - }), - ), - ], - ) - : const SizedBox(), - ), - ), - ), - ), - ); - } -} - -// difference.inDays is not reliable -bool _sameDate(DateTime a, DateTime b) => - (a.year == b.year && a.month == b.month && a.day == b.day); diff --git a/filcnaplo_mobile_ui/lib/premium/components/plan_card.dart b/filcnaplo_mobile_ui/lib/premium/components/plan_card.dart deleted file mode 100755 index e2ef406..0000000 --- a/filcnaplo_mobile_ui/lib/premium/components/plan_card.dart +++ /dev/null @@ -1,158 +0,0 @@ -import 'package:filcnaplo/theme/colors/colors.dart'; -import 'package:flutter/material.dart'; -import 'package:url_launcher/url_launcher.dart'; - -class PremiumPlanCard extends StatelessWidget { - const PremiumPlanCard({ - super.key, - this.icon, - this.title, - this.description, - this.price = 0, - this.url, - this.gradient, - this.active = false, - }); - - final Widget? icon; - final Widget? title; - final int price; - final Widget? description; - final String? url; - final Gradient? gradient; - final bool active; - - @override - Widget build(BuildContext context) { - return Card( - margin: EdgeInsets.zero, - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0)), - child: InkWell( - customBorder: - RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0)), - onTap: () { - if (url != null) { - launchUrl( - Uri.parse(url!), - mode: LaunchMode.externalApplication, - ); - } - }, - child: Padding( - padding: const EdgeInsets.all(20.0), - child: Column( - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (!active) - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (icon != null) ...[ - IconTheme( - data: Theme.of(context) - .iconTheme - .copyWith(size: 42.0), - child: icon!, - ), - const SizedBox(height: 12.0), - ], - DefaultTextStyle( - style: Theme.of(context) - .textTheme - .displaySmall! - .copyWith( - fontWeight: FontWeight.bold, - fontSize: 25.0), - child: title!, - ), - ], - ), - ) - else - Expanded( - child: Align( - alignment: Alignment.centerLeft, - child: Container( - decoration: BoxDecoration( - gradient: gradient, - borderRadius: BorderRadius.circular(99.0), - ), - child: Container( - decoration: BoxDecoration( - color: Theme.of(context).scaffoldBackgroundColor, - borderRadius: BorderRadius.circular(99.0), - ), - margin: const EdgeInsets.all(4.0), - padding: - const EdgeInsets.symmetric(horizontal: 12.0), - child: const Text( - "Aktív", - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 20.0, - ), - ), - ), - ), - ), - ), - Text.rich( - TextSpan(children: [ - TextSpan(text: "\$$price"), - TextSpan( - text: " / hó", - style: TextStyle( - color: Theme.of(context) - .textTheme - .bodyMedium! - .color! - .withOpacity(.7)), - ), - ]), - style: const TextStyle( - fontWeight: FontWeight.bold, fontSize: 24.0), - ), - ], - ), - if (active) ...[ - const SizedBox(height: 18.0), - Row( - children: [ - if (icon != null) ...[ - IconTheme( - data: Theme.of(context).iconTheme.copyWith( - size: 24.0, color: AppColors.of(context).text), - child: icon!, - ), - ], - const SizedBox(width: 12.0), - DefaultTextStyle( - style: Theme.of(context).textTheme.displaySmall!.copyWith( - fontWeight: FontWeight.bold, fontSize: 25.0), - child: title!, - ), - ], - ), - ], - const SizedBox(height: 6.0), - if (description != null) - DefaultTextStyle( - style: Theme.of(context).textTheme.bodyMedium!.copyWith( - color: Theme.of(context) - .textTheme - .bodyMedium! - .color! - .withOpacity(.8), - fontSize: 18), - child: description!, - ), - ], - ), - ), - ), - ); - } -} diff --git a/filcnaplo_mobile_ui/lib/premium/premium_screen.dart b/filcnaplo_mobile_ui/lib/premium/premium_screen.dart deleted file mode 100755 index 0e7d6ab..0000000 --- a/filcnaplo_mobile_ui/lib/premium/premium_screen.dart +++ /dev/null @@ -1,349 +0,0 @@ -import 'package:filcnaplo/api/client.dart'; -import 'package:filcnaplo/icons/filc_icons.dart'; -import 'package:filcnaplo/models/supporter.dart'; -import 'package:filcnaplo_mobile_ui/premium/components/active_sponsor_card.dart'; -import 'package:filcnaplo_mobile_ui/premium/components/github_card.dart'; -import 'package:filcnaplo_mobile_ui/premium/components/github_connect_button.dart'; -import 'package:filcnaplo_mobile_ui/premium/components/goal_card.dart'; -import 'package:filcnaplo_mobile_ui/premium/components/plan_card.dart'; -import 'package:filcnaplo_mobile_ui/premium/components/reward_card.dart'; -import 'package:filcnaplo_mobile_ui/premium/components/supporters_button.dart'; -import 'package:filcnaplo_mobile_ui/premium/styles/gradients.dart'; -import 'package:filcnaplo_premium/providers/premium_provider.dart'; -import 'package:filcnaplo_premium/ui/mobile/premium/activation_view/activation_view.dart'; -import 'package:filcnaplo_premium/ui/mobile/premium/upsell.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_svg/svg.dart'; -import 'package:provider/provider.dart'; - -class PremiumScreen extends StatelessWidget { - const PremiumScreen({super.key}); - - @override - Widget build(BuildContext context) { - final middleColor = Theme.of(context).brightness == Brightness.dark - ? const Color.fromARGB(255, 20, 57, 46) - : const Color.fromARGB(255, 10, 140, 123); - - final future = FilcAPI.getSupporters(); - - return FutureBuilder( - future: future, - builder: (context, snapshot) { - return Scaffold( - body: CustomScrollView( - physics: const ClampingScrollPhysics(), - slivers: [ - SliverAppBar( - surfaceTintColor: Theme.of(context).scaffoldBackgroundColor, - automaticallyImplyLeading: false, - flexibleSpace: Container( - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [ - const Color(0xff124F3D), - middleColor, - ], - ), - ), - ), - actions: [ - Padding( - padding: const EdgeInsets.only(right: 8.0), - child: IconButton( - onPressed: () { - Navigator.of(context).pop(); - }, - icon: const Icon(Icons.close, color: Colors.white), - ), - ), - ], - ), - SliverPadding( - padding: const EdgeInsets.only(bottom: 25.0), - sliver: SliverToBoxAdapter( - child: Container( - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [ - middleColor, - Theme.of(context).scaffoldBackgroundColor, - ], - ), - ), - child: Row( - children: [ - Expanded( - child: Padding( - padding: - const EdgeInsets.symmetric(horizontal: 24.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox(height: 64.0), - Image.asset("assets/images/logo.png"), - const SizedBox(height: 12.0), - const Text( - "Még több filc.", - style: TextStyle( - fontWeight: FontWeight.w600, - fontSize: 25.0, - color: Colors.white), - ), - const Text( - "reFilc Premium.", - style: TextStyle( - fontWeight: FontWeight.w800, - fontSize: 35.0, - color: Colors.white), - ), - const SizedBox(height: 15.0), - Text( - "Támogasd a filcet, és szerezz cserébe pár kényelmes jutalmat!", - style: TextStyle( - fontWeight: FontWeight.w500, - fontSize: 20, - color: Colors.white.withOpacity(.8)), - ), - const SizedBox(height: 25.0), - SupportersButton(supporters: future), - ], - ), - ), - ), - ], - ), - ), - ), - ), - SliverPadding( - padding: const EdgeInsets.symmetric(horizontal: 24.0) - .add(const EdgeInsets.only(bottom: 100)), - sliver: SliverToBoxAdapter( - child: Column( - children: [ - PremiumPlanCard( - icon: const Icon(FilcIcons.kupak), - title: Text("Kupak", - style: TextStyle( - foreground: GradientStyles.kupakPaint)), - gradient: GradientStyles.kupak, - price: 2, - description: const Text( - "Szabd személyre a filcet és láss részletesebb statisztikákat."), - url: - "https://github.com/sponsors/filc/sponsorships?tier_id=238453&preview=true", - active: ActiveSponsorCard.estimateLevel( - context.watch().scopes) == - PremiumFeatureLevel.cap, - ), - const SizedBox(height: 8.0), - PremiumPlanCard( - icon: const Icon(FilcIcons.tinta), - title: Text("Tinta", - style: TextStyle( - foreground: GradientStyles.tintaPaint)), - gradient: GradientStyles.tinta, - price: 5, - description: const Text( - "Kényelmesebb órarend, asztali alkalmazás és célok kitűzése."), - url: - "https://github.com/sponsors/filc/sponsorships?tier_id=238454&preview=true", - active: ActiveSponsorCard.estimateLevel( - context.watch().scopes) == - PremiumFeatureLevel.ink, - ), - const SizedBox(height: 12.0), - PremiumGoalCard( - progress: snapshot.data?.progress ?? 0, - target: snapshot.data?.max ?? 1), - const SizedBox(height: 12.0), - const GithubConnectButton(), - Padding( - padding: const EdgeInsets.symmetric(vertical: 14.0) - .add(const EdgeInsets.only(top: 12.0)), - child: const Row( - children: [ - Icon(FilcIcons.kupak), - SizedBox(width: 12.0), - Expanded( - child: Text( - "Kupak jutalmak", - style: TextStyle( - fontWeight: FontWeight.w500, - fontSize: 20), - ), - ), - ], - ), - ), - PremiumRewardCard( - imageKey: "premium_nickname_showcase", - icon: SvgPicture.asset( - "assets/images/nickname_icon.svg", - color: Theme.of(context).iconTheme.color), - title: const Text("Profil személyre szabás"), - description: const Text( - "Állíts be egy saját becenevet és egy profilképet (akár animáltat is!)"), - ), - const SizedBox(height: 14.0), - PremiumRewardCard( - imageKey: "premium_theme_showcase", - icon: SvgPicture.asset("assets/images/theme_icon.svg", - color: Theme.of(context).iconTheme.color), - title: const Text("Téma+"), - description: const Text( - "Válassz saját háttérszínt és kártyaszínt is, akár saját HEX-kóddal!"), - ), - const SizedBox(height: 14.0), - PremiumRewardCard( - imageKey: "premium_stats_showcase", - icon: SvgPicture.asset("assets/images/stats_icon.svg", - color: Theme.of(context).iconTheme.color), - title: const Text("Részletes jegy statisztika"), - description: const Text( - "Válassz heti, havi és háromhavi időtartam közül, és pontosan lásd, mennyi jegyed van."), - ), - const SizedBox(height: 14.0), - const PremiumRewardCard( - title: Text("Még pár dolog..."), - description: Text( - "🔣\tVálassz ikon témát\n✨\tPrémium rang és csevegő a discord szerverünkön\n📬\tElsőbbségi segítségnyújtás"), - ), - Padding( - padding: const EdgeInsets.symmetric(vertical: 14.0) - .add(const EdgeInsets.only(top: 12.0)), - child: const Row( - children: [ - Icon(FilcIcons.tinta), - SizedBox(width: 12.0), - Expanded( - child: Text( - "Tinta jutalmak", - style: TextStyle( - fontWeight: FontWeight.w500, - fontSize: 20), - ), - ), - ], - ), - ), - PremiumRewardCard( - imageKey: "premium_timetable_showcase", - icon: SvgPicture.asset( - "assets/images/timetable_icon.svg", - color: Theme.of(context).iconTheme.color), - title: const Text("Heti órarend nézet"), - description: const Text( - "Egy órarend, ami a teljes képernyődet kihasználja, csak nem olyan idegesítő, mint az eKRÉTA féle."), - ), - const SizedBox(height: 14.0), - PremiumRewardCard( - imageKey: "premium_widget_showcase", - icon: SvgPicture.asset( - "assets/images/widget_icon.svg", - color: Theme.of(context).iconTheme.color), - title: const Text("Widget"), - description: const Text( - "Mindig lásd, milyen órád lesz, a kezdőképernyőd kényelméből."), - ), - const SizedBox(height: 14.0), - PremiumRewardCard( - soon: true, - imageKey: "premium_goal_showcase", - icon: SvgPicture.asset("assets/images/goal_icon.svg", - color: Theme.of(context).iconTheme.color), - title: const Text("Cél követés"), - description: const Text( - "Add meg, mi a célod, és mi majd kiszámoljuk, hogyan juthatsz oda!"), - ), - const SizedBox(height: 14.0), - PremiumRewardCard( - soon: true, - imageKey: "premium_desktop_showcase", - icon: SvgPicture.asset( - "assets/images/desktop_icon.svg", - color: Theme.of(context).iconTheme.color), - title: const Text("Asztali verzió"), - description: const Text( - "Érd el a reFilcet a gépeden is, és menekülj meg a csúnya felhasználói felületektől!"), - ), - const SizedBox(height: 14.0), - const PremiumRewardCard( - title: Text("Még pár dolog..."), - description: Text( - "🖋️\tMinden kupak jutalom\n✨\tKorai hozzáférés új verziókhoz"), - ), - Padding( - padding: const EdgeInsets.symmetric(vertical: 14.0) - .add(const EdgeInsets.only(top: 12.0)), - child: const Row( - children: [ - SizedBox(width: 12.0), - Expanded( - child: Text( - "Mire vársz még?", - style: TextStyle( - fontWeight: FontWeight.w500, - fontSize: 20), - ), - ), - ], - ), - ), - GithubCard( - onPressed: () { - Navigator.of(context) - .push(MaterialPageRoute(builder: (context) { - return const PremiumActivationView(); - })); - }, - ), - Padding( - padding: const EdgeInsets.symmetric(vertical: 14.0) - .add(const EdgeInsets.only(top: 12.0)), - child: const Row( - children: [ - SizedBox(width: 12.0), - Expanded( - child: Text( - "Gyakori kérdések", - style: TextStyle( - fontWeight: FontWeight.w500, - fontSize: 20), - ), - ), - ], - ), - ), - const PremiumRewardCard( - title: Text("Mire költitek a pénzt?"), - description: Text( - "A pénz elsősorban az appstore évi \$100-os díját fedezi, a maradék a szerver a weboldal és új funkciók fejlesztésére fordítjuk."), - ), - const SizedBox(height: 14.0), - const PremiumRewardCard( - title: Text("Még mindig nyílt a forráskód?"), - description: Text( - "Igen, a reFilc teljesen nyílt forráskódú, és ez így is fog maradni. A prémium funkciók forráskódjához hozzáférnek a támogatók."), - ), - const SizedBox(height: 14.0), - const PremiumRewardCard( - title: Text("Hol tudok támogatni?"), - description: Text( - "A támogatáshoz szükséged van egy Github profilra, amit hozzá kell kötnöd a filc naplóhoz. A Github “Sponsors” funkciója segítségével kezeljük az támogatásod."), - ), - ], - ), - ), - ), - ], - ), - ); - }); - } -} diff --git a/filcnaplo_mobile_ui/lib/screens/login/login_screen.i18n.dart b/filcnaplo_mobile_ui/lib/screens/login/login_screen.i18n.dart deleted file mode 100755 index c73dff0..0000000 --- a/filcnaplo_mobile_ui/lib/screens/login/login_screen.i18n.dart +++ /dev/null @@ -1,55 +0,0 @@ -import 'package:i18n_extension/i18n_extension.dart'; - -extension Localization on String { - static final _t = Translations.byLocale("hu_hu") + - { - "en_en": { - "username": "Username", - "usernameHint": "Student ID number", - "password": "Password", - "passwordHint": "Date of birth", - "school": "School", - "login": "Log in", - "welcome": "Welcome, %s!", - "missing_fields": "Missing Fields!", - "invalid_grant": - // "Invalid Username/Password! (Try adding spaces after Username)", - "Invalid Username/Password!", - "error": "Failed to log in.", - "schools_error": "Failed to get schools." - }, - "hu_hu": { - "username": "Felhasználónév", - "usernameHint": "Oktatási azonosító", - "password": "Jelszó", - "passwordHint": "Születési dátum", - "school": "Iskola", - "login": "Belépés", - "welcome": "Üdv, %s!", - "missing_fields": "Hiányzó adatok!", - "invalid_grant": - // "Helytelen Felhasználónév/Jelszó! (Próbálj szóközöket írni a Felhasználónév után)", - "Helytelen Felhasználónév/Jelszó!", - "error": "Sikertelen bejelentkezés.", - "schools_error": "Nem sikerült lekérni az iskolákat." - }, - "de_de": { - "username": "Benutzername", - "usernameHint": "Ausbildung ID", - "password": "Passwort", - "passwordHint": "Geburtsdatum", - "school": "Schule", - "login": "Einloggen", - "welcome": "Wilkommen, %s!", - "missing_fields": "Fehlende Felder!", - "invalid_grant": "Ungültiger Benutzername/Passwort!", - "error": "Anmeldung fehlgeschlagen.", - "schools_error": "Keine Schulen gefunden." - }, - }; - - String get i18n => localize(this, _t); - String fill(List params) => localizeFill(this, params); - String plural(int value) => localizePlural(value, this, _t); - String version(Object modifier) => localizeVersion(modifier, this, _t); -} diff --git a/filcnaplo_mobile_ui/lib/screens/navigation/navigation_screen.dart b/filcnaplo_mobile_ui/lib/screens/navigation/navigation_screen.dart deleted file mode 100755 index 5d15fea..0000000 --- a/filcnaplo_mobile_ui/lib/screens/navigation/navigation_screen.dart +++ /dev/null @@ -1,342 +0,0 @@ -import 'package:filcnaplo/api/providers/update_provider.dart'; -import 'package:filcnaplo/helpers/quick_actions.dart'; -import 'package:filcnaplo/models/settings.dart'; -import 'package:filcnaplo/theme/observer.dart'; -import 'package:filcnaplo_kreta_api/client/client.dart'; -import 'package:filcnaplo_kreta_api/providers/grade_provider.dart'; -import 'package:filcnaplo_mobile_ui/common/system_chrome.dart'; -import 'package:filcnaplo_mobile_ui/screens/navigation/nabar.dart'; -import 'package:filcnaplo_mobile_ui/screens/navigation/navbar_item.dart'; -import 'package:filcnaplo_mobile_ui/screens/navigation/navigation_route.dart'; -import 'package:filcnaplo_mobile_ui/screens/navigation/navigation_route_handler.dart'; -import 'package:filcnaplo/icons/filc_icons.dart'; -import 'package:filcnaplo_mobile_ui/screens/navigation/status_bar.dart'; -import 'package:filcnaplo_mobile_ui/screens/news/news_view.dart'; -import 'package:filcnaplo_mobile_ui/screens/settings/settings_screen.dart'; -import 'package:filcnaplo_premium/ui/mobile/goal_planner/goal_complete_modal.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_feather_icons/flutter_feather_icons.dart'; -import 'package:provider/provider.dart'; -import 'package:filcnaplo_mobile_ui/common/screens.i18n.dart'; -import 'package:filcnaplo/api/providers/news_provider.dart'; -import 'package:filcnaplo/api/providers/sync.dart'; -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({super.key}); - - static NavigationScreenState? of(BuildContext context) => - context.findAncestorStateOfType(); - - @override - NavigationScreenState createState() => NavigationScreenState(); -} - -class NavigationScreenState extends State - with WidgetsBindingObserver { - late NavigationRoute selected; - List initializers = []; - final _navigatorState = GlobalKey(); - - late SettingsProvider settings; - late NewsProvider newsProvider; - late GoalProvider goalProvider; - late UpdateProvider updateProvider; - late GradeProvider gradeProvicer; - late AdProvider adProvider; - - NavigatorState? get navigator => _navigatorState.currentState; - - void customRoute(Route route) => navigator?.pushReplacement(route); - - bool init(String id) { - if (initializers.contains(id)) return false; - - initializers.add(id); - - return true; - } - - void _checkForWidgetLaunch() { - HomeWidget.initiallyLaunchedFromHomeWidget().then(_launchedFromWidget); - } - - void _launchedFromWidget(Uri? uri) async { - if (uri == null) return; - - if (uri.scheme == "timetable" && uri.authority == "refresh") { - Navigator.of(context).popUntil((route) => route.isFirst); - - setPage("timetable"); - _navigatorState.currentState - ?.pushNamedAndRemoveUntil("timetable", (_) => false); - } else if (uri.scheme == "settings" && uri.authority == "premium") { - Navigator.of(context).popUntil((route) => route.isFirst); - - showSlidingBottomSheet( - context, - useRootNavigator: true, - builder: (context) => SlidingSheetDialog( - color: Theme.of(context).scaffoldBackgroundColor, - duration: const Duration(milliseconds: 400), - scrollSpec: const ScrollSpec.bouncingScroll(), - snapSpec: const SnapSpec( - snap: true, - snappings: [1.0], - initialSnap: 1.0, - positioning: SnapPositioning.relativeToSheetHeight, - ), - cornerRadius: 16, - cornerRadiusOnFullscreen: 0, - builder: (context, state) => Material( - color: Theme.of(context).scaffoldBackgroundColor, - child: const SettingsScreen(), - ), - ), - ); - } - } - - // Platform messages are asynchronous, so we initialize in an async method. - Future initPlatformState() async { - // Configure BackgroundFetch. - int status = await BackgroundFetch.configure( - BackgroundFetchConfig( - minimumFetchInterval: 15, - stopOnTerminate: false, - enableHeadless: true, - requiresBatteryNotLow: false, - requiresCharging: false, - requiresStorageNotLow: false, - requiresDeviceIdle: false, - requiredNetworkType: NetworkType.ANY), (String taskId) async { - // <-- Event handler - // This is the fetch-event callback. - if (kDebugMode) { - print("[BackgroundFetch] Event received $taskId"); - } - - // IMPORTANT: You must signal completion of your task or the OS can punish your app - // for taking too long in the background. - BackgroundFetch.finish(taskId); - }, (String taskId) async { - // <-- Task timeout handler. - // This task has exceeded its allowed running-time. You must stop what you're doing and immediately .finish(taskId) - if (kDebugMode) { - print("[BackgroundFetch] TASK TIMEOUT taskId: $taskId"); - } - BackgroundFetch.finish(taskId); - }); - if (kDebugMode) { - print('[BackgroundFetch] configure success: $status'); - } - - // If the widget was removed from the tree while the asynchronous platform - // message was in flight, we want to discard the reply rather than calling - // setState to update our non-existent appearance. - if (!mounted) return; - } - - @override - void initState() { - super.initState(); - - HomeWidget.setAppGroupId('hu.refilc.naplo.group'); - - _checkForWidgetLaunch(); - HomeWidget.widgetClicked.listen(_launchedFromWidget); - - settings = Provider.of(context, listen: false); - selected = NavigationRoute(); - selected.index = settings.startPage.index; // set page index to start page - - // add brightness observer - WidgetsBinding.instance.addObserver(this); - - // set client User-Agent - Provider.of(context, listen: false).userAgent = - settings.config.userAgent; - - // get news - newsProvider = Provider.of(context, listen: false); - newsProvider.restore().then((value) => newsProvider.fetch()); - - // init grade provider (for goals) - gradeProvicer = Provider.of(context, listen: false); - - // get goals - goalProvider = Provider.of(context, listen: false); - goalProvider.fetchDone(gradeProvider: gradeProvicer); - - // get releases - updateProvider = Provider.of(context, listen: false); - updateProvider.fetch(); - - // get advertisements - adProvider = Provider.of(context, listen: false); - adProvider.fetch(); - - // initial sync - syncAll(context); - setupQuickActions(); - } - - @override - void dispose() { - WidgetsBinding.instance.removeObserver(this); - super.dispose(); - } - - @override - void didChangePlatformBrightness() { - if (settings.theme == ThemeMode.system) { - // ignore: deprecated_member_use - Brightness? brightness = - // ignore: deprecated_member_use - WidgetsBinding.instance.window.platformBrightness; - Provider.of(context, listen: false).changeTheme( - brightness == Brightness.light ? ThemeMode.light : ThemeMode.dark); - } - super.didChangePlatformBrightness(); - } - - void setPage(String page) => setState(() => selected.name = page); - - @override - Widget build(BuildContext context) { - setSystemChrome(context); - settings = Provider.of(context); - newsProvider = Provider.of(context); - goalProvider = Provider.of(context); - - // show news and complete goals - WidgetsBinding.instance.addPostFrameCallback((_) { - if (newsProvider.show) { - NewsView.show(newsProvider.news[0], context: context) - .then((value) => newsProvider.release()); - newsProvider.lock(); - } - - if (goalProvider.hasDoneGoals) { - GoalCompleteModal.show(goalProvider.doneSubject!, context: context); - goalProvider.lock(); - } - }); - - handleQuickActions(context, (page) { - setPage(page); - _navigatorState.currentState?.pushReplacementNamed(page); - }); - - // ignore: deprecated_member_use - return WillPopScope( - onWillPop: () async { - if (_navigatorState.currentState?.canPop() ?? false) { - _navigatorState.currentState?.pop(); - if (!kDebugMode) { - return true; - } - return false; - } - - if (selected.index != 0) { - setState(() => selected.index = 0); - _navigatorState.currentState?.pushReplacementNamed(selected.name); - } - - return false; - }, - child: Scaffold( - body: Column( - children: [ - Expanded( - child: Stack( - alignment: Alignment.bottomCenter, - children: [ - Navigator( - key: _navigatorState, - initialRoute: selected.name, - onGenerateRoute: (settings) => - navigationRouteHandler(settings), - ), - ], - ), - ), - - // Status bar - Material( - color: Theme.of(context).colorScheme.background, - child: const StatusBar(), - ), - - // Bottom Navigaton Bar - Material( - color: Theme.of(context).scaffoldBackgroundColor, - child: MediaQuery.removePadding( - context: context, - removeTop: true, - child: Navbar( - selectedIndex: selected.index, - onSelected: onPageSelected, - items: [ - NavItem( - title: "home".i18n, - icon: const Icon(FilcIcons.home), - activeIcon: const Icon(FilcIcons.homefill), - ), - NavItem( - title: "grades".i18n, - icon: const Icon(FeatherIcons.bookmark), - activeIcon: const Icon(FilcIcons.gradesfill), - ), - NavItem( - title: "timetable".i18n, - icon: const Icon(FeatherIcons.calendar), - activeIcon: const Icon(FilcIcons.timetablefill), - ), - NavItem( - title: "messages".i18n, - icon: const Icon(FeatherIcons.messageSquare), - activeIcon: const Icon(FilcIcons.messagesfill), - ), - NavItem( - title: "absences".i18n, - icon: const Icon(FeatherIcons.clock), - activeIcon: const Icon(FilcIcons.absencesfill), - ), - ], - ), - ), - ), - ], - ), - ), - ); - } - - void onPageSelected(int index) { - // Vibrate, then set the active screen - if (selected.index != index) { - switch (settings.vibrate) { - case VibrationStrength.light: - HapticFeedback.lightImpact(); - break; - case VibrationStrength.medium: - HapticFeedback.mediumImpact(); - break; - case VibrationStrength.strong: - HapticFeedback.heavyImpact(); - break; - default: - } - setState(() => selected.index = index); - _navigatorState.currentState?.pushReplacementNamed(selected.name); - } - } -} diff --git a/filcnaplo_mobile_ui/lib/screens/settings/notifications_screen.dart b/filcnaplo_mobile_ui/lib/screens/settings/notifications_screen.dart deleted file mode 100644 index 6f90f82..0000000 --- a/filcnaplo_mobile_ui/lib/screens/settings/notifications_screen.dart +++ /dev/null @@ -1,226 +0,0 @@ -import 'package:filcnaplo/models/settings.dart'; -import 'package:filcnaplo/theme/colors/colors.dart'; -import 'package:filcnaplo_mobile_ui/common/beta_chip.dart'; -import 'package:filcnaplo_mobile_ui/common/panel/panel.dart'; -import 'package:filcnaplo_mobile_ui/common/panel/panel_button.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_feather_icons/flutter_feather_icons.dart'; -import 'package:provider/provider.dart'; -import 'notifications_screen.i18n.dart'; - -class MenuNotifications extends StatelessWidget { - const MenuNotifications({super.key, required this.settings}); - - final SettingsProvider settings; - - @override - Widget build(BuildContext context) { - return PanelButton( - padding: const EdgeInsets.only(left: 14.0), - onPressed: () { - Navigator.of(context, rootNavigator: true).push( - CupertinoPageRoute(builder: (context) => const NotificationsScreen()), - ); - }, - title: Row( - children: [ - Text( - "notifications_screen".i18n, - style: TextStyle( - color: AppColors.of(context) - .text - .withOpacity(settings.notificationsEnabled ? 1.0 : .5)), - ), - const SizedBox(width: 5.0), - BetaChip( - disabled: !settings.notificationsEnabled, - ), - ], - ), - leading: settings.notificationsEnabled - ? const Icon(FeatherIcons.messageSquare) - : Icon(FeatherIcons.messageSquare, - color: AppColors.of(context).text.withOpacity(.25)), - trailingDivider: true, - trailing: Switch( - onChanged: (v) async { - settings.update(notificationsEnabled: v); - }, - value: settings.notificationsEnabled, - activeColor: Theme.of(context).colorScheme.secondary, - ), - ); - } -} - -class NotificationsScreen extends StatelessWidget { - const NotificationsScreen({super.key}); - - @override - Widget build(BuildContext context) { - SettingsProvider settings = Provider.of(context); - - return Scaffold( - appBar: AppBar( - surfaceTintColor: Theme.of(context).scaffoldBackgroundColor, - leading: BackButton(color: AppColors.of(context).text), - title: Text( - "notifications_screen".i18n, - style: TextStyle(color: AppColors.of(context).text), - ), - ), - body: SingleChildScrollView( - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 24.0), - child: Panel( - child: Column( - children: [ - Material( - type: MaterialType.transparency, - child: SwitchListTile( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12.0)), - value: settings.notificationsGradesEnabled, - onChanged: (v) => - settings.update(notificationsGradesEnabled: v), - title: Row( - children: [ - Icon( - FeatherIcons.bookmark, - color: settings.notificationsGradesEnabled - ? Theme.of(context).colorScheme.secondary - : AppColors.of(context).text.withOpacity(.25), - ), - const SizedBox(width: 14.0), - Expanded( - child: Text( - "grades".i18n, - style: TextStyle( - fontWeight: FontWeight.w600, - fontSize: 16.0, - color: AppColors.of(context).text.withOpacity( - settings.notificationsGradesEnabled - ? 1.0 - : .5, - ), - ), - ), - ), - ], - ), - ), - ), - Material( - type: MaterialType.transparency, - child: SwitchListTile( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12.0)), - value: settings.notificationsAbsencesEnabled, - onChanged: (v) => - settings.update(notificationsAbsencesEnabled: v), - title: Row( - children: [ - Icon( - FeatherIcons.clock, - color: settings.notificationsAbsencesEnabled - ? Theme.of(context).colorScheme.secondary - : AppColors.of(context).text.withOpacity(.25), - ), - const SizedBox(width: 14.0), - Expanded( - child: Text( - "absences".i18n, - style: TextStyle( - fontWeight: FontWeight.w600, - fontSize: 16.0, - color: AppColors.of(context).text.withOpacity( - settings.notificationsAbsencesEnabled - ? 1.0 - : .5, - ), - ), - ), - ), - ], - ), - ), - ), - Material( - type: MaterialType.transparency, - child: SwitchListTile( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12.0)), - value: settings.notificationsMessagesEnabled, - onChanged: (v) => - settings.update(notificationsMessagesEnabled: v), - title: Row( - children: [ - Icon( - FeatherIcons.messageSquare, - color: settings.notificationsMessagesEnabled - ? Theme.of(context).colorScheme.secondary - : AppColors.of(context).text.withOpacity(.25), - ), - const SizedBox(width: 14.0), - Expanded( - child: Text( - "messages".i18n, - style: TextStyle( - fontWeight: FontWeight.w600, - fontSize: 16.0, - color: AppColors.of(context).text.withOpacity( - settings.notificationsMessagesEnabled - ? 1.0 - : .5, - ), - ), - ), - ), - ], - ), - ), - ), - Material( - type: MaterialType.transparency, - child: SwitchListTile( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12.0)), - value: settings.notificationsLessonsEnabled, - onChanged: (v) => - settings.update(notificationsLessonsEnabled: v), - title: Row( - children: [ - Icon( - FeatherIcons.calendar, - color: settings.notificationsLessonsEnabled - ? Theme.of(context).colorScheme.secondary - : AppColors.of(context).text.withOpacity(.25), - ), - const SizedBox(width: 14.0), - Expanded( - child: Text( - "lessons".i18n, - style: TextStyle( - fontWeight: FontWeight.w600, - fontSize: 16.0, - color: AppColors.of(context).text.withOpacity( - settings.notificationsLessonsEnabled - ? 1.0 - : .5, - ), - ), - ), - ), - ], - ), - ), - ), - ], - ), - ), - ), - ), - ); - } -} diff --git a/filcnaplo_mobile_ui/lib/screens/settings/settings_screen.dart b/filcnaplo_mobile_ui/lib/screens/settings/settings_screen.dart deleted file mode 100755 index 55832aa..0000000 --- a/filcnaplo_mobile_ui/lib/screens/settings/settings_screen.dart +++ /dev/null @@ -1,1093 +0,0 @@ -// ignore_for_file: no_leading_underscores_for_local_identifiers, use_build_context_synchronously, deprecated_member_use - -import 'package:filcnaplo/api/providers/update_provider.dart'; -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'; -import 'package:filcnaplo_kreta_api/providers/grade_provider.dart'; -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/api/providers/user_provider.dart'; -import 'package:filcnaplo/api/providers/database_provider.dart'; -import 'package:filcnaplo/utils/format.dart'; -import 'package:filcnaplo/models/settings.dart'; -import 'package:filcnaplo/models/user.dart'; -import 'package:filcnaplo/theme/colors/colors.dart'; -import 'package:filcnaplo_kreta_api/client/client.dart'; -import 'package:filcnaplo_mobile_ui/common/action_button.dart'; -import 'package:filcnaplo_mobile_ui/common/bottom_sheet_menu/bottom_sheet_menu.dart'; -import 'package:filcnaplo_mobile_ui/common/bottom_sheet_menu/bottom_sheet_menu_item.dart'; -import 'package:filcnaplo_mobile_ui/common/panel/panel.dart'; -import 'package:filcnaplo_mobile_ui/common/panel/panel_button.dart'; -import 'package:filcnaplo_mobile_ui/common/profile_image/profile_image.dart'; -import 'package:filcnaplo_mobile_ui/common/system_chrome.dart'; -import 'package:filcnaplo_mobile_ui/common/widgets/update/updates_view.dart'; -import 'package:filcnaplo_mobile_ui/screens/news/news_screen.dart'; -import 'package:filcnaplo_mobile_ui/screens/settings/accounts/account_tile.dart'; -import 'package:filcnaplo_mobile_ui/screens/settings/accounts/account_view.dart'; -import 'package:filcnaplo_mobile_ui/screens/settings/debug/subject_icon_gallery.dart'; -import 'package:filcnaplo_mobile_ui/screens/settings/modify_subject_names.dart'; -import 'package:filcnaplo_mobile_ui/screens/settings/notifications_screen.dart'; -import 'package:filcnaplo_mobile_ui/screens/settings/privacy_view.dart'; -import 'package:filcnaplo_mobile_ui/screens/settings/settings_helper.dart'; -import 'package:filcnaplo_premium/ui/mobile/settings/app_icon_screen.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_custom_tabs/flutter_custom_tabs.dart' as tabs; -import 'package:flutter_feather_icons/flutter_feather_icons.dart'; -import 'package:provider/provider.dart'; -import 'package:url_launcher/url_launcher.dart'; -import 'settings_screen.i18n.dart'; -import 'package:flutter/services.dart'; -import 'package:filcnaplo_mobile_ui/screens/settings/user/nickname.dart'; -import 'package:filcnaplo_mobile_ui/screens/settings/user/profile_pic.dart'; -import 'package:filcnaplo_premium/ui/mobile/settings/modify_teacher_names.dart'; -import 'package:filcnaplo_premium/ui/mobile/settings/welcome_message.dart'; - -class SettingsScreen extends StatefulWidget { - const SettingsScreen({super.key}); - - @override - SettingsScreenState createState() => SettingsScreenState(); -} - -class SettingsScreenState extends State - with SingleTickerProviderStateMixin { - int devmodeCountdown = 5; - bool __ss = false; // secret settings - - Future? futureRelease; - - late UserProvider user; - late UpdateProvider updateProvider; - late SettingsProvider settings; - late KretaClient kretaClient; - late String firstName; - List accountTiles = []; - - late AnimationController _hideContainersController; - - Future restore() => Future.wait([ - Provider.of(context, listen: false).restore(), - Provider.of(context, listen: false).restoreUser(), - Provider.of(context, listen: false).restore(), - Provider.of(context, listen: false).restore(), - Provider.of(context, listen: false).restore(), - Provider.of(context, listen: false) - .restoreRecipients(), - Provider.of(context, listen: false).restore(), - Provider.of(context, listen: false).restore(), - Provider.of(context, listen: false).restore(), - Provider.of(context, listen: false).refreshLogin(), - ]); - - void buildAccountTiles() { - accountTiles = []; - user.getUsers().forEach((account) { - if (account.id == user.id) return; - - String _firstName; - - List _nameParts = - (account.nickname != '' ? account.nickname : account.displayName) - .split(" "); - if (!settings.presentationMode) { - _firstName = _nameParts.length > 1 ? _nameParts[1] : _nameParts[0]; - } else { - _firstName = "János"; - } - - accountTiles.add( - AccountTile( - name: Text( - !settings.presentationMode - ? (account.nickname != '' ? account.nickname : account.name) - : "János", - style: const TextStyle(fontWeight: FontWeight.w500)), - username: Text( - !settings.presentationMode ? account.username : "01234567890"), - profileImage: ProfileImage( - name: _firstName, - role: account.role, - profilePictureString: account.picture, - backgroundColor: Theme.of(context) - .colorScheme - .primary, //!settings.presentationMode - //? ColorUtils.stringToColor(account.name) - //: Theme.of(context).colorScheme.secondary, - ), - onTap: () { - user.setUser(account.id); - restore().then((_) => user.setUser(account.id)); - Navigator.of(context).pop(); - }, - onTapMenu: () => _showBottomSheet(account), - ), - ); - }); - } - - void _showBottomSheet(User u) { - showBottomSheetMenu(context, items: [ - BottomSheetMenuItem( - onPressed: () => AccountView.show(u, context: context), - icon: const Icon(FeatherIcons.user), - title: Text("personal_details".i18n), - ), - BottomSheetMenuItem( - onPressed: () => _openDKT(u), - icon: Icon(FeatherIcons.grid, color: AppColors.of(context).teal), - title: Text("open_dkt".i18n), - ), - UserMenuNickname(u), - UserMenuProfilePic(u), - // BottomSheetMenuItem( - // onPressed: () {}, - // icon: Icon(FeatherIcons.camera), - // title: Text("edit_profile_picture".i18n), - // ), - // BottomSheetMenuItem( - // onPressed: () {}, - // icon: Icon(FeatherIcons.trash2, color: AppColors.of(context).red), - // title: Text("remove_profile_picture".i18n), - // ), - ]); - } - - void _openDKT(User u) => tabs.launch( - "https://dkttanulo.e-kreta.hu/sso?id_token=${kretaClient.idToken}", - customTabsOption: tabs.CustomTabsOption( - toolbarColor: Theme.of(context).scaffoldBackgroundColor, - showPageTitle: true, - )); - - @override - void initState() { - super.initState(); - Future.delayed(Duration.zero, () { - futureRelease = Provider.of(context, listen: false) - .installedVersion(); - }); - _hideContainersController = AnimationController( - vsync: this, duration: const Duration(milliseconds: 200)); - } - - @override - Widget build(BuildContext context) { - user = Provider.of(context); - settings = Provider.of(context); - updateProvider = Provider.of(context); - kretaClient = Provider.of(context); - - List nameParts = user.displayName?.split(" ") ?? ["?"]; - if (!settings.presentationMode) { - firstName = nameParts.length > 1 ? nameParts[1] : nameParts[0]; - } else { - firstName = "János"; - } - - String startPageTitle = - SettingsHelper.localizedPageTitles()[settings.startPage] ?? "?"; - String themeModeText = { - ThemeMode.light: "light".i18n, - ThemeMode.dark: "dark".i18n, - ThemeMode.system: "system".i18n - }[settings.theme] ?? - "?"; - String languageText = SettingsHelper.langMap[settings.language] ?? "?"; - String vibrateTitle = { - VibrationStrength.off: "voff".i18n, - VibrationStrength.light: "vlight".i18n, - VibrationStrength.medium: "vmedium".i18n, - VibrationStrength.strong: "vstrong".i18n, - }[settings.vibrate] ?? - "?"; - - buildAccountTiles(); - - if (settings.developerMode) devmodeCountdown = -1; - - return AnimatedBuilder( - animation: _hideContainersController, - builder: (context, child) => Opacity( - opacity: 1 - _hideContainersController.value, - child: Column( - children: [ - const SizedBox(height: 45.0), - - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - IconButton( - splashRadius: 32.0, - onPressed: () => - _showBottomSheet(user.getUser(user.id ?? "")), - icon: Icon(FeatherIcons.moreVertical, - color: AppColors.of(context).text.withOpacity(0.8)), - ), - IconButton( - splashRadius: 26.0, - onPressed: () { - Navigator.of(context).pop(); - }, - icon: Icon(FeatherIcons.x, - color: AppColors.of(context).text.withOpacity(0.8)), - ), - ], - ), - - Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: ProfileImage( - heroTag: "profile", - radius: 36.0, - onTap: () => _showBottomSheet(user.getUser(user.id ?? "")), - name: firstName, - badge: updateProvider.available, - role: user.role, - profilePictureString: user.picture, - backgroundColor: Theme.of(context) - .colorScheme - .primary, //!settings.presentationMode - //? ColorUtils.stringToColor(user.displayName ?? "?") - //: Theme.of(context).colorScheme.secondary, - ), - ), - - Padding( - padding: const EdgeInsets.only(top: 4.0, bottom: 12.0), - child: GestureDetector( - onTap: () => _showBottomSheet(user.getUser(user.id ?? "")), - onDoubleTap: () => setState(() => __ss = true), - child: Text( - !settings.presentationMode - ? (user.displayName ?? "?") - : "János", - maxLines: 1, - softWrap: false, - overflow: TextOverflow.ellipsis, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 20.0, - fontWeight: FontWeight.w600, - color: AppColors.of(context).text), - ), - ), - ), - - Padding( - padding: - const EdgeInsets.symmetric(vertical: 12.0, horizontal: 24.0), - child: Panel( - child: Column( - children: [ - // account list - ...accountTiles, - - if (accountTiles.isNotEmpty) - Center( - child: Container( - margin: const EdgeInsets.only(top: 12.0, bottom: 4.0), - height: 3.0, - width: 75.0, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(12.0), - color: AppColors.of(context).text.withOpacity(.25), - ), - ), - ), - - // account settings - PanelButton( - onPressed: () { - Navigator.of(context) - .pushNamed("login_back") - .then((value) { - setSystemChrome(context); - }); - }, - title: Text("add_user".i18n), - leading: const Icon(FeatherIcons.userPlus), - ), - PanelButton( - onPressed: () async { - String? userId = user.id; - if (userId == null) return; - - // Delete User - user.removeUser(userId); - await Provider.of(context, - listen: false) - .store - .removeUser(userId); - - // If no other Users left, go back to LoginScreen - if (user.getUsers().isNotEmpty) { - user.setUser(user.getUsers().first.id); - restore().then( - (_) => user.setUser(user.getUsers().first.id)); - } else { - Navigator.of(context) - .pushNamedAndRemoveUntil("login", (_) => false); - } - }, - title: Text("log_out".i18n), - leading: Icon(FeatherIcons.logOut, - color: AppColors.of(context).red), - ), - ], - ), - ), - ), - - // updates - if (updateProvider.available) - Padding( - padding: const EdgeInsets.symmetric( - vertical: 12.0, horizontal: 24.0), - child: Panel( - child: PanelButton( - onPressed: () => _openUpdates(context), - title: Text("update_available".i18n), - leading: const Icon(FeatherIcons.download), - trailing: Text( - updateProvider.releases.first.tag, - style: TextStyle( - fontWeight: FontWeight.w500, - color: Theme.of(context).colorScheme.secondary, - ), - ), - ), - ), - ), - - // const Padding( - // padding: EdgeInsets.symmetric(vertical: 12.0, horizontal: 24.0), - // child: PremiumBannerButton(), - // ), - // if (!context.watch().hasPremium) - // const ClipRect( - // child: Padding( - // padding: EdgeInsets.symmetric(vertical: 12.0), - // child: PremiumButton(), - // ), - // ) - // else - // const Padding( - // padding: EdgeInsets.symmetric(vertical: 12.0, horizontal: 24.0), - // child: ActiveSponsorCard(), - // ), - - // secret settings - if (__ss) - Padding( - padding: const EdgeInsets.symmetric( - vertical: 12.0, horizontal: 24.0), - child: Panel( - title: Text("secret".i18n), - child: Column( - children: [ - // Good student mode - Material( - type: MaterialType.transparency, - child: SwitchListTile( - contentPadding: const EdgeInsets.only(left: 12.0), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12.0)), - title: Text("goodstudent".i18n, - style: - const TextStyle(fontWeight: FontWeight.w500)), - onChanged: (v) { - if (v) { - showDialog( - context: context, - builder: (context) => WillPopScope( - onWillPop: () async => false, - child: AlertDialog( - shape: RoundedRectangleBorder( - borderRadius: - BorderRadius.circular(12.0)), - title: Text("attention".i18n), - content: - Text("goodstudent_disclaimer".i18n), - actions: [ - ActionButton( - label: "understand".i18n, - onTap: () { - Navigator.of(context).pop(); - settings.update(goodStudent: v); - Provider.of(context, - listen: false) - .convertBySettings(); - }) - ], - ), - ), - ); - } else { - settings.update(goodStudent: v); - Provider.of(context, listen: false) - .convertBySettings(); - } - }, - value: settings.goodStudent, - activeColor: Theme.of(context).colorScheme.secondary, - ), - ), - - // Presentation mode - Material( - type: MaterialType.transparency, - child: SwitchListTile( - contentPadding: const EdgeInsets.only(left: 12.0), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12.0)), - title: Text("presentation".i18n, - style: - const TextStyle(fontWeight: FontWeight.w500)), - onChanged: (v) => - settings.update(presentationMode: v), - value: settings.presentationMode, - activeColor: Theme.of(context).colorScheme.secondary, - ), - ), - - // UwU-fied mode (why????) - // Material( - // type: MaterialType.transparency, - // child: SwitchListTile( - // contentPadding: const EdgeInsets.only(left: 12.0), - // shape: RoundedRectangleBorder( - // borderRadius: BorderRadius.circular(12.0)), - // title: Text("uwufymode".i18n, - // style: - // const TextStyle(fontWeight: FontWeight.w500)), - // onChanged: (v) { - // SettingsHelper.uwuMode(context, v); - // setState(() {}); - // }, - // value: settings.presentationMode, - // activeColor: Theme.of(context).colorScheme.secondary, - // ), - // ), - ], - ), - ), - ), - - // general things - Padding( - padding: - const EdgeInsets.symmetric(vertical: 12.0, horizontal: 24.0), - child: Panel( - title: Text("general".i18n), - child: Column( - children: [ - PanelButton( - onPressed: () { - SettingsHelper.language(context); - setState(() {}); - }, - title: Text("language".i18n), - leading: const Icon(FeatherIcons.globe), - trailing: Text( - languageText, - style: const TextStyle(fontSize: 14.0), - ), - ), - PanelButton( - onPressed: () { - SettingsHelper.startPage(context); - setState(() {}); - }, - title: Text("startpage".i18n), - leading: const Icon(FeatherIcons.play), - trailing: Text( - startPageTitle.capital(), - style: const TextStyle(fontSize: 14.0), - ), - ), - PanelButton( - onPressed: () { - SettingsHelper.rounding(context); - setState(() {}); - }, - title: Text("rounding".i18n), - leading: const Icon(FeatherIcons.gitCommit), - trailing: Text( - (settings.rounding / 10).toStringAsFixed(1), - style: const TextStyle(fontSize: 14.0), - ), - ), - PanelButton( - onPressed: () { - SettingsHelper.vibrate(context); - setState(() {}); - }, - title: Text("vibrate".i18n), - leading: const Icon(FeatherIcons.radio), - trailing: Text( - vibrateTitle, - style: const TextStyle(fontSize: 14.0), - ), - ), - PanelButton( - padding: const EdgeInsets.only(left: 14.0), - onPressed: () { - SettingsHelper.bellDelay(context); - setState(() {}); - }, - title: Text( - "bell_delay".i18n, - style: TextStyle( - color: AppColors.of(context).text.withOpacity( - settings.bellDelayEnabled ? 1.0 : .5)), - ), - leading: settings.bellDelayEnabled - ? const Icon(FeatherIcons.bell) - : Icon(FeatherIcons.bellOff, - color: - AppColors.of(context).text.withOpacity(.25)), - trailingDivider: true, - trailing: Switch( - onChanged: (v) => settings.update(bellDelayEnabled: v), - value: settings.bellDelayEnabled, - activeColor: Theme.of(context).colorScheme.secondary, - ), - ), - Material( - type: MaterialType.transparency, - child: MenuNotifications(settings: settings)), - WelcomeMessagePanelButton(settings, user), - ], - ), - ), - ), - - // icon gallery (debug mode) - if (kDebugMode) - Padding( - padding: const EdgeInsets.symmetric( - vertical: 12.0, horizontal: 24.0), - child: Panel( - title: const Text("Debug"), - child: Column( - children: [ - PanelButton( - title: const Text("Subject Icon Gallery"), - leading: - const Icon(CupertinoIcons.rectangle_3_offgrid_fill), - trailing: const Icon(Icons.arrow_forward), - onPressed: () { - Navigator.of(context, rootNavigator: true).push( - CupertinoPageRoute( - builder: (context) => - const SubjectIconGallery()), - ); - }, - ) - ], - ), - ), - ), - - // appearance things - Padding( - padding: - const EdgeInsets.symmetric(vertical: 12.0, horizontal: 24.0), - child: Panel( - title: Text("appearance".i18n), - child: Column( - children: [ - PanelButton( - onPressed: () { - SettingsHelper.theme(context); - setState(() {}); - }, - title: Text("theme".i18n), - leading: const Icon(FeatherIcons.sun), - trailing: Text( - themeModeText, - style: const TextStyle(fontSize: 14.0), - ), - ), - PanelButton( - onPressed: () async { - await _hideContainersController.forward(); - SettingsHelper.accentColor(context); - setState(() {}); - _hideContainersController.reset(); - }, - title: Text("color".i18n), - leading: const Icon(FeatherIcons.droplet), - trailing: Container( - width: 12.0, - height: 12.0, - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.secondary, - shape: BoxShape.circle, - ), - ), - ), - PanelButton( - onPressed: () { - SettingsHelper.gradeColors(context); - setState(() {}); - }, - title: Text("grade_colors".i18n), - leading: const Icon(FeatherIcons.star), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: List.generate( - 5, - (i) => Container( - margin: const EdgeInsets.only(left: 2.0), - width: 12.0, - height: 12.0, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: settings.gradeColors[i], - ), - ), - ), - ), - ), - Material( - type: MaterialType.transparency, - child: SwitchListTile( - contentPadding: const EdgeInsets.only(left: 12.0), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12.0)), - title: Row( - children: [ - Icon( - FeatherIcons.barChart, - color: settings.graphClassAvg - ? Theme.of(context).colorScheme.secondary - : AppColors.of(context).text.withOpacity(.25), - ), - const SizedBox(width: 14.0), - Expanded( - child: Text( - "graph_class_avg".i18n, - style: TextStyle( - fontWeight: FontWeight.w600, - fontSize: 16.0, - color: AppColors.of(context).text.withOpacity( - settings.graphClassAvg ? 1.0 : .5), - ), - ), - ), - ], - ), - onChanged: (v) => settings.update(graphClassAvg: v), - value: settings.graphClassAvg, - activeColor: Theme.of(context).colorScheme.secondary, - ), - ), - PanelButton( - onPressed: () { - SettingsHelper.iconPack(context); - }, - title: Text("icon_pack".i18n), - leading: const Icon(FeatherIcons.grid), - trailing: Text( - settings.iconPack.name.capital(), - style: const TextStyle(fontSize: 14.0), - ), - ), - - // if ios show live activity color option - if (defaultTargetPlatform == TargetPlatform.iOS) - PanelButton( - onPressed: () { - SettingsHelper.liveActivityColor(context); - setState(() {}); - }, - title: Text("live_activity_color".i18n), - leading: const Icon(FeatherIcons.activity), - trailing: Container( - width: 12.0, - height: 12.0, - decoration: BoxDecoration( - color: settings.liveActivityColor, - shape: BoxShape.circle, - ), - ), - ), - - Material( - type: MaterialType.transparency, - child: SwitchListTile( - contentPadding: const EdgeInsets.only(left: 14.0), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12.0)), - title: Row( - children: [ - Icon( - FeatherIcons.moon, - color: settings.shadowEffect - ? Theme.of(context).colorScheme.secondary - : AppColors.of(context).text.withOpacity(.25), - ), - const SizedBox(width: 14.0), - Expanded( - child: Text( - "shadow_effect".i18n, - style: TextStyle( - fontWeight: FontWeight.w600, - fontSize: 16.0, - color: AppColors.of(context).text.withOpacity( - settings.shadowEffect ? 1.0 : .5), - ), - ), - ), - ], - ), - onChanged: (v) => settings.update(shadowEffect: v), - value: settings.shadowEffect, - activeColor: Theme.of(context).colorScheme.secondary, - ), - ), - ], - ), - ), - ), - - // popup alerts - Padding( - padding: - const EdgeInsets.symmetric(vertical: 12.0, horizontal: 24.0), - child: Panel( - title: Text("popups".i18n), - child: Material( - type: MaterialType.transparency, - child: SwitchListTile( - contentPadding: const EdgeInsets.only(left: 12.0), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12.0)), - title: Row( - children: [ - Icon( - Icons.newspaper_outlined, - color: settings.newsEnabled - ? Theme.of(context).colorScheme.secondary - : AppColors.of(context).text.withOpacity(.25), - ), - const SizedBox(width: 14.0), - Expanded( - child: Text( - "news".i18n, - style: TextStyle( - fontWeight: FontWeight.w600, - fontSize: 16.0, - color: AppColors.of(context) - .text - .withOpacity(settings.newsEnabled ? 1.0 : .5), - ), - ), - ), - ], - ), - onChanged: (v) => settings.update(newsEnabled: v), - value: settings.newsEnabled, - activeColor: Theme.of(context).colorScheme.secondary, - ), - ), - ), - ), - - // extra settings - Padding( - padding: - const EdgeInsets.symmetric(vertical: 12.0, horizontal: 24.0), - child: Panel( - title: Text("extras".i18n), - child: Column( - children: [ - Material( - type: MaterialType.transparency, - child: SwitchListTile( - contentPadding: const EdgeInsets.only(left: 12.0), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12.0)), - title: Row( - children: [ - Icon( - FeatherIcons.gift, - color: settings.gradeOpeningFun - ? Theme.of(context).colorScheme.secondary - : AppColors.of(context).text.withOpacity(.25), - ), - const SizedBox(width: 14.0), - Expanded( - child: Text( - "surprise_grades".i18n, - style: TextStyle( - fontWeight: FontWeight.w600, - fontSize: 16.0, - color: AppColors.of(context).text.withOpacity( - settings.gradeOpeningFun ? 1.0 : .5), - ), - ), - ), - ], - ), - onChanged: (v) => settings.update(gradeOpeningFun: v), - value: settings.gradeOpeningFun, - activeColor: Theme.of(context).colorScheme.secondary, - ), - ), - MenuRenamedSubjects( - settings: settings, - ), - MenuRenamedTeachers( - settings: settings, - ), - PremiumCustomAppIconMenu( - settings: settings, - ), - // PanelButton( - // onPressed: () { - // SoonAlert.show(context: context); - // }, - // title: Text('app_icon'.i18n), - // leading: const Icon(FeatherIcons.edit), - // // trailing: Text( - // // 'default'.i18n, - // // style: const TextStyle(fontSize: 14.0), - // // ), - // ), - ], - ), - ), - ), - - // about sweetie - Padding( - padding: - const EdgeInsets.symmetric(vertical: 12.0, horizontal: 24.0), - child: Panel( - title: Text("about".i18n), - child: Column(children: [ - PanelButton( - leading: const Icon(FeatherIcons.mail), - title: Text("news".i18n), - onPressed: () => _openNews(context), - ), - PanelButton( - leading: const Icon(FeatherIcons.lock), - title: Text("privacy".i18n), - // onPressed: () => launchUrl( - // Uri.parse("https://refilc.hu/privacy-policy"), - // mode: LaunchMode.inAppWebView), - onPressed: () => _openPrivacy(context), - ), - PanelButton( - leading: const Icon(FeatherIcons.atSign), - title: const Text("Discord"), - onPressed: () => launchUrl( - Uri.parse("https://dc.refilc.hu"), - mode: LaunchMode.externalApplication), - ), - PanelButton( - leading: const Icon(FeatherIcons.globe), - title: const Text("www.refilc.hu"), - onPressed: () => launchUrl( - Uri.parse("https://www.refilc.hu"), - mode: LaunchMode.externalApplication), - ), - PanelButton( - leading: const Icon(FeatherIcons.github), - title: const Text("Github"), - onPressed: () => launchUrl( - Uri.parse("https://github.com/refilc"), - mode: LaunchMode.externalApplication), - ), - PanelButton( - leading: const Icon(FeatherIcons.award), - title: Text("licenses".i18n), - onPressed: () => showLicensePage(context: context), - ), - Tooltip( - message: "data_collected".i18n, - padding: const EdgeInsets.all(4.0), - textStyle: TextStyle( - fontWeight: FontWeight.w500, - color: AppColors.of(context).text), - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.background), - child: Material( - type: MaterialType.transparency, - child: SwitchListTile( - contentPadding: const EdgeInsets.only(left: 12.0), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12.0)), - secondary: Icon( - FeatherIcons.barChart2, - color: settings.xFilcId != "none" - ? Theme.of(context).colorScheme.secondary - : AppColors.of(context).text.withOpacity(.25), - ), - title: Text( - "Analytics".i18n, - style: TextStyle( - fontWeight: FontWeight.w600, - fontSize: 16.0, - color: AppColors.of(context).text.withOpacity( - settings.xFilcId != "none" ? 1.0 : .5), - ), - ), - subtitle: Text( - "Anonymous Usage Analytics".i18n, - style: TextStyle( - color: AppColors.of(context).text.withOpacity( - settings.xFilcId != "none" ? .5 : .2), - ), - ), - onChanged: (v) { - String newId; - if (v == false) { - newId = "none"; - } else if (settings.xFilcId == "none") { - newId = SettingsProvider.defaultSettings().xFilcId; - } else { - newId = settings.xFilcId; - } - settings.update(xFilcId: newId); - }, - value: settings.xFilcId != "none", - activeColor: Theme.of(context).colorScheme.secondary, - ), - ), - ), - ]), - ), - ), - if (settings.developerMode) - Padding( - padding: const EdgeInsets.symmetric( - vertical: 12.0, horizontal: 24.0), - child: Panel( - title: Text("devsettings".i18n), - child: Column( - children: [ - Material( - type: MaterialType.transparency, - child: SwitchListTile( - contentPadding: const EdgeInsets.only(left: 12.0), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12.0)), - title: Text("devmode".i18n, - style: - const TextStyle(fontWeight: FontWeight.w500)), - onChanged: (v) => - settings.update(developerMode: false), - value: settings.developerMode, - activeColor: Theme.of(context).colorScheme.secondary, - ), - ), - PanelButton( - leading: const Icon(FeatherIcons.copy), - title: Text("copy_jwt".i18n), - onPressed: () => Clipboard.setData(ClipboardData( - text: - Provider.of(context, listen: false) - .accessToken!)), - ), - // if (Provider.of(context, listen: false) - // .hasPremium) - // PanelButton( - // leading: const Icon(FeatherIcons.key), - // title: const Text("Remove Premium"), - // onPressed: () { - // Provider.of(context, listen: false) - // .activate(removePremium: true); - // settings.update( - // accentColor: AccentColor.filc, store: true); - // Provider.of(context, - // listen: false) - // .changeTheme(settings.theme); - // }, - // ), - ], - ), - ), - ), - - // version info - SafeArea( - top: false, - child: Center( - child: GestureDetector( - child: FutureBuilder( - future: futureRelease, - builder: (context, release) { - if (release.hasData) { - return DefaultTextStyle( - style: Theme.of(context) - .textTheme - .titleMedium! - .copyWith( - fontWeight: FontWeight.w600, - color: AppColors.of(context) - .text - .withOpacity(0.65)), - child: Text("v${release.data!['version']}"), - ); - } else { - String envAppVer = const String.fromEnvironment( - "APPVER", - defaultValue: "?"); - return DefaultTextStyle( - style: Theme.of(context) - .textTheme - .titleMedium! - .copyWith( - fontWeight: FontWeight.w600, - color: AppColors.of(context) - .text - .withOpacity(0.65)), - child: Text("v$envAppVer"), - ); - } - }, - ), - onTap: () { - if (devmodeCountdown > 0) { - ScaffoldMessenger.of(context).showSnackBar(SnackBar( - duration: const Duration(milliseconds: 200), - content: - Text("devmoretaps".i18n.fill([devmodeCountdown])), - )); - - setState(() => devmodeCountdown--); - } else if (devmodeCountdown == 0) { - ScaffoldMessenger.of(context).showSnackBar(SnackBar( - content: Text("devactivated".i18n), - )); - - settings.update(developerMode: true); - - setState(() => devmodeCountdown--); - } - }, - ), - ), - ), - ], - ), - ), - ); - } - - void _openNews(BuildContext context) => - Navigator.of(context, rootNavigator: true) - .push(CupertinoPageRoute(builder: (context) => const NewsScreen())); - void _openUpdates(BuildContext context) => - UpdateView.show(updateProvider.releases.first, context: context); - void _openPrivacy(BuildContext context) => PrivacyView.show(context); -} diff --git a/filcnaplo_mobile_ui/pubspec.yaml b/filcnaplo_mobile_ui/pubspec.yaml deleted file mode 100644 index d02517f..0000000 --- a/filcnaplo_mobile_ui/pubspec.yaml +++ /dev/null @@ -1,67 +0,0 @@ -name: filcnaplo_mobile_ui -publish_to: "none" - -environment: - sdk: ">=2.17.0 <3.0.0" - -dependencies: - flutter: - sdk: flutter - cupertino_icons: ^1.0.2 - - # Filcnaplo main dep - filcnaplo: - path: ../filcnaplo/ - filcnaplo_kreta_api: - path: ../filcnaplo_kreta_api/ - filcnaplo_premium: - path: ../filcnaplo_premium/ - - flutter_feather_icons: ^2.0.0+1 - provider: ^5.0.0 - fl_chart: ^0.45.1 - url_launcher: ^6.0.9 - flutter_material_color_picker: ^1.1.0+2 - photo_view: ^0.14.0 - flutter_linkify: ^5.0.2 - flutter_custom_tabs: ^1.0.3 - flutter_markdown: ^0.6.5 - animations: ^2.0.1 - animated_list_plus: ^0.5.0 - confetti: ^0.6.0 - live_activities: ^1.0.0 - animated_flip_counter: ^0.2.5 - lottie: ^1.4.3 - rive: ^0.9.1 - animated_background: ^2.0.0 - home_widget: ^0.1.6 - dropdown_button2: ^1.8.9 - flutter_svg: ^1.1.6 - background_fetch: ^1.1.5 - wtf_sliding_sheet: ^1.0.0 - package_info_plus: ^4.0.2 - dotted_border: ^2.0.0+3 - screenshot: ^2.1.0 - image_gallery_saver: ^2.0.2 - rounded_expansion_tile: - git: - url: https://github.com/kimaah/rounded_expansion_tile.git - go_router: ^12.1.3 - flutter_expandable_fab: ^2.0.0 - intl: ^0.18.1 - i18n_extension: ^10.0.1 - auto_size_text: ^3.0.0 - connectivity_plus: ^5.0.2 - collection: ^1.18.0 - share_plus: ^7.2.1 - image_picker: ^0.8.9 - path_provider: ^2.1.1 - image_crop: - git: - url: https://github.com/kimaah/image_crop.git - -dev_dependencies: - flutter_lints: ^3.0.1 - -flutter: - uses-material-design: true \ No newline at end of file diff --git a/filcnaplo_premium b/filcnaplo_premium deleted file mode 160000 index 6c1cf58..0000000 --- a/filcnaplo_premium +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6c1cf5886ec8b2d1e6bcbf0ab3b4d70449d319d0 diff --git a/fix-d8dx.sh b/fix-d8dx.sh deleted file mode 100755 index ef172d1..0000000 --- a/fix-d8dx.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh - -cd $ANDROID_SDK/build-tools/31.0.0 && - mv -v d8 dx && - cd lib && - mv -v d8.jar dx.jar diff --git a/fix-darwin.sh b/fix-darwin.sh deleted file mode 100755 index a4c501e..0000000 --- a/fix-darwin.sh +++ /dev/null @@ -1,26 +0,0 @@ -cd ./filcnaplo -flutter clean -flutter pub get -cd .. - -cd ./filcnaplo_kreta_api -flutter clean -flutter pub get -cd .. - -cd ./filcnaplo_mobile_ui -flutter clean -flutter pub get -cd .. - -cd ./filcnaplo_desktop_ui -flutter clean -flutter pub get -cd .. - -cd ./filcnaplo_premium -flutter clean -flutter pub get -cd .. - -echo Fixed pub. \ No newline at end of file diff --git a/fix-pub.sh b/fix-pub.sh deleted file mode 100755 index 27e50db..0000000 --- a/fix-pub.sh +++ /dev/null @@ -1,7 +0,0 @@ -cd filcnaplo && flutter clean && flutter pub get && cd .. -cd filcnaplo_kreta_api && flutter clean && flutter pub get && cd .. -cd filcnaplo_mobile_ui && flutter clean && flutter pub get && cd .. -cd filcnaplo_desktop_ui && flutter clean && flutter pub get && cd .. -cd filcnaplo_premium && flutter clean && flutter pub get && cd .. - -echo Fixed pub. \ No newline at end of file diff --git a/refilc/.gitignore b/refilc/.gitignore new file mode 100644 index 0000000..4257c18 --- /dev/null +++ b/refilc/.gitignore @@ -0,0 +1,77 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release + +.symlinks/ +Pods +Podfile.lock +UserInterfaceState.xcuserstate +**/ios/**/*.mode1v3 +**/ios/**/*.mode2v3 +**/ios/**/*.moved-aside +**/ios/**/*.pbxuser +**/ios/**/*.perspectivev3 +**/ios/**/*sync/ +**/ios/**/.sconsign.dblite +**/ios/**/.tags* +**/ios/**/.vagrant/ +**/ios/**/DerivedData/ +**/ios/**/Icon? +**/ios/**/Pods/ +**/ios/**/.symlinks/ +**/ios/**/profile +**/ios/**/xcuserdata +**/ios/.generated/ +**/ios/Flutter/.last_build_id +**/ios/Flutter/App.framework +**/ios/Flutter/Flutter.framework +**/ios/Flutter/Flutter.podspec +**/ios/Flutter/Generated.xcconfig +**/ios/Flutter/ephemeral +**/ios/Flutter/app.flx +**/ios/Flutter/app.zip +**/ios/Flutter/flutter_assets/ +**/ios/Flutter/flutter_export_environment.sh +**/ios/ServiceDefinitions.json +**/ios/Runner/GeneratedPluginRegistrant.* diff --git a/filcnaplo/.metadata b/refilc/.metadata similarity index 100% rename from filcnaplo/.metadata rename to refilc/.metadata diff --git a/filcnaplo/README.md b/refilc/README.md similarity index 86% rename from filcnaplo/README.md rename to refilc/README.md index 02c4c20..775cf06 100644 --- a/filcnaplo/README.md +++ b/refilc/README.md @@ -1,3 +1,3 @@ -# refilc - -Main lib +# refilc + +Main lib diff --git a/filcnaplo_desktop_ui/analysis_options.yaml b/refilc/analysis_options.yaml similarity index 98% rename from filcnaplo_desktop_ui/analysis_options.yaml rename to refilc/analysis_options.yaml index 16f5f56..61b6c4d 100644 --- a/filcnaplo_desktop_ui/analysis_options.yaml +++ b/refilc/analysis_options.yaml @@ -1,28 +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 +# 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 diff --git a/filcnaplo/android/app/build.gradle b/refilc/android/app/build.gradle similarity index 67% rename from filcnaplo/android/app/build.gradle rename to refilc/android/app/build.gradle index 49825fb..42f71d7 100644 --- a/filcnaplo/android/app/build.gradle +++ b/refilc/android/app/build.gradle @@ -1,99 +1,123 @@ -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - throw new GradleException("Undefined VersionCode") -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - throw new GradleException("Undefined VersionName") -} - -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - -def keystoreProperties = new Properties() -def keystorePropertiesFile = rootProject.file("key.properties") -keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) - -android { - compileSdkVersion rootProject.ext.compileSdkVersion - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - - lintOptions { - disable 'InvalidPackage' - disable "Instantiatable" - checkReleaseBuilds false - abortOnError false - } - - defaultConfig { - applicationId "hu.refilc.naplo" - minSdkVersion 21 - targetSdkVersion rootProject.ext.targetSdkVersion - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - multiDexEnabled true - } - - compileOptions { - // Flag to enable support for the new language APIs - coreLibraryDesugaringEnabled true - // Sets Java compatibility to Java 8 - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - - signingConfigs { - release { - keyAlias keystoreProperties['keyAlias'] - keyPassword keystoreProperties['keyPassword'] - storeFile file(keystoreProperties['storeFile']) - storePassword keystoreProperties['storePassword'] - } - } - - buildTypes { - release { - signingConfig signingConfigs.release - shrinkResources false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } - } - - buildFeatures { - viewBinding true - } -} - -flutter { - source '../..' -} - -dependencies { - implementation 'com.android.support:multidex:2.0.1' - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation 'joda-time:joda-time:2.9.4' - androidTestImplementation 'androidx.test:runner:1.1.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' - coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5' - implementation 'androidx.window:window:1.0.0' - implementation 'androidx.window:window-java:1.0.0' -} +plugins { + id "com.android.application" + id "kotlin-android" + id "dev.flutter.flutter-gradle-plugin" +} + +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +// def flutterRoot = localProperties.getProperty('flutter.sdk') +// if (flutterRoot == null) { +// throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +// } + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + throw new GradleException("Undefined VersionCode") +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + throw new GradleException("Undefined VersionName") +} + +// apply plugin: 'com.android.application' +// apply plugin: 'kotlin-android' +// apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +def keystoreProperties = new Properties() +def keystorePropertiesFile = rootProject.file("key.properties") +keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) + +def debugKeystoreProperties = new Properties() +def debugKeystorePropertiesFile = rootProject.file("debugkey.properties") +debugKeystoreProperties.load(new FileInputStream(debugKeystorePropertiesFile)) + +android { + ndkVersion "25.1.8937393" + + // compileSdkVersion rootProject.ext.compileSdkVersion + compileSdkVersion 34 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + disable "Instantiatable" + checkReleaseBuilds false + abortOnError false + } + + defaultConfig { + applicationId "hu.refilc.naplo" + minSdkVersion 21 + targetSdkVersion 34 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + multiDexEnabled true + } + + compileOptions { + // Flag to enable support for the new language APIs + coreLibraryDesugaringEnabled true + // Sets Java compatibility to Java 8 + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + signingConfigs { + debug { + keyAlias "androiddebugkey" + keyPassword debugKeystoreProperties['keyPassword'] + storeFile file(debugKeystoreProperties['storeFile']) + storePassword debugKeystoreProperties['storePassword'] + } + + release { + keyAlias keystoreProperties['keyAlias'] + keyPassword keystoreProperties['keyPassword'] + storeFile file(keystoreProperties['storeFile']) + storePassword keystoreProperties['storePassword'] + } + } + + buildTypes { + debug { + signingConfig signingConfigs.debug + } + + release { + signingConfig signingConfigs.release + shrinkResources false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + + buildFeatures { + viewBinding true + } +} + +flutter { + source '../..' +} + +dependencies { + implementation 'com.android.support:multidex:2.0.1' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.21" + implementation 'joda-time:joda-time:2.9.4' + androidTestImplementation 'androidx.test:runner:1.1.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' + coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5' + implementation 'androidx.window:window:1.0.0' + implementation 'androidx.window:window-java:1.0.0' +} diff --git a/refilc/android/app/google-services.json b/refilc/android/app/google-services.json new file mode 100644 index 0000000..09ea9d9 --- /dev/null +++ b/refilc/android/app/google-services.json @@ -0,0 +1,38 @@ +{ + "project_info": { + "project_number": "584481527599", + "project_id": "refilc-mobile-login", + "storage_bucket": "refilc-mobile-login.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:584481527599:android:cd0fef08720efc4de033da", + "android_client_info": { + "package_name": "hu.refilc.naplo" + } + }, + "oauth_client": [ + { + "client_id": "584481527599-2cpalmvit8kl489aoj3v6t28ujcbcd62.apps.googleusercontent.com", + "client_type": 1, + "android_info": { + "package_name": "hu.refilc.naplo", + "certificate_hash": "3c61db0984e5db01569cb084c83f9b3e058d94dc" + } + } + ], + "api_key": [ + { + "current_key": "AIzaSyAl8eWn7XVeWeA9dPMrWtzdRhhH4XOWOaY" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/refilc/android/app/proguard-rules.pro b/refilc/android/app/proguard-rules.pro new file mode 100644 index 0000000..2f9ff85 --- /dev/null +++ b/refilc/android/app/proguard-rules.pro @@ -0,0 +1,11 @@ +-keep class io.flutter.plugin.editing.** { *; } +-keep class androidx.lifecycle.DefaultLifecycleObserver +-keep class com.pauldemarco.flutter_blue.** { *; } +-keep class com.mr.flutter.plugin.filepicker.** { *; } +-keep class com.shockwave.** + +-dontwarn com.stripe.android.pushProvisioning.PushProvisioningActivity$g +-dontwarn com.stripe.android.pushProvisioning.PushProvisioningActivityStarter$Args +-dontwarn com.stripe.android.pushProvisioning.PushProvisioningActivityStarter$Error +-dontwarn com.stripe.android.pushProvisioning.PushProvisioningActivityStarter +-dontwarn com.stripe.android.pushProvisioning.PushProvisioningEphemeralKeyProvider \ No newline at end of file diff --git a/filcnaplo/android/app/src/debug/AndroidManifest.xml b/refilc/android/app/src/debug/AndroidManifest.xml similarity index 98% rename from filcnaplo/android/app/src/debug/AndroidManifest.xml rename to refilc/android/app/src/debug/AndroidManifest.xml index 826ca84..fcc14fa 100644 --- a/filcnaplo/android/app/src/debug/AndroidManifest.xml +++ b/refilc/android/app/src/debug/AndroidManifest.xml @@ -1,8 +1,8 @@ - - - - - - - - + + + + + + + + diff --git a/filcnaplo/android/app/src/main/AndroidManifest.xml b/refilc/android/app/src/main/AndroidManifest.xml similarity index 73% rename from filcnaplo/android/app/src/main/AndroidManifest.xml rename to refilc/android/app/src/main/AndroidManifest.xml index ef5b9d0..f22abc0 100644 --- a/filcnaplo/android/app/src/main/AndroidManifest.xml +++ b/refilc/android/app/src/main/AndroidManifest.xml @@ -1,150 +1,207 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/refilc/android/app/src/main/java/hu/refilc/naplo/MainActivity.kt b/refilc/android/app/src/main/java/hu/refilc/naplo/MainActivity.kt new file mode 100644 index 0000000..ca3052f --- /dev/null +++ b/refilc/android/app/src/main/java/hu/refilc/naplo/MainActivity.kt @@ -0,0 +1,5 @@ +package hu.refilc.naplo + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() diff --git a/refilc/android/app/src/main/java/hu/refilc/naplo/database/DBManager.kt b/refilc/android/app/src/main/java/hu/refilc/naplo/database/DBManager.kt new file mode 100644 index 0000000..0ea69dc --- /dev/null +++ b/refilc/android/app/src/main/java/hu/refilc/naplo/database/DBManager.kt @@ -0,0 +1,73 @@ +package hu.refilc.naplo.database + +import android.content.ContentValues +import android.content.Context +import android.database.Cursor +import android.database.sqlite.SQLiteDatabase + +import java.sql.SQLException + +import hu.refilc.naplo.database.SQLiteHelper +import kotlin.arrayOf + +class DBManager(private val context: Context) { + private lateinit var database: SQLiteDatabase + private lateinit var dbHelper: SQLiteHelper + + fun open(): DBManager { + this.dbHelper = SQLiteHelper(this.context) + this.database = this.dbHelper.getWritableDatabase() + return this + } + + fun close() { + this.dbHelper.close() + } + + fun fetchWidget(wid: Int): Cursor { + val cursor: Cursor = this.database.query(SQLiteHelper.TABLE_NAME_WIDGETS, arrayOf(SQLiteHelper._ID, SQLiteHelper.DAY_SEL), "${SQLiteHelper._ID} = $wid", null, null, null, null) + if (cursor != null) cursor.moveToFirst() + return cursor + } + + fun fetchTimetable(): Cursor { + val cursor: Cursor = this.database.query(SQLiteHelper.TABLE_NAME_USER_DATA, arrayOf(SQLiteHelper.TIMETABLE), null, null, null, null, null) + if (cursor != null) cursor.moveToFirst() + return cursor + } + + fun fetchLastUser(): Cursor { + val cursor: Cursor = this.database.query(SQLiteHelper.TABLE_NAME_SETTINGS, arrayOf(SQLiteHelper.LAST_ACCOUNT_ID), null, null, null, null, null) + if (cursor != null) cursor.moveToFirst() + return cursor + } + + fun fetchTheme(): Cursor { + val cursor: Cursor = this.database.query(SQLiteHelper.TABLE_NAME_SETTINGS, arrayOf(SQLiteHelper.THEME, SQLiteHelper.CUSTOM_ACCENT_COLOR, SQLiteHelper.CUSTOM_BACKGROUND_COLOR), null, null, null, null, null) + if (cursor != null) cursor.moveToFirst() + return cursor + } + + fun fetchLocale(): Cursor { + val cursor: Cursor = this.database.query(SQLiteHelper.TABLE_NAME_SETTINGS, arrayOf(SQLiteHelper.LOCALE), null, null, null, null, null) + if (cursor != null) cursor.moveToFirst() + return cursor + } + + fun deleteWidget(_id: Int) { + this.database.delete(SQLiteHelper.TABLE_NAME_WIDGETS, "_id=$_id", null) + } + + fun insertSelDay(_id: Int, day_sel: Int) { + val con: ContentValues = ContentValues() + con.put(SQLiteHelper._ID, _id) + con.put(SQLiteHelper.DAY_SEL, day_sel) + this.database.insert(SQLiteHelper.TABLE_NAME_WIDGETS, null, con) + } + + fun update(_id: Int, day_sel: Int): Int { + val con: ContentValues = ContentValues() + con.put(SQLiteHelper.DAY_SEL, day_sel) + return this.database.update(SQLiteHelper.TABLE_NAME_WIDGETS, con, "${SQLiteHelper._ID} = $_id", null) + } +} diff --git a/refilc/android/app/src/main/java/hu/refilc/naplo/database/SQLiteHelper.kt b/refilc/android/app/src/main/java/hu/refilc/naplo/database/SQLiteHelper.kt new file mode 100644 index 0000000..69588b2 --- /dev/null +++ b/refilc/android/app/src/main/java/hu/refilc/naplo/database/SQLiteHelper.kt @@ -0,0 +1,33 @@ +package hu.refilc.naplo.database + +import android.content.Context +import android.database.sqlite.SQLiteDatabase +import android.database.sqlite.SQLiteOpenHelper + +class SQLiteHelper(context: Context): SQLiteOpenHelper(context, DB_NAME, null, 7) { + companion object { + private final val CREATE_TABLE_WIDGET: String = " create table widgets ( _id INTEGER NOT NULL, day_sel INTEGER NOT NULL);" + private final val DB_NAME: String = "app.db" + private final val DB_VERSION: Int = 1 + final val _ID: String = "_id" + final val DAY_SEL: String = "day_sel" + final val TIMETABLE: String = "timetable" + final val LAST_ACCOUNT_ID: String = "last_account_id" + final val THEME: String = "theme" + final val LOCALE: String = "language" + final val CUSTOM_ACCENT_COLOR: String = "custom_accent_color" + final val CUSTOM_BACKGROUND_COLOR: String = "custom_background_color" + final val TABLE_NAME_WIDGETS: String = "widgets" + final val TABLE_NAME_USER_DATA: String = "user_data" + final val TABLE_NAME_SETTINGS: String = "settings" + } + + override fun onCreate(db: SQLiteDatabase) { + db.execSQL(CREATE_TABLE_WIDGET) + } + + override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + db.execSQL("DROP TABLE IF EXISTS widgets") + onCreate(db) + } +} diff --git a/refilc/android/app/src/main/java/hu/refilc/naplo/utils/Utils.kt b/refilc/android/app/src/main/java/hu/refilc/naplo/utils/Utils.kt new file mode 100644 index 0000000..bf8a2ff --- /dev/null +++ b/refilc/android/app/src/main/java/hu/refilc/naplo/utils/Utils.kt @@ -0,0 +1,41 @@ +package hu.refilc.naplo.utils + +import android.content.Context +import android.net.ConnectivityManager +import android.net.NetworkInfo + +import java.util.Calendar +import java.util.Date + +class Utils { + companion object { + @JvmStatic + fun hasNetwork(context: Context): Boolean { + val cm: ConnectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + val netInfo: NetworkInfo = cm.getActiveNetworkInfo() as NetworkInfo + if (netInfo != null && netInfo.isConnectedOrConnecting()) { + return true + } + return false + } + + @JvmStatic + fun getWeekStartDate(): Date { + var calendar: Calendar = Calendar.getInstance() + while (calendar.get(Calendar.DAY_OF_WEEK) != Calendar.MONDAY) { + calendar.add(Calendar.DATE, -1) + } + return calendar.getTime() + } + + @JvmStatic + fun getWeekEndDate(): Date { + var calendar: Calendar = Calendar.getInstance() + while (calendar.get(Calendar.DAY_OF_WEEK) != Calendar.MONDAY) { + calendar.add(Calendar.DATE, 1) + } + calendar.add(Calendar.DATE, -1) + return calendar.getTime() + } + } +} diff --git a/refilc/android/app/src/main/java/hu/refilc/naplo/utils/Week.kt b/refilc/android/app/src/main/java/hu/refilc/naplo/utils/Week.kt new file mode 100644 index 0000000..860b8f2 --- /dev/null +++ b/refilc/android/app/src/main/java/hu/refilc/naplo/utils/Week.kt @@ -0,0 +1,57 @@ +package hu.refilc.naplo.utils + +import java.time.DayOfWeek +import java.time.Duration +import java.time.LocalDate +import kotlin.math.ceil + +class Week private constructor(private final val start: LocalDate, private final val end: LocalDate) { + companion object { + fun current(): Week { + return fromDate(LocalDate.now()) + } + + fun fromId(id: Int): Week { + val _now: LocalDate = getYearStart().plusDays(id * 7L) + return Week(_now.minusDays(_now.getDayOfWeek().getValue() - 1L), _now.plusDays(7L - _now.getDayOfWeek().getValue())) + } + + fun fromDate(date: LocalDate): Week { + return Week(date.minusDays(date.getDayOfWeek().getValue() - 1L), date.plusDays(7L - date.getDayOfWeek().getValue())) + } + + private fun getYearStart(): LocalDate { + val now: LocalDate = LocalDate.now() + val start: LocalDate = getYearStart(now.getYear()) + return if (start.isBefore(now)) start else getYearStart(now.getYear() - 1) + } + + private fun getYearStart(year: Int): LocalDate { + val time: LocalDate = LocalDate.of(year, 9, 1) + if (time.getDayOfWeek() == DayOfWeek.SATURDAY) + return time.plusDays(2) + else if (time.getDayOfWeek() == DayOfWeek.SUNDAY) + return time.plusDays(1) + return time + } + } + + fun next(): Week { + return Week.fromDate(start.plusDays(8)) + } + + fun id(): Int { + return Math.ceil(Duration.between(getYearStart().atStartOfDay(), start.atStartOfDay()).toDays() / 7.0).toInt() + } + + override fun equals(o: Any?): Boolean { + if (this == o as Week) return true + if (o == null || Week::class != o::class) return false + val week: Week = o as Week + return this.id() == week.id() + } + + override fun hashCode(): Int { + return id() + } +} diff --git a/refilc/android/app/src/main/java/hu/refilc/naplo/widget_timetable/WidgetTimetable.kt b/refilc/android/app/src/main/java/hu/refilc/naplo/widget_timetable/WidgetTimetable.kt new file mode 100644 index 0000000..e9f70cf --- /dev/null +++ b/refilc/android/app/src/main/java/hu/refilc/naplo/widget_timetable/WidgetTimetable.kt @@ -0,0 +1,402 @@ +package hu.refilc.naplo.widget_timetable + +import android.app.PendingIntent +import android.app.UiModeManager +import android.appwidget.AppWidgetManager +import android.appwidget.AppWidgetProvider +import android.content.Context +import android.content.Intent +import android.content.SharedPreferences +import android.database.Cursor +import android.net.Uri +import android.os.Build +import android.util.Log +import android.view.View +import android.widget.RemoteViews +import android.widget.Toast + +import org.joda.time.DateTime +import org.json.JSONArray +import org.json.JSONException +import org.json.JSONObject + +import java.time.DayOfWeek +import java.time.format.TextStyle +import java.util.Collections +import java.util.Comparator +import java.util.Locale +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 +import hu.refilc.naplo.R + +import hu.refilc.naplo.utils.Week + +import es.antonborri.home_widget.HomeWidgetBackgroundIntent +import es.antonborri.home_widget.HomeWidgetLaunchIntent +import es.antonborri.home_widget.HomeWidgetProvider +import kotlin.collections.mutableMapOf + +class WidgetTimetable : HomeWidgetProvider() { + override fun onUpdate( + context: Context, + appWidgetManager: AppWidgetManager, + appWidgetIds: IntArray, + widgetData: SharedPreferences + ) { + val fullTheme: Array = getFullTheme(context) + val textColors: Array = getTextColors(context, fullTheme) + for (i in appWidgetIds.indices) { + val views: RemoteViews = generateView(context, appWidgetIds[i]) + if (userLoggedIn(context)) { + val rday = selectDay(context, appWidgetIds[i], 0, true) + views.setTextViewText(R.id.nav_current, convertDayOfWeek(context, rday)) + views.setInt(R.id.nav_current, "setTextColor", getColor(context, textColors[0])) + } + pushUpdate(context, views, appWidgetIds[i]) + } + } + + override fun onReceive(context: Context, intent: Intent) { + super.onReceive(context, intent) + if (intent.hasExtra(AppWidgetManager.EXTRA_APPWIDGET_ID)) { + val appId: Int = intent.getIntExtra( + AppWidgetManager.EXTRA_APPWIDGET_ID, + AppWidgetManager.INVALID_APPWIDGET_ID + ) + val views: RemoteViews = generateView(context, appId) + try { + if (userLoggedIn(context)) { + if (intent.getAction().equals(ACTION_WIDGET_CLICK_NAV_LEFT)) { + val rday = selectDay(context, appId, -1, false) + views.setTextViewText(R.id.nav_current, convertDayOfWeek(context, rday)) + pushUpdate(context, views, appId) + } else if (intent.getAction().equals(ACTION_WIDGET_CLICK_NAV_RIGHT)) { + val rday = selectDay(context, appId, 1, false) + views.setTextViewText(R.id.nav_current, convertDayOfWeek(context, rday)) + pushUpdate(context, views, appId) + } else if (intent.getAction().equals(ACTION_WIDGET_CLICK_NAV_TODAY)) { + val rday = getToday(context) + setSelectedDay(context, appId, rday) + views.setTextViewText(R.id.nav_current, convertDayOfWeek(context, rday)) + pushUpdate(context, views, appId) + } else if (intent.getAction().equals(ACTION_WIDGET_CLICK_NAV_REFRESH)) { + val pendingIntent: PendingIntent = + HomeWidgetLaunchIntent.getActivity( + context, + MainActivity::class.java, + Uri.parse("timetable://refresh") + ) + pendingIntent.send() + } else if (intent.getAction() + .equals("android.appwidget.action.APPWIDGET_DELETED") + ) { + val dbManager = DBManager(context.getApplicationContext()) + try { + dbManager.open() + dbManager.deleteWidget(appId) + dbManager.close() + } catch (e: Exception) { + e.printStackTrace() + } + } + } + if (intent.getAction().equals(ACTION_WIDGET_CLICK_BUY_PREMIUM)) { + val pendingIntent: PendingIntent = HomeWidgetLaunchIntent.getActivity( + context, + MainActivity::class.java, + Uri.parse("settings://premium") + ) + pendingIntent.send() + } + } catch (e: Exception) { + e.printStackTrace() + } + } + } + + override fun onEnabled(context: Context?) { + } + + override fun onDisabled(context: Context?) { + } + + companion object { + private const val ACTION_WIDGET_CLICK_NAV_LEFT = "list_widget.ACTION_WIDGET_CLICK_NAV_LEFT" + private const val ACTION_WIDGET_CLICK_NAV_RIGHT = + "list_widget.ACTION_WIDGET_CLICK_NAV_RIGHT" + private const val ACTION_WIDGET_CLICK_NAV_TODAY = + "list_widget.ACTION_WIDGET_CLICK_NAV_TODAY" + private const val ACTION_WIDGET_CLICK_NAV_REFRESH = + "list_widget.ACTION_WIDGET_CLICK_NAV_REFRESH" + private const val ACTION_WIDGET_CLICK_BUY_PREMIUM = + "list_widget.ACTION_WIDGET_CLICK_BUY_PREMIUM" + + fun pushUpdate(context: Context?, remoteViews: RemoteViews?, appWidgetSingleId: Int) { + val manager: AppWidgetManager = AppWidgetManager.getInstance(context) + manager.updateAppWidget(appWidgetSingleId, remoteViews) + manager.notifyAppWidgetViewDataChanged(appWidgetSingleId, R.id.widget_list) + } + + fun getColor(context: Context, color: Int): Int { + return context.getResources().getColor(color) + } + + fun getTextColors(context: Context, fullTheme: Array): Array { + val uiModeManager: UiModeManager = + context.getSystemService(Context.UI_MODE_SERVICE) as UiModeManager + val nightMode: Int = uiModeManager.getNightMode() + val textColor: Int + val textDescColor: Int + if (fullTheme[0] == 0 && nightMode == UiModeManager.MODE_NIGHT_NO) { + textColor = R.color.text_light + textDescColor = R.color.text_desc_light + } else if (fullTheme[0] == 1) { + textColor = R.color.text_light + textDescColor = R.color.text_desc_light + } else { + textColor = R.color.text + textDescColor = R.color.text_desc + } + return arrayOf(textColor, textDescColor) + } + + fun getFullTheme(context: Context): Array { + val dbManager = DBManager(context.getApplicationContext()) + try { + dbManager.open() + val cursor: Cursor = dbManager.fetchTheme() + dbManager.close() + val theme: Int = cursor.getInt(0) + val customBackgroundColor: Int = cursor.getInt(2) + return arrayOf(theme, customBackgroundColor) + } catch (e: Exception) { + e.printStackTrace() + } + return arrayOf(0, 0) + } + + fun generateView(context: Context, appId: Int): RemoteViews { + val fullTheme: Array = getFullTheme(context) + val textColors: Array = getTextColors(context, fullTheme) + val serviceIntent = Intent(context, WidgetTimetableService::class.java) + serviceIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appId) + serviceIntent.setData(Uri.parse(serviceIntent.toUri(Intent.URI_INTENT_SCHEME))) + val views = RemoteViews(context.getPackageName(), R.layout.widget_timetable) + views.setViewVisibility(R.id.need_login, View.GONE) + views.setViewVisibility(R.id.tt_grid_cont, View.GONE) + views.setInt(R.id.nav_to_left, "setColorFilter", getColor(context, textColors[1])) + views.setInt(R.id.nav_to_right, "setColorFilter", getColor(context, textColors[1])) + views.setInt(R.id.nav_refresh, "setColorFilter", getColor(context, textColors[1])) + views.setInt(R.id.empty_view, "setTextColor", getColor(context, textColors[0])) + if (!userLoggedIn(context)) { + views.setViewVisibility(R.id.need_login, View.VISIBLE) + views.setOnClickPendingIntent( + R.id.open_login, + makePending(context, ACTION_WIDGET_CLICK_BUY_PREMIUM, appId) + ) + } else { + views.setViewVisibility(R.id.tt_grid_cont, View.VISIBLE) + views.setInt(R.id.widget_list, "setBackgroundColor", fullTheme[1]) + views.setInt(R.id.bottom_nav, "setBackgroundColor", fullTheme[1]) + views.setOnClickPendingIntent( + R.id.nav_to_left, + makePending(context, ACTION_WIDGET_CLICK_NAV_LEFT, appId) + ) + views.setOnClickPendingIntent( + R.id.nav_to_right, + makePending(context, ACTION_WIDGET_CLICK_NAV_RIGHT, appId) + ) + views.setOnClickPendingIntent( + R.id.nav_current, + makePending(context, ACTION_WIDGET_CLICK_NAV_TODAY, appId) + ) + views.setOnClickPendingIntent( + R.id.nav_refresh, + makePending(context, ACTION_WIDGET_CLICK_NAV_REFRESH, appId) + ) + views.setRemoteAdapter(R.id.widget_list, serviceIntent) + views.setEmptyView(R.id.widget_list, R.id.empty_view) + views.setInt(R.id.empty_view, "setBackgroundColor", fullTheme[1]) + } + return views + } + + fun makePending(context: Context?, action: String?, appWidgetId: Int): PendingIntent { + val activebtnnext = Intent(context, WidgetTimetable::class.java) + activebtnnext.setAction(action) + activebtnnext.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId) + return PendingIntent.getBroadcast( + context, + appWidgetId, + activebtnnext, + PendingIntent.FLAG_IMMUTABLE + ) + } + + fun convertDayOfWeek(context: Context, rday: Int): String { + + /*if(rday == -1) return DayOfWeek.of(1).getDisplayName(TextStyle.FULL, new Locale("hu", "HU")) + + String dayOfWeek = DayOfWeek.of(rday + 1).getDisplayName(TextStyle.FULL, new Locale("hu", "HU"))*/ + var dayOfWeek = "Unknown" + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val loc: Locale = getLocale(context) + if (rday == -1) return DayOfWeek.of(1).getDisplayName(TextStyle.FULL, loc) + dayOfWeek = DayOfWeek.of(rday + 1).getDisplayName(TextStyle.FULL, loc) + } + return dayOfWeek.substring(0, 1).toUpperCase() + dayOfWeek.substring(1).toLowerCase() + } + + fun setSelectedDay(context: Context, wid: Int, day: Int) { + val dbManager = DBManager(context.getApplicationContext()) + try { + dbManager.open() + dbManager.update(wid, day) + dbManager.close() + } catch (e: Exception) { + e.printStackTrace() + } + } + + fun getToday(context: Context): Int { + var rday: Int = DateTime().getDayOfWeek() - 1 + val s: MutableList = genJsonDays(context) + try { + if (checkIsAfter(s, rday)) rday += 1 + } catch (e: Exception) { + e.printStackTrace() + } + return retDay(rday, s.size) + } + + fun selectDay(context: Context, wid: Int, add: Int, afterSubjects: Boolean): Int { + val dbManager = DBManager(context.getApplicationContext()) + try { + dbManager.open() + val cursor: Cursor = dbManager.fetchWidget(wid) + val s: MutableList = genJsonDays(context) + var retday: Int = DateTime().getDayOfWeek() - 1 + if (cursor.getCount() !== 0) retday = retDay(cursor.getInt(1) + add, s.size) + if (afterSubjects) if (checkIsAfter(s, retday)) retday += 1 + retday = retDay(retday, s.size) + if (cursor.getCount() === 0) dbManager.insertSelDay( + wid, + retday + ) else dbManager.update(wid, retday) + dbManager.close() + + // get the date of the first lesson + val dt = DateTime(s[retday].getJSONObject(0).getString("Datum")) + retday = dt.getDayOfWeek() - 1 + return retday + } catch (e: Exception) { + e.printStackTrace() + } + return 0 + } + + fun checkIsAfter(s: MutableList, retday: Int): Boolean { + var retday = retday + retday = retDay(retday, s.size) + val vegIdopont: String = + s[retday].getJSONObject(s[retday].length() - 1).getString("VegIdopont") + return DateTime().isAfter(DateTime(vegIdopont)) + } + + fun retDay(retday: Int, size: Int): Int { + var retday = retday + if (retday < 0) retday = size - 1 else if (retday > size - 1) retday = 0 + return retday + } + + fun genJsonDays(context: Context): MutableList { + val genDays: MutableList = mutableListOf() + val dayMap: MutableMap = mutableMapOf() + val dbManager = DBManager(context.getApplicationContext()) + try { + dbManager.open() + val ct: Cursor = dbManager.fetchTimetable() + if (ct.getCount() === 0) { + return genDays + } + val fetchedTimetable = JSONObject(ct.getString(0)) + val currentWeek: String = Week.current().id().toString() + val week: JSONArray = fetchedTimetable.getJSONArray(currentWeek) + + // Organize lessons into dates + for (i in 0 until week.length()) { + try { + val entry: JSONObject = week.getJSONObject(i) + val date: String = entry.getString("Datum") + dayMap.computeIfAbsent(date) { k -> JSONArray() }.put(entry) + } catch (e: JSONException) { + e.printStackTrace() + } + } + genDays.addAll(dayMap.values) + + // Sort the 'genDays' list of JSON based on the start time of the first entry + genDays.sortWith( { day1, day2 -> + // Extract the start time of the first entry in each day's JSON + val startTime1: String = day1.getJSONObject(0).getString("KezdetIdopont") + val startTime2: String = day2.getJSONObject(0).getString("KezdetIdopont") + // Compare the start times and return the result for sorting + startTime1.compareTo(startTime2) + }) + } catch (e: Exception) { + e.printStackTrace() + } finally { + dbManager.close() + } + return genDays + } + + fun zeroPad(value: Int, padding: Int): String { + val b = StringBuilder() + b.append(value) + while (b.length < padding) { + b.insert(0, "0") + } + return b.toString() + } + + fun getLocale(context: Context): Locale { + val dbManager = DBManager(context.getApplicationContext()) + try { + dbManager.open() + val loc: String = dbManager.fetchLocale().getString(0) + dbManager.close() + if (loc.equals("hu") || loc.equals("de")) { + return Locale(loc, loc.toUpperCase()) + } + } catch (e: Exception) { + e.printStackTrace() + } + return Locale("en", "GB") + } + + fun userLoggedIn(context: Context): Boolean { + return !lastUserId(context).equals("") + } + + fun lastUserId(context: Context): String { + val dbManager = DBManager(context.getApplicationContext()) + try { + dbManager.open() + val cursor: Cursor = dbManager.fetchLastUser() + dbManager.close() + if (cursor != null && !cursor.getString(0).equals("")) { + return cursor.getString(0) + } + } catch (e: Exception) { + e.printStackTrace() + } + return "" + } + } +} diff --git a/refilc/android/app/src/main/java/hu/refilc/naplo/widget_timetable/WidgetTimetableDataProvider.kt b/refilc/android/app/src/main/java/hu/refilc/naplo/widget_timetable/WidgetTimetableDataProvider.kt new file mode 100644 index 0000000..b3229f3 --- /dev/null +++ b/refilc/android/app/src/main/java/hu/refilc/naplo/widget_timetable/WidgetTimetableDataProvider.kt @@ -0,0 +1,328 @@ +package hu.refilc.naplo.widget_timetable + +import android.app.UiModeManager +import android.appwidget.AppWidgetManager +import android.content.Context +import android.content.Intent +import android.database.Cursor +import android.os.Build +import android.util.Log +import android.view.View +import android.widget.RemoteViews +import android.widget.RemoteViewsService + +import org.joda.time.DateTime +import org.json.JSONArray +import org.json.JSONException +import org.json.JSONObject + +import java.util.Collections +import java.util.Comparator + +import hu.refilc.naplo.database.DBManager +import hu.refilc.naplo.R + +class WidgetTimetableDataProvider(context: Context, intent: Intent) : RemoteViewsService.RemoteViewsFactory { + private val context: Context + private val appWidgetId: Int + private var rday = 0 + private var fullTheme: Array + private val uiModeManager: UiModeManager + private val nightMode: Int + var day_subjects: MutableList = mutableListOf() + var lessonIndexes: MutableList = mutableListOf() + var witem: Item? = null + + /* Default values */ + class Item( + var Layout: Int, + var BackgroundColor: Int, + var NumVisibility: Int, + var NameVisibility: Int, + var NameNodescVisibility: Int, + var DescVisibility: Int, + var RoomVisibility: Int, + var TimeVisibility: Int, + var NumColor: Int, + var NameColor: Int, + var NameNodescColor: Int, + var DescColor: Int, + var RoomColor: Int, + var TimeColor: Int + ) { + var NameNodescPadding: Array = arrayOf(0, 0, 0, 0) + } + + class Lesson( + var status: String, + var lessonIndex: String, + var lessonName: String, + var lessonTopic: String, + var lessonRoom: String, + var lessonStart: Long, + var lessonEnd: Long, + var substituteTeacher: String + ) + + var itemNameNodescPadding: Array = arrayOf(0, 0, 0, 0) + + init { + this.context = context + appWidgetId = intent.getIntExtra( + AppWidgetManager.EXTRA_APPWIDGET_ID, + AppWidgetManager.INVALID_APPWIDGET_ID + ) + fullTheme = getFullTheme(context) + uiModeManager = context.getSystemService(Context.UI_MODE_SERVICE) as UiModeManager + nightMode = uiModeManager.getNightMode() + } + + override fun onCreate() { + initData() + } + + override fun onDataSetChanged() { + initData() + } + + override fun onDestroy() {} + + override fun getCount(): Int { + return day_subjects.size + } + + fun setLayout(view: RemoteViews) { + /* Visibilities */ + view.setViewVisibility(R.id.tt_item_num, witem!!.NumVisibility) + view.setViewVisibility(R.id.tt_item_name, witem!!.NameVisibility) + view.setViewVisibility(R.id.tt_item_name_nodesc, witem!!.NameNodescVisibility) + view.setViewVisibility(R.id.tt_item_desc, witem!!.DescVisibility) + view.setViewVisibility(R.id.tt_item_room, witem!!.RoomVisibility) + view.setViewVisibility(R.id.tt_item_time, witem!!.TimeVisibility) + + /* backgroundResources */ + view.setInt(R.id.main_lay, "setBackgroundResource", witem!!.Layout) + view.setInt(R.id.main_lay, "setBackgroundColor", witem!!.BackgroundColor) + + /* Paddings */ + view.setViewPadding( + R.id.tt_item_name_nodesc, + witem!!.NameNodescPadding[0], + witem!!.NameNodescPadding[1], + witem!!.NameNodescPadding[2], + witem!!.NameNodescPadding[3] + ) + + /* Text Colors */ + view.setInt(R.id.tt_item_num, "setTextColor", witem!!.NumColor) + view.setInt(R.id.tt_item_name, "setTextColor", getColor(context, witem!!.NameColor)) + view.setInt(R.id.tt_item_name_nodesc, "setTextColor", getColor(context, witem!!.NameNodescColor)) + view.setInt(R.id.tt_item_desc, "setTextColor", getColor(context, witem!!.DescColor)) + view.setInt(R.id.tt_item_room, "setTextColor", getColor(context, witem!!.RoomColor)) + view.setInt(R.id.tt_item_time, "setTextColor", getColor(context, witem!!.TimeColor)) + } + + fun getColor(context: Context, color: Int): Int { + return context.getResources().getColor(color) + } + + override fun getViewAt(position: Int): RemoteViews { + val view = RemoteViews(context.getPackageName(), R.layout.timetable_item) + witem = defaultItem(fullTheme, nightMode) + val curr_subject = day_subjects[position] + if (curr_subject.status.equals("empty")) { + witem!!.NumColor = getColor(context, R.color.text_miss_num) + witem!!.TimeVisibility = View.GONE + witem!!.RoomVisibility = View.GONE + witem!!.NameNodescColor = R.color.text_miss + } + if (!curr_subject.substituteTeacher.equals("null")) { + witem!!.NumColor = getColor(context, R.color.yellow) + witem!!.Layout = R.drawable.card_layout_tile_helyetesitett + } + if (curr_subject.status.equals("Elmaradt")) { + witem!!.NumColor = getColor(context, R.color.red) + witem!!.Layout = R.drawable.card_layout_tile_elmarad + } else if (curr_subject.status.equals("TanevRendjeEsemeny")) { + witem!!.NumVisibility = View.GONE + witem!!.TimeVisibility = View.GONE + witem!!.RoomVisibility = View.GONE + witem!!.NameNodescPadding[0] = 50 + witem!!.NameNodescPadding[2] = 50 + witem!!.NameNodescColor = R.color.text_miss + } + if (curr_subject.lessonTopic.equals("null")) { + witem!!.DescVisibility = View.GONE + witem!!.NameVisibility = View.GONE + witem!!.NameNodescVisibility = View.VISIBLE + } + setLayout(view) + val lessonIndexTrailing = if (curr_subject.lessonIndex.equals("+")) "" else "." + view.setTextViewText(R.id.tt_item_num, curr_subject.lessonIndex + lessonIndexTrailing) + view.setTextViewText(R.id.tt_item_name, curr_subject.lessonName) + view.setTextViewText(R.id.tt_item_name_nodesc, curr_subject.lessonName) + view.setTextViewText(R.id.tt_item_desc, curr_subject.lessonTopic) + view.setTextViewText(R.id.tt_item_room, curr_subject.lessonRoom) + if (curr_subject.lessonStart != 0L && curr_subject.lessonEnd != 0L) view.setTextViewText( + R.id.tt_item_time, + ((WidgetTimetable.zeroPad( + DateTime(curr_subject.lessonStart).getHourOfDay(), + 2 + ) + ":" + WidgetTimetable.zeroPad( + DateTime(curr_subject.lessonStart).getMinuteOfHour(), + 2 + )).toString() + + "\n" + WidgetTimetable.zeroPad( + DateTime(curr_subject.lessonEnd).getHourOfDay(), + 2 + )).toString() + ":" + WidgetTimetable.zeroPad( + DateTime(curr_subject.lessonEnd).getMinuteOfHour(), + 2 + ) + ) + return view + } + + override fun getLoadingView(): RemoteViews { + val view = RemoteViews(context.getPackageName(), R.layout.timetable_item) + return view + } + + override fun getViewTypeCount(): Int { + return 1 + } + + override fun getItemId(position: Int): Long { + return position.toLong() + } + + override fun hasStableIds(): Boolean { + return true + } + + private fun initData() { + // refresh theme + fullTheme = getFullTheme(context) + rday = WidgetTimetable.selectDay(context, appWidgetId, 0, false) + day_subjects.clear() + lessonIndexes.clear() + try { + val arr: MutableList = WidgetTimetable.genJsonDays(context) as MutableList + if (arr.isEmpty()) { + return + } + val arr_lessons: JSONArray = WidgetTimetable.genJsonDays(context).get(rday) + for (i in 0 until arr_lessons.length()) { + val obj_lessons: JSONObject = arr_lessons.getJSONObject(i) + day_subjects.add(jsonToLesson(obj_lessons)) + } + } catch (e: JSONException) { + e.printStackTrace() + } + if (day_subjects.size > 0) { + Collections.sort(day_subjects, object : Comparator { + override fun compare(o1: Lesson?, o2: Lesson?): Int { + return DateTime(o1?.lessonStart).compareTo(DateTime(o2?.lessonStart)) + } + }) + for (i in 0 until day_subjects.size) { + if (!day_subjects[i].lessonIndex.equals("+")) { + lessonIndexes.add(Integer.valueOf(day_subjects[i].lessonIndex)) + } + } + if (lessonIndexes.size > 0) { + var lessonsChecked: Int = Collections.min(lessonIndexes) + var i = 0 + while (lessonsChecked < Collections.max(lessonIndexes)) { + if (!lessonIndexes.contains(lessonsChecked)) { + day_subjects.add(i, emptyLesson(lessonsChecked)) + } + lessonsChecked++ + i++ + } + } + } + } + + fun defaultItem(fullTheme: Array, nightMode: Int): Item { + val textColor: Int + val textDescColor: Int + if (fullTheme[0] == 0 && nightMode == UiModeManager.MODE_NIGHT_NO) { + textColor = R.color.text_light + textDescColor = R.color.text_desc_light + } else if (fullTheme[0] == 1) { + textColor = R.color.text_light + textDescColor = R.color.text_desc_light + } else { + textColor = R.color.text + textDescColor = R.color.text_desc + } + return Item( + R.drawable.card_layout_tile, + fullTheme[2], + View.VISIBLE, + View.VISIBLE, + View.INVISIBLE, + View.VISIBLE, + View.VISIBLE, + View.VISIBLE, + fullTheme[1], + textColor, + textColor, + textDescColor, + textDescColor, + textColor + ) + } + + fun emptyLesson(lessonIndex: Int): Lesson { + return Lesson( + "empty", + lessonIndex.toString(), + "Lyukasóra", + "null", + "null", + 0, + 0, + "null" + ) + } + + fun jsonToLesson(json: JSONObject): Lesson { + try { + var name: String = json.getString("Nev") + name = name.substring(0, 1).toUpperCase() + name.substring(1) // Capitalize name + return Lesson( + json.getJSONObject("Allapot").getString("Nev"), + if (!json.getString("Oraszam").equals("null")) json.getString("Oraszam") else "+", + name, + json.getString("Tema"), + json.getString("TeremNeve"), + DateTime(json.getString("KezdetIdopont")).getMillis(), + DateTime(json.getString("VegIdopont")).getMillis(), + json.getString("HelyettesTanarNeve") + ) + } catch (e: Exception) { + Log.d("Filc", "exception: $e") + } + return Lesson("", "", "", "", "", 0, 0, "") + } + + companion object { + fun getFullTheme(context: Context): Array { + val dbManager = DBManager(context.getApplicationContext()) + try { + dbManager.open() + val cursor: Cursor = dbManager.fetchTheme() + dbManager.close() + val theme: Int = cursor.getInt(0) + val customAccentColor: Int = cursor.getInt(1) + val customBackgroundColor: Int = cursor.getInt(2) + return arrayOf(theme, customAccentColor, customBackgroundColor) + } catch (e: Exception) { + e.printStackTrace() + } + return arrayOf(0, 0, 0) + } + } +} diff --git a/refilc/android/app/src/main/java/hu/refilc/naplo/widget_timetable/WidgetTimetableService.kt b/refilc/android/app/src/main/java/hu/refilc/naplo/widget_timetable/WidgetTimetableService.kt new file mode 100644 index 0000000..7990e4b --- /dev/null +++ b/refilc/android/app/src/main/java/hu/refilc/naplo/widget_timetable/WidgetTimetableService.kt @@ -0,0 +1,12 @@ +package hu.refilc.naplo.widget_timetable + +import android.content.Context +import android.content.Intent +import android.os.Build +import android.widget.RemoteViewsService + +class WidgetTimetableService: RemoteViewsService() { + override fun onGetViewFactory(intent: Intent): RemoteViewsFactory { + return WidgetTimetableDataProvider(getApplicationContext(), intent) + } +} diff --git a/refilc/android/app/src/main/res/drawable-hdpi/android12splash.png b/refilc/android/app/src/main/res/drawable-hdpi/android12splash.png new file mode 100644 index 0000000..44270d2 Binary files /dev/null and b/refilc/android/app/src/main/res/drawable-hdpi/android12splash.png differ diff --git a/refilc/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png b/refilc/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..9ab61ac Binary files /dev/null and b/refilc/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png differ diff --git a/filcnaplo/android/app/src/main/res/drawable-hdpi/ic_stat_splash_logo.png b/refilc/android/app/src/main/res/drawable-hdpi/ic_stat_splash_logo.png similarity index 100% rename from filcnaplo/android/app/src/main/res/drawable-hdpi/ic_stat_splash_logo.png rename to refilc/android/app/src/main/res/drawable-hdpi/ic_stat_splash_logo.png diff --git a/refilc/android/app/src/main/res/drawable-hdpi/splash.png b/refilc/android/app/src/main/res/drawable-hdpi/splash.png new file mode 100644 index 0000000..44270d2 Binary files /dev/null and b/refilc/android/app/src/main/res/drawable-hdpi/splash.png differ diff --git a/filcnaplo/android/app/src/main/res/drawable-hdpi/tinta_image.png b/refilc/android/app/src/main/res/drawable-hdpi/tinta_image.png similarity index 100% rename from filcnaplo/android/app/src/main/res/drawable-hdpi/tinta_image.png rename to refilc/android/app/src/main/res/drawable-hdpi/tinta_image.png diff --git a/refilc/android/app/src/main/res/drawable-mdpi/android12splash.png b/refilc/android/app/src/main/res/drawable-mdpi/android12splash.png new file mode 100644 index 0000000..8bbb6c5 Binary files /dev/null and b/refilc/android/app/src/main/res/drawable-mdpi/android12splash.png differ diff --git a/refilc/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png b/refilc/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..26787bb Binary files /dev/null and b/refilc/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png differ diff --git a/filcnaplo/android/app/src/main/res/drawable-mdpi/ic_stat_splash_logo.png b/refilc/android/app/src/main/res/drawable-mdpi/ic_stat_splash_logo.png similarity index 100% rename from filcnaplo/android/app/src/main/res/drawable-mdpi/ic_stat_splash_logo.png rename to refilc/android/app/src/main/res/drawable-mdpi/ic_stat_splash_logo.png diff --git a/refilc/android/app/src/main/res/drawable-mdpi/splash.png b/refilc/android/app/src/main/res/drawable-mdpi/splash.png new file mode 100644 index 0000000..8bbb6c5 Binary files /dev/null and b/refilc/android/app/src/main/res/drawable-mdpi/splash.png differ diff --git a/refilc/android/app/src/main/res/drawable-night-hdpi/android12splash.png b/refilc/android/app/src/main/res/drawable-night-hdpi/android12splash.png new file mode 100644 index 0000000..44270d2 Binary files /dev/null and b/refilc/android/app/src/main/res/drawable-night-hdpi/android12splash.png differ diff --git a/refilc/android/app/src/main/res/drawable-night-mdpi/android12splash.png b/refilc/android/app/src/main/res/drawable-night-mdpi/android12splash.png new file mode 100644 index 0000000..8bbb6c5 Binary files /dev/null and b/refilc/android/app/src/main/res/drawable-night-mdpi/android12splash.png differ diff --git a/refilc/android/app/src/main/res/drawable-night-xhdpi/android12splash.png b/refilc/android/app/src/main/res/drawable-night-xhdpi/android12splash.png new file mode 100644 index 0000000..f0be66f Binary files /dev/null and b/refilc/android/app/src/main/res/drawable-night-xhdpi/android12splash.png differ diff --git a/refilc/android/app/src/main/res/drawable-night-xxhdpi/android12splash.png b/refilc/android/app/src/main/res/drawable-night-xxhdpi/android12splash.png new file mode 100644 index 0000000..dff19fd Binary files /dev/null and b/refilc/android/app/src/main/res/drawable-night-xxhdpi/android12splash.png differ diff --git a/refilc/android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png b/refilc/android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png new file mode 100644 index 0000000..1cfecc9 Binary files /dev/null and b/refilc/android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png differ diff --git a/filcnaplo/android/app/src/main/res/drawable-nodpi/ic_check.xml b/refilc/android/app/src/main/res/drawable-nodpi/ic_check.xml similarity index 97% rename from filcnaplo/android/app/src/main/res/drawable-nodpi/ic_check.xml rename to refilc/android/app/src/main/res/drawable-nodpi/ic_check.xml index 4545224..62d6723 100644 --- a/filcnaplo/android/app/src/main/res/drawable-nodpi/ic_check.xml +++ b/refilc/android/app/src/main/res/drawable-nodpi/ic_check.xml @@ -1,13 +1,13 @@ - - - + + + diff --git a/filcnaplo/android/app/src/main/res/drawable-nodpi/ic_chevron_left.xml b/refilc/android/app/src/main/res/drawable-nodpi/ic_chevron_left.xml similarity index 97% rename from filcnaplo/android/app/src/main/res/drawable-nodpi/ic_chevron_left.xml rename to refilc/android/app/src/main/res/drawable-nodpi/ic_chevron_left.xml index a7f5dd6..01e9d40 100644 --- a/filcnaplo/android/app/src/main/res/drawable-nodpi/ic_chevron_left.xml +++ b/refilc/android/app/src/main/res/drawable-nodpi/ic_chevron_left.xml @@ -1,13 +1,13 @@ - - - + + + diff --git a/filcnaplo/android/app/src/main/res/drawable-nodpi/ic_chevron_right.xml b/refilc/android/app/src/main/res/drawable-nodpi/ic_chevron_right.xml similarity index 97% rename from filcnaplo/android/app/src/main/res/drawable-nodpi/ic_chevron_right.xml rename to refilc/android/app/src/main/res/drawable-nodpi/ic_chevron_right.xml index 93ad67e..c1e9015 100644 --- a/filcnaplo/android/app/src/main/res/drawable-nodpi/ic_chevron_right.xml +++ b/refilc/android/app/src/main/res/drawable-nodpi/ic_chevron_right.xml @@ -1,13 +1,13 @@ - - - + + + diff --git a/filcnaplo/android/app/src/main/res/drawable-nodpi/ic_droplet.xml b/refilc/android/app/src/main/res/drawable-nodpi/ic_droplet.xml similarity index 97% rename from filcnaplo/android/app/src/main/res/drawable-nodpi/ic_droplet.xml rename to refilc/android/app/src/main/res/drawable-nodpi/ic_droplet.xml index 865d06c..cc3690b 100644 --- a/filcnaplo/android/app/src/main/res/drawable-nodpi/ic_droplet.xml +++ b/refilc/android/app/src/main/res/drawable-nodpi/ic_droplet.xml @@ -1,13 +1,13 @@ - - - + + + diff --git a/filcnaplo/android/app/src/main/res/drawable-nodpi/ic_launcher_background.xml b/refilc/android/app/src/main/res/drawable-nodpi/ic_launcher_background.xml similarity index 97% rename from filcnaplo/android/app/src/main/res/drawable-nodpi/ic_launcher_background.xml rename to refilc/android/app/src/main/res/drawable-nodpi/ic_launcher_background.xml index a4f78de..07d5da9 100644 --- a/filcnaplo/android/app/src/main/res/drawable-nodpi/ic_launcher_background.xml +++ b/refilc/android/app/src/main/res/drawable-nodpi/ic_launcher_background.xml @@ -1,170 +1,170 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/filcnaplo/android/app/src/main/res/drawable-nodpi/ic_launcher_foreground.xml b/refilc/android/app/src/main/res/drawable-nodpi/ic_launcher_foreground.xml similarity index 97% rename from filcnaplo/android/app/src/main/res/drawable-nodpi/ic_launcher_foreground.xml rename to refilc/android/app/src/main/res/drawable-nodpi/ic_launcher_foreground.xml index cc14f03..2b068d1 100644 --- a/filcnaplo/android/app/src/main/res/drawable-nodpi/ic_launcher_foreground.xml +++ b/refilc/android/app/src/main/res/drawable-nodpi/ic_launcher_foreground.xml @@ -1,30 +1,30 @@ - - - - - - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/filcnaplo/android/app/src/main/res/drawable-nodpi/ic_navigation_2.xml b/refilc/android/app/src/main/res/drawable-nodpi/ic_navigation_2.xml similarity index 97% rename from filcnaplo/android/app/src/main/res/drawable-nodpi/ic_navigation_2.xml rename to refilc/android/app/src/main/res/drawable-nodpi/ic_navigation_2.xml index 90b35d8..273720c 100644 --- a/filcnaplo/android/app/src/main/res/drawable-nodpi/ic_navigation_2.xml +++ b/refilc/android/app/src/main/res/drawable-nodpi/ic_navigation_2.xml @@ -1,13 +1,13 @@ - - - + + + diff --git a/filcnaplo/android/app/src/main/res/drawable-nodpi/ic_refresh_cw.xml b/refilc/android/app/src/main/res/drawable-nodpi/ic_refresh_cw.xml similarity index 97% rename from filcnaplo/android/app/src/main/res/drawable-nodpi/ic_refresh_cw.xml rename to refilc/android/app/src/main/res/drawable-nodpi/ic_refresh_cw.xml index 289cd49..f2365a8 100644 --- a/filcnaplo/android/app/src/main/res/drawable-nodpi/ic_refresh_cw.xml +++ b/refilc/android/app/src/main/res/drawable-nodpi/ic_refresh_cw.xml @@ -1,27 +1,27 @@ - - - - - + + + + + diff --git a/filcnaplo/android/app/src/main/res/drawable-v21/app_widget_background.xml b/refilc/android/app/src/main/res/drawable-v21/app_widget_background.xml similarity index 95% rename from filcnaplo/android/app/src/main/res/drawable-v21/app_widget_background.xml rename to refilc/android/app/src/main/res/drawable-v21/app_widget_background.xml index 6721d42..785445c 100644 --- a/filcnaplo/android/app/src/main/res/drawable-v21/app_widget_background.xml +++ b/refilc/android/app/src/main/res/drawable-v21/app_widget_background.xml @@ -1,10 +1,10 @@ - - - - - + + + + + \ No newline at end of file diff --git a/filcnaplo/android/app/src/main/res/drawable-v21/app_widget_inner_view_background.xml b/refilc/android/app/src/main/res/drawable-v21/app_widget_inner_view_background.xml similarity index 95% rename from filcnaplo/android/app/src/main/res/drawable-v21/app_widget_inner_view_background.xml rename to refilc/android/app/src/main/res/drawable-v21/app_widget_inner_view_background.xml index 5ae60cf..007e287 100644 --- a/filcnaplo/android/app/src/main/res/drawable-v21/app_widget_inner_view_background.xml +++ b/refilc/android/app/src/main/res/drawable-v21/app_widget_inner_view_background.xml @@ -1,10 +1,10 @@ - - - - - + + + + + \ No newline at end of file diff --git a/refilc/android/app/src/main/res/drawable-v21/background.png b/refilc/android/app/src/main/res/drawable-v21/background.png new file mode 100644 index 0000000..7b563c8 Binary files /dev/null and b/refilc/android/app/src/main/res/drawable-v21/background.png differ diff --git a/filcnaplo/android/app/src/main/res/drawable-v21/launch_background.xml b/refilc/android/app/src/main/res/drawable-v21/launch_background.xml similarity index 100% rename from filcnaplo/android/app/src/main/res/drawable-v21/launch_background.xml rename to refilc/android/app/src/main/res/drawable-v21/launch_background.xml diff --git a/refilc/android/app/src/main/res/drawable-xhdpi/android12splash.png b/refilc/android/app/src/main/res/drawable-xhdpi/android12splash.png new file mode 100644 index 0000000..f0be66f Binary files /dev/null and b/refilc/android/app/src/main/res/drawable-xhdpi/android12splash.png differ diff --git a/filcnaplo/android/app/src/main/res/drawable-xhdpi/widget_card_top_dark.xml b/refilc/android/app/src/main/res/drawable-xhdpi/card_layout_bg.xml similarity index 78% rename from filcnaplo/android/app/src/main/res/drawable-xhdpi/widget_card_top_dark.xml rename to refilc/android/app/src/main/res/drawable-xhdpi/card_layout_bg.xml index c41e2b5..78dab0f 100644 --- a/filcnaplo/android/app/src/main/res/drawable-xhdpi/widget_card_top_dark.xml +++ b/refilc/android/app/src/main/res/drawable-xhdpi/card_layout_bg.xml @@ -1,7 +1,7 @@ - - - - - - - \ No newline at end of file + + + + + + + diff --git a/filcnaplo/android/app/src/main/res/drawable-xhdpi/card_layout_tile.xml b/refilc/android/app/src/main/res/drawable-xhdpi/card_layout_tile.xml similarity index 95% rename from filcnaplo/android/app/src/main/res/drawable-xhdpi/card_layout_tile.xml rename to refilc/android/app/src/main/res/drawable-xhdpi/card_layout_tile.xml index f12f731..6466eba 100644 --- a/filcnaplo/android/app/src/main/res/drawable-xhdpi/card_layout_tile.xml +++ b/refilc/android/app/src/main/res/drawable-xhdpi/card_layout_tile.xml @@ -1,6 +1,6 @@ - - - - - + + + + + \ No newline at end of file diff --git a/filcnaplo/android/app/src/main/res/drawable-xhdpi/card_layout_tile_elmarad.xml b/refilc/android/app/src/main/res/drawable-xhdpi/card_layout_tile_elmarad.xml similarity index 95% rename from filcnaplo/android/app/src/main/res/drawable-xhdpi/card_layout_tile_elmarad.xml rename to refilc/android/app/src/main/res/drawable-xhdpi/card_layout_tile_elmarad.xml index ee09eea..426d5c1 100644 --- a/filcnaplo/android/app/src/main/res/drawable-xhdpi/card_layout_tile_elmarad.xml +++ b/refilc/android/app/src/main/res/drawable-xhdpi/card_layout_tile_elmarad.xml @@ -1,6 +1,6 @@ - - - - - + + + + + \ No newline at end of file diff --git a/filcnaplo/android/app/src/main/res/drawable-xhdpi/card_layout_tile_helyetesitett.xml b/refilc/android/app/src/main/res/drawable-xhdpi/card_layout_tile_helyetesitett.xml similarity index 95% rename from filcnaplo/android/app/src/main/res/drawable-xhdpi/card_layout_tile_helyetesitett.xml rename to refilc/android/app/src/main/res/drawable-xhdpi/card_layout_tile_helyetesitett.xml index 030aaf2..6e5cbff 100644 --- a/filcnaplo/android/app/src/main/res/drawable-xhdpi/card_layout_tile_helyetesitett.xml +++ b/refilc/android/app/src/main/res/drawable-xhdpi/card_layout_tile_helyetesitett.xml @@ -1,6 +1,6 @@ - - - - - + + + + + \ No newline at end of file diff --git a/refilc/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png b/refilc/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..ce3adc9 Binary files /dev/null and b/refilc/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png differ diff --git a/filcnaplo/android/app/src/main/res/drawable-xhdpi/ic_stat_splash_logo.png b/refilc/android/app/src/main/res/drawable-xhdpi/ic_stat_splash_logo.png similarity index 100% rename from filcnaplo/android/app/src/main/res/drawable-xhdpi/ic_stat_splash_logo.png rename to refilc/android/app/src/main/res/drawable-xhdpi/ic_stat_splash_logo.png diff --git a/refilc/android/app/src/main/res/drawable-xhdpi/splash.png b/refilc/android/app/src/main/res/drawable-xhdpi/splash.png new file mode 100644 index 0000000..f0be66f Binary files /dev/null and b/refilc/android/app/src/main/res/drawable-xhdpi/splash.png differ diff --git a/filcnaplo/android/app/src/main/res/drawable-xhdpi/timetable_widget_preview.png b/refilc/android/app/src/main/res/drawable-xhdpi/timetable_widget_preview.png similarity index 100% rename from filcnaplo/android/app/src/main/res/drawable-xhdpi/timetable_widget_preview.png rename to refilc/android/app/src/main/res/drawable-xhdpi/timetable_widget_preview.png diff --git a/filcnaplo/android/app/src/main/res/drawable-xhdpi/widget_card_bottom.xml b/refilc/android/app/src/main/res/drawable-xhdpi/widget_card_bottom.xml similarity index 96% rename from filcnaplo/android/app/src/main/res/drawable-xhdpi/widget_card_bottom.xml rename to refilc/android/app/src/main/res/drawable-xhdpi/widget_card_bottom.xml index 80b52be..8a99162 100644 --- a/filcnaplo/android/app/src/main/res/drawable-xhdpi/widget_card_bottom.xml +++ b/refilc/android/app/src/main/res/drawable-xhdpi/widget_card_bottom.xml @@ -1,7 +1,7 @@ - - - - - - + + + + + + \ No newline at end of file diff --git a/filcnaplo/android/app/src/main/res/drawable-xhdpi/widget_card_bottom_dark.xml b/refilc/android/app/src/main/res/drawable-xhdpi/widget_card_bottom_dark.xml similarity index 68% rename from filcnaplo/android/app/src/main/res/drawable-xhdpi/widget_card_bottom_dark.xml rename to refilc/android/app/src/main/res/drawable-xhdpi/widget_card_bottom_dark.xml index f2d52b0..d8ad4a8 100644 --- a/filcnaplo/android/app/src/main/res/drawable-xhdpi/widget_card_bottom_dark.xml +++ b/refilc/android/app/src/main/res/drawable-xhdpi/widget_card_bottom_dark.xml @@ -1,7 +1,7 @@ - - - - - - - \ No newline at end of file + + + + + + + diff --git a/filcnaplo/android/app/src/main/res/drawable-xhdpi/widget_card_top.xml b/refilc/android/app/src/main/res/drawable-xhdpi/widget_card_top.xml similarity index 96% rename from filcnaplo/android/app/src/main/res/drawable-xhdpi/widget_card_top.xml rename to refilc/android/app/src/main/res/drawable-xhdpi/widget_card_top.xml index a37fed6..e0e9376 100644 --- a/filcnaplo/android/app/src/main/res/drawable-xhdpi/widget_card_top.xml +++ b/refilc/android/app/src/main/res/drawable-xhdpi/widget_card_top.xml @@ -1,7 +1,7 @@ - - - - - - + + + + + + \ No newline at end of file diff --git a/filcnaplo/android/app/src/main/res/drawable-xhdpi/card_layout_bg.xml b/refilc/android/app/src/main/res/drawable-xhdpi/widget_card_top_dark.xml similarity index 52% rename from filcnaplo/android/app/src/main/res/drawable-xhdpi/card_layout_bg.xml rename to refilc/android/app/src/main/res/drawable-xhdpi/widget_card_top_dark.xml index 0def536..b17a764 100644 --- a/filcnaplo/android/app/src/main/res/drawable-xhdpi/card_layout_bg.xml +++ b/refilc/android/app/src/main/res/drawable-xhdpi/widget_card_top_dark.xml @@ -1,7 +1,7 @@ - - - - - - - \ No newline at end of file + + + + + + + diff --git a/filcnaplo/android/app/src/main/res/drawable-xhdpi/widget_scroll_style.xml b/refilc/android/app/src/main/res/drawable-xhdpi/widget_scroll_style.xml similarity index 94% rename from filcnaplo/android/app/src/main/res/drawable-xhdpi/widget_scroll_style.xml rename to refilc/android/app/src/main/res/drawable-xhdpi/widget_scroll_style.xml index a4eab7e..a8f281e 100644 --- a/filcnaplo/android/app/src/main/res/drawable-xhdpi/widget_scroll_style.xml +++ b/refilc/android/app/src/main/res/drawable-xhdpi/widget_scroll_style.xml @@ -1,17 +1,17 @@ - - - - - - - - - - - + + + + + + + + + + + \ No newline at end of file diff --git a/refilc/android/app/src/main/res/drawable-xxhdpi/android12splash.png b/refilc/android/app/src/main/res/drawable-xxhdpi/android12splash.png new file mode 100644 index 0000000..dff19fd Binary files /dev/null and b/refilc/android/app/src/main/res/drawable-xxhdpi/android12splash.png differ diff --git a/refilc/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png b/refilc/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..4eb9f08 Binary files /dev/null and b/refilc/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png differ diff --git a/filcnaplo/android/app/src/main/res/drawable-xxhdpi/ic_stat_splash_logo.png b/refilc/android/app/src/main/res/drawable-xxhdpi/ic_stat_splash_logo.png similarity index 100% rename from filcnaplo/android/app/src/main/res/drawable-xxhdpi/ic_stat_splash_logo.png rename to refilc/android/app/src/main/res/drawable-xxhdpi/ic_stat_splash_logo.png diff --git a/refilc/android/app/src/main/res/drawable-xxhdpi/splash.png b/refilc/android/app/src/main/res/drawable-xxhdpi/splash.png new file mode 100644 index 0000000..dff19fd Binary files /dev/null and b/refilc/android/app/src/main/res/drawable-xxhdpi/splash.png differ diff --git a/refilc/android/app/src/main/res/drawable-xxxhdpi/android12splash.png b/refilc/android/app/src/main/res/drawable-xxxhdpi/android12splash.png new file mode 100644 index 0000000..1cfecc9 Binary files /dev/null and b/refilc/android/app/src/main/res/drawable-xxxhdpi/android12splash.png differ diff --git a/refilc/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png b/refilc/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..253bcd0 Binary files /dev/null and b/refilc/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png differ diff --git a/filcnaplo/android/app/src/main/res/drawable-xxxhdpi/ic_stat_splash_logo.png b/refilc/android/app/src/main/res/drawable-xxxhdpi/ic_stat_splash_logo.png similarity index 100% rename from filcnaplo/android/app/src/main/res/drawable-xxxhdpi/ic_stat_splash_logo.png rename to refilc/android/app/src/main/res/drawable-xxxhdpi/ic_stat_splash_logo.png diff --git a/refilc/android/app/src/main/res/drawable-xxxhdpi/splash.png b/refilc/android/app/src/main/res/drawable-xxxhdpi/splash.png new file mode 100644 index 0000000..1cfecc9 Binary files /dev/null and b/refilc/android/app/src/main/res/drawable-xxxhdpi/splash.png differ diff --git a/refilc/android/app/src/main/res/drawable/background.png b/refilc/android/app/src/main/res/drawable/background.png new file mode 100644 index 0000000..7b563c8 Binary files /dev/null and b/refilc/android/app/src/main/res/drawable/background.png differ diff --git a/filcnaplo/android/app/src/main/res/drawable/btn_shape.xml b/refilc/android/app/src/main/res/drawable/btn_shape.xml similarity index 95% rename from filcnaplo/android/app/src/main/res/drawable/btn_shape.xml rename to refilc/android/app/src/main/res/drawable/btn_shape.xml index b820ec8..d91b3b2 100644 --- a/filcnaplo/android/app/src/main/res/drawable/btn_shape.xml +++ b/refilc/android/app/src/main/res/drawable/btn_shape.xml @@ -1,18 +1,18 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/filcnaplo/android/app/src/main/res/drawable/btn_shape_login.xml b/refilc/android/app/src/main/res/drawable/btn_shape_login.xml similarity index 70% rename from filcnaplo/android/app/src/main/res/drawable/btn_shape_login.xml rename to refilc/android/app/src/main/res/drawable/btn_shape_login.xml index 84bb6fe..99824d4 100644 --- a/filcnaplo/android/app/src/main/res/drawable/btn_shape_login.xml +++ b/refilc/android/app/src/main/res/drawable/btn_shape_login.xml @@ -1,18 +1,18 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + + + diff --git a/filcnaplo/android/app/src/main/res/drawable/ic_absences.png b/refilc/android/app/src/main/res/drawable/ic_absences.png similarity index 100% rename from filcnaplo/android/app/src/main/res/drawable/ic_absences.png rename to refilc/android/app/src/main/res/drawable/ic_absences.png diff --git a/filcnaplo/android/app/src/main/res/drawable/ic_grades.png b/refilc/android/app/src/main/res/drawable/ic_grades.png similarity index 100% rename from filcnaplo/android/app/src/main/res/drawable/ic_grades.png rename to refilc/android/app/src/main/res/drawable/ic_grades.png diff --git a/filcnaplo/android/app/src/main/res/drawable/ic_home.png b/refilc/android/app/src/main/res/drawable/ic_home.png similarity index 100% rename from filcnaplo/android/app/src/main/res/drawable/ic_home.png rename to refilc/android/app/src/main/res/drawable/ic_home.png diff --git a/filcnaplo/android/app/src/main/res/drawable/ic_messages.png b/refilc/android/app/src/main/res/drawable/ic_messages.png similarity index 100% rename from filcnaplo/android/app/src/main/res/drawable/ic_messages.png rename to refilc/android/app/src/main/res/drawable/ic_messages.png diff --git a/filcnaplo/android/app/src/main/res/drawable/ic_notification.png b/refilc/android/app/src/main/res/drawable/ic_notification.png similarity index 100% rename from filcnaplo/android/app/src/main/res/drawable/ic_notification.png rename to refilc/android/app/src/main/res/drawable/ic_notification.png diff --git a/filcnaplo/android/app/src/main/res/drawable/ic_timetable.png b/refilc/android/app/src/main/res/drawable/ic_timetable.png similarity index 100% rename from filcnaplo/android/app/src/main/res/drawable/ic_timetable.png rename to refilc/android/app/src/main/res/drawable/ic_timetable.png diff --git a/filcnaplo/android/app/src/main/res/drawable/launch_background.xml b/refilc/android/app/src/main/res/drawable/launch_background.xml similarity index 100% rename from filcnaplo/android/app/src/main/res/drawable/launch_background.xml rename to refilc/android/app/src/main/res/drawable/launch_background.xml diff --git a/filcnaplo/android/app/src/main/res/font/montserrat_medium.ttf b/refilc/android/app/src/main/res/font/montserrat_medium.ttf similarity index 100% rename from filcnaplo/android/app/src/main/res/font/montserrat_medium.ttf rename to refilc/android/app/src/main/res/font/montserrat_medium.ttf diff --git a/filcnaplo/android/app/src/main/res/ic_launcher-web.png b/refilc/android/app/src/main/res/ic_launcher-web.png similarity index 100% rename from filcnaplo/android/app/src/main/res/ic_launcher-web.png rename to refilc/android/app/src/main/res/ic_launcher-web.png diff --git a/filcnaplo/android/app/src/main/res/layout/home_widget_test.xml b/refilc/android/app/src/main/res/layout/home_widget_test.xml similarity index 95% rename from filcnaplo/android/app/src/main/res/layout/home_widget_test.xml rename to refilc/android/app/src/main/res/layout/home_widget_test.xml index b12af8d..f0a315a 100644 --- a/filcnaplo/android/app/src/main/res/layout/home_widget_test.xml +++ b/refilc/android/app/src/main/res/layout/home_widget_test.xml @@ -1,26 +1,26 @@ - - - - - - + + + + + + \ No newline at end of file diff --git a/filcnaplo/android/app/src/main/res/layout/timetable_item.xml b/refilc/android/app/src/main/res/layout/timetable_item.xml similarity index 96% rename from filcnaplo/android/app/src/main/res/layout/timetable_item.xml rename to refilc/android/app/src/main/res/layout/timetable_item.xml index aa23af8..f057d2d 100644 --- a/filcnaplo/android/app/src/main/res/layout/timetable_item.xml +++ b/refilc/android/app/src/main/res/layout/timetable_item.xml @@ -1,113 +1,113 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/filcnaplo/android/app/src/main/res/layout/widget_timetable.xml b/refilc/android/app/src/main/res/layout/widget_timetable.xml similarity index 64% rename from filcnaplo/android/app/src/main/res/layout/widget_timetable.xml rename to refilc/android/app/src/main/res/layout/widget_timetable.xml index 75496ef..93af688 100644 --- a/filcnaplo/android/app/src/main/res/layout/widget_timetable.xml +++ b/refilc/android/app/src/main/res/layout/widget_timetable.xml @@ -1,232 +1,154 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -