forked from github/szkolny
Compare commits
68 Commits
v3.9.9-dev
...
v3.9.13-de
Author | SHA1 | Date | |
---|---|---|---|
1acf1547d5 | |||
5d3de35c10 | |||
8f8d613f6e | |||
6a161b3c97 | |||
3e97572100 | |||
fc3b6fd1e0 | |||
9bc7f9ac11 | |||
0a2f252405 | |||
09bc658f97 | |||
7b04202a00 | |||
acf364166b | |||
4e88efae94 | |||
8df24dc1c4 | |||
8482c27689 | |||
d1265dc1f2 | |||
47d395de71 | |||
5b443e02a3 | |||
f8a7d52b1d | |||
a133a96819 | |||
c71b8f994c | |||
9b02c97926 | |||
ab06efc934 | |||
928b73f139 | |||
a36fb09bc3 | |||
eaed4b76aa | |||
6d8960f089 | |||
ca3b6d0705 | |||
c2e7931ea6 | |||
d1a5d8cba9 | |||
c2f91e6867 | |||
55e32b8d88 | |||
462b1df767 | |||
d17d2c8417 | |||
6892832fff | |||
66d54c7c45 | |||
d432685aa8 | |||
37f3d76fb8 | |||
7961a74995 | |||
9d590508ad | |||
f79b7eaf83 | |||
ae13bf946f | |||
f116c4f1f4 | |||
867c8920a8 | |||
6e6dd34872 | |||
0759468fa7 | |||
1b1fb09211 | |||
de414c912c | |||
d274a2fed1 | |||
285b7e9b9e | |||
875efcff7e | |||
07ae37167d | |||
f689f4d427 | |||
19bc2b8b37 | |||
673116e27e | |||
59fcb0a050 | |||
cd76f99bbf | |||
6a4994b9c2 | |||
63960c5e05 | |||
540afb6a28 | |||
ae10b8abbd | |||
db2ebab879 | |||
6ec3d062df | |||
86b6060a09 | |||
83d123e341 | |||
34061695f9 | |||
de68476442 | |||
678a81a44b | |||
cfb3096d53 |
2
.gitignore
vendored
2
.gitignore
vendored
@ -81,3 +81,5 @@ lint/generated/
|
||||
lint/outputs/
|
||||
lint/tmp/
|
||||
# lint/reports/
|
||||
|
||||
app/schemas/
|
||||
|
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@ -50,7 +50,7 @@
|
||||
</value>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="JDK" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
|
@ -24,6 +24,7 @@
|
||||
-keep class pl.szczodrzynski.edziennik.utils.models.** { *; }
|
||||
-keep class pl.szczodrzynski.edziennik.data.db.modules.events.Event { *; }
|
||||
-keep class pl.szczodrzynski.edziennik.data.db.modules.events.EventFull { *; }
|
||||
-keep class pl.szczodrzynski.edziennik.ui.modules.home.HomeCardModel { *; }
|
||||
-keepclassmembers class pl.szczodrzynski.edziennik.widgets.WidgetConfig { public *; }
|
||||
-keepnames class pl.szczodrzynski.edziennik.WidgetTimetable
|
||||
-keepnames class pl.szczodrzynski.edziennik.notifications.WidgetNotifications
|
||||
|
13
app/sampledata/settings/ic_settings.xml
Normal file
13
app/sampledata/settings/ic_settings.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<!--
|
||||
~ Copyright (c) Kuba Szczodrzyński 2019-11-25.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M12,8A4,4 0,0 1,16 12A4,4 0,0 1,12 16A4,4 0,0 1,8 12A4,4 0,0 1,12 8M12,10A2,2 0,0 0,10 12A2,2 0,0 0,12 14A2,2 0,0 0,14 12A2,2 0,0 0,12 10M10,22C9.75,22 9.54,21.82 9.5,21.58L9.13,18.93C8.5,18.68 7.96,18.34 7.44,17.94L4.95,18.95C4.73,19.03 4.46,18.95 4.34,18.73L2.34,15.27C2.21,15.05 2.27,14.78 2.46,14.63L4.57,12.97L4.5,12L4.57,11L2.46,9.37C2.27,9.22 2.21,8.95 2.34,8.73L4.34,5.27C4.46,5.05 4.73,4.96 4.95,5.05L7.44,6.05C7.96,5.66 8.5,5.32 9.13,5.07L9.5,2.42C9.54,2.18 9.75,2 10,2H14C14.25,2 14.46,2.18 14.5,2.42L14.87,5.07C15.5,5.32 16.04,5.66 16.56,6.05L19.05,5.05C19.27,4.96 19.54,5.05 19.66,5.27L21.66,8.73C21.79,8.95 21.73,9.22 21.54,9.37L19.43,11L19.5,12L19.43,13L21.54,14.63C21.73,14.78 21.79,15.05 21.66,15.27L19.66,18.73C19.54,18.95 19.27,19.04 19.05,18.95L16.56,17.95C16.04,18.34 15.5,18.68 14.87,18.93L14.5,21.58C14.46,21.82 14.25,22 14,22H10M11.25,4L10.88,6.61C9.68,6.86 8.62,7.5 7.85,8.39L5.44,7.35L4.69,8.65L6.8,10.2C6.4,11.37 6.4,12.64 6.8,13.8L4.68,15.36L5.43,16.66L7.86,15.62C8.63,16.5 9.68,17.14 10.87,17.38L11.24,20H12.76L13.13,17.39C14.32,17.14 15.37,16.5 16.14,15.62L18.57,16.66L19.32,15.36L17.2,13.81C17.6,12.64 17.6,11.37 17.2,10.2L19.31,8.65L18.56,7.35L16.15,8.39C15.38,7.5 14.32,6.86 13.12,6.62L12.75,4H11.25Z"/>
|
||||
</vector>
|
@ -18,7 +18,6 @@ import android.os.Handler;
|
||||
import android.provider.Settings;
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
@ -68,9 +67,9 @@ import me.leolin.shortcutbadger.ShortcutBadger;
|
||||
import okhttp3.ConnectionSpec;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.TlsVersion;
|
||||
import pl.szczodrzynski.edziennik.config.Config;
|
||||
import pl.szczodrzynski.edziennik.data.db.AppDb;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.debuglog.DebugLog;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.ProfileFull;
|
||||
import pl.szczodrzynski.edziennik.network.NetworkUtils;
|
||||
@ -83,9 +82,7 @@ import pl.szczodrzynski.edziennik.utils.Themes;
|
||||
import pl.szczodrzynski.edziennik.utils.Utils;
|
||||
import pl.szczodrzynski.edziennik.utils.models.AppConfig;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore.LOGIN_TYPE_LIBRUS;
|
||||
import static pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore.LOGIN_TYPE_MOBIDZIENNIK;
|
||||
import static pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore.LOGIN_TYPE_VULCAN;
|
||||
|
||||
public class App extends androidx.multidex.MultiDexApplication implements Configuration.Provider {
|
||||
private static final String TAG = "App";
|
||||
@ -145,6 +142,11 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
|
||||
//public Register register; // REGISTER for current profile, read from registerStore
|
||||
|
||||
public ProfileFull profile;
|
||||
public Config config;
|
||||
private static Config mConfig;
|
||||
public static Config getConfig() {
|
||||
return mConfig;
|
||||
}
|
||||
|
||||
// other stuff
|
||||
public Gson gson;
|
||||
@ -194,6 +196,10 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
|
||||
gson = new Gson();
|
||||
networkUtils = new NetworkUtils(this);
|
||||
|
||||
config = new Config(db);
|
||||
config.migrate(this);
|
||||
mConfig = config;
|
||||
|
||||
Iconics.init(getApplicationContext());
|
||||
Iconics.registerFont(SzkolnyFont.INSTANCE);
|
||||
|
||||
@ -208,7 +214,7 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
|
||||
|
||||
loadConfig();
|
||||
|
||||
Themes.INSTANCE.setThemeInt(appConfig.appTheme);
|
||||
Themes.INSTANCE.setThemeInt(config.getUi().getTheme());
|
||||
|
||||
try {
|
||||
PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES);
|
||||
@ -227,7 +233,7 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
|
||||
if ("f054761fbdb6a238".equals(deviceId) || BuildConfig.DEBUG) {
|
||||
devMode = true;
|
||||
}
|
||||
else if (appConfig.devModePassword != null) {
|
||||
else if (config.getDevModePassword() != null) {
|
||||
checkDevModePassword();
|
||||
}
|
||||
|
||||
@ -298,7 +304,7 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
|
||||
|
||||
//profileLoadById(appSharedPrefs.getInt("current_profile_id", 1));
|
||||
|
||||
if (appConfig.registerSyncEnabled) {
|
||||
if (config.getSync().getEnabled()) {
|
||||
SyncWorker.Companion.scheduleNext(this, false);
|
||||
}
|
||||
else {
|
||||
@ -362,11 +368,10 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
|
||||
shortcutManager.setDynamicShortcuts(Arrays.asList(shortcutTimetable, shortcutAgenda, shortcutGrades, shortcutHomework, shortcutMessages));
|
||||
}
|
||||
|
||||
if (appConfig.appInstalledTime == 0) {
|
||||
if (config.getAppInstalledTime() == 0) {
|
||||
try {
|
||||
appConfig.appInstalledTime = getPackageManager().getPackageInfo(getPackageName(), 0).firstInstallTime;
|
||||
appConfig.appRateSnackbarTime = appConfig.appInstalledTime + 7 * 24 * 60 * 60 * 1000;
|
||||
saveConfig("appInstalledTime", "appRateSnackbarTime");
|
||||
config.setAppInstalledTime(getPackageManager().getPackageInfo(getPackageName(), 0).firstInstallTime);
|
||||
config.setAppRateSnackbarTime(config.getAppInstalledTime() + 7 * 24 * 60 * 60 * 1000);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@ -434,9 +439,9 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
|
||||
final long startTime = System.currentTimeMillis();
|
||||
FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(instanceIdResult -> {
|
||||
Log.d(TAG, "Token for App is " + instanceIdResult.getToken() + ", ID is " + instanceIdResult.getId()+". Time is "+(System.currentTimeMillis() - startTime));
|
||||
appConfig.fcmToken = instanceIdResult.getToken();
|
||||
config.getSync().setTokenApp(instanceIdResult.getToken());
|
||||
});
|
||||
FirebaseInstanceId.getInstance(pushMobidziennikApp).getInstanceId().addOnSuccessListener(instanceIdResult -> {
|
||||
/*FirebaseInstanceId.getInstance(pushMobidziennikApp).getInstanceId().addOnSuccessListener(instanceIdResult -> {
|
||||
Log.d(TAG, "Token for Mobidziennik is " + instanceIdResult.getToken() + ", ID is " + instanceIdResult.getId());
|
||||
appConfig.fcmTokens.put(LOGIN_TYPE_MOBIDZIENNIK, new Pair<>(instanceIdResult.getToken(), new ArrayList<>()));
|
||||
});
|
||||
@ -450,7 +455,7 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
|
||||
if (pair == null || pair.first == null || !pair.first.equals(instanceIdResult.getToken())) {
|
||||
appConfig.fcmTokens.put(LOGIN_TYPE_VULCAN, new Pair<>(instanceIdResult.getToken(), new ArrayList<>()));
|
||||
}
|
||||
});
|
||||
});*/
|
||||
|
||||
|
||||
FirebaseMessaging.getInstance().subscribeToTopic(getPackageName());
|
||||
@ -513,7 +518,8 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchFieldException e) {
|
||||
e.printStackTrace();
|
||||
appSharedPrefs.edit().remove("app.appConfig."+fieldName).apply();
|
||||
Log.w(TAG, "Should remove app.appConfig."+fieldName);
|
||||
//appSharedPrefs.edit().remove("app.appConfig."+fieldName).apply(); TODO migration
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -585,7 +591,11 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
|
||||
//appSharedPrefs.edit().putString("config", gson.toJson(appConfig)).apply();
|
||||
}
|
||||
|
||||
|
||||
public void profileSave() {
|
||||
AsyncTask.execute(() -> {
|
||||
db.profileDao().add(profile);
|
||||
});
|
||||
}
|
||||
|
||||
public void profileSaveAsync() {
|
||||
AsyncTask.execute(() -> {
|
||||
@ -606,14 +616,6 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
|
||||
db.profileDao().add(profileFull);
|
||||
db.loginStoreDao().add(profileFull);
|
||||
}
|
||||
public void profileSaveFull(Profile profile, LoginStore loginStore) {
|
||||
db.profileDao().add(profile);
|
||||
db.loginStoreDao().add(loginStore);
|
||||
}
|
||||
|
||||
public ProfileFull profileGetOrNull(int id) {
|
||||
return db.profileDao().getFullByIdNow(id);
|
||||
}
|
||||
|
||||
public void profileLoadById(int id) {
|
||||
profileLoadById(id, false);
|
||||
@ -636,6 +638,7 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
|
||||
MainActivity.Companion.setUseOldMessages(profile.getLoginStoreType() == LOGIN_TYPE_MOBIDZIENNIK && appConfig.mobidziennikOldMessages == 1);
|
||||
profileId = profile.getId();
|
||||
appSharedPrefs.edit().putInt("current_profile_id", profile.getId()).apply();
|
||||
config.setProfile(profileId);
|
||||
}
|
||||
else if (!loadedLast) {
|
||||
profileLoadById(profileLastId(), true);
|
||||
@ -706,7 +709,7 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
|
||||
|
||||
public void checkDevModePassword() {
|
||||
try {
|
||||
devMode = Utils.AESCrypt.decrypt("nWFVxY65Pa8/aRrT7EylNAencmOD+IxUY2Gg/beiIWY=", appConfig.devModePassword).equals("ok here you go it's enabled now")
|
||||
devMode = Utils.AESCrypt.decrypt("nWFVxY65Pa8/aRrT7EylNAencmOD+IxUY2Gg/beiIWY=", config.getDevModePassword()).equals("ok here you go it's enabled now")
|
||||
|| BuildConfig.DEBUG;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
319
app/src/main/java/pl/szczodrzynski/edziennik/App.kt
Normal file
319
app/src/main/java/pl/szczodrzynski/edziennik/App.kt
Normal file
@ -0,0 +1,319 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-11-26.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik
|
||||
|
||||
import android.util.Log
|
||||
import androidx.work.Configuration
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class Szkolny : /*MultiDexApplication(),*/ Configuration.Provider, CoroutineScope {
|
||||
companion object {
|
||||
var devMode = false
|
||||
}
|
||||
|
||||
//lateinit var db: AppDb
|
||||
//val config by lazy { Config(db); // TODO migrate }
|
||||
|
||||
private val job = Job()
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Main
|
||||
override fun getWorkManagerConfiguration() = Configuration.Builder()
|
||||
.setMinimumLoggingLevel(Log.VERBOSE)
|
||||
.build()
|
||||
|
||||
/*val preferences by lazy { getSharedPreferences(getString(R.string.preference_file), Context.MODE_PRIVATE) }
|
||||
val notifier by lazy { Notifier(this) }
|
||||
val permissionChecker by lazy { PermissionChecker(this) }
|
||||
|
||||
lateinit var profile: ProfileFull
|
||||
|
||||
/* _ _ _______ _______ _____
|
||||
| | | |__ __|__ __| __ \
|
||||
| |__| | | | | | | |__) |
|
||||
| __ | | | | | | ___/
|
||||
| | | | | | | | | |
|
||||
|_| |_| |_| |_| |*/
|
||||
val http: OkHttpClient by lazy {
|
||||
val builder = OkHttpClient.Builder()
|
||||
.cache(null)
|
||||
.followRedirects(true)
|
||||
.followSslRedirects(true)
|
||||
.retryOnConnectionFailure(true)
|
||||
.cookieJar(cookieJar)
|
||||
.connectTimeout(20, TimeUnit.SECONDS)
|
||||
.writeTimeout(5, TimeUnit.SECONDS)
|
||||
.readTimeout(10, TimeUnit.SECONDS)
|
||||
builder.installHttpsSupport()
|
||||
|
||||
if (devMode || BuildConfig.DEBUG) {
|
||||
HyperLog.initialize(this)
|
||||
HyperLog.setLogLevel(Log.VERBOSE)
|
||||
HyperLog.setLogFormat(DebugLogFormat(this))
|
||||
val chuckerCollector = ChuckerCollector(this, true, Period.ONE_HOUR)
|
||||
val chuckerInterceptor = ChuckerInterceptor(this, chuckerCollector)
|
||||
builder.addInterceptor(chuckerInterceptor)
|
||||
}
|
||||
|
||||
builder.build()
|
||||
}
|
||||
val httpLazy: OkHttpClient by lazy {
|
||||
http.newBuilder()
|
||||
.followRedirects(false)
|
||||
.followSslRedirects(false)
|
||||
.build()
|
||||
}
|
||||
val cookieJar by lazy { PersistentCookieJar(SetCookieCache(), SharedPrefsCookiePersistor(this)) }
|
||||
|
||||
/* _____ _ _
|
||||
/ ____(_) | |
|
||||
| (___ _ __ _ _ __ __ _| |_ _ _ _ __ ___
|
||||
\___ \| |/ _` | '_ \ / _` | __| | | | '__/ _ \
|
||||
____) | | (_| | | | | (_| | |_| |_| | | | __/
|
||||
|_____/|_|\__, |_| |_|\__,_|\__|\__,_|_| \___|
|
||||
__/ |
|
||||
|__*/
|
||||
private val deviceId: String by lazy { Settings.Secure.getString(contentResolver, Settings.Secure.ANDROID_ID) ?: "" }
|
||||
private val signature: String by lazy {
|
||||
var str = ""
|
||||
try {
|
||||
val packageInfo: PackageInfo = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES)
|
||||
for (signature in packageInfo.signatures) {
|
||||
val signatureBytes = signature.toByteArray()
|
||||
val md = MessageDigest.getInstance("SHA")
|
||||
md.update(signatureBytes)
|
||||
str = Base64.encodeToString(md.digest(), Base64.DEFAULT)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
str
|
||||
}
|
||||
private var unreadBadgesAvailable = true
|
||||
|
||||
/* _____ _
|
||||
/ ____| | |
|
||||
___ _ __ | | _ __ ___ __ _| |_ ___
|
||||
/ _ \| '_ \| | | '__/ _ \/ _` | __/ _ \
|
||||
| (_) | | | | |____| | | __/ (_| | || __/
|
||||
\___/|_| |_|\_____|_| \___|\__,_|\__\__*/
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
|
||||
CaocConfig.Builder.create()
|
||||
.backgroundMode(CaocConfig.BACKGROUND_MODE_SHOW_CUSTOM)
|
||||
.enabled(true)
|
||||
.showErrorDetails(true)
|
||||
.showRestartButton(true)
|
||||
.logErrorOnRestart(true)
|
||||
.trackActivities(true)
|
||||
.minTimeBetweenCrashesMs(60*1000)
|
||||
.errorDrawable(R.drawable.ic_rip)
|
||||
.restartActivity(MainActivity::class.java)
|
||||
.errorActivity(CrashActivity::class.java)
|
||||
.apply()
|
||||
Iconics.init(applicationContext)
|
||||
Iconics.registerFont(SzkolnyFont)
|
||||
db = AppDb.getDatabase(this)
|
||||
Themes.themeInt = config.ui.theme
|
||||
MHttp.instance().customOkHttpClient(http)
|
||||
|
||||
devMode = "f054761fbdb6a238" == deviceId || BuildConfig.DEBUG
|
||||
if (config.devModePassword != null)
|
||||
checkDevModePassword()
|
||||
|
||||
|
||||
|
||||
launch { async(Dispatchers.Default) {
|
||||
if (config.sync.enabled) {
|
||||
scheduleNext(this@App, false)
|
||||
} else {
|
||||
cancelNext(this@App)
|
||||
}
|
||||
|
||||
db.metadataDao().countUnseen().observeForever { count: Int ->
|
||||
if (unreadBadgesAvailable)
|
||||
unreadBadgesAvailable = ShortcutBadger.applyCount(this@App, count)
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
|
||||
val shortcutManager = getSystemService(ShortcutManager::class.java)
|
||||
|
||||
val shortcutTimetable = ShortcutInfo.Builder(this@App, "item_timetable")
|
||||
.setShortLabel(getString(R.string.shortcut_timetable)).setLongLabel(getString(R.string.shortcut_timetable))
|
||||
.setIcon(Icon.createWithResource(this@App, R.mipmap.ic_shortcut_timetable))
|
||||
.setIntent(Intent(Intent.ACTION_MAIN, null, this@App, MainActivity::class.java)
|
||||
.putExtra("fragmentId", MainActivity.DRAWER_ITEM_TIMETABLE))
|
||||
.build()
|
||||
|
||||
val shortcutAgenda = ShortcutInfo.Builder(this@App, "item_agenda")
|
||||
.setShortLabel(getString(R.string.shortcut_agenda)).setLongLabel(getString(R.string.shortcut_agenda))
|
||||
.setIcon(Icon.createWithResource(this@App, R.mipmap.ic_shortcut_agenda))
|
||||
.setIntent(Intent(Intent.ACTION_MAIN, null, this@App, MainActivity::class.java)
|
||||
.putExtra("fragmentId", MainActivity.DRAWER_ITEM_AGENDA))
|
||||
.build()
|
||||
|
||||
val shortcutGrades = ShortcutInfo.Builder(this@App, "item_grades")
|
||||
.setShortLabel(getString(R.string.shortcut_grades)).setLongLabel(getString(R.string.shortcut_grades))
|
||||
.setIcon(Icon.createWithResource(this@App, R.mipmap.ic_shortcut_grades))
|
||||
.setIntent(Intent(Intent.ACTION_MAIN, null, this@App, MainActivity::class.java)
|
||||
.putExtra("fragmentId", MainActivity.DRAWER_ITEM_GRADES))
|
||||
.build()
|
||||
|
||||
val shortcutHomework = ShortcutInfo.Builder(this@App, "item_homeworks")
|
||||
.setShortLabel(getString(R.string.shortcut_homework)).setLongLabel(getString(R.string.shortcut_homework))
|
||||
.setIcon(Icon.createWithResource(this@App, R.mipmap.ic_shortcut_homework))
|
||||
.setIntent(Intent(Intent.ACTION_MAIN, null, this@App, MainActivity::class.java)
|
||||
.putExtra("fragmentId", MainActivity.DRAWER_ITEM_HOMEWORK))
|
||||
.build()
|
||||
|
||||
val shortcutMessages = ShortcutInfo.Builder(this@App, "item_messages")
|
||||
.setShortLabel(getString(R.string.shortcut_messages)).setLongLabel(getString(R.string.shortcut_messages))
|
||||
.setIcon(Icon.createWithResource(this@App, R.mipmap.ic_shortcut_messages))
|
||||
.setIntent(Intent(Intent.ACTION_MAIN, null, this@App, MainActivity::class.java)
|
||||
.putExtra("fragmentId", MainActivity.DRAWER_ITEM_MESSAGES))
|
||||
.build()
|
||||
|
||||
shortcutManager.dynamicShortcuts = listOf(
|
||||
shortcutTimetable,
|
||||
shortcutAgenda,
|
||||
shortcutGrades,
|
||||
shortcutHomework,
|
||||
shortcutMessages
|
||||
)
|
||||
} // shortcuts - end
|
||||
|
||||
if (config.appInstalledTime == 0L)
|
||||
try {
|
||||
config.appInstalledTime = packageManager.getPackageInfo(packageName, 0).firstInstallTime
|
||||
config.appRateSnackbarTime = config.appInstalledTime + 7*DAY*MS
|
||||
} catch (e: NameNotFoundException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
val pushMobidziennikApp = FirebaseApp.initializeApp(
|
||||
this@App,
|
||||
FirebaseOptions.Builder()
|
||||
.setApiKey("AIzaSyCi5LmsZ5BBCQnGtrdvWnp1bWLCNP8OWQE")
|
||||
.setApplicationId("1:747285019373:android:f6341bf7b158621d")
|
||||
.build(),
|
||||
"Mobidziennik2"
|
||||
)
|
||||
|
||||
val pushLibrusApp = FirebaseApp.initializeApp(
|
||||
this@App,
|
||||
FirebaseOptions.Builder()
|
||||
.setApiKey("AIzaSyDfTuEoYPKdv4aceEws1CO3n0-HvTndz-o")
|
||||
.setApplicationId("1:513056078587:android:1e29083b760af544")
|
||||
.build(),
|
||||
"Librus"
|
||||
)
|
||||
|
||||
val pushVulcanApp = FirebaseApp.initializeApp(
|
||||
this@App,
|
||||
FirebaseOptions.Builder()
|
||||
.setApiKey("AIzaSyDW8MUtanHy64_I0oCpY6cOxB3jrvJd_iA")
|
||||
.setApplicationId("1:987828170337:android:ac97431a0a4578c3")
|
||||
.build(),
|
||||
"Vulcan"
|
||||
)
|
||||
|
||||
try {
|
||||
FirebaseInstanceId.getInstance().instanceId.addOnSuccessListener { instanceIdResult ->
|
||||
val token = instanceIdResult.token
|
||||
config.sync.tokenApp = token
|
||||
}
|
||||
FirebaseInstanceId.getInstance(pushMobidziennikApp).instanceId.addOnSuccessListener { instanceIdResult ->
|
||||
val token = instanceIdResult.token
|
||||
if (token != config.sync.tokenMobidziennik) {
|
||||
config.sync.tokenMobidziennik = token
|
||||
config.sync.tokenMobidziennikList = listOf()
|
||||
}
|
||||
}
|
||||
FirebaseInstanceId.getInstance(pushLibrusApp).instanceId.addOnSuccessListener { instanceIdResult ->
|
||||
val token = instanceIdResult.token
|
||||
if (token != config.sync.tokenLibrus) {
|
||||
config.sync.tokenLibrus = token
|
||||
config.sync.tokenLibrusList = listOf()
|
||||
}
|
||||
}
|
||||
FirebaseInstanceId.getInstance(pushVulcanApp).instanceId.addOnSuccessListener { instanceIdResult ->
|
||||
val token = instanceIdResult.token
|
||||
if (token != config.sync.tokenVulcan) {
|
||||
config.sync.tokenVulcan = token
|
||||
config.sync.tokenVulcanList = listOf()
|
||||
}
|
||||
}
|
||||
FirebaseMessaging.getInstance().subscribeToTopic(packageName)
|
||||
} catch (e: IllegalStateException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
private fun profileLoad(profileId: Int) {
|
||||
db.profileDao().getFullByIdNow(profileId)?.also {
|
||||
profile = it
|
||||
} ?: run {
|
||||
if (!::profile.isInitialized) {
|
||||
profile = ProfileFull(-1, "", "", -1)
|
||||
}
|
||||
}
|
||||
}
|
||||
fun profileLoad(profileId: Int, onSuccess: (profile: ProfileFull) -> Unit) {
|
||||
launch {
|
||||
val deferred = async(Dispatchers.Default) {
|
||||
profileLoad(profileId)
|
||||
}
|
||||
deferred.await()
|
||||
onSuccess(profile)
|
||||
}
|
||||
}
|
||||
|
||||
private fun OkHttpClient.Builder.installHttpsSupport() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP_MR1) {
|
||||
try {
|
||||
try {
|
||||
ProviderInstaller.installIfNeeded(this@App)
|
||||
} catch (e: Exception) {
|
||||
Log.e("OkHttpTLSCompat", "Play Services not found or outdated")
|
||||
|
||||
val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
|
||||
trustManagerFactory.init(null as KeyStore?)
|
||||
|
||||
val x509TrustManager = trustManagerFactory.trustManagers.singleOrNull { it is X509TrustManager } as X509TrustManager?
|
||||
?: return
|
||||
|
||||
val sc = SSLContext.getInstance("TLSv1.2")
|
||||
sc.init(null, null, null)
|
||||
sslSocketFactory(TLSSocketFactory(sc.socketFactory), x509TrustManager)
|
||||
val cs: ConnectionSpec = ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
|
||||
.tlsVersions(TlsVersion.TLS_1_0)
|
||||
.tlsVersions(TlsVersion.TLS_1_1)
|
||||
.tlsVersions(TlsVersion.TLS_1_2)
|
||||
.build()
|
||||
val specs: MutableList<ConnectionSpec> = ArrayList()
|
||||
specs.add(cs)
|
||||
specs.add(ConnectionSpec.COMPATIBLE_TLS)
|
||||
specs.add(ConnectionSpec.CLEARTEXT)
|
||||
connectionSpecs(specs)
|
||||
}
|
||||
} catch (exc: Exception) {
|
||||
Log.e("OkHttpTLSCompat", "Error while setting TLS 1.2", exc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun checkDevModePassword() {
|
||||
devMode = try {
|
||||
Utils.AESCrypt.decrypt("nWFVxY65Pa8/aRrT7EylNAencmOD+IxUY2Gg/beiIWY=", config.devModePassword) == "ok here you go it's enabled now" || BuildConfig.DEBUG
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
false
|
||||
}
|
||||
}*/
|
||||
}
|
@ -5,6 +5,8 @@ import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.res.Resources
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.PorterDuffColorFilter
|
||||
import android.graphics.Typeface
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Build
|
||||
@ -17,6 +19,7 @@ import android.util.LongSparseArray
|
||||
import android.util.SparseArray
|
||||
import android.util.TypedValue
|
||||
import android.view.View
|
||||
import android.widget.CompoundButton
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.*
|
||||
import androidx.core.app.ActivityCompat
|
||||
@ -28,10 +31,14 @@ import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonObject
|
||||
import im.wangchao.mhttp.Response
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teams.Team
|
||||
import pl.szczodrzynski.navlib.R
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
import pl.szczodrzynski.navlib.getColorFromAttr
|
||||
import pl.szczodrzynski.navlib.getColorFromRes
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
@ -196,6 +203,7 @@ const val DAY = 24L*HOUR
|
||||
const val WEEK = 7L*DAY
|
||||
const val MONTH = 30L*DAY
|
||||
const val YEAR = 365L*DAY
|
||||
const val MS = 1000L
|
||||
|
||||
fun <T> LongSparseArray<T>.values(): List<T> {
|
||||
val result = mutableListOf<T>()
|
||||
@ -374,13 +382,13 @@ fun CharSequence?.asItalicSpannable(): Spannable {
|
||||
*/
|
||||
fun <T : CharSequence> listOfNotEmpty(vararg elements: T): List<T> = elements.filterNot { it.isEmpty() }
|
||||
|
||||
fun List<CharSequence>.concat(delimiter: String? = null): CharSequence {
|
||||
fun List<CharSequence?>.concat(delimiter: String? = null): CharSequence {
|
||||
if (this.isEmpty()) {
|
||||
return ""
|
||||
}
|
||||
|
||||
if (this.size == 1) {
|
||||
return this[0]
|
||||
return this[0] ?: ""
|
||||
}
|
||||
|
||||
var spanned = false
|
||||
@ -395,6 +403,8 @@ fun List<CharSequence>.concat(delimiter: String? = null): CharSequence {
|
||||
if (spanned) {
|
||||
val ssb = SpannableStringBuilder()
|
||||
for (piece in this) {
|
||||
if (piece == null)
|
||||
continue
|
||||
if (!first && delimiter != null)
|
||||
ssb.append(delimiter)
|
||||
first = false
|
||||
@ -404,6 +414,8 @@ fun List<CharSequence>.concat(delimiter: String? = null): CharSequence {
|
||||
} else {
|
||||
val sb = StringBuilder()
|
||||
for (piece in this) {
|
||||
if (piece == null)
|
||||
continue
|
||||
if (!first && delimiter != null)
|
||||
sb.append(delimiter)
|
||||
first = false
|
||||
@ -417,15 +429,15 @@ fun TextView.setText(@StringRes resid: Int, vararg formatArgs: Any) {
|
||||
text = context.getString(resid, *formatArgs)
|
||||
}
|
||||
|
||||
fun JsonObject(vararg properties: Pair<String, Any>): JsonObject {
|
||||
fun JsonObject(vararg properties: Pair<String, Any?>): JsonObject {
|
||||
return JsonObject().apply {
|
||||
for (property in properties) {
|
||||
when (property.second) {
|
||||
is JsonElement -> add(property.first, property.second as JsonElement)
|
||||
is String -> addProperty(property.first, property.second as String)
|
||||
is Char -> addProperty(property.first, property.second as Char)
|
||||
is Number -> addProperty(property.first, property.second as Number)
|
||||
is Boolean -> addProperty(property.first, property.second as Boolean)
|
||||
is JsonElement -> add(property.first, property.second as JsonElement?)
|
||||
is String -> addProperty(property.first, property.second as String?)
|
||||
is Char -> addProperty(property.first, property.second as Char?)
|
||||
is Number -> addProperty(property.first, property.second as Number?)
|
||||
is Boolean -> addProperty(property.first, property.second as Boolean?)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -441,6 +453,13 @@ inline fun <T : View> T.onClick(crossinline onClickListener: (v: T) -> Unit) {
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
inline fun <T : CompoundButton> T.onChange(crossinline onChangeListener: (v: T, isChecked: Boolean) -> Unit) {
|
||||
setOnCheckedChangeListener { buttonView, isChecked ->
|
||||
onChangeListener(buttonView as T, isChecked)
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> LiveData<T>.observeOnce(lifecycleOwner: LifecycleOwner, observer: Observer<T>) {
|
||||
observe(lifecycleOwner, object : Observer<T> {
|
||||
override fun onChanged(t: T?) {
|
||||
@ -494,4 +513,96 @@ fun View.findParentById(targetId: Int): View? {
|
||||
return viewParent.findParentById(targetId)
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
fun CoroutineScope.startCoroutineTimer(delayMillis: Long = 0, repeatMillis: Long = 0, action: () -> Unit) = launch {
|
||||
delay(delayMillis)
|
||||
if (repeatMillis > 0) {
|
||||
while (true) {
|
||||
action()
|
||||
delay(repeatMillis)
|
||||
}
|
||||
} else {
|
||||
action()
|
||||
}
|
||||
}
|
||||
|
||||
operator fun Time?.compareTo(other: Time?): Int {
|
||||
if (this == null && other == null)
|
||||
return 0
|
||||
if (this == null)
|
||||
return -1
|
||||
if (other == null)
|
||||
return 1
|
||||
return this.compareTo(other)
|
||||
}
|
||||
|
||||
operator fun StringBuilder.plusAssign(str: String?) {
|
||||
this.append(str)
|
||||
}
|
||||
|
||||
fun Context.timeTill(time: Int, delimiter: String = " "): String {
|
||||
val parts = mutableListOf<Pair<Int, Int>>()
|
||||
|
||||
val hours = time / 3600
|
||||
val minutes = (time - hours*3600) / 60
|
||||
val seconds = time - minutes*60 - hours*3600
|
||||
|
||||
var prefixAdded = false
|
||||
if (hours > 0) {
|
||||
if (!prefixAdded) parts += R.plurals.time_till_text to hours; prefixAdded = true
|
||||
parts += R.plurals.time_till_hours to hours
|
||||
}
|
||||
if (minutes > 0) {
|
||||
if (!prefixAdded) parts += R.plurals.time_till_text to minutes; prefixAdded = true
|
||||
parts += R.plurals.time_till_minutes to minutes
|
||||
}
|
||||
if (hours == 0 && minutes < 10) {
|
||||
if (!prefixAdded) parts += R.plurals.time_till_text to seconds; prefixAdded = true
|
||||
parts += R.plurals.time_till_seconds to seconds
|
||||
}
|
||||
|
||||
return parts.joinToString(delimiter) { resources.getQuantityString(it.first, it.second, it.second) }
|
||||
}
|
||||
|
||||
fun Context.timeLeft(time: Int, delimiter: String = " "): String {
|
||||
val parts = mutableListOf<Pair<Int, Int>>()
|
||||
|
||||
val hours = time / 3600
|
||||
val minutes = (time - hours*3600) / 60
|
||||
val seconds = time - minutes*60 - hours*3600
|
||||
|
||||
var prefixAdded = false
|
||||
if (hours > 0) {
|
||||
if (!prefixAdded) parts += R.plurals.time_left_text to hours
|
||||
prefixAdded = true
|
||||
parts += R.plurals.time_left_hours to hours
|
||||
}
|
||||
if (minutes > 0) {
|
||||
if (!prefixAdded) parts += R.plurals.time_left_text to minutes
|
||||
prefixAdded = true
|
||||
parts += R.plurals.time_left_minutes to minutes
|
||||
}
|
||||
if (hours == 0 && minutes < 10) {
|
||||
if (!prefixAdded) parts += R.plurals.time_left_text to seconds
|
||||
prefixAdded = true
|
||||
parts += R.plurals.time_left_seconds to seconds
|
||||
}
|
||||
|
||||
return parts.joinToString(delimiter) { resources.getQuantityString(it.first, it.second, it.second) }
|
||||
}
|
||||
|
||||
inline fun <reified T> Any?.instanceOfOrNull(): T? {
|
||||
return when (this) {
|
||||
is T -> this
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
fun Drawable.setTintColor(color: Int): Drawable {
|
||||
colorFilter = PorterDuffColorFilter(
|
||||
color,
|
||||
PorterDuff.Mode.SRC_ATOP
|
||||
)
|
||||
return this
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ import pl.szczodrzynski.edziennik.ui.modules.feedback.FeedbackFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.feedback.HelpFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.grades.GradesFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.grades.editor.GradesEditorFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.home.HomeFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.home.HomeFragmentV2
|
||||
import pl.szczodrzynski.edziennik.ui.modules.homework.HomeworkFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.login.LoginActivity
|
||||
import pl.szczodrzynski.edziennik.ui.modules.messages.MessageFragment
|
||||
@ -122,9 +122,9 @@ class MainActivity : AppCompatActivity() {
|
||||
val list: MutableList<NavTarget> = mutableListOf()
|
||||
|
||||
// home item
|
||||
list += NavTarget(DRAWER_ITEM_HOME, R.string.menu_home_page, HomeFragment::class)
|
||||
list += NavTarget(DRAWER_ITEM_HOME, R.string.menu_home_page, HomeFragmentV2::class)
|
||||
.withTitle(R.string.app_name)
|
||||
.withIcon(CommunityMaterial.Icon2.cmd_home)
|
||||
.withIcon(CommunityMaterial.Icon2.cmd_home_outline)
|
||||
.isInDrawer(true)
|
||||
.isStatic(true)
|
||||
.withPopToHome(false)
|
||||
@ -135,50 +135,50 @@ class MainActivity : AppCompatActivity() {
|
||||
.isInDrawer(true)
|
||||
|
||||
list += NavTarget(DRAWER_ITEM_AGENDA, R.string.menu_agenda, AgendaFragment::class)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_calendar)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_calendar_outline)
|
||||
.withBadgeTypeId(TYPE_EVENT)
|
||||
.isInDrawer(true)
|
||||
|
||||
list += NavTarget(DRAWER_ITEM_GRADES, R.string.menu_grades, GradesFragment::class)
|
||||
.withIcon(CommunityMaterial.Icon2.cmd_numeric_5_box)
|
||||
.withIcon(CommunityMaterial.Icon2.cmd_numeric_5_box_outline)
|
||||
.withBadgeTypeId(TYPE_GRADE)
|
||||
.isInDrawer(true)
|
||||
|
||||
list += NavTarget(DRAWER_ITEM_MESSAGES, R.string.menu_messages, MessagesFragment::class)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_email)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_email_outline)
|
||||
.withBadgeTypeId(TYPE_MESSAGE)
|
||||
.isInDrawer(true)
|
||||
|
||||
list += NavTarget(DRAWER_ITEM_HOMEWORK, R.string.menu_homework, HomeworkFragment::class)
|
||||
.withIcon(SzkolnyFont.Icon.szf_file_document_edit)
|
||||
.withIcon(SzkolnyFont.Icon.szf_notebook_outline)
|
||||
.withBadgeTypeId(TYPE_HOMEWORK)
|
||||
.isInDrawer(true)
|
||||
|
||||
list += NavTarget(DRAWER_ITEM_BEHAVIOUR, R.string.menu_notices, BehaviourFragment::class)
|
||||
.withIcon(CommunityMaterial.Icon2.cmd_message_alert)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_emoticon_outline)
|
||||
.withBadgeTypeId(TYPE_NOTICE)
|
||||
.isInDrawer(true)
|
||||
|
||||
list += NavTarget(DRAWER_ITEM_ATTENDANCE, R.string.menu_attendance, AttendanceFragment::class)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_calendar_remove)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_calendar_remove_outline)
|
||||
.withBadgeTypeId(TYPE_ATTENDANCE)
|
||||
.isInDrawer(true)
|
||||
|
||||
list += NavTarget(DRAWER_ITEM_ANNOUNCEMENTS, R.string.menu_announcements, AnnouncementsFragment::class)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_bulletin_board)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_bullhorn_outline)
|
||||
.withBadgeTypeId(TYPE_ANNOUNCEMENT)
|
||||
.isInDrawer(true)
|
||||
|
||||
|
||||
// static drawer items
|
||||
list += NavTarget(DRAWER_ITEM_NOTIFICATIONS, R.string.menu_notifications, NotificationsFragment::class)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_bell_ring)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_bell_ring_outline)
|
||||
.isInDrawer(true)
|
||||
.isStatic(true)
|
||||
.isBelowSeparator(true)
|
||||
|
||||
list += NavTarget(DRAWER_ITEM_SETTINGS, R.string.menu_settings, SettingsNewFragment::class)
|
||||
.withIcon(CommunityMaterial.Icon2.cmd_settings)
|
||||
.withIcon(CommunityMaterial.Icon2.cmd_settings_outline)
|
||||
.isInDrawer(true)
|
||||
.isStatic(true)
|
||||
.isBelowSeparator(true)
|
||||
@ -197,7 +197,7 @@ class MainActivity : AppCompatActivity() {
|
||||
.isInProfileList(false)
|
||||
|
||||
list += NavTarget(DRAWER_PROFILE_SYNC_ALL, R.string.menu_sync_all, null)
|
||||
.withIcon(CommunityMaterial.Icon2.cmd_sync)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_download_outline)
|
||||
.isInProfileList(true)
|
||||
|
||||
|
||||
@ -243,7 +243,7 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
setTheme(Themes.appTheme)
|
||||
|
||||
app.appConfig.language?.let {
|
||||
app.config.ui.language?.let {
|
||||
setLanguage(it)
|
||||
}
|
||||
|
||||
@ -306,10 +306,10 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
drawer.apply {
|
||||
setAccountHeaderBackground(app.appConfig.headerBackground)
|
||||
setAccountHeaderBackground(app.config.ui.headerBackground)
|
||||
|
||||
drawerProfileListEmptyListener = {
|
||||
app.appConfig.loginFinished = false
|
||||
app.config.loginFinished = false
|
||||
app.saveConfig("loginFinished")
|
||||
profileListEmptyListener()
|
||||
}
|
||||
@ -334,7 +334,7 @@ class MainActivity : AppCompatActivity() {
|
||||
drawerProfileSettingClickListener = this@MainActivity.profileSettingClickListener
|
||||
|
||||
miniDrawerVisibleLandscape = null
|
||||
miniDrawerVisiblePortrait = app.appConfig.miniDrawerVisible
|
||||
miniDrawerVisiblePortrait = app.config.ui.miniMenuVisible
|
||||
}
|
||||
}
|
||||
|
||||
@ -387,21 +387,23 @@ class MainActivity : AppCompatActivity() {
|
||||
SyncWorker.scheduleNext(app)
|
||||
|
||||
// APP BACKGROUND
|
||||
if (app.appConfig.appBackground != null) {
|
||||
if (app.config.ui.appBackground != null) {
|
||||
try {
|
||||
var bg = app.appConfig.appBackground
|
||||
val bgDir = File(Environment.getExternalStoragePublicDirectory("Szkolny.eu"), "bg")
|
||||
if (bgDir.exists()) {
|
||||
val files = bgDir.listFiles()
|
||||
val r = Random()
|
||||
val i = r.nextInt(files.size)
|
||||
bg = files[i].toString()
|
||||
}
|
||||
val linearLayout = b.root
|
||||
if (bg.endsWith(".gif")) {
|
||||
linearLayout.background = GifDrawable(bg)
|
||||
} else {
|
||||
linearLayout.background = BitmapDrawable.createFromPath(bg)
|
||||
app.config.ui.appBackground?.let {
|
||||
var bg = it
|
||||
val bgDir = File(Environment.getExternalStoragePublicDirectory("Szkolny.eu"), "bg")
|
||||
if (bgDir.exists()) {
|
||||
val files = bgDir.listFiles()
|
||||
val r = Random()
|
||||
val i = r.nextInt(files.size)
|
||||
bg = files[i].toString()
|
||||
}
|
||||
val linearLayout = b.root
|
||||
if (bg.endsWith(".gif")) {
|
||||
linearLayout.background = GifDrawable(bg)
|
||||
} else {
|
||||
linearLayout.background = BitmapDrawable.createFromPath(bg)
|
||||
}
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
@ -409,7 +411,7 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
// WHAT'S NEW DIALOG
|
||||
if (app.appConfig.lastAppVersion != BuildConfig.VERSION_CODE) {
|
||||
if (app.config.appVersion < BuildConfig.VERSION_CODE) {
|
||||
ServerRequest(app, app.requestScheme + APP_URL + "main.php?just_updated", "MainActivity/JU")
|
||||
.run { e, result ->
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
@ -420,21 +422,20 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (app.appConfig.lastAppVersion < 170) {
|
||||
if (app.config.appVersion < 170) {
|
||||
//Intent intent = new Intent(this, ChangelogIntroActivity.class);
|
||||
//startActivity(intent);
|
||||
} else {
|
||||
app.appConfig.lastAppVersion = BuildConfig.VERSION_CODE
|
||||
app.saveConfig("lastAppVersion")
|
||||
app.config.appVersion = BuildConfig.VERSION_CODE
|
||||
}
|
||||
}
|
||||
|
||||
// RATE SNACKBAR
|
||||
if (app.appConfig.appRateSnackbarTime != 0L && app.appConfig.appRateSnackbarTime <= System.currentTimeMillis()) {
|
||||
if (app.config.appRateSnackbarTime != 0L && app.config.appRateSnackbarTime <= System.currentTimeMillis()) {
|
||||
navView.coordinator.postDelayed({
|
||||
CafeBar.builder(this)
|
||||
.content(R.string.rate_snackbar_text)
|
||||
.icon(IconicsDrawable(this).icon(CommunityMaterial.Icon2.cmd_star).size(IconicsSize.dp(20)).color(IconicsColor.colorInt(Themes.getPrimaryTextColor(this))))
|
||||
.icon(IconicsDrawable(this).icon(CommunityMaterial.Icon2.cmd_star_outline).size(IconicsSize.dp(20)).color(IconicsColor.colorInt(Themes.getPrimaryTextColor(this))))
|
||||
.positiveText(R.string.rate_snackbar_positive)
|
||||
.positiveColor(-0xb350b0)
|
||||
.negativeText(R.string.rate_snackbar_negative)
|
||||
@ -444,20 +445,17 @@ class MainActivity : AppCompatActivity() {
|
||||
.onPositive { cafeBar ->
|
||||
Utils.openGooglePlay(this)
|
||||
cafeBar.dismiss()
|
||||
app.appConfig.appRateSnackbarTime = 0
|
||||
app.saveConfig("appRateSnackbarTime")
|
||||
app.config.appRateSnackbarTime = 0
|
||||
}
|
||||
.onNegative { cafeBar ->
|
||||
Toast.makeText(this, "Szkoda, opinie innych pomagają mi rozwijać aplikację.", Toast.LENGTH_LONG).show()
|
||||
cafeBar.dismiss()
|
||||
app.appConfig.appRateSnackbarTime = 0
|
||||
app.saveConfig("appRateSnackbarTime")
|
||||
app.config.appRateSnackbarTime = 0
|
||||
}
|
||||
.onNeutral { cafeBar ->
|
||||
Toast.makeText(this, "OK", Toast.LENGTH_LONG).show()
|
||||
cafeBar.dismiss()
|
||||
app.appConfig.appRateSnackbarTime = System.currentTimeMillis() + 7 * 24 * 60 * 60 * 1000
|
||||
app.saveConfig("appRateSnackbarTime")
|
||||
app.config.appRateSnackbarTime = System.currentTimeMillis() + 7 * 24 * 60 * 60 * 1000
|
||||
}
|
||||
.autoDismiss(false)
|
||||
.swipeToDismiss(true)
|
||||
@ -471,7 +469,7 @@ class MainActivity : AppCompatActivity() {
|
||||
bottomSheet.appendItems(
|
||||
BottomSheetPrimaryItem(false)
|
||||
.withTitle(R.string.menu_sync)
|
||||
.withIcon(CommunityMaterial.Icon2.cmd_sync)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_download_outline)
|
||||
.withOnClickListener(View.OnClickListener {
|
||||
bottomSheet.close()
|
||||
SyncViewListDialog(this, navTargetId)
|
||||
@ -479,17 +477,17 @@ class MainActivity : AppCompatActivity() {
|
||||
BottomSheetSeparatorItem(false),
|
||||
BottomSheetPrimaryItem(false)
|
||||
.withTitle(R.string.menu_settings)
|
||||
.withIcon(CommunityMaterial.Icon2.cmd_settings)
|
||||
.withIcon(CommunityMaterial.Icon2.cmd_settings_outline)
|
||||
.withOnClickListener(View.OnClickListener { loadTarget(DRAWER_ITEM_SETTINGS) }),
|
||||
BottomSheetPrimaryItem(false)
|
||||
.withTitle(R.string.menu_feedback)
|
||||
.withIcon(CommunityMaterial.Icon2.cmd_help_circle)
|
||||
.withIcon(CommunityMaterial.Icon2.cmd_help_circle_outline)
|
||||
.withOnClickListener(View.OnClickListener { loadTarget(TARGET_FEEDBACK) })
|
||||
)
|
||||
if (App.devMode) {
|
||||
bottomSheet += BottomSheetPrimaryItem(false)
|
||||
.withTitle(R.string.menu_debug)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_android_debug_bridge)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_android_studio)
|
||||
.withOnClickListener(View.OnClickListener { loadTarget(DRAWER_ITEM_DEBUG) })
|
||||
}
|
||||
|
||||
@ -537,9 +535,14 @@ class MainActivity : AppCompatActivity() {
|
||||
DRAWER_ITEM_MESSAGES -> MessagesFragment.pageSelection
|
||||
else -> 0
|
||||
}
|
||||
val arguments = when (navTargetId) {
|
||||
DRAWER_ITEM_TIMETABLE -> JsonObject("weekStart" to TimetableFragment.pageSelection?.weekStart?.stringY_m_d)
|
||||
else -> null
|
||||
}
|
||||
EdziennikTask.syncProfile(
|
||||
App.profileId,
|
||||
listOf(navTargetId to fragmentParam)
|
||||
listOf(navTargetId to fragmentParam),
|
||||
arguments
|
||||
).enqueue(this)
|
||||
}
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
@ -684,30 +687,33 @@ class MainActivity : AppCompatActivity() {
|
||||
}*/
|
||||
|
||||
if (navLoading) {
|
||||
navLoading = false
|
||||
b.fragment.removeAllViews()
|
||||
if (intentTargetId == -1)
|
||||
intentTargetId = HOME_ID
|
||||
}
|
||||
|
||||
when {
|
||||
app.profile == null -> {
|
||||
app.profile == null || app.profile.id == -1 -> {
|
||||
if (intentProfileId == -1)
|
||||
intentProfileId = app.appSharedPrefs.getInt("current_profile_id", 1)
|
||||
loadProfile(intentProfileId, intentTargetId)
|
||||
loadProfile(intentProfileId, intentTargetId, extras)
|
||||
}
|
||||
intentProfileId != -1 -> {
|
||||
loadProfile(intentProfileId, intentTargetId)
|
||||
if (app.profile.id != intentProfileId)
|
||||
loadProfile(intentProfileId, intentTargetId, extras)
|
||||
else
|
||||
loadTarget(intentTargetId, extras)
|
||||
}
|
||||
intentTargetId != -1 -> {
|
||||
drawer.currentProfile = app.profile.id
|
||||
if (navTargetId != intentTargetId)
|
||||
if (navTargetId != intentTargetId || navLoading)
|
||||
loadTarget(intentTargetId, extras)
|
||||
}
|
||||
else -> {
|
||||
drawer.currentProfile = app.profile.id
|
||||
}
|
||||
}
|
||||
navLoading = false
|
||||
}
|
||||
|
||||
override fun recreate() {
|
||||
@ -755,7 +761,7 @@ class MainActivity : AppCompatActivity() {
|
||||
finish()
|
||||
}
|
||||
else {
|
||||
if (!app.appConfig.loginFinished)
|
||||
if (!app.config.loginFinished)
|
||||
finish()
|
||||
else {
|
||||
handleIntent(data?.extras)
|
||||
@ -792,13 +798,16 @@ class MainActivity : AppCompatActivity() {
|
||||
this.runOnUiThread {
|
||||
if (app.profile == null) {
|
||||
LoginActivity.firstCompleted = false
|
||||
if (app.appConfig.loginFinished) {
|
||||
if (app.config.loginFinished) {
|
||||
// this shouldn't run
|
||||
profileListEmptyListener()
|
||||
}
|
||||
} else {
|
||||
setDrawerItems()
|
||||
drawer.currentProfile = app.profile.id
|
||||
// the drawer profile is updated automatically when the drawer item is clicked
|
||||
// update it manually when switching profiles from other source
|
||||
//if (drawer.currentProfile != app.profile.id)
|
||||
drawer.currentProfile = app.profile.id
|
||||
loadTarget(drawerSelection, arguments)
|
||||
}
|
||||
}
|
||||
@ -965,7 +974,7 @@ class MainActivity : AppCompatActivity() {
|
||||
val item = DrawerPrimaryItem()
|
||||
.withIdentifier(target.id.toLong())
|
||||
.withName(target.name)
|
||||
.withHiddenInMiniDrawer(!app.appConfig.miniDrawerButtonIds.contains(target.id))
|
||||
.withHiddenInMiniDrawer(!app.config.ui.miniMenuButtons.contains(target.id))
|
||||
.also { if (target.description != null) it.withDescription(target.description!!) }
|
||||
.also { if (target.icon != null) it.withIcon(target.icon!!) }
|
||||
.also { if (target.title != null) it.withAppTitle(getString(target.title!!)) }
|
||||
|
@ -93,8 +93,8 @@ public class Notifier {
|
||||
|
||||
public boolean shouldBeQuiet() {
|
||||
long now = Time.getNow().getInMillis();
|
||||
long start = app.appConfig.quietHoursStart;
|
||||
long end = app.appConfig.quietHoursEnd;
|
||||
long start = app.config.getSync().getQuietHoursStart();
|
||||
long end = app.config.getSync().getQuietHoursEnd();
|
||||
if (start > end) {
|
||||
end += 1000 * 60 * 60 * 24;
|
||||
//Log.d(TAG, "Night passing");
|
||||
@ -104,7 +104,7 @@ public class Notifier {
|
||||
//Log.d(TAG, "Now is smaller");
|
||||
}
|
||||
//Log.d(TAG, "Start is "+start+", now is "+now+", end is "+end);
|
||||
return app.appConfig.quietHoursStart > 0 && now >= start && now <= end;
|
||||
return start > 0 && now >= start && now <= end;
|
||||
}
|
||||
|
||||
public int getNotificationDefaults() {
|
||||
@ -312,7 +312,7 @@ public class Notifier {
|
||||
| |
|
||||
|*/
|
||||
public void notificationUpdatesShow(String updateVersion, String updateUrl, String updateFilename, boolean updateDirect) {
|
||||
if (!app.appConfig.notifyAboutUpdates)
|
||||
if (!app.config.getSync().getNotifyAboutUpdates())
|
||||
return;
|
||||
Intent notificationIntent = new Intent(app.getContext(), BootReceiver.NotificationActionService.class)
|
||||
.putExtra("update_version", updateVersion)
|
||||
@ -340,7 +340,7 @@ public class Notifier {
|
||||
}
|
||||
|
||||
public void notificationUpdatesHide() {
|
||||
if (!app.appConfig.notifyAboutUpdates)
|
||||
if (!app.config.getSync().getNotifyAboutUpdates())
|
||||
return;
|
||||
notificationManager.cancel(ID_UPDATES);
|
||||
}
|
||||
|
@ -52,9 +52,9 @@ class WidgetTimetable : AppWidgetProvider() {
|
||||
val app = context.applicationContext as App
|
||||
|
||||
var bellSyncDiffMillis: Long = 0
|
||||
if (app.appConfig.bellSyncDiff != null) {
|
||||
bellSyncDiffMillis = (app.appConfig.bellSyncDiff.hour * 60 * 60 * 1000 + app.appConfig.bellSyncDiff.minute * 60 * 1000 + app.appConfig.bellSyncDiff.second * 1000).toLong()
|
||||
bellSyncDiffMillis *= app.appConfig.bellSyncMultiplier.toLong()
|
||||
app.config.timetable.bellSyncDiff?.let {
|
||||
bellSyncDiffMillis = (it.hour * 60 * 60 * 1000 + it.minute * 60 * 1000 + it.second * 1000).toLong()
|
||||
bellSyncDiffMillis *= app.config.timetable.bellSyncMultiplier.toLong()
|
||||
bellSyncDiffMillis *= -1
|
||||
}
|
||||
|
||||
@ -87,7 +87,7 @@ class WidgetTimetable : AppWidgetProvider() {
|
||||
.colorInt(Color.WHITE)
|
||||
.sizeDp(if (widgetConfig.bigStyle) 24 else 16).toBitmap())
|
||||
|
||||
views.setImageViewBitmap(R.id.widgetTimetableSync, IconicsDrawable(context, CommunityMaterial.Icon2.cmd_sync)
|
||||
views.setImageViewBitmap(R.id.widgetTimetableSync, IconicsDrawable(context, CommunityMaterial.Icon.cmd_download_outline)
|
||||
.colorInt(Color.WHITE)
|
||||
.sizeDp(if (widgetConfig.bigStyle) 24 else 16).toBitmap())
|
||||
|
||||
|
@ -60,6 +60,9 @@ class ApiService : Service() {
|
||||
|
||||
private val notification by lazy { EdziennikNotification(this) }
|
||||
|
||||
private var lastEventTime = System.currentTimeMillis()
|
||||
private var taskCancelTries = 0
|
||||
|
||||
/* ______ _ _ _ _ _____ _ _ _ _
|
||||
| ____| | | (_) (_) | / ____| | | | | | |
|
||||
| |__ __| |_____ ___ _ __ _ __ _| | __ | | __ _| | | |__ __ _ ___| | __
|
||||
@ -68,22 +71,17 @@ class ApiService : Service() {
|
||||
|______\__,_/___|_|\___|_| |_|_| |_|_|_|\_\ \_____\__,_|_|_|_.__/ \__,_|\___|_|\*/
|
||||
private val taskCallback = object : EdziennikCallback {
|
||||
override fun onCompleted() {
|
||||
lastEventTime = System.currentTimeMillis()
|
||||
d(TAG, "Task $taskRunningId (profile $taskProfileId) - $taskProgressText - finished")
|
||||
//if (!taskCancelled) {
|
||||
EventBus.getDefault().post(ApiTaskFinishedEvent(taskProfileId))
|
||||
//}
|
||||
taskIsRunning = false
|
||||
taskRunningId = -1
|
||||
taskRunning = null
|
||||
taskProfileId = -1
|
||||
taskProgress = -1f
|
||||
taskProgressText = null
|
||||
EventBus.getDefault().post(ApiTaskFinishedEvent(taskProfileId))
|
||||
clearTask()
|
||||
|
||||
notification.setIdle().post()
|
||||
runTask()
|
||||
}
|
||||
|
||||
override fun onError(apiError: ApiError) {
|
||||
lastEventTime = System.currentTimeMillis()
|
||||
d(TAG, "Task $taskRunningId threw an error - $apiError")
|
||||
apiError.profileId = taskProfileId
|
||||
EventBus.getDefault().post(ApiTaskErrorEvent(apiError))
|
||||
@ -92,9 +90,7 @@ class ApiService : Service() {
|
||||
if (apiError.isCritical) {
|
||||
taskRunning?.cancel()
|
||||
notification.setCriticalError().post()
|
||||
taskRunning = null
|
||||
taskIsRunning = false
|
||||
taskRunningId = -1
|
||||
clearTask()
|
||||
runTask()
|
||||
}
|
||||
else {
|
||||
@ -103,6 +99,7 @@ class ApiService : Service() {
|
||||
}
|
||||
|
||||
override fun onProgress(step: Float) {
|
||||
lastEventTime = System.currentTimeMillis()
|
||||
if (step <= 0)
|
||||
return
|
||||
if (taskProgress < 0)
|
||||
@ -115,6 +112,7 @@ class ApiService : Service() {
|
||||
}
|
||||
|
||||
override fun onStartProgress(stringRes: Int) {
|
||||
lastEventTime = System.currentTimeMillis()
|
||||
taskProgressText = getString(stringRes)
|
||||
d(TAG, "Task $taskRunningId progress: $taskProgressText")
|
||||
EventBus.getDefault().post(ApiTaskProgressEvent(taskProfileId, taskProgress, taskProgressText))
|
||||
@ -129,6 +127,7 @@ class ApiService : Service() {
|
||||
| | (_| \__ \ < | __/> < __/ (__| |_| | |_| | (_) | | | |
|
||||
|_|\__,_|___/_|\_\ \___/_/\_\___|\___|\__,_|\__|_|\___/|_| |*/
|
||||
private fun runTask() {
|
||||
checkIfTaskFrozen()
|
||||
if (taskIsRunning)
|
||||
return
|
||||
if (taskCancelled || serviceClosed || (taskQueue.isEmpty() && finishingTaskQueue.isEmpty())) {
|
||||
@ -137,6 +136,8 @@ class ApiService : Service() {
|
||||
return
|
||||
}
|
||||
|
||||
lastEventTime = System.currentTimeMillis()
|
||||
|
||||
val task = if (taskQueue.isEmpty()) finishingTaskQueue.removeAt(0) else taskQueue.removeAt(0)
|
||||
task.taskId = ++taskMaximumId
|
||||
task.prepare(app)
|
||||
@ -166,6 +167,48 @@ class ApiService : Service() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a task is inactive for more than 30 seconds.
|
||||
* If the user tries to cancel a task with no success at least three times,
|
||||
* consider it frozen as well.
|
||||
*
|
||||
* This usually means it is broken and won't become active again.
|
||||
* This method cancels the task and removes any pointers to it.
|
||||
*/
|
||||
private fun checkIfTaskFrozen(): Boolean {
|
||||
if (System.currentTimeMillis() - lastEventTime > 30*1000
|
||||
|| taskCancelTries >= 3) {
|
||||
val time = System.currentTimeMillis() - lastEventTime
|
||||
d(TAG, "!!! Task $taskRunningId froze for $time ms. $taskRunning")
|
||||
clearTask()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the service if the current task is frozen/broken.
|
||||
*/
|
||||
private fun stopIfTaskFrozen() {
|
||||
if (checkIfTaskFrozen()) {
|
||||
stopSelf()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove any task descriptors or pointers from the service.
|
||||
*/
|
||||
private fun clearTask() {
|
||||
taskIsRunning = false
|
||||
taskRunningId = -1
|
||||
taskRunning = null
|
||||
taskProfileId = -1
|
||||
taskProgress = -1f
|
||||
taskProgressText = null
|
||||
taskCancelled = false
|
||||
taskCancelTries = 0
|
||||
}
|
||||
|
||||
private fun allCompleted() {
|
||||
EventBus.getDefault().post(ApiTaskAllFinishedEvent())
|
||||
stopSelf()
|
||||
@ -211,8 +254,10 @@ class ApiService : Service() {
|
||||
EventBus.getDefault().removeStickyEvent(request)
|
||||
d(TAG, request.toString())
|
||||
|
||||
taskCancelTries++
|
||||
taskCancelled = true
|
||||
taskRunning?.cancel()
|
||||
stopIfTaskFrozen()
|
||||
}
|
||||
@Subscribe(sticky = true, threadMode = ThreadMode.ASYNC)
|
||||
fun onServiceCloseRequest(request: ServiceCloseRequest) {
|
||||
|
@ -64,6 +64,7 @@ const val IDZIENNIK_WEB_TIMETABLE = "mod_panelRodzica/plan/WS_Plan.asmx/pobierzP
|
||||
const val IDZIENNIK_WEB_GRADES = "mod_panelRodzica/oceny/WS_ocenyUcznia.asmx/pobierzOcenyUcznia"
|
||||
const val IDZIENNIK_WEB_MISSING_GRADES = "mod_panelRodzica/brak_ocen/WS_BrakOcenUcznia.asmx/pobierzBrakujaceOcenyUcznia"
|
||||
const val IDZIENNIK_WEB_EXAMS = "mod_panelRodzica/sprawdziany/mod_sprawdzianyPanel.asmx/pobierzListe"
|
||||
const val IDZIENNIK_WEB_HOMEWORK = "mod_panelRodzica/pracaDomowa/WS_pracaDomowa.asmx/pobierzPraceDomowe"
|
||||
const val IDZIENNIK_WEB_NOTICES = "mod_panelRodzica/uwagi/WS_uwagiUcznia.asmx/pobierzUwagiUcznia"
|
||||
const val IDZIENNIK_WEB_ATTENDANCE = "mod_panelRodzica/obecnosci/WS_obecnosciUcznia.asmx/pobierzObecnosciUcznia"
|
||||
const val IDZIENNIK_WEB_ANNOUNCEMENTS = "mod_panelRodzica/tabOgl/WS_tablicaOgloszen.asmx/GetOgloszenia"
|
||||
|
@ -45,8 +45,8 @@ class DataNotifications(val data: Data) {
|
||||
return@run
|
||||
}
|
||||
|
||||
for (change in app.db.lessonChangeDao().getNotNotifiedNow(profileId)) {
|
||||
val text = app.getString(R.string.notification_lesson_change_format, change.changeTypeStr(app), if (change.lessonDate == null) "" else change.lessonDate!!.formattedString, change.subjectLongName)
|
||||
for (lesson in app.db.timetableDao().getNotNotifiedNow(profileId)) {
|
||||
val text = app.getString(R.string.notification_lesson_change_format, lesson.getDisplayChangeType(app), if (lesson.displayDate == null) "" else lesson.displayDate!!.formattedString, lesson.changeSubjectName)
|
||||
data.notifications += Notification(
|
||||
title = app.getNotificationTitle(TYPE_TIMETABLE_LESSON_CHANGE),
|
||||
text = text,
|
||||
@ -54,8 +54,8 @@ class DataNotifications(val data: Data) {
|
||||
profileId = profileId,
|
||||
profileName = profileName,
|
||||
viewId = DRAWER_ITEM_TIMETABLE,
|
||||
addedDate = change.addedDate
|
||||
).addExtra("timetableDate", change.lessonDate?.value?.toLong())
|
||||
addedDate = lesson.addedDate
|
||||
).addExtra("timetableDate", lesson.displayDate?.stringY_m_d ?: "")
|
||||
}
|
||||
|
||||
for (event in app.db.eventDao().getNotNotifiedNow(profileId)) {
|
||||
@ -186,10 +186,10 @@ class DataNotifications(val data: Data) {
|
||||
val luckyNumbers = app.db.luckyNumberDao().getNotNotifiedNow(profileId)
|
||||
luckyNumbers?.removeAll { it.date < today }
|
||||
luckyNumbers?.forEach { luckyNumber ->
|
||||
val text = when {
|
||||
luckyNumber.date.value == todayValue -> // LN for today
|
||||
val text = when (luckyNumber.date.value) {
|
||||
todayValue -> // LN for today
|
||||
app.getString(if (profile.studentNumber != -1 && profile.studentNumber == luckyNumber.number) R.string.notification_lucky_number_yours_format else R.string.notification_lucky_number_format, luckyNumber.number)
|
||||
luckyNumber.date.value == todayValue + 1 -> // LN for tomorrow
|
||||
todayValue + 1 -> // LN for tomorrow
|
||||
app.getString(if (profile.studentNumber != -1 && profile.studentNumber == luckyNumber.number) R.string.notification_lucky_number_yours_tomorrow_format else R.string.notification_lucky_number_tomorrow_format, luckyNumber.number)
|
||||
else -> // LN for later
|
||||
app.getString(if (profile.studentNumber != -1 && profile.studentNumber == luckyNumber.number) R.string.notification_lucky_number_yours_later_format else R.string.notification_lucky_number_later_format, luckyNumber.date.formattedString, luckyNumber.number)
|
||||
@ -207,4 +207,4 @@ class DataNotifications(val data: Data) {
|
||||
|
||||
data.db.metadataDao().setAllNotified(profileId, true)
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
@ -48,6 +48,7 @@ const val ERROR_PROFILE_MISSING = 105
|
||||
const val ERROR_INVALID_LOGIN_MODE = 110
|
||||
const val ERROR_LOGIN_METHOD_NOT_SATISFIED = 111
|
||||
const val ERROR_NOT_IMPLEMENTED = 112
|
||||
const val ERROR_FILE_DOWNLOAD = 113
|
||||
|
||||
const val ERROR_NO_STUDENTS_IN_ACCOUNT = 115
|
||||
|
||||
@ -167,6 +168,8 @@ const val EXCEPTION_LIBRUS_API_REQUEST = 904
|
||||
const val EXCEPTION_LIBRUS_SYNERGIA_REQUEST = 905
|
||||
const val EXCEPTION_MOBIDZIENNIK_WEB_REQUEST = 906
|
||||
const val EXCEPTION_VULCAN_API_REQUEST = 907
|
||||
const val EXCEPTION_MOBIDZIENNIK_WEB_FILE_REQUEST = 908
|
||||
const val EXCEPTION_LIBRUS_MESSAGES_FILE_REQUEST = 909
|
||||
const val EXCEPTION_NOTIFY_AND_SYNC = 910
|
||||
const val EXCEPTION_LIBRUS_MESSAGES_REQUEST = 911
|
||||
const val EXCEPTION_IDZIENNIK_WEB_REQUEST = 912
|
||||
|
@ -24,7 +24,7 @@ object Regexes {
|
||||
"""Liczona do średniej:.*?<strong>nie<br/?></strong>""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_GRADES_DETAILS by lazy {
|
||||
"""<strong.*?>(.+?)</strong>.*?<sup>.+?</sup>.*?<small>\((.+?)\)</small>.*?<span>.*?Wartość oceny:.*?<strong>([0-9.]+)</strong>.*?Wpisał\(a\):.*?<strong>(.+?)</strong>""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
"""<strong.*?>(.+?)</strong>.*?<sup>.+?</sup>.*?(?:<small>\((.+?)\)</small>.*?)?<span>.*?Wartość oceny:.*?<strong>([0-9.]+)</strong>.*?Wpisał\(a\):.*?<strong>(.+?)</strong>.*?(?:Komentarz:.*?<strong>(.+?)</strong>)?</span>""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
}
|
||||
|
||||
val MOBIDZIENNIK_EVENT_TYPE by lazy {
|
||||
@ -76,4 +76,10 @@ object Regexes {
|
||||
val VULCAN_SHITFT_ANNOTATION by lazy {
|
||||
"""\(przeniesiona (z|na) lekcj[ię] ([0-9]+), (.+)\)""".toRegex()
|
||||
}
|
||||
|
||||
|
||||
|
||||
val LIBRUS_ATTACHMENT_KEY by lazy {
|
||||
"""singleUseKey=([0-9A-f_]+)""".toRegex()
|
||||
}
|
||||
}
|
||||
|
@ -5,8 +5,8 @@ import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_AGENDA
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOMEWORK
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.AppError.CODE_APP_SERVER_ERROR
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.Data
|
||||
import pl.szczodrzynski.edziennik.data.api.AppError.CODE_APP_SERVER_ERROR
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event.TYPE_HOMEWORK
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||
@ -176,4 +176,4 @@ class ServerSync(val data: Data, val onSuccess: () -> Unit) {
|
||||
|
||||
onSuccess()
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-11-24
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.events
|
||||
|
||||
data class AttachmentGetEvent(val profileId: Int, val messageId: Long, val attachmentId: Long,
|
||||
var eventType: Int = TYPE_PROGRESS, val fileName: String? = null,
|
||||
val bytesWritten: Long = 0) {
|
||||
companion object {
|
||||
const val TYPE_PROGRESS = 0
|
||||
const val TYPE_FINISHED = 1
|
||||
}
|
||||
}
|
@ -12,6 +12,7 @@ import pl.szczodrzynski.edziennik.api.v2.mobidziennik.Mobidziennik
|
||||
import pl.szczodrzynski.edziennik.api.v2.template.Template
|
||||
import pl.szczodrzynski.edziennik.api.v2.vulcan.Vulcan
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
|
||||
|
||||
open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTask(profileId) {
|
||||
@ -24,6 +25,7 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa
|
||||
fun syncProfileList(profileList: List<Int>) = EdziennikTask(-1, SyncProfileListRequest(profileList))
|
||||
fun messageGet(profileId: Int, message: MessageFull) = EdziennikTask(profileId, MessageGetRequest(message))
|
||||
fun announcementsRead(profileId: Int) = EdziennikTask(profileId, AnnouncementsReadRequest())
|
||||
fun attachmentGet(profileId: Int, message: Message, attachmentId: Long, attachmentName: String) = EdziennikTask(profileId, AttachmentGetRequest(message, attachmentId, attachmentName))
|
||||
}
|
||||
|
||||
private lateinit var loginStore: LoginStore
|
||||
@ -35,8 +37,7 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa
|
||||
loginStore = request.loginStore
|
||||
// save the profile ID and name as the current task's
|
||||
taskName = app.getString(R.string.edziennik_notification_api_first_login_title)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// get the requested profile and login store
|
||||
val profile = app.db.profileDao().getByIdNow(profileId)
|
||||
this.profile = profile
|
||||
@ -67,12 +68,14 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa
|
||||
|
||||
when (request) {
|
||||
is SyncProfileRequest -> edziennikInterface?.sync(
|
||||
featureIds = request.viewIds?.flatMap { Features.getIdsByView(it.first, it.second) } ?: Features.getAllIds(),
|
||||
featureIds = request.viewIds?.flatMap { Features.getIdsByView(it.first, it.second) }
|
||||
?: Features.getAllIds(),
|
||||
viewId = request.viewIds?.get(0)?.first,
|
||||
arguments = request.arguments)
|
||||
is MessageGetRequest -> edziennikInterface?.getMessage(request.message)
|
||||
is FirstLoginRequest -> edziennikInterface?.firstLogin()
|
||||
is AnnouncementsReadRequest -> edziennikInterface?.markAllAnnouncementsAsRead()
|
||||
is AttachmentGetRequest -> edziennikInterface?.getAttachment(request.message, request.attachmentId, request.attachmentName)
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,4 +93,5 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa
|
||||
data class SyncProfileListRequest(val profileList: List<Int>)
|
||||
data class MessageGetRequest(val message: MessageFull)
|
||||
class AnnouncementsReadRequest
|
||||
data class AttachmentGetRequest(val message: Message, val attachmentId: Long, val attachmentName: String)
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.Notifier.ID_NOTIFICATIONS
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikCallback
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.notification.getNotificationTitle
|
||||
import pl.szczodrzynski.edziennik.utils.models.Notification
|
||||
import kotlin.math.min
|
||||
|
||||
@ -33,9 +34,9 @@ class NotifyTask : IApiTask(-1) {
|
||||
val pendingIntent = PendingIntent.getActivity(app, notification.id, intent, 0)
|
||||
val notificationBuilder = NotificationCompat.Builder(app, app.notifier.notificationGroup)
|
||||
// title, text, type, date
|
||||
.setContentTitle(notification.title)
|
||||
.setContentTitle(notification.profileName)
|
||||
.setContentText(notification.text)
|
||||
.setSubText(Notification.stringType(app, notification.type))
|
||||
.setSubText(app.getNotificationTitle(notification.type))
|
||||
.setWhen(notification.addedDate)
|
||||
.setTicker(app.getString(R.string.notification_ticker_format, Notification.stringType(app, notification.type)))
|
||||
// icon, color, lights, priority
|
||||
|
@ -138,10 +138,12 @@ class DataIdziennik(app: App, profile: Profile?, loginStore: LoginStore) : Data(
|
||||
val teacher = teacherList.singleOrNull { it.fullName == "$firstName $lastName" }
|
||||
return validateTeacher(teacher, firstName, lastName)
|
||||
}
|
||||
|
||||
fun getTeacher(firstNameChar: Char, lastName: String): Teacher {
|
||||
val teacher = teacherList.singleOrNull { it.shortName == "$firstNameChar.$lastName" }
|
||||
return validateTeacher(teacher, firstNameChar.toString(), lastName)
|
||||
}
|
||||
|
||||
fun getTeacherByLastFirst(nameLastFirst: String): Teacher {
|
||||
val nameParts = nameLastFirst.split(" ")
|
||||
return if (nameParts.size == 1) getTeacher(nameParts[0], "") else getTeacher(nameParts[1], nameParts[0])
|
||||
|
@ -16,6 +16,7 @@ import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikInterface
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.api.v2.prepare
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
@ -70,6 +71,10 @@ class Idziennik(val app: App, val profile: Profile?, val loginStore: LoginStore,
|
||||
|
||||
}
|
||||
|
||||
override fun getAttachment(message: Message, attachmentId: Long, attachmentName: String) {
|
||||
|
||||
}
|
||||
|
||||
override fun firstLogin() {
|
||||
IdziennikFirstLogin(data) {
|
||||
completed()
|
||||
|
@ -11,6 +11,7 @@ const val ENDPOINT_IDZIENNIK_WEB_TIMETABLE = 1030
|
||||
const val ENDPOINT_IDZIENNIK_WEB_GRADES = 1040
|
||||
const val ENDPOINT_IDZIENNIK_WEB_PROPOSED_GRADES = 1050
|
||||
const val ENDPOINT_IDZIENNIK_WEB_EXAMS = 1060
|
||||
const val ENDPOINT_IDZIENNIK_WEB_HOMEWORK = 1061
|
||||
const val ENDPOINT_IDZIENNIK_WEB_NOTICES = 1070
|
||||
const val ENDPOINT_IDZIENNIK_WEB_ANNOUNCEMENTS = 1080
|
||||
const val ENDPOINT_IDZIENNIK_WEB_ATTENDANCE = 1090
|
||||
@ -34,6 +35,10 @@ val IdziennikFeatures = listOf(
|
||||
ENDPOINT_IDZIENNIK_WEB_EXAMS to LOGIN_METHOD_IDZIENNIK_WEB
|
||||
), listOf(LOGIN_METHOD_IDZIENNIK_WEB)),
|
||||
|
||||
Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_HOMEWORK, listOf(
|
||||
ENDPOINT_IDZIENNIK_WEB_HOMEWORK to LOGIN_METHOD_IDZIENNIK_WEB
|
||||
), listOf(LOGIN_METHOD_IDZIENNIK_WEB)),
|
||||
|
||||
Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_BEHAVIOUR, listOf(
|
||||
ENDPOINT_IDZIENNIK_WEB_NOTICES to LOGIN_METHOD_IDZIENNIK_WEB
|
||||
), listOf(LOGIN_METHOD_IDZIENNIK_WEB)),
|
||||
|
@ -55,6 +55,10 @@ class IdziennikData(val data: DataIdziennik, val onSuccess: () -> Unit) {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_exams)
|
||||
IdziennikWebExams(data, onSuccess)
|
||||
}
|
||||
ENDPOINT_IDZIENNIK_WEB_HOMEWORK -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_homework)
|
||||
IdziennikWebHomework(data, onSuccess)
|
||||
}
|
||||
ENDPOINT_IDZIENNIK_WEB_NOTICES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_notices)
|
||||
IdziennikWebNotices(data, onSuccess)
|
||||
|
@ -94,6 +94,7 @@ open class IdziennikWeb(open val data: DataIdziennik) {
|
||||
is Long -> json.addProperty(name, value)
|
||||
is Float -> json.addProperty(name, value)
|
||||
is Char -> json.addProperty(name, value)
|
||||
is Boolean -> json.addProperty(name, value)
|
||||
}
|
||||
}
|
||||
setJsonBody(json)
|
||||
|
@ -5,21 +5,21 @@
|
||||
package pl.szczodrzynski.edziennik.api.v2.idziennik.data.web
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
|
||||
import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_WEB_EXAMS
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_WEB_EXAMS
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.data.IdziennikWeb
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.Lesson
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.getJsonObject
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class IdziennikWebExams(override val data: DataIdziennik,
|
||||
val onSuccess: () -> Unit) : IdziennikWeb(data) {
|
||||
val onSuccess: () -> Unit) : IdziennikWeb(data) {
|
||||
companion object {
|
||||
private const val TAG = "IdziennikWebExams"
|
||||
}
|
||||
@ -34,14 +34,15 @@ class IdziennikWebExams(override val data: DataIdziennik,
|
||||
}
|
||||
|
||||
private fun getExams() {
|
||||
val param = JsonObject()
|
||||
param.addProperty("strona", 1)
|
||||
param.addProperty("iloscNaStrone", "99")
|
||||
param.addProperty("iloscRekordow", -1)
|
||||
param.addProperty("kolumnaSort", "ss.Nazwa,sp.Data_sprawdzianu")
|
||||
param.addProperty("kierunekSort", 0)
|
||||
param.addProperty("maxIloscZaznaczonych", 0)
|
||||
param.addProperty("panelFiltrow", 0)
|
||||
val param = JsonObject().apply {
|
||||
addProperty("strona", 1)
|
||||
addProperty("iloscNaStrone", "99")
|
||||
addProperty("iloscRekordow", -1)
|
||||
addProperty("kolumnaSort", "ss.Nazwa,sp.Data_sprawdzianu")
|
||||
addProperty("kierunekSort", 0)
|
||||
addProperty("maxIloscZaznaczonych", 0)
|
||||
addProperty("panelFiltrow", 0)
|
||||
}
|
||||
|
||||
webApiGet(TAG, IDZIENNIK_WEB_EXAMS, mapOf(
|
||||
"idP" to data.registerId,
|
||||
@ -55,28 +56,34 @@ class IdziennikWebExams(override val data: DataIdziennik,
|
||||
return@webApiGet
|
||||
}
|
||||
|
||||
for (jExamEl in json.getAsJsonArray("ListK")) {
|
||||
val jExam = jExamEl.asJsonObject
|
||||
// jExam
|
||||
val eventId = jExam.get("_recordId").asLong
|
||||
val rSubject = data.getSubject(jExam.get("przedmiot").asString, -1, "")
|
||||
val rTeacher = data.getTeacherByLastFirst(jExam.get("wpisal").asString)
|
||||
val examDate = Date.fromY_m_d(jExam.get("data").asString)
|
||||
val lessonObject = Lesson.getByWeekDayAndSubject(data.lessonList, examDate.weekDay, rSubject.id)
|
||||
val examTime = lessonObject?.startTime
|
||||
json.getJsonArray("ListK")?.asJsonObjectList()?.forEach { exam ->
|
||||
val id = exam.getLong("_recordId") ?: return@forEach
|
||||
val examDate = Date.fromY_m_d(exam.getString("data") ?: return@forEach)
|
||||
val subjectName = exam.getString("przedmiot") ?: return@forEach
|
||||
val subjectId = data.getSubject(subjectName, null, subjectName).id
|
||||
val teacherName = exam.getString("wpisal") ?: return@forEach
|
||||
val teacherId = data.getTeacherByLastFirst(teacherName).id
|
||||
val topic = exam.getString("zakres") ?: ""
|
||||
|
||||
val lessonList = data.db.timetableDao().getForDateNow(profileId, examDate)
|
||||
val startTime = lessonList.firstOrNull { it.subjectId == subjectId }?.startTime
|
||||
|
||||
val eventType = when (exam.getString("rodzaj")) {
|
||||
"sprawdzian/praca klasowa" -> Event.TYPE_EXAM
|
||||
else -> Event.TYPE_SHORT_QUIZ
|
||||
}
|
||||
|
||||
val eventType = if (jExam.get("rodzaj").asString == "sprawdzian/praca klasowa") Event.TYPE_EXAM else Event.TYPE_SHORT_QUIZ
|
||||
val eventObject = Event(
|
||||
profileId,
|
||||
eventId,
|
||||
id,
|
||||
examDate,
|
||||
examTime,
|
||||
jExam.get("zakres").asString,
|
||||
startTime,
|
||||
topic,
|
||||
-1,
|
||||
eventType,
|
||||
false,
|
||||
rTeacher.id,
|
||||
rSubject.id,
|
||||
teacherId,
|
||||
subjectId,
|
||||
data.teamClass?.id ?: -1
|
||||
)
|
||||
|
||||
@ -106,9 +113,11 @@ class IdziennikWebExams(override val data: DataIdziennik,
|
||||
examsNextMonthChecked = true
|
||||
getExams()
|
||||
} else {
|
||||
data.toRemove.add(DataRemoveModel.Events.futureExceptType(Event.TYPE_HOMEWORK))
|
||||
|
||||
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_EXAMS, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-11-25
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.idziennik.data.web
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
|
||||
import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_WEB_HOMEWORK
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_WEB_HOMEWORK
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.data.IdziennikWeb
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class IdziennikWebHomework(override val data: DataIdziennik,
|
||||
val onSuccess: () -> Unit) : IdziennikWeb(data) {
|
||||
companion object {
|
||||
private const val TAG = "IdziennikWebHomework"
|
||||
}
|
||||
|
||||
init {
|
||||
val param = JsonObject().apply {
|
||||
addProperty("strona", 1)
|
||||
addProperty("iloscNaStrone", 997)
|
||||
addProperty("iloscRekordow", -1)
|
||||
addProperty("kolumnaSort", "DataZadania")
|
||||
addProperty("kierunekSort", 0)
|
||||
addProperty("maxIloscZaznaczonych", 0)
|
||||
addProperty("panelFiltrow", 0)
|
||||
}
|
||||
|
||||
webApiGet(TAG, IDZIENNIK_WEB_HOMEWORK, mapOf(
|
||||
"idP" to data.registerId,
|
||||
"data" to Date.getToday().stringY_m_d,
|
||||
"wszystkie" to true,
|
||||
"param" to param
|
||||
)) { result ->
|
||||
val json = result.getJsonObject("d") ?: run {
|
||||
data.error(ApiError(TAG, ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA)
|
||||
.withApiResponse(result))
|
||||
return@webApiGet
|
||||
}
|
||||
|
||||
json.getJsonArray("ListK")?.asJsonObjectList()?.forEach { homework ->
|
||||
val id = homework.getLong("_recordId") ?: return@forEach
|
||||
val eventDate = Date.fromY_m_d(homework.getString("dataO") ?: return@forEach)
|
||||
val subjectName = homework.getString("przed") ?: return@forEach
|
||||
val subjectId = data.getSubject(subjectName, null, subjectName).id
|
||||
val teacherName = homework.getString("usr") ?: return@forEach
|
||||
val teacherId = data.getTeacherByLastFirst(teacherName).id
|
||||
val lessonList = data.db.timetableDao().getForDateNow(profileId, eventDate)
|
||||
val startTime = lessonList.firstOrNull { it.subjectId == subjectId }?.displayStartTime
|
||||
val topic = homework.getString("tytul") ?: ""
|
||||
|
||||
val seen = when (profile?.empty) {
|
||||
true -> true
|
||||
else -> eventDate < Date.getToday()
|
||||
}
|
||||
|
||||
|
||||
val eventObject = Event(
|
||||
profileId,
|
||||
id,
|
||||
eventDate,
|
||||
startTime,
|
||||
topic,
|
||||
-1,
|
||||
Event.TYPE_HOMEWORK,
|
||||
false,
|
||||
teacherId,
|
||||
subjectId,
|
||||
data.teamClass?.id ?: -1
|
||||
)
|
||||
|
||||
data.eventList.add(eventObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_HOMEWORK,
|
||||
eventObject.id,
|
||||
seen,
|
||||
seen,
|
||||
System.currentTimeMillis()
|
||||
))
|
||||
}
|
||||
|
||||
data.toRemove.add(DataRemoveModel.Events.futureWithType(Event.TYPE_HOMEWORK))
|
||||
|
||||
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_HOMEWORK, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -10,21 +10,24 @@ import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_WEB_PROPOSED_GRADES
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.data.IdziennikWeb
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.asJsonObjectList
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade.TYPE_SEMESTER1_PROPOSED
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade.TYPE_YEAR_PROPOSED
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.getJsonArray
|
||||
import pl.szczodrzynski.edziennik.getJsonObject
|
||||
import pl.szczodrzynski.edziennik.getString
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.getWordGradeValue
|
||||
|
||||
class IdziennikWebProposedGrades(override val data: DataIdziennik,
|
||||
val onSuccess: () -> Unit) : IdziennikWeb(data) {
|
||||
val onSuccess: () -> Unit) : IdziennikWeb(data) {
|
||||
companion object {
|
||||
private const val TAG = "IdziennikWebProposedGrades"
|
||||
}
|
||||
|
||||
init {
|
||||
init { data.profile?.also { profile ->
|
||||
webApiGet(TAG, IDZIENNIK_WEB_MISSING_GRADES, mapOf(
|
||||
"idPozDziennika" to data.registerId
|
||||
)) { result ->
|
||||
@ -34,17 +37,17 @@ class IdziennikWebProposedGrades(override val data: DataIdziennik,
|
||||
return@webApiGet
|
||||
}
|
||||
|
||||
val jSubjects = json.getAsJsonArray("Przedmioty")
|
||||
for (jSubjectEl in jSubjects) {
|
||||
val jSubject = jSubjectEl.getAsJsonObject()
|
||||
// jSubject
|
||||
val rSubject = data.getSubject(jSubject.get("Przedmiot").getAsString(), -1, jSubject.get("Przedmiot").getAsString())
|
||||
val semester1Proposed = jSubject.get("OcenaSem1").getAsString()
|
||||
val semester2Proposed = jSubject.get("OcenaSem2").getAsString()
|
||||
json.getJsonArray("Przedmioty")?.asJsonObjectList()?.forEach { subject ->
|
||||
val subjectName = subject.getString("Przedmiot") ?: return@forEach
|
||||
val subjectObject = data.getSubject(subjectName, null, subjectName)
|
||||
|
||||
val semester1Proposed = subject.getString("OcenaSem1") ?: ""
|
||||
val semester1Value = getWordGradeValue(semester1Proposed)
|
||||
val semester1Id = subjectObject.id * (-100) - 1
|
||||
|
||||
val semester2Proposed = subject.getString("OcenaSem2") ?: ""
|
||||
val semester2Value = getWordGradeValue(semester2Proposed)
|
||||
val semester1Id = rSubject.id * -100 - 1
|
||||
val semester2Id = rSubject.id * -100 - 2
|
||||
val semester2Id = subjectObject.id * (-100) - 2
|
||||
|
||||
if (semester1Proposed != "") {
|
||||
val gradeObject = Grade(
|
||||
@ -58,17 +61,18 @@ class IdziennikWebProposedGrades(override val data: DataIdziennik,
|
||||
0f,
|
||||
1,
|
||||
-1,
|
||||
rSubject.id)
|
||||
|
||||
gradeObject.type = TYPE_SEMESTER1_PROPOSED
|
||||
subjectObject.id
|
||||
).apply {
|
||||
type = TYPE_SEMESTER1_PROPOSED
|
||||
}
|
||||
|
||||
data.gradeList.add(gradeObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_GRADE,
|
||||
gradeObject.id,
|
||||
profile?.empty ?: false,
|
||||
profile?.empty ?: false,
|
||||
profile.empty,
|
||||
profile.empty,
|
||||
System.currentTimeMillis()
|
||||
))
|
||||
}
|
||||
@ -85,17 +89,18 @@ class IdziennikWebProposedGrades(override val data: DataIdziennik,
|
||||
0f,
|
||||
2,
|
||||
-1,
|
||||
rSubject.id)
|
||||
|
||||
gradeObject.type = TYPE_YEAR_PROPOSED
|
||||
subjectObject.id
|
||||
).apply {
|
||||
type = TYPE_YEAR_PROPOSED
|
||||
}
|
||||
|
||||
data.gradeList.add(gradeObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_GRADE,
|
||||
gradeObject.id,
|
||||
profile?.empty ?: false,
|
||||
profile?.empty ?: false,
|
||||
profile.empty,
|
||||
profile.empty,
|
||||
System.currentTimeMillis()
|
||||
))
|
||||
}
|
||||
@ -104,5 +109,5 @@ class IdziennikWebProposedGrades(override val data: DataIdziennik,
|
||||
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_PROPOSED_GRADES, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-27.
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-11-22
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.idziennik.data.web
|
||||
@ -12,33 +12,38 @@ import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_WEB_TIMETABLE
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.data.IdziennikWeb
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.Lesson
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonChange
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonChange.TYPE_CANCELLED
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonChange.TYPE_CHANGE
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonRange
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.timetable.Lesson
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
import pl.szczodrzynski.edziennik.utils.models.Week
|
||||
|
||||
class IdziennikWebTimetable(override val data: DataIdziennik,
|
||||
val onSuccess: () -> Unit) : IdziennikWeb(data) {
|
||||
val onSuccess: () -> Unit) : IdziennikWeb(data) {
|
||||
companion object {
|
||||
private const val TAG = "IdziennikWebTimetable"
|
||||
}
|
||||
|
||||
init {
|
||||
val weekStart = Week.getWeekStart()
|
||||
init { data.profile?.also { profile ->
|
||||
val currentWeekStart = Week.getWeekStart()
|
||||
|
||||
if (Date.getToday().weekDay > 4) {
|
||||
weekStart.stepForward(0, 0, 7)
|
||||
currentWeekStart.stepForward(0, 0, 7)
|
||||
}
|
||||
|
||||
val getDate = data.arguments?.getString("weekStart") ?: currentWeekStart.stringY_m_d
|
||||
|
||||
val weekStart = Date.fromY_m_d(getDate)
|
||||
val weekEnd = weekStart.clone().stepForward(0, 0, 6)
|
||||
|
||||
webApiGet(TAG, IDZIENNIK_WEB_TIMETABLE, mapOf(
|
||||
"idPozDziennika" to data.registerId,
|
||||
"pidRokSzkolny" to data.schoolYearId,
|
||||
"data" to weekStart.stringY_m_d+"T10:00:00.000Z"
|
||||
"data" to "${weekStart.stringY_m_d}T10:00:00.000Z"
|
||||
)) { result ->
|
||||
val json = result.getJsonObject("d") ?: run {
|
||||
data.error(ApiError(TAG, ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA)
|
||||
@ -56,73 +61,132 @@ class IdziennikWebTimetable(override val data: DataIdziennik,
|
||||
data.lessonRanges[lessonRange.lessonNumber] = lessonRange
|
||||
}
|
||||
|
||||
val dates = mutableSetOf<Int>()
|
||||
val lessons = mutableListOf<Lesson>()
|
||||
|
||||
json.getJsonArray("Przedmioty")?.asJsonObjectList()?.forEach { lesson ->
|
||||
val subject = data.getSubject(
|
||||
lesson.getString("Nazwa") ?: return@forEach,
|
||||
lesson.getLong("Id"),
|
||||
lesson.getString("Skrot") ?: ""
|
||||
)
|
||||
val teacher = data.getTeacherByFDotLast(lesson.getString("Nauczyciel") ?: return@forEach)
|
||||
val weekDay = lesson.getInt("DzienTygodnia")?.minus(1) ?: return@forEach
|
||||
val lessonRange = data.lessonRanges[lesson.getInt("Godzina")?.plus(1) ?: return@forEach]
|
||||
val teacher = data.getTeacherByFDotLast(lesson.getString("Nauczyciel")
|
||||
?: return@forEach)
|
||||
|
||||
val lessonObject = Lesson(
|
||||
profileId,
|
||||
weekDay,
|
||||
lessonRange.startTime,
|
||||
lessonRange.endTime
|
||||
).apply {
|
||||
subjectId = subject.id
|
||||
teacherId = teacher.id
|
||||
teamId = data.teamClass?.id ?: -1
|
||||
classroomName = lesson.getString("NazwaSali") ?: ""
|
||||
val newSubjectName = lesson.getString("PrzedmiotZastepujacy")
|
||||
val newSubject = when (newSubjectName.isNullOrBlank()) {
|
||||
true -> null
|
||||
else -> data.getSubject(newSubjectName, null, newSubjectName)
|
||||
}
|
||||
|
||||
data.lessonList.add(lessonObject)
|
||||
val newTeacherName = lesson.getString("NauZastepujacy")
|
||||
val newTeacher = when (newTeacherName.isNullOrBlank()) {
|
||||
true -> null
|
||||
else -> data.getTeacherByFDotLast(newTeacherName)
|
||||
}
|
||||
|
||||
val weekDay = lesson.getInt("DzienTygodnia")?.minus(1) ?: return@forEach
|
||||
val lessonRange = data.lessonRanges[lesson.getInt("Godzina")?.plus(1)
|
||||
?: return@forEach]
|
||||
val lessonDate = weekStart.clone().stepForward(0, 0, weekDay)
|
||||
val classroom = lesson.getString("NazwaSali")
|
||||
|
||||
val type = lesson.getInt("TypZastepstwa") ?: -1
|
||||
if (type != -1) {
|
||||
// we have a lesson change to process
|
||||
val lessonChangeObject = LessonChange(
|
||||
profileId,
|
||||
weekStart.clone().stepForward(0, 0, weekDay),
|
||||
lessonObject.startTime,
|
||||
lessonObject.endTime
|
||||
)
|
||||
|
||||
lessonChangeObject.teamId = lessonObject.teamId
|
||||
lessonChangeObject.teacherId = lessonObject.teacherId
|
||||
lessonChangeObject.subjectId = lessonObject.subjectId
|
||||
lessonChangeObject.classroomName = lessonObject.classroomName
|
||||
when (type) {
|
||||
0 -> lessonChangeObject.type = TYPE_CANCELLED
|
||||
1, 2, 3, 4, 5 -> {
|
||||
lessonChangeObject.type = TYPE_CHANGE
|
||||
val newTeacher = lesson.getString("NauZastepujacy")
|
||||
val newSubject = lesson.getString("PrzedmiotZastepujacy")
|
||||
if (newTeacher != null) {
|
||||
lessonChangeObject.teacherId = data.getTeacherByFDotLast(newTeacher).id
|
||||
}
|
||||
if (newSubject != null) {
|
||||
lessonChangeObject.subjectId = data.getSubject(newSubject, null, "").id
|
||||
}
|
||||
val lessonObject = Lesson(profileId, -1)
|
||||
|
||||
when (type) {
|
||||
1, 2, 3, 4, 5 -> {
|
||||
lessonObject.apply {
|
||||
this.type = Lesson.TYPE_CHANGE
|
||||
|
||||
this.date = lessonDate
|
||||
this.lessonNumber = lessonRange.lessonNumber
|
||||
this.startTime = lessonRange.startTime
|
||||
this.endTime = lessonRange.endTime
|
||||
this.subjectId = newSubject?.id
|
||||
this.teacherId = newTeacher?.id
|
||||
this.teamId = data.teamClass?.id
|
||||
this.classroom = classroom
|
||||
|
||||
this.oldDate = lessonDate
|
||||
this.oldLessonNumber = lessonRange.lessonNumber
|
||||
this.oldStartTime = lessonRange.startTime
|
||||
this.oldEndTime = lessonRange.endTime
|
||||
this.oldSubjectId = subject.id
|
||||
this.oldTeacherId = teacher.id
|
||||
this.oldTeamId = data.teamClass?.id
|
||||
this.oldClassroom = classroom
|
||||
}
|
||||
}
|
||||
0 -> {
|
||||
lessonObject.apply {
|
||||
this.type = Lesson.TYPE_CANCELLED
|
||||
|
||||
data.lessonChangeList.add(lessonChangeObject)
|
||||
this.oldDate = lessonDate
|
||||
this.oldLessonNumber = lessonRange.lessonNumber
|
||||
this.oldStartTime = lessonRange.startTime
|
||||
this.oldEndTime = lessonRange.endTime
|
||||
this.oldSubjectId = subject.id
|
||||
this.oldTeacherId = teacher.id
|
||||
this.oldTeamId = data.teamClass?.id
|
||||
this.oldClassroom = classroom
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
lessonObject.apply {
|
||||
this.type = Lesson.TYPE_NORMAL
|
||||
|
||||
this.date = lessonDate
|
||||
this.lessonNumber = lessonRange.lessonNumber
|
||||
this.startTime = lessonRange.startTime
|
||||
this.endTime = lessonRange.endTime
|
||||
this.subjectId = subject.id
|
||||
this.teacherId = teacher.id
|
||||
this.teamId = data.teamClass?.id
|
||||
this.classroom = classroom
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lessonObject.id = lessonObject.buildId()
|
||||
|
||||
dates.add(lessonDate.value)
|
||||
lessons.add(lessonObject)
|
||||
|
||||
val seen = profile.empty || lessonDate < Date.getToday()
|
||||
|
||||
if (lessonObject.type != Lesson.TYPE_NORMAL && lessonDate >= Date.getToday()) {
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_LESSON_CHANGE,
|
||||
lessonChangeObject.id,
|
||||
profile?.empty ?: false,
|
||||
profile?.empty ?: false,
|
||||
lessonObject.id,
|
||||
seen,
|
||||
seen,
|
||||
System.currentTimeMillis()
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
val date: Date = weekStart.clone()
|
||||
while (date <= weekEnd) {
|
||||
if (!dates.contains(date.value)) {
|
||||
lessons.add(Lesson(profileId, date.value.toLong()).apply {
|
||||
this.type = Lesson.TYPE_NO_LESSONS
|
||||
this.date = date.clone()
|
||||
})
|
||||
}
|
||||
|
||||
date.stepForward(0, 0, 1)
|
||||
}
|
||||
|
||||
d(TAG, "Clearing lessons between ${weekStart.stringY_m_d} and ${weekEnd.stringY_m_d} - timetable downloaded for $getDate")
|
||||
|
||||
data.lessonNewList.addAll(lessons)
|
||||
data.toRemove.add(DataRemoveModel.Timetable.between(weekStart, weekEnd))
|
||||
|
||||
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_TIMETABLE, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
@ -5,12 +5,14 @@
|
||||
package pl.szczodrzynski.edziennik.api.v2.interfaces
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
|
||||
|
||||
interface EdziennikInterface {
|
||||
fun sync(featureIds: List<Int>, viewId: Int? = null, arguments: JsonObject? = null)
|
||||
fun getMessage(message: MessageFull)
|
||||
fun markAllAnnouncementsAsRead()
|
||||
fun getAttachment(message: Message, attachmentId: Long, attachmentName: String)
|
||||
fun firstLogin()
|
||||
fun cancel()
|
||||
}
|
||||
|
@ -10,15 +10,14 @@ import pl.szczodrzynski.edziennik.api.v2.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikCallback
|
||||
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikInterface
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusData
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.messages.LibrusMessagesGetAttachment
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.messages.LibrusMessagesGetMessage
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.synergia.LibrusSynergiaMarkAllAnnouncementsAsRead
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.firstlogin.LibrusFirstLogin
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.login.LibrusLogin
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.login.LibrusLoginApi
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.login.LibrusLoginMessages
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.login.LibrusLoginSynergia
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.login.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
@ -82,11 +81,13 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
||||
}
|
||||
|
||||
override fun getMessage(message: MessageFull) {
|
||||
LibrusLoginApi(data) {
|
||||
LibrusLoginSynergia(data) {
|
||||
LibrusLoginMessages(data) {
|
||||
LibrusMessagesGetMessage(data, message) {
|
||||
completed()
|
||||
LibrusLoginPortal(data) {
|
||||
LibrusLoginApi(data) {
|
||||
LibrusLoginSynergia(data) {
|
||||
LibrusLoginMessages(data) {
|
||||
LibrusMessagesGetMessage(data, message) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -94,10 +95,26 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
||||
}
|
||||
|
||||
override fun markAllAnnouncementsAsRead() {
|
||||
LibrusLoginApi(data) {
|
||||
LibrusLoginSynergia(data) {
|
||||
LibrusSynergiaMarkAllAnnouncementsAsRead(data) {
|
||||
completed()
|
||||
LibrusLoginPortal(data) {
|
||||
LibrusLoginApi(data) {
|
||||
LibrusLoginSynergia(data) {
|
||||
LibrusSynergiaMarkAllAnnouncementsAsRead(data) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getAttachment(message: Message, attachmentId: Long, attachmentName: String) {
|
||||
LibrusLoginPortal(data) {
|
||||
LibrusLoginApi(data) {
|
||||
LibrusLoginSynergia(data) {
|
||||
LibrusLoginMessages(data) {
|
||||
LibrusMessagesGetAttachment(data, message, attachmentId, attachmentName) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ val LibrusFeatures = listOf(
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_PUSH_CONFIG, listOf(
|
||||
ENDPOINT_LIBRUS_API_PUSH_CONFIG to LOGIN_METHOD_LIBRUS_API
|
||||
), listOf(LOGIN_METHOD_LIBRUS_API)).withShouldSync { data ->
|
||||
data.app.appConfig.fcmTokens[LOGIN_TYPE_LIBRUS]?.second?.contains(data.profileId) == false
|
||||
!data.app.config.sync.tokenLibrusList.contains(data.profileId)
|
||||
},
|
||||
|
||||
|
||||
|
@ -4,9 +4,12 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import im.wangchao.mhttp.Request
|
||||
import im.wangchao.mhttp.Response
|
||||
import im.wangchao.mhttp.body.MediaTypeUtils
|
||||
import im.wangchao.mhttp.callback.FileCallbackHandler
|
||||
import im.wangchao.mhttp.callback.JsonCallbackHandler
|
||||
import im.wangchao.mhttp.callback.TextCallbackHandler
|
||||
import okhttp3.Cookie
|
||||
import org.jsoup.Jsoup
|
||||
@ -16,6 +19,7 @@ import pl.szczodrzynski.edziennik.api.v2.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import java.io.File
|
||||
import java.io.StringWriter
|
||||
import javax.xml.parsers.DocumentBuilderFactory
|
||||
import javax.xml.transform.OutputKeys
|
||||
@ -131,4 +135,95 @@ open class LibrusMessages(open val data: DataLibrus) {
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
|
||||
fun sandboxGet(tag: String, action: String, parameters: Map<String, Any>? = null,
|
||||
onSuccess: (json: JsonObject) -> Unit) {
|
||||
|
||||
d(tag, "Request: Librus/Messages - $LIBRUS_SANDBOX_URL$action")
|
||||
|
||||
val callback = object : JsonCallbackHandler() {
|
||||
override fun onSuccess(json: JsonObject?, response: Response?) {
|
||||
if (json == null) {
|
||||
data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
onSuccess(json)
|
||||
} catch (e: Exception) {
|
||||
data.error(ApiError(tag, EXCEPTION_LIBRUS_MESSAGES_REQUEST)
|
||||
.withResponse(response)
|
||||
.withThrowable(e)
|
||||
.withApiResponse(json))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||
data.error(ApiError(tag, ERROR_REQUEST_FAILURE)
|
||||
.withResponse(response)
|
||||
.withThrowable(throwable))
|
||||
}
|
||||
}
|
||||
|
||||
Request.builder()
|
||||
.url("$LIBRUS_SANDBOX_URL$action")
|
||||
.userAgent(SYNERGIA_USER_AGENT)
|
||||
.apply {
|
||||
parameters?.forEach { (k, v) ->
|
||||
addParameter(k, v)
|
||||
}
|
||||
}
|
||||
.post()
|
||||
.callback(callback)
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
|
||||
fun sandboxGetFile(tag: String, action: String, targetFile: File, onSuccess: (file: File) -> Unit,
|
||||
onProgress: (written: Long, total: Long) -> Unit) {
|
||||
|
||||
d(tag, "Request: Librus/Messages - $LIBRUS_SANDBOX_URL$action")
|
||||
|
||||
val callback = object : FileCallbackHandler(targetFile) {
|
||||
override fun onSuccess(file: File?, response: Response?) {
|
||||
if (file == null) {
|
||||
data.error(ApiError(TAG, ERROR_FILE_DOWNLOAD)
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
onSuccess(file)
|
||||
} catch (e: Exception) {
|
||||
data.error(ApiError(tag, EXCEPTION_LIBRUS_MESSAGES_FILE_REQUEST)
|
||||
.withResponse(response)
|
||||
.withThrowable(e))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onProgress(bytesWritten: Long, bytesTotal: Long) {
|
||||
try {
|
||||
onProgress(bytesWritten, bytesTotal)
|
||||
} catch (e: Exception) {
|
||||
data.error(ApiError(tag, EXCEPTION_LIBRUS_MESSAGES_FILE_REQUEST)
|
||||
.withThrowable(e))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||
data.error(ApiError(tag, ERROR_REQUEST_FAILURE)
|
||||
.withResponse(response)
|
||||
.withThrowable(throwable))
|
||||
}
|
||||
}
|
||||
|
||||
Request.builder()
|
||||
.url("$LIBRUS_SANDBOX_URL$action")
|
||||
.userAgent(SYNERGIA_USER_AGENT)
|
||||
.post()
|
||||
.callback(callback)
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
}
|
||||
|
@ -36,14 +36,14 @@ class LibrusApiAttendances(override val data: DataLibrus,
|
||||
val lessonNo = attendance.getInt("LessonNo") ?: return@forEach
|
||||
val startTime = data.lessonRanges.get(lessonNo).startTime
|
||||
val lessonDate = Date.fromY_m_d(attendance.getString("Date"))
|
||||
val subjectId = data.lessonList.singleOrNull {
|
||||
it.weekDay == lessonDate.weekDay && it.startTime.value == startTime.value
|
||||
}?.subjectId ?: -1
|
||||
val semester = attendance.getInt("Semester") ?: return@forEach
|
||||
val type = attendance.getJsonObject("Type")?.getLong("Id") ?: return@forEach
|
||||
val typeObject = data.attendanceTypes.get(type)
|
||||
val topic = typeObject?.name ?: ""
|
||||
|
||||
val lessonList = data.db.timetableDao().getForDateNow(profileId, lessonDate)
|
||||
val subjectId = lessonList.firstOrNull { it.startTime == startTime }?.subjectId ?: -1
|
||||
|
||||
val attendanceObject = Attendance(
|
||||
profileId,
|
||||
id,
|
||||
|
@ -9,6 +9,7 @@ import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_EVENTS
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
@ -69,6 +70,8 @@ class LibrusApiEvents(override val data: DataLibrus,
|
||||
))
|
||||
}
|
||||
|
||||
data.toRemove.add(DataRemoveModel.Events.futureExceptType(Event.TYPE_HOMEWORK))
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_EVENTS, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_HOMEWORK
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
@ -55,6 +56,8 @@ class LibrusApiHomework(override val data: DataLibrus,
|
||||
))
|
||||
}
|
||||
|
||||
data.toRemove.add(DataRemoveModel.Events.futureWithType(Event.TYPE_HOMEWORK))
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_HOMEWORK, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ import pl.szczodrzynski.edziennik.data.db.modules.timetable.Lesson
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
import pl.szczodrzynski.edziennik.utils.models.Week
|
||||
|
||||
class LibrusApiTimetables(override val data: DataLibrus,
|
||||
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||
@ -29,9 +30,18 @@ class LibrusApiTimetables(override val data: DataLibrus,
|
||||
data.db.classroomDao().getAllNow(profileId).toSparseArray(data.classrooms) { it.id }
|
||||
}
|
||||
|
||||
val currentWeekStart = Date.getToday().let { it.stepForward(0, 0, -it.weekDay) }
|
||||
val currentWeekStart = Week.getWeekStart()
|
||||
|
||||
if (Date.getToday().weekDay > 4) {
|
||||
currentWeekStart.stepForward(0, 0, 7)
|
||||
}
|
||||
|
||||
val getDate = data.arguments?.getString("weekStart") ?: currentWeekStart.stringY_m_d
|
||||
apiGet(TAG, "Timetables?weekStart=$getDate") { json ->
|
||||
|
||||
val weekStart = Date.fromY_m_d(getDate)
|
||||
val weekEnd = weekStart.clone().stepForward(0, 0, 6)
|
||||
|
||||
apiGet(TAG, "Timetables?weekStart=${weekStart.stringY_m_d}") { json ->
|
||||
val days = json.getJsonObject("Timetable")
|
||||
|
||||
days?.entrySet()?.forEach { (dateString, dayEl) ->
|
||||
@ -57,8 +67,6 @@ class LibrusApiTimetables(override val data: DataLibrus,
|
||||
}
|
||||
}
|
||||
|
||||
val weekStart = Date.fromY_m_d(getDate)
|
||||
val weekEnd = weekStart.clone().stepForward(0, 0, 6)
|
||||
d(TAG, "Clearing lessons between ${weekStart.stringY_m_d} and ${weekEnd.stringY_m_d} - timetable downloaded for $getDate")
|
||||
|
||||
data.toRemove.add(DataRemoveModel.Timetable.between(weekStart, weekEnd))
|
||||
@ -67,7 +75,7 @@ class LibrusApiTimetables(override val data: DataLibrus,
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseLesson(lessonDate: Date, lesson: JsonObject) {
|
||||
private fun parseLesson(lessonDate: Date, lesson: JsonObject) { data.profile?.also { profile ->
|
||||
val isSubstitution = lesson.getBoolean("IsSubstitutionClass") ?: false
|
||||
val isCancelled = lesson.getBoolean("IsCanceled") ?: false
|
||||
|
||||
@ -80,8 +88,7 @@ class LibrusApiTimetables(override val data: DataLibrus,
|
||||
val virtualClassId = lesson.getJsonObject("VirtualClass")?.getLong("Id")
|
||||
val teamId = lesson.getJsonObject("Class")?.getLong("Id") ?: virtualClassId
|
||||
|
||||
val id = lessonDate.combineWith(startTime) / 6L * 10L + (lesson.hashCode() and 0xFFFF)
|
||||
val lessonObject = Lesson(profileId, id)
|
||||
val lessonObject = Lesson(profileId, -1)
|
||||
|
||||
if (isSubstitution && isCancelled) {
|
||||
// shifted lesson - source
|
||||
@ -176,17 +183,21 @@ class LibrusApiTimetables(override val data: DataLibrus,
|
||||
}
|
||||
}
|
||||
|
||||
lessonObject.id = lessonObject.buildId()
|
||||
|
||||
val seen = profile.empty || lessonDate < Date.getToday()
|
||||
|
||||
if (lessonObject.type != Lesson.TYPE_NORMAL) {
|
||||
data.metadataList.add(
|
||||
Metadata(
|
||||
data.profileId,
|
||||
profileId,
|
||||
Metadata.TYPE_LESSON_CHANGE,
|
||||
lessonObject.id,
|
||||
data.profile?.empty ?: false,
|
||||
data.profile?.empty ?: false,
|
||||
seen,
|
||||
seen,
|
||||
System.currentTimeMillis()
|
||||
))
|
||||
}
|
||||
data.lessonNewList.add(lessonObject)
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-11-24
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data.messages
|
||||
|
||||
import kotlinx.coroutines.*
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import pl.szczodrzynski.edziennik.api.v2.ERROR_FILE_DOWNLOAD
|
||||
import pl.szczodrzynski.edziennik.api.v2.EXCEPTION_LIBRUS_MESSAGES_REQUEST
|
||||
import pl.szczodrzynski.edziennik.api.v2.Regexes
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.AttachmentGetEvent
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.AttachmentGetEvent.Companion.TYPE_FINISHED
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.AttachmentGetEvent.Companion.TYPE_PROGRESS
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusMessages
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.getString
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
import java.io.File
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class LibrusMessagesGetAttachment(
|
||||
override val data: DataLibrus, val message: Message, val attachmentId: Long,
|
||||
val attachmentName: String, val onSuccess: () -> Unit) : LibrusMessages(data), CoroutineScope {
|
||||
companion object {
|
||||
const val TAG = "LibrusMessagesGetAttachment"
|
||||
}
|
||||
|
||||
private var job = Job()
|
||||
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Default
|
||||
|
||||
private var getAttachmentCheckKeyTries = 0
|
||||
|
||||
init {
|
||||
messagesGet(TAG, "GetFileDownloadLink", parameters = mapOf(
|
||||
"fileId" to attachmentId,
|
||||
"msgId" to message.id,
|
||||
"archive" to 0
|
||||
)) { doc ->
|
||||
val downloadLink = doc.select("response GetFileDownloadLink downloadLink").text()
|
||||
val keyMatcher = Regexes.LIBRUS_ATTACHMENT_KEY.find(downloadLink)
|
||||
|
||||
if (keyMatcher != null) {
|
||||
getAttachmentCheckKeyTries = 0
|
||||
|
||||
val attachmentKey = keyMatcher[1]
|
||||
getAttachmentCheckKey(attachmentKey) {
|
||||
downloadAttachment(attachmentKey)
|
||||
}
|
||||
} else {
|
||||
data.error(ApiError(TAG, ERROR_FILE_DOWNLOAD)
|
||||
.withApiResponse(doc.toString()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAttachmentCheckKey(attachmentKey: String, callback: () -> Unit) {
|
||||
sandboxGet(TAG, "CSCheckKey",
|
||||
parameters = mapOf("singleUseKey" to attachmentKey)) { json ->
|
||||
|
||||
when (json.getString("status")) {
|
||||
"not_downloaded_yet" -> {
|
||||
if (getAttachmentCheckKeyTries++ > 5) {
|
||||
data.error(ApiError(TAG, ERROR_FILE_DOWNLOAD)
|
||||
.withApiResponse(json))
|
||||
return@sandboxGet
|
||||
}
|
||||
launch {
|
||||
delay(2000)
|
||||
getAttachmentCheckKey(attachmentKey, callback)
|
||||
}
|
||||
}
|
||||
|
||||
"ready" -> {
|
||||
launch { callback() }
|
||||
}
|
||||
|
||||
else -> {
|
||||
data.error(ApiError(TAG, EXCEPTION_LIBRUS_MESSAGES_REQUEST)
|
||||
.withApiResponse(json))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun downloadAttachment(attachmentKey: String) {
|
||||
val targetFile = File(Utils.getStorageDir(), attachmentName)
|
||||
|
||||
sandboxGetFile(TAG, "CSDownload&singleUseKey=$attachmentKey", targetFile, { file ->
|
||||
|
||||
val event = AttachmentGetEvent(
|
||||
profileId,
|
||||
message.id,
|
||||
attachmentId,
|
||||
TYPE_FINISHED,
|
||||
file.absolutePath
|
||||
)
|
||||
|
||||
val attachmentDataFile = File(Utils.getStorageDir(), ".${profileId}_${event.messageId}_${event.attachmentId}")
|
||||
Utils.writeStringToFile(attachmentDataFile, event.fileName)
|
||||
|
||||
EventBus.getDefault().post(event)
|
||||
|
||||
onSuccess()
|
||||
|
||||
}) { written, _ ->
|
||||
val event = AttachmentGetEvent(
|
||||
profileId,
|
||||
message.id,
|
||||
attachmentId,
|
||||
TYPE_PROGRESS,
|
||||
bytesWritten = written
|
||||
)
|
||||
|
||||
EventBus.getDefault().post(event)
|
||||
}
|
||||
}
|
||||
}
|
@ -11,6 +11,7 @@ import pl.szczodrzynski.edziennik.api.v2.POST
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_SYNERGIA_HOMEWORK
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusSynergia
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
@ -55,19 +56,18 @@ class LibrusSynergiaHomework(override val data: DataLibrus, val onSuccess: () ->
|
||||
val id = "/podglad/([0-9]+)'".toRegex().find(
|
||||
elements[9].select("input").attr("onclick")
|
||||
)?.get(1)?.toLong() ?: return@forEachIndexed
|
||||
val startTime = data.lessonList.singleOrNull {
|
||||
it.weekDay == eventDate.weekDay && it.subjectId == subjectId
|
||||
}?.startTime
|
||||
|
||||
val lessons = data.db.timetableDao().getForDateNow(profileId, eventDate)
|
||||
val startTime = lessons.firstOrNull { it.subjectId == subjectId }?.startTime
|
||||
|
||||
val moreInfo = graphElements[2 * i + 1].select("td[title]")
|
||||
.attr("title").trim()
|
||||
val description = "Treść: (.*)".toRegex(RegexOption.DOT_MATCHES_ALL).find(moreInfo)
|
||||
?.get(1)?.replace("<br.*/>".toRegex(), "\n")?.trim()
|
||||
|
||||
val notified = when (profile?.empty) {
|
||||
val seen = when (profile?.empty) {
|
||||
true -> true
|
||||
false -> Date.getToday() < eventDate
|
||||
else -> false
|
||||
else -> eventDate < Date.getToday()
|
||||
}
|
||||
|
||||
val eventObject = Event(
|
||||
@ -89,13 +89,15 @@ class LibrusSynergiaHomework(override val data: DataLibrus, val onSuccess: () ->
|
||||
profileId,
|
||||
Metadata.TYPE_HOMEWORK,
|
||||
id,
|
||||
notified,
|
||||
notified,
|
||||
seen,
|
||||
seen,
|
||||
addedDate
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
data.toRemove.add(DataRemoveModel.Events.futureWithType(Event.TYPE_HOMEWORK))
|
||||
|
||||
// because this requires a synergia login (2 more requests) sync this every two hours or if explicit :D
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_SYNERGIA_HOMEWORK, 2 * HOUR, DRAWER_ITEM_HOMEWORK)
|
||||
onSuccess()
|
||||
|
@ -13,8 +13,8 @@ import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusPortal
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.login.LibrusLoginApi
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.login.LibrusLoginPortal
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.api.AppError.CODE_LIBRUS_DISCONNECTED
|
||||
import pl.szczodrzynski.edziennik.data.api.AppError.CODE_SYNERGIA_NOT_ACTIVATED
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.AppError.CODE_LIBRUS_DISCONNECTED
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.AppError.CODE_SYNERGIA_NOT_ACTIVATED
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||
|
||||
class LibrusFirstLogin(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
@ -89,4 +89,4 @@ class LibrusFirstLogin(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ class LibrusLoginMessages(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
val loginElement = doc.createElement("login")
|
||||
loginElement.appendChild(doc.createTextNode(data.apiLogin))
|
||||
dataElement.appendChild(loginElement)
|
||||
val passwordElement = doc.createElement("login")
|
||||
val passwordElement = doc.createElement("password")
|
||||
passwordElement.appendChild(doc.createTextNode(data.apiPassword))
|
||||
dataElement.appendChild(passwordElement)
|
||||
val keyStrokeElement = doc.createElement("KeyStroke")
|
||||
@ -150,6 +150,7 @@ class LibrusLoginMessages(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
private fun saveSessionId(response: Response?, text: String?) {
|
||||
var sessionId = data.app.cookieJar.getCookie("wiadomosci.librus.pl", "DZIENNIKSID")
|
||||
sessionId = sessionId?.replace("-MAINT", "") // dunno what's this
|
||||
sessionId = sessionId?.replace("MAINT", "") // dunno what's this
|
||||
if (sessionId == null) {
|
||||
data.error(ApiError(TAG, ERROR_LOGIN_LIBRUS_MESSAGES_NO_SESSION_ID)
|
||||
.withResponse(response)
|
||||
|
@ -10,6 +10,7 @@ import pl.szczodrzynski.edziennik.api.v2.CODE_INTERNAL_LIBRUS_ACCOUNT_410
|
||||
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikCallback
|
||||
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikInterface
|
||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.MobidziennikData
|
||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.web.MobidziennikWebGetAttachment
|
||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.web.MobidziennikWebGetMessage
|
||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.firstlogin.MobidziennikFirstLogin
|
||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.login.MobidziennikLogin
|
||||
@ -18,6 +19,7 @@ import pl.szczodrzynski.edziennik.api.v2.mobidziennikLoginMethods
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.api.v2.prepare
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
@ -76,6 +78,14 @@ class Mobidziennik(val app: App, val profile: Profile?, val loginStore: LoginSto
|
||||
|
||||
}
|
||||
|
||||
override fun getAttachment(message: Message, attachmentId: Long, attachmentName: String) {
|
||||
MobidziennikLoginWeb(data) {
|
||||
MobidziennikWebGetAttachment(data, message, attachmentId, attachmentName) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun firstLogin() {
|
||||
MobidziennikFirstLogin(data) {
|
||||
completed()
|
||||
|
@ -6,12 +6,14 @@ package pl.szczodrzynski.edziennik.api.v2.mobidziennik.data
|
||||
|
||||
import im.wangchao.mhttp.Request
|
||||
import im.wangchao.mhttp.Response
|
||||
import im.wangchao.mhttp.callback.FileCallbackHandler
|
||||
import im.wangchao.mhttp.callback.TextCallbackHandler
|
||||
import okhttp3.Cookie
|
||||
import pl.szczodrzynski.edziennik.api.v2.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.DataMobidziennik
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import java.io.File
|
||||
|
||||
open class MobidziennikWeb(open val data: DataMobidziennik) {
|
||||
companion object {
|
||||
@ -93,4 +95,77 @@ open class MobidziennikWeb(open val data: DataMobidziennik) {
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
|
||||
fun webGetFile(tag: String, action: String, targetFile: File, onSuccess: (file: File) -> Unit,
|
||||
onProgress: (written: Long, total: Long) -> Unit) {
|
||||
val url = "https://${data.loginServerName}.mobidziennik.pl$action"
|
||||
|
||||
d(tag, "Request: Mobidziennik/Web - $url")
|
||||
|
||||
if (data.webSessionKey == null) {
|
||||
data.error(TAG, ERROR_MOBIDZIENNIK_WEB_NO_SESSION_KEY)
|
||||
return
|
||||
}
|
||||
if (data.webSessionValue == null) {
|
||||
data.error(TAG, ERROR_MOBIDZIENNIK_WEB_NO_SESSION_VALUE)
|
||||
return
|
||||
}
|
||||
if (data.webServerId == null) {
|
||||
data.error(TAG, ERROR_MOBIDZIENNIK_WEB_NO_SERVER_ID)
|
||||
return
|
||||
}
|
||||
|
||||
val callback = object : FileCallbackHandler(targetFile) {
|
||||
override fun onSuccess(file: File?, response: Response?) {
|
||||
if (file == null) {
|
||||
data.error(ApiError(TAG, ERROR_FILE_DOWNLOAD)
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
onSuccess(file)
|
||||
} catch (e: Exception) {
|
||||
data.error(ApiError(tag, EXCEPTION_MOBIDZIENNIK_WEB_FILE_REQUEST)
|
||||
.withResponse(response)
|
||||
.withThrowable(e))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onProgress(bytesWritten: Long, bytesTotal: Long) {
|
||||
try {
|
||||
onProgress(bytesWritten, bytesTotal)
|
||||
} catch (e: Exception) {
|
||||
data.error(ApiError(tag, EXCEPTION_MOBIDZIENNIK_WEB_FILE_REQUEST)
|
||||
.withThrowable(e))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||
data.error(ApiError(TAG, ERROR_REQUEST_FAILURE)
|
||||
.withResponse(response)
|
||||
.withThrowable(throwable))
|
||||
}
|
||||
}
|
||||
|
||||
data.app.cookieJar.saveFromResponse(null, listOf(
|
||||
Cookie.Builder()
|
||||
.name(data.webSessionKey!!)
|
||||
.value(data.webSessionValue!!)
|
||||
.domain("${data.loginServerName}.mobidziennik.pl")
|
||||
.secure().httpOnly().build(),
|
||||
Cookie.Builder()
|
||||
.name("SERVERID")
|
||||
.value(data.webServerId!!)
|
||||
.domain("${data.loginServerName}.mobidziennik.pl")
|
||||
.secure().httpOnly().build()
|
||||
))
|
||||
|
||||
Request.builder()
|
||||
.url(url)
|
||||
.userAgent(MOBIDZIENNIK_USER_AGENT)
|
||||
.callback(callback)
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@ package pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.api
|
||||
import androidx.core.util.contains
|
||||
import pl.szczodrzynski.edziennik.api.v2.Regexes
|
||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.DataMobidziennik
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
@ -74,5 +75,7 @@ class MobidziennikApiEvents(val data: DataMobidziennik, rows: List<String>) {
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
data.toRemove.add(DataRemoveModel.Events.futureExceptType(Event.TYPE_HOMEWORK))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ package pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.api
|
||||
|
||||
import androidx.core.util.contains
|
||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.DataMobidziennik
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
@ -53,5 +54,7 @@ class MobidziennikApiHomework(val data: DataMobidziennik, rows: List<String>) {
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
data.toRemove.add(DataRemoveModel.Events.futureWithType(Event.TYPE_HOMEWORK))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
|
||||
class MobidziennikApiTimetable(val data: DataMobidziennik, rows: List<String>) {
|
||||
init {
|
||||
init { data.profile?.also { profile ->
|
||||
val lessons = rows.filterNot { it.isEmpty() }.map { it.split("|") }
|
||||
|
||||
val dataStart = Date.getToday()
|
||||
@ -32,7 +32,6 @@ class MobidziennikApiTimetable(val data: DataMobidziennik, rows: List<String>) {
|
||||
val date = Date.fromYmd(lesson[2])
|
||||
val startTime = Time.fromYmdHm(lesson[3])
|
||||
val endTime = Time.fromYmdHm(lesson[4])
|
||||
val id = date.combineWith(startTime) / 6L * 10L + (lesson.joinToString("|").hashCode() and 0xFFFF)
|
||||
|
||||
dataDays.remove(date.value)
|
||||
|
||||
@ -41,7 +40,7 @@ class MobidziennikApiTimetable(val data: DataMobidziennik, rows: List<String>) {
|
||||
val teamId = data.teamList.singleOrNull { it.name == lesson[8]+lesson[9] }?.id ?: -1
|
||||
val classroom = lesson[11]
|
||||
|
||||
Lesson(data.profileId, id).also {
|
||||
Lesson(data.profileId, -1).also {
|
||||
when (lesson[1]) {
|
||||
"plan_lekcji", "lekcja" -> {
|
||||
it.type = Lesson.TYPE_NORMAL
|
||||
@ -75,14 +74,18 @@ class MobidziennikApiTimetable(val data: DataMobidziennik, rows: List<String>) {
|
||||
}
|
||||
}
|
||||
|
||||
it.id = it.buildId()
|
||||
|
||||
val seen = profile.empty || date < Date.getToday()
|
||||
|
||||
if (it.type != Lesson.TYPE_NORMAL) {
|
||||
data.metadataList.add(
|
||||
Metadata(
|
||||
data.profileId,
|
||||
Metadata.TYPE_LESSON_CHANGE,
|
||||
it.id,
|
||||
data.profile?.empty ?: false,
|
||||
data.profile?.empty ?: false,
|
||||
seen,
|
||||
seen,
|
||||
System.currentTimeMillis()
|
||||
))
|
||||
}
|
||||
@ -194,5 +197,5 @@ class MobidziennikApiTimetable(val data: DataMobidziennik, rows: List<String>) {
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-11-28.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.web
|
||||
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.AttachmentGetEvent
|
||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.DataMobidziennik
|
||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.MobidziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
import java.io.File
|
||||
|
||||
class MobidziennikWebGetAttachment(
|
||||
override val data: DataMobidziennik, val message: Message, val attachmentId: Long,
|
||||
val attachmentName: String, val onSuccess: () -> Unit) : MobidziennikWeb(data) {
|
||||
companion object {
|
||||
private const val TAG = "MobidziennikWebGetAttachment"
|
||||
}
|
||||
|
||||
init {
|
||||
val targetFile = File(Utils.getStorageDir(), attachmentName)
|
||||
|
||||
val typeUrl = if (message.type == Message.TYPE_SENT)
|
||||
"wiadwyslana"
|
||||
else
|
||||
"wiadodebrana"
|
||||
|
||||
webGetFile(TAG, "/dziennik/$typeUrl/?id=${message.id}&zalacznik=$attachmentId", targetFile, { file ->
|
||||
|
||||
val event = AttachmentGetEvent(
|
||||
profileId,
|
||||
message.id,
|
||||
attachmentId,
|
||||
AttachmentGetEvent.TYPE_FINISHED,
|
||||
file.absolutePath
|
||||
)
|
||||
|
||||
val attachmentDataFile = File(Utils.getStorageDir(), ".${profileId}_${event.messageId}_${event.attachmentId}")
|
||||
Utils.writeStringToFile(attachmentDataFile, event.fileName)
|
||||
|
||||
EventBus.getDefault().post(event)
|
||||
|
||||
onSuccess()
|
||||
|
||||
}) { written, _ ->
|
||||
// TODO make use of bytesTotal
|
||||
val event = AttachmentGetEvent(
|
||||
profileId,
|
||||
message.id,
|
||||
attachmentId,
|
||||
AttachmentGetEvent.TYPE_PROGRESS,
|
||||
bytesWritten = written
|
||||
)
|
||||
|
||||
EventBus.getDefault().post(event)
|
||||
}
|
||||
}
|
||||
}
|
@ -124,7 +124,7 @@ class MobidziennikWebGetMessage(
|
||||
val attachmentName = it.ownText()
|
||||
Regexes.MOBIDZIENNIK_MESSAGE_ATTACHMENT.find(it.outerHtml())?.let { match ->
|
||||
val attachmentId = match[1].toLong()
|
||||
var size = match[2].toFloatOrNull() ?: 0f
|
||||
var size = match[2].toFloatOrNull() ?: -1f
|
||||
when (match[3]) {
|
||||
"K" -> size *= 1024f
|
||||
"M" -> size *= 1024f * 1024f
|
||||
|
@ -96,13 +96,17 @@ class MobidziennikWebGrades(override val data: DataMobidziennik,
|
||||
if (Regexes.MOBIDZIENNIK_GRADES_COUNT_TO_AVG.containsMatchIn(html)) {
|
||||
Regexes.MOBIDZIENNIK_GRADES_DETAILS.find(html)?.let { match ->
|
||||
val gradeName = match[1]
|
||||
val gradeDescription = match[2]
|
||||
var gradeDescription = match[2]
|
||||
val gradeValue = match[3].toFloatOrNull() ?: 0.0f
|
||||
val teacherName = match[4].fixWhiteSpaces()
|
||||
|
||||
val teacherId = data.teacherList.singleOrNull { it.fullNameLastFirst == teacherName }?.id ?: -1
|
||||
val subjectId = data.subjectList.singleOrNull { it.longName == subjectName }?.id ?: -1
|
||||
|
||||
if (match[5].isNotEmpty()) {
|
||||
gradeDescription += "\n"+match[5].replace("<br>", "\n")
|
||||
}
|
||||
|
||||
val gradeObject = Grade(
|
||||
profileId,
|
||||
gradeId,
|
||||
|
@ -91,7 +91,7 @@ class MobidziennikLoginWeb(val data: DataMobidziennik, val onSuccess: () -> Unit
|
||||
.addParameter("ip", data.app.deviceId)
|
||||
.addParameter("login", data.loginUsername)
|
||||
.addParameter("haslo", data.loginPassword)
|
||||
.addParameter("token", data.app.appConfig.fcmTokens[LOGIN_TYPE_MOBIDZIENNIK]?.first)
|
||||
.addParameter("token", data.app.config.sync.tokenMobidziennik)
|
||||
.post()
|
||||
.callback(callback)
|
||||
.build()
|
||||
|
@ -8,7 +8,6 @@ import android.content.Context
|
||||
import com.google.gson.JsonObject
|
||||
import im.wangchao.mhttp.Request
|
||||
import im.wangchao.mhttp.Response
|
||||
import pl.szczodrzynski.edziennik.data.api.AppError
|
||||
|
||||
class ApiError(val tag: String, val errorCode: Int) {
|
||||
var profileId: Int? = null
|
||||
@ -67,4 +66,4 @@ class ApiError(val tag: String, val errorCode: Int) {
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,8 @@
|
||||
package pl.szczodrzynski.edziennik.data.api;
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-11-26
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.models;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.AsyncTask;
|
@ -10,7 +10,7 @@ import pl.szczodrzynski.edziennik.api.v2.DataNotifications
|
||||
import pl.szczodrzynski.edziennik.api.v2.EXCEPTION_NOTIFY_AND_SYNC
|
||||
import pl.szczodrzynski.edziennik.api.v2.ServerSync
|
||||
import pl.szczodrzynski.edziennik.api.v2.interfaces.EndpointCallback
|
||||
import pl.szczodrzynski.edziennik.data.api.AppError.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.AppError.*
|
||||
import pl.szczodrzynski.edziennik.data.db.AppDb
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.announcements.Announcement
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.EndpointTimer
|
||||
@ -283,6 +283,7 @@ open class Data(val app: App, val profile: Profile?, val loginStore: LoginStore)
|
||||
when (model) {
|
||||
is DataRemoveModel.Timetable -> model.commit(profileId, db.timetableDao())
|
||||
is DataRemoveModel.Grades -> model.commit(profileId, db.gradeDao())
|
||||
is DataRemoveModel.Events -> model.commit(profileId, db.eventDao())
|
||||
}
|
||||
}
|
||||
|
||||
@ -305,7 +306,6 @@ open class Data(val app: App, val profile: Profile?, val loginStore: LoginStore)
|
||||
db.gradeDao().addAll(gradeList)
|
||||
}
|
||||
if (eventList.isNotEmpty()) {
|
||||
db.eventDao().removeFuture(profile.id, Date.getToday())
|
||||
db.eventDao().addAll(eventList)
|
||||
}
|
||||
if (noticeList.isNotEmpty()) {
|
||||
@ -375,7 +375,7 @@ open class Data(val app: App, val profile: Profile?, val loginStore: LoginStore)
|
||||
}
|
||||
|
||||
fun shouldSyncLuckyNumber(): Boolean {
|
||||
return (db.luckyNumberDao().getNearestFutureNow(profileId, Date.getToday()) ?: -1) == -1
|
||||
return (db.luckyNumberDao().getNearestFutureNow(profileId, Date.getToday().value) ?: -1) == -1
|
||||
}
|
||||
|
||||
fun error(tag: String, errorCode: Int, response: Response? = null, throwable: Throwable? = null, apiResponse: JsonObject? = null) {
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.models
|
||||
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.EventDao
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.GradeDao
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.timetable.TimetableDao
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
@ -15,21 +16,23 @@ open class DataRemoveModel {
|
||||
fun to(dateTo: Date) = Timetable(null, dateTo)
|
||||
fun between(dateFrom: Date, dateTo: Date) = Timetable(dateFrom, dateTo)
|
||||
}
|
||||
|
||||
fun commit(profileId: Int, dao: TimetableDao) {
|
||||
if (dateFrom != null && dateTo != null) {
|
||||
dao.clearBetweenDates(profileId, dateFrom, dateTo)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
dateFrom?.let { dateFrom -> dao.clearFromDate(profileId, dateFrom) }
|
||||
dateTo?.let { dateTo -> dao.clearToDate(profileId, dateTo) }
|
||||
}
|
||||
}
|
||||
}
|
||||
class Grades(val all: Boolean, val semester: Int?) : DataRemoveModel() {
|
||||
|
||||
class Grades(private val all: Boolean, private val semester: Int?) : DataRemoveModel() {
|
||||
companion object {
|
||||
fun all() = Grades(true, null)
|
||||
fun semester(semester: Int) = Grades(false, semester)
|
||||
}
|
||||
|
||||
fun commit(profileId: Int, dao: GradeDao) {
|
||||
if (all) {
|
||||
dao.clear(profileId)
|
||||
@ -37,4 +40,16 @@ open class DataRemoveModel {
|
||||
semester?.let { dao.clearForSemester(profileId, it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Events(private val type: Int?, private val exceptType: Int?) : DataRemoveModel() {
|
||||
companion object {
|
||||
fun futureExceptType(exceptType: Int) = Events(null, exceptType)
|
||||
fun futureWithType(type: Int) = Events(type, null)
|
||||
}
|
||||
|
||||
fun commit(profileId: Int, dao: EventDao) {
|
||||
type?.let { dao.removeFutureWithType(profileId, Date.getToday(), it) }
|
||||
exceptType?.let { dao.removeFutureExceptType(profileId, Date.getToday(), it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ import pl.szczodrzynski.edziennik.api.v2.template.firstlogin.TemplateFirstLogin
|
||||
import pl.szczodrzynski.edziennik.api.v2.template.login.TemplateLogin
|
||||
import pl.szczodrzynski.edziennik.api.v2.templateLoginMethods
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
@ -70,6 +71,10 @@ class Template(val app: App, val profile: Profile?, val loginStore: LoginStore,
|
||||
|
||||
}
|
||||
|
||||
override fun getAttachment(message: Message, attachmentId: Long, attachmentName: String) {
|
||||
|
||||
}
|
||||
|
||||
override fun firstLogin() {
|
||||
TemplateFirstLogin(data) {
|
||||
completed()
|
||||
|
@ -164,6 +164,8 @@ class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
||||
"GD1" -> "https://uonetplus-komunikacja.edu.gdansk.pl"
|
||||
"KA1" -> "https://uonetplus-komunikacja.mcuw.katowice.eu"
|
||||
"KA2" -> "https://uonetplus-komunikacja-test.mcuw.katowice.eu"
|
||||
"LU1" -> "https://uonetplus-komunikacja.edu.lublin.eu"
|
||||
"LU2" -> "https://test-uonetplus-komunikacja.edu.lublin.eu"
|
||||
"P03" -> "https://efeb-komunikacja-pro-efebmobile.pro.vulcan.pl"
|
||||
"P01" -> "http://efeb-komunikacja.pro-hudson.win.vulcan.pl"
|
||||
"P02" -> "http://efeb-komunikacja.pro-hudsonrc.win.vulcan.pl"
|
||||
@ -172,7 +174,7 @@ class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
||||
"SZ9" -> "http://vulcan.szkolny.eu"
|
||||
else -> null
|
||||
}
|
||||
return if (url != null) "$url/$symbol" else null
|
||||
return if (url != null) "$url/$symbol" else loginStore.getLoginData("apiUrl", null)
|
||||
}
|
||||
|
||||
val fullApiUrl: String?
|
||||
|
@ -18,6 +18,7 @@ import pl.szczodrzynski.edziennik.api.v2.vulcan.login.VulcanLogin
|
||||
import pl.szczodrzynski.edziennik.api.v2.vulcan.login.VulcanLoginApi
|
||||
import pl.szczodrzynski.edziennik.api.v2.vulcanLoginMethods
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
@ -76,6 +77,10 @@ class Vulcan(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
||||
|
||||
}
|
||||
|
||||
override fun getAttachment(message: Message, attachmentId: Long, attachmentName: String) {
|
||||
|
||||
}
|
||||
|
||||
override fun firstLogin() {
|
||||
VulcanFirstLogin(data) {
|
||||
completed()
|
||||
|
@ -6,6 +6,7 @@ package pl.szczodrzynski.edziennik.api.v2.vulcan.data.api
|
||||
|
||||
import pl.szczodrzynski.edziennik.api.v2.VULCAN_API_ENDPOINT_EVENTS
|
||||
import pl.szczodrzynski.edziennik.api.v2.VULCAN_API_ENDPOINT_HOMEWORK
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.api.v2.vulcan.DataVulcan
|
||||
import pl.szczodrzynski.edziennik.api.v2.vulcan.ENDPOINT_VULCAN_API_EVENTS
|
||||
import pl.szczodrzynski.edziennik.api.v2.vulcan.ENDPOINT_VULCAN_API_HOMEWORK
|
||||
@ -52,10 +53,11 @@ class VulcanApiEvents(override val data: DataVulcan, private val isHomework: Boo
|
||||
val eventDate = Date.fromY_m_d(event.getString("DataTekst") ?: return@forEach)
|
||||
val subjectId = event.getLong("IdPrzedmiot") ?: -1
|
||||
val teacherId = event.getLong("IdPracownik") ?: -1
|
||||
val startTime = data.lessonList.singleOrNull {
|
||||
it.weekDay == eventDate.weekDay && it.subjectId == subjectId
|
||||
}?.startTime
|
||||
val topic = event.getString("Opis") ?: ""
|
||||
|
||||
val lessonList = data.db.timetableDao().getForDateNow(profileId, eventDate)
|
||||
val startTime = lessonList.firstOrNull { it.subjectId == subjectId }?.startTime
|
||||
|
||||
val type = when (isHomework) {
|
||||
true -> Event.TYPE_HOMEWORK
|
||||
else -> when (event.getBoolean("Rodzaj")) {
|
||||
@ -91,8 +93,14 @@ class VulcanApiEvents(override val data: DataVulcan, private val isHomework: Boo
|
||||
}
|
||||
|
||||
when (isHomework) {
|
||||
true -> data.setSyncNext(ENDPOINT_VULCAN_API_HOMEWORK, SYNC_ALWAYS)
|
||||
false -> data.setSyncNext(ENDPOINT_VULCAN_API_EVENTS, SYNC_ALWAYS)
|
||||
true -> {
|
||||
data.toRemove.add(DataRemoveModel.Events.futureWithType(Event.TYPE_HOMEWORK))
|
||||
data.setSyncNext(ENDPOINT_VULCAN_API_HOMEWORK, SYNC_ALWAYS)
|
||||
}
|
||||
false -> {
|
||||
data.toRemove.add(DataRemoveModel.Events.futureExceptType(Event.TYPE_HOMEWORK))
|
||||
data.setSyncNext(ENDPOINT_VULCAN_API_EVENTS, SYNC_ALWAYS)
|
||||
}
|
||||
}
|
||||
onSuccess()
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import pl.szczodrzynski.edziennik.data.db.modules.timetable.Lesson
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.crc16
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Week
|
||||
|
||||
class VulcanApiTimetable(override val data: DataVulcan, val onSuccess: () -> Unit) : VulcanApi(data) {
|
||||
companion object {
|
||||
@ -27,7 +28,12 @@ class VulcanApiTimetable(override val data: DataVulcan, val onSuccess: () -> Uni
|
||||
}
|
||||
|
||||
init { data.profile?.also { profile ->
|
||||
val currentWeekStart = Date.getToday().let { it.stepForward(0, 0, -it.weekDay) }
|
||||
val currentWeekStart = Week.getWeekStart()
|
||||
|
||||
if (Date.getToday().weekDay > 4) {
|
||||
currentWeekStart.stepForward(0, 0, 7)
|
||||
}
|
||||
|
||||
val getDate = data.arguments?.getString("weekStart") ?: currentWeekStart.stringY_m_d
|
||||
|
||||
val weekStart = Date.fromY_m_d(getDate)
|
||||
@ -40,8 +46,8 @@ class VulcanApiTimetable(override val data: DataVulcan, val onSuccess: () -> Uni
|
||||
"IdOddzial" to data.studentClassId,
|
||||
"IdOkresKlasyfikacyjny" to data.studentSemesterId
|
||||
)) { json, _ ->
|
||||
val dates: MutableSet<Int> = mutableSetOf()
|
||||
val lessons: MutableList<Lesson> = mutableListOf()
|
||||
val dates = mutableSetOf<Int>()
|
||||
val lessons = mutableListOf<Lesson>()
|
||||
|
||||
json.getJsonArray("Data")?.asJsonObjectList()?.forEach { lesson ->
|
||||
if (lesson.getBoolean("PlanUcznia") != true)
|
||||
@ -108,9 +114,7 @@ class VulcanApiTimetable(override val data: DataVulcan, val onSuccess: () -> Uni
|
||||
}
|
||||
}
|
||||
|
||||
val id = lessonDate.combineWith(startTime) / 6L * 10L + (lesson.hashCode() and 0xFFFF)
|
||||
|
||||
val lessonObject = Lesson(profileId, id).apply {
|
||||
val lessonObject = Lesson(profileId, -1).apply {
|
||||
this.type = type
|
||||
|
||||
when (type) {
|
||||
@ -164,15 +168,19 @@ class VulcanApiTimetable(override val data: DataVulcan, val onSuccess: () -> Uni
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.id = buildId()
|
||||
}
|
||||
|
||||
val seen = profile.empty || lessonDate < Date.getToday()
|
||||
|
||||
if (type != Lesson.TYPE_NORMAL) {
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_LESSON_CHANGE,
|
||||
id,
|
||||
profile.empty,
|
||||
profile.empty,
|
||||
lessonObject.id,
|
||||
seen,
|
||||
seen,
|
||||
System.currentTimeMillis()
|
||||
))
|
||||
}
|
||||
|
@ -38,10 +38,12 @@ class VulcanLoginApi(val data: DataVulcan, val onSuccess: () -> Unit) {
|
||||
if (data.apiToken?.get(0) == 'F') VULCAN_API_PASSWORD_FAKELOG else VULCAN_API_PASSWORD,
|
||||
data.apiCertificatePfx ?: ""
|
||||
)
|
||||
onSuccess()
|
||||
return@run
|
||||
data.loginStore.removeLoginData("certificatePfx")
|
||||
} catch (e: Throwable) {
|
||||
e.printStackTrace()
|
||||
} finally {
|
||||
onSuccess()
|
||||
return@run
|
||||
}
|
||||
}
|
||||
if (data.symbol.isNotNullNorEmpty() && data.apiToken.isNotNullNorEmpty() && data.apiPin.isNotNullNorEmpty()) {
|
||||
|
@ -0,0 +1,9 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-11-27.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.config
|
||||
|
||||
interface AbstractConfig {
|
||||
fun set(key: String, value: String?)
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-11-26.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.config
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.BuildConfig
|
||||
import pl.szczodrzynski.edziennik.config.db.ConfigEntry
|
||||
import pl.szczodrzynski.edziennik.config.utils.ConfigMigration
|
||||
import pl.szczodrzynski.edziennik.config.utils.get
|
||||
import pl.szczodrzynski.edziennik.config.utils.set
|
||||
import pl.szczodrzynski.edziennik.config.utils.toHashMap
|
||||
import pl.szczodrzynski.edziennik.data.db.AppDb
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class Config(val db: AppDb) : CoroutineScope, AbstractConfig {
|
||||
companion object {
|
||||
const val DATA_VERSION = 2
|
||||
}
|
||||
|
||||
private val job = Job()
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Default
|
||||
|
||||
val values: HashMap<String, String?> = hashMapOf()
|
||||
|
||||
val ui by lazy { ConfigUI(this) }
|
||||
val sync by lazy { ConfigSync(this) }
|
||||
val timetable by lazy { ConfigTimetable(this) }
|
||||
val grades by lazy { ConfigGrades(this) }
|
||||
|
||||
private var mDataVersion: Int? = null
|
||||
var dataVersion: Int
|
||||
get() { mDataVersion = mDataVersion ?: values.get("dataVersion", 0); return mDataVersion ?: 0 }
|
||||
set(value) { set("dataVersion", value); mDataVersion = value }
|
||||
|
||||
private var mAppVersion: Int? = null
|
||||
var appVersion: Int
|
||||
get() { mAppVersion = mAppVersion ?: values.get("appVersion", BuildConfig.VERSION_CODE); return mAppVersion ?: BuildConfig.VERSION_CODE }
|
||||
set(value) { set("appVersion", value); mAppVersion = value }
|
||||
|
||||
private var mLoginFinished: Boolean? = null
|
||||
var loginFinished: Boolean
|
||||
get() { mLoginFinished = mLoginFinished ?: values.get("loginFinished", false); return mLoginFinished ?: false }
|
||||
set(value) { set("loginFinished", value); mLoginFinished = value }
|
||||
|
||||
private var mDevModePassword: String? = null
|
||||
var devModePassword: String?
|
||||
get() { mDevModePassword = mDevModePassword ?: values.get("devModePassword", null as String?); return mDevModePassword }
|
||||
set(value) { set("devModePassword", value); mDevModePassword = value }
|
||||
|
||||
private var mAppInstalledTime: Long? = null
|
||||
var appInstalledTime: Long
|
||||
get() { mAppInstalledTime = mAppInstalledTime ?: values.get("appInstalledTime", 0L); return mAppInstalledTime ?: 0L }
|
||||
set(value) { set("appInstalledTime", value); mAppInstalledTime = value }
|
||||
|
||||
private var mAppRateSnackbarTime: Long? = null
|
||||
var appRateSnackbarTime: Long
|
||||
get() { mAppRateSnackbarTime = mAppRateSnackbarTime ?: values.get("appRateSnackbarTime", 0L); return mAppRateSnackbarTime ?: 0L }
|
||||
set(value) { set("appRateSnackbarTime", value); mAppRateSnackbarTime = value }
|
||||
|
||||
private var rawEntries: List<ConfigEntry> = db.configDao().getAllNow()
|
||||
private val profileConfigs: HashMap<Int, ProfileConfig> = hashMapOf()
|
||||
init {
|
||||
rawEntries.toHashMap(-1, values)
|
||||
}
|
||||
fun migrate(app: App) {
|
||||
if (dataVersion < DATA_VERSION)
|
||||
ConfigMigration(app, this)
|
||||
}
|
||||
fun getFor(profileId: Int): ProfileConfig {
|
||||
return profileConfigs[profileId] ?: ProfileConfig(db, profileId, rawEntries)
|
||||
}
|
||||
|
||||
fun setProfile(profileId: Int) {
|
||||
}
|
||||
|
||||
override fun set(key: String, value: String?) {
|
||||
values[key] = value
|
||||
launch {
|
||||
db.configDao().add(ConfigEntry(-1, key, value))
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-11-26.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.config
|
||||
|
||||
import pl.szczodrzynski.edziennik.config.utils.get
|
||||
import pl.szczodrzynski.edziennik.config.utils.set
|
||||
|
||||
class ConfigGrades(private val config: Config) {
|
||||
companion object {
|
||||
const val ORDER_BY_DATE_DESC = 0
|
||||
const val ORDER_BY_SUBJECT_ASC = 1
|
||||
const val ORDER_BY_DATE_ASC = 2
|
||||
const val ORDER_BY_SUBJECT_DESC = 3
|
||||
}
|
||||
|
||||
private var mOrderBy: Int? = null
|
||||
var orderBy: Int
|
||||
get() { mOrderBy = mOrderBy ?: config.values.get("gradesOrderBy", 0); return mOrderBy ?: 0 }
|
||||
set(value) { config.set("gradesOrderBy", value); mOrderBy = value }
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-11-26.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.config
|
||||
|
||||
import pl.szczodrzynski.edziennik.config.utils.get
|
||||
import pl.szczodrzynski.edziennik.config.utils.getIntList
|
||||
import pl.szczodrzynski.edziennik.config.utils.set
|
||||
|
||||
class ConfigSync(private val config: Config) {
|
||||
private var mSyncEnabled: Boolean? = null
|
||||
var enabled: Boolean
|
||||
get() { mSyncEnabled = mSyncEnabled ?: config.values.get("syncEnabled", true); return mSyncEnabled ?: true }
|
||||
set(value) { config.set("syncEnabled", value); mSyncEnabled = value }
|
||||
|
||||
private var mSyncOnlyWifi: Boolean? = null
|
||||
var onlyWifi: Boolean
|
||||
get() { mSyncOnlyWifi = mSyncOnlyWifi ?: config.values.get("syncOnlyWifi", false); return mSyncOnlyWifi ?: notifyAboutUpdates }
|
||||
set(value) { config.set("syncOnlyWifi", value); mSyncOnlyWifi = value }
|
||||
|
||||
private var mSyncInterval: Int? = null
|
||||
var interval: Int
|
||||
get() { mSyncInterval = mSyncInterval ?: config.values.get("syncInterval", 60*60); return mSyncInterval ?: 60*60 }
|
||||
set(value) { config.set("syncInterval", value); mSyncInterval = value }
|
||||
|
||||
private var mNotifyAboutUpdates: Boolean? = null
|
||||
var notifyAboutUpdates: Boolean
|
||||
get() { mNotifyAboutUpdates = mNotifyAboutUpdates ?: config.values.get("notifyAboutUpdates", true); return mNotifyAboutUpdates ?: true }
|
||||
set(value) { config.set("notifyAboutUpdates", value); mNotifyAboutUpdates = value }
|
||||
|
||||
/* ____ _ _ _
|
||||
/ __ \ (_) | | | |
|
||||
| | | |_ _ _ ___| |_ | |__ ___ _ _ _ __ ___
|
||||
| | | | | | | |/ _ \ __| | '_ \ / _ \| | | | '__/ __|
|
||||
| |__| | |_| | | __/ |_ | | | | (_) | |_| | | \__ \
|
||||
\___\_\\__,_|_|\___|\__| |_| |_|\___/ \__,_|_| |__*/
|
||||
private var mQuietHoursStart: Long? = null
|
||||
var quietHoursStart: Long
|
||||
get() { mQuietHoursStart = mQuietHoursStart ?: config.values.get("quietHoursStart", 0L); return mQuietHoursStart ?: 0L }
|
||||
set(value) { config.set("quietHoursStart", value); mQuietHoursStart = value }
|
||||
|
||||
private var mQuietHoursEnd: Long? = null
|
||||
var quietHoursEnd: Long
|
||||
get() { mQuietHoursEnd = mQuietHoursEnd ?: config.values.get("quietHoursEnd", 0L); return mQuietHoursEnd ?: 0L }
|
||||
set(value) { config.set("quietHoursEnd", value); mQuietHoursEnd = value }
|
||||
|
||||
private var mQuietDuringLessons: Boolean? = null
|
||||
var quietDuringLessons: Boolean
|
||||
get() { mQuietDuringLessons = mQuietDuringLessons ?: config.values.get("quietDuringLessons", false); return mQuietDuringLessons ?: false }
|
||||
set(value) { config.set("quietDuringLessons", value); mQuietDuringLessons = value }
|
||||
|
||||
/* ______ _____ __ __ _______ _
|
||||
| ____/ ____| \/ | |__ __| | |
|
||||
| |__ | | | \ / | | | ___ | | _____ _ __ ___
|
||||
| __|| | | |\/| | | |/ _ \| |/ / _ \ '_ \/ __|
|
||||
| | | |____| | | | | | (_) | < __/ | | \__ \
|
||||
|_| \_____|_| |_| |_|\___/|_|\_\___|_| |_|__*/
|
||||
private var mTokenApp: String? = null
|
||||
var tokenApp: String?
|
||||
get() { mTokenApp = mTokenApp ?: config.values.get("tokenApp", null as String?); return mTokenApp }
|
||||
set(value) { config.set("tokenApp", value); mTokenApp = value }
|
||||
private var mTokenMobidziennik: String? = null
|
||||
var tokenMobidziennik: String?
|
||||
get() { mTokenMobidziennik = mTokenMobidziennik ?: config.values.get("tokenMobidziennik", null as String?); return mTokenMobidziennik }
|
||||
set(value) { config.set("tokenMobidziennik", value); mTokenMobidziennik = value }
|
||||
private var mTokenLibrus: String? = null
|
||||
var tokenLibrus: String?
|
||||
get() { mTokenLibrus = mTokenLibrus ?: config.values.get("tokenLibrus", null as String?); return mTokenLibrus }
|
||||
set(value) { config.set("tokenLibrus", value); mTokenLibrus = value }
|
||||
private var mTokenVulcan: String? = null
|
||||
var tokenVulcan: String?
|
||||
get() { mTokenVulcan = mTokenVulcan ?: config.values.get("tokenVulcan", null as String?); return mTokenVulcan }
|
||||
set(value) { config.set("tokenVulcan", value); mTokenVulcan = value }
|
||||
|
||||
private var mTokenMobidziennikList: List<Int>? = null
|
||||
var tokenMobidziennikList: List<Int>
|
||||
get() { mTokenMobidziennikList = mTokenMobidziennikList ?: config.values.getIntList("tokenMobidziennikList", listOf()); return mTokenMobidziennikList ?: listOf() }
|
||||
set(value) { config.set("tokenMobidziennikList", value); mTokenMobidziennikList = value }
|
||||
private var mTokenLibrusList: List<Int>? = null
|
||||
var tokenLibrusList: List<Int>
|
||||
get() { mTokenLibrusList = mTokenLibrusList ?: config.values.getIntList("tokenLibrusList", listOf()); return mTokenLibrusList ?: listOf() }
|
||||
set(value) { config.set("tokenLibrusList", value); mTokenLibrusList = value }
|
||||
private var mTokenVulcanList: List<Int>? = null
|
||||
var tokenVulcanList: List<Int>
|
||||
get() { mTokenVulcanList = mTokenVulcanList ?: config.values.getIntList("tokenVulcanList", listOf()); return mTokenVulcanList ?: listOf() }
|
||||
set(value) { config.set("tokenVulcanList", value); mTokenVulcanList = value }
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-11-26.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.config
|
||||
|
||||
import pl.szczodrzynski.edziennik.config.utils.get
|
||||
import pl.szczodrzynski.edziennik.config.utils.set
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
|
||||
class ConfigTimetable(private val config: Config) {
|
||||
private var mBellSyncMultiplier: Int? = null
|
||||
var bellSyncMultiplier: Int
|
||||
get() { mBellSyncMultiplier = mBellSyncMultiplier ?: config.values.get("bellSyncMultiplier", 0); return mBellSyncMultiplier ?: 0 }
|
||||
set(value) { config.set("bellSyncMultiplier", value); mBellSyncMultiplier = value }
|
||||
|
||||
private var mBellSyncDiff: Time? = null
|
||||
var bellSyncDiff: Time?
|
||||
get() { mBellSyncDiff = mBellSyncDiff ?: config.values.get("bellSyncDiff", null as Time?); return mBellSyncDiff }
|
||||
set(value) { config.set("bellSyncDiff", value); mBellSyncDiff = value }
|
||||
|
||||
private var mCountInSeconds: Boolean? = null
|
||||
var countInSeconds: Boolean
|
||||
get() { mCountInSeconds = mCountInSeconds ?: config.values.get("countInSeconds", false); return mCountInSeconds ?: false }
|
||||
set(value) { config.set("countInSeconds", value); mCountInSeconds = value }
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-11-26.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.config
|
||||
|
||||
import pl.szczodrzynski.edziennik.config.utils.get
|
||||
import pl.szczodrzynski.edziennik.config.utils.getIntList
|
||||
import pl.szczodrzynski.edziennik.config.utils.set
|
||||
import pl.szczodrzynski.edziennik.ui.modules.home.HomeCardModel
|
||||
|
||||
class ConfigUI(private val config: Config) {
|
||||
private var mTheme: Int? = null
|
||||
var theme: Int
|
||||
get() { mTheme = mTheme ?: config.values.get("theme", 1); return mTheme ?: 1 }
|
||||
set(value) { config.set("theme", value); mTheme = value }
|
||||
|
||||
private var mLanguage: String? = null
|
||||
var language: String?
|
||||
get() { mLanguage = mLanguage ?: config.values.get("language", null as String?); return mLanguage }
|
||||
set(value) { config.set("language", value); mLanguage = value }
|
||||
|
||||
private var mHeaderBackground: String? = null
|
||||
var headerBackground: String?
|
||||
get() { mHeaderBackground = mHeaderBackground ?: config.values.get("headerBackground", null as String?); return mHeaderBackground }
|
||||
set(value) { config.set("headerBg", value); mHeaderBackground = value }
|
||||
|
||||
private var mAppBackground: String? = null
|
||||
var appBackground: String?
|
||||
get() { mAppBackground = mAppBackground ?: config.values.get("appBackground", null as String?); return mAppBackground }
|
||||
set(value) { config.set("appBg", value); mAppBackground = value }
|
||||
|
||||
private var mMiniMenuVisible: Boolean? = null
|
||||
var miniMenuVisible: Boolean
|
||||
get() { mMiniMenuVisible = mMiniMenuVisible ?: config.values.get("miniMenuVisible", false); return mMiniMenuVisible ?: false }
|
||||
set(value) { config.set("miniMenuVisible", value); mMiniMenuVisible = value }
|
||||
|
||||
private var mMiniMenuButtons: List<Int>? = null
|
||||
var miniMenuButtons: List<Int>
|
||||
get() { mMiniMenuButtons = mMiniMenuButtons ?: config.values.getIntList("miniMenuButtons", listOf()); return mMiniMenuButtons ?: listOf() }
|
||||
set(value) { config.set("miniMenuButtons", value); mMiniMenuButtons = value }
|
||||
|
||||
private var mAgendaViewType: Int? = null
|
||||
var agendaViewType: Int
|
||||
get() { mAgendaViewType = mAgendaViewType ?: config.values.get("agendaViewType", 0); return mAgendaViewType ?: 0 }
|
||||
set(value) { config.set("agendaViewType", value); mAgendaViewType = value }
|
||||
|
||||
private var mHomeCards: List<HomeCardModel>? = null
|
||||
var homeCards: List<HomeCardModel>
|
||||
get() { mHomeCards = mHomeCards ?: config.values.get("homeCards", listOf(), HomeCardModel::class.java); return mHomeCards ?: listOf() }
|
||||
set(value) { config.set("homeCards", value); mHomeCards = value }
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-11-27.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.config
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import pl.szczodrzynski.edziennik.config.db.ConfigEntry
|
||||
import pl.szczodrzynski.edziennik.config.utils.get
|
||||
import pl.szczodrzynski.edziennik.config.utils.set
|
||||
import pl.szczodrzynski.edziennik.config.utils.toHashMap
|
||||
import pl.szczodrzynski.edziennik.data.db.AppDb
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class ProfileConfig(val db: AppDb, val profileId: Int, rawEntries: List<ConfigEntry>) : CoroutineScope, AbstractConfig {
|
||||
companion object {
|
||||
const val DATA_VERSION = 1
|
||||
}
|
||||
|
||||
private val job = Job()
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Default
|
||||
|
||||
val values: HashMap<String, String?> = hashMapOf()
|
||||
|
||||
val grades by lazy { ProfileConfigGrades(this) }
|
||||
/*
|
||||
val sync by lazy { ConfigSync(this) }
|
||||
val timetable by lazy { ConfigTimetable(this) }
|
||||
val grades by lazy { ConfigGrades(this) }*/
|
||||
|
||||
private var mDataVersion: Int? = null
|
||||
var dataVersion: Int
|
||||
get() { mDataVersion = mDataVersion ?: values.get("dataVersion", 0); return mDataVersion ?: 0 }
|
||||
set(value) { set("dataVersion", value); mDataVersion = value }
|
||||
|
||||
init {
|
||||
rawEntries.toHashMap(profileId, values)
|
||||
/*if (dataVersion < DATA_VERSION)
|
||||
ProfileConfigMigration(this)*/
|
||||
}
|
||||
|
||||
override fun set(key: String, value: String?) {
|
||||
values[key] = value
|
||||
launch {
|
||||
db.configDao().add(ConfigEntry(profileId, key, value))
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-11-27.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.config
|
||||
|
||||
import pl.szczodrzynski.edziennik.config.utils.get
|
||||
import pl.szczodrzynski.edziennik.config.utils.set
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile.Companion.COLOR_MODE_WEIGHTED
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile.Companion.YEAR_ALL_GRADES
|
||||
|
||||
class ProfileConfigGrades(private val config: ProfileConfig) {
|
||||
private var mColorMode: Int? = null
|
||||
var colorMode: Int
|
||||
get() { mColorMode = mColorMode ?: config.values.get("gradesColorMode", COLOR_MODE_WEIGHTED); return mColorMode ?: COLOR_MODE_WEIGHTED }
|
||||
set(value) { config.set("gradesColorMode", value); mColorMode = value }
|
||||
|
||||
private var mYearAverageMode: Int? = null
|
||||
var yearAverageMode: Int
|
||||
get() { mYearAverageMode = mYearAverageMode ?: config.values.get("yearAverageMode", YEAR_ALL_GRADES); return mYearAverageMode ?: YEAR_ALL_GRADES }
|
||||
set(value) { config.set("yearAverageMode", value); mYearAverageMode = value }
|
||||
|
||||
private var mCountZeroToAvg: Boolean? = null
|
||||
var countZeroToAvg: Boolean
|
||||
get() { mCountZeroToAvg = mCountZeroToAvg ?: config.values.get("countZeroToAvg", true); return mCountZeroToAvg ?: true }
|
||||
set(value) { config.set("countZeroToAvg", value); mCountZeroToAvg = value }
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-11-27.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.config.db
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
|
||||
@Dao
|
||||
interface ConfigDao {
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
fun add(entry: ConfigEntry)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
fun addAll(list: List<ConfigEntry>)
|
||||
|
||||
@Query("SELECT * FROM config WHERE profileId = -1")
|
||||
fun getAllNow(): List<ConfigEntry>
|
||||
|
||||
@Query("SELECT * FROM config WHERE profileId = :profileId")
|
||||
fun getAllNow(profileId: Int): List<ConfigEntry>
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-11-26.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.config.db
|
||||
|
||||
import androidx.room.Entity
|
||||
|
||||
@Entity(tableName = "config", primaryKeys = ["profileId", "key"])
|
||||
data class ConfigEntry(
|
||||
val profileId: Int = -1,
|
||||
val key: String,
|
||||
val value: String?
|
||||
)
|
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-11-27.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.config.utils
|
||||
|
||||
import com.google.gson.*
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import pl.szczodrzynski.edziennik.config.AbstractConfig
|
||||
import pl.szczodrzynski.edziennik.config.db.ConfigEntry
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
|
||||
private val gson = Gson()
|
||||
|
||||
fun AbstractConfig.set(key: String, value: Int) {
|
||||
set(key, value.toString())
|
||||
}
|
||||
fun AbstractConfig.set(key: String, value: Boolean) {
|
||||
set(key, value.toString())
|
||||
}
|
||||
fun AbstractConfig.set(key: String, value: Long) {
|
||||
set(key, value.toString())
|
||||
}
|
||||
fun AbstractConfig.set(key: String, value: Float) {
|
||||
set(key, value.toString())
|
||||
}
|
||||
fun AbstractConfig.set(key: String, value: Date?) {
|
||||
set(key, value?.stringY_m_d)
|
||||
}
|
||||
fun AbstractConfig.set(key: String, value: Time?) {
|
||||
set(key, value?.stringValue)
|
||||
}
|
||||
fun AbstractConfig.set(key: String, value: JsonElement?) {
|
||||
set(key, value?.toString())
|
||||
}
|
||||
fun AbstractConfig.set(key: String, value: List<Any>?) {
|
||||
set(key, value?.let { gson.toJson(it) })
|
||||
}
|
||||
fun AbstractConfig.setStringList(key: String, value: List<String>?) {
|
||||
set(key, value?.let { gson.toJson(it) })
|
||||
}
|
||||
fun AbstractConfig.setIntList(key: String, value: List<Int>?) {
|
||||
set(key, value?.let { gson.toJson(it) })
|
||||
}
|
||||
fun AbstractConfig.setLongList(key: String, value: List<Long>?) {
|
||||
set(key, value?.let { gson.toJson(it) })
|
||||
}
|
||||
|
||||
fun HashMap<String, String?>.get(key: String, default: String?): String? {
|
||||
return this[key] ?: default
|
||||
}
|
||||
fun HashMap<String, String?>.get(key: String, default: Boolean): Boolean {
|
||||
return this[key]?.toBoolean() ?: default
|
||||
}
|
||||
fun HashMap<String, String?>.get(key: String, default: Int): Int {
|
||||
return this[key]?.toIntOrNull() ?: default
|
||||
}
|
||||
fun HashMap<String, String?>.get(key: String, default: Long): Long {
|
||||
return this[key]?.toLongOrNull() ?: default
|
||||
}
|
||||
fun HashMap<String, String?>.get(key: String, default: Float): Float {
|
||||
return this[key]?.toFloatOrNull() ?: default
|
||||
}
|
||||
fun HashMap<String, String?>.get(key: String, default: Date?): Date? {
|
||||
return this[key]?.let { Date.fromY_m_d(it) } ?: default
|
||||
}
|
||||
fun HashMap<String, String?>.get(key: String, default: Time?): Time? {
|
||||
return this[key]?.let { Time.fromHms(it) } ?: default
|
||||
}
|
||||
fun HashMap<String, String?>.get(key: String, default: JsonObject?): JsonObject? {
|
||||
return this[key]?.let { JsonParser().parse(it)?.asJsonObject } ?: default
|
||||
}
|
||||
fun HashMap<String, String?>.get(key: String, default: JsonArray?): JsonArray? {
|
||||
return this[key]?.let { JsonParser().parse(it)?.asJsonArray } ?: default
|
||||
}
|
||||
/* !!! cannot use mutable list here - modifying it will not update the DB */
|
||||
fun <T> HashMap<String, String?>.get(key: String, default: List<T>?, classOfT: Class<T>): List<T>? {
|
||||
return this[key]?.let { ConfigGsonUtils().deserializeList<T>(gson, it, classOfT) } ?: default
|
||||
}
|
||||
fun HashMap<String, String?>.getStringList(key: String, default: List<String>?): List<String>? {
|
||||
return this[key]?.let { gson.fromJson<List<String>>(it, object: TypeToken<List<String>>(){}.type) } ?: default
|
||||
}
|
||||
fun HashMap<String, String?>.getIntList(key: String, default: List<Int>?): List<Int>? {
|
||||
return this[key]?.let { gson.fromJson<List<Int>>(it, object: TypeToken<List<Int>>(){}.type) } ?: default
|
||||
}
|
||||
fun HashMap<String, String?>.getLongList(key: String, default: List<Long>?): List<Long>? {
|
||||
return this[key]?.let { gson.fromJson<List<Long>>(it, object: TypeToken<List<Long>>(){}.type) } ?: default
|
||||
}
|
||||
|
||||
fun List<ConfigEntry>.toHashMap(profileId: Int, map: HashMap<String, String?>) {
|
||||
map.clear()
|
||||
forEach {
|
||||
if (it.profileId == profileId)
|
||||
map[it.key] = it.value
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-12-2.
|
||||
*/
|
||||
package pl.szczodrzynski.edziennik.config.utils
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonParser
|
||||
import pl.szczodrzynski.edziennik.getInt
|
||||
import pl.szczodrzynski.edziennik.ui.modules.home.HomeCardModel
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
|
||||
class ConfigGsonUtils {
|
||||
fun <T> deserializeList(gson: Gson, str: String?, classOfT: Class<T>): List<T> {
|
||||
val json = JsonParser().parse(str)
|
||||
val list: MutableList<T> = mutableListOf()
|
||||
if (!json.isJsonArray)
|
||||
return list
|
||||
|
||||
json.asJsonArray.forEach { e ->
|
||||
when (classOfT) {
|
||||
String::class.java -> {
|
||||
list += e.asString as T
|
||||
}
|
||||
HomeCardModel::class.java -> {
|
||||
val o = e.asJsonObject
|
||||
list += HomeCardModel(
|
||||
o.getInt("profileId", 0),
|
||||
o.getInt("cardId", 0)
|
||||
) as T
|
||||
}
|
||||
Time::class.java -> {
|
||||
val o = e.asJsonObject
|
||||
list += Time(
|
||||
o.getInt("hour", 0),
|
||||
o.getInt("minute", 0),
|
||||
o.getInt("second", 0)
|
||||
) as T
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-11-27.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.config.utils
|
||||
|
||||
import android.content.Context
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.BuildConfig
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.api.v2.LOGIN_TYPE_LIBRUS
|
||||
import pl.szczodrzynski.edziennik.api.v2.LOGIN_TYPE_MOBIDZIENNIK
|
||||
import pl.szczodrzynski.edziennik.api.v2.LOGIN_TYPE_VULCAN
|
||||
import pl.szczodrzynski.edziennik.config.Config
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
|
||||
class ConfigMigration(app: App, config: Config) {
|
||||
init { config.apply {
|
||||
val p = app.getSharedPreferences("pl.szczodrzynski.edziennik_profiles", Context.MODE_PRIVATE)
|
||||
val s = "app.appConfig"
|
||||
|
||||
if (dataVersion < 1) {
|
||||
ui.theme = p.getString("$s.appTheme", null)?.toIntOrNull() ?: 1
|
||||
sync.enabled = p.getString("$s.registerSyncEnabled", null)?.toBoolean() ?: true
|
||||
sync.interval = p.getString("$s.registerSyncEnabled", null)?.toIntOrNull() ?: 3600
|
||||
val oldButtons = p.getString("$s.miniDrawerButtonIds", null)?.let { str ->
|
||||
str.replace("[\\[\\]]*".toRegex(), "")
|
||||
.split(",\\s?".toRegex())
|
||||
.mapNotNull { it.toIntOrNull() }
|
||||
}
|
||||
ui.miniMenuButtons = oldButtons ?: listOf(
|
||||
MainActivity.DRAWER_ITEM_HOME,
|
||||
MainActivity.DRAWER_ITEM_TIMETABLE,
|
||||
MainActivity.DRAWER_ITEM_AGENDA,
|
||||
MainActivity.DRAWER_ITEM_GRADES,
|
||||
MainActivity.DRAWER_ITEM_MESSAGES,
|
||||
MainActivity.DRAWER_ITEM_HOMEWORK,
|
||||
MainActivity.DRAWER_ITEM_SETTINGS
|
||||
)
|
||||
dataVersion = 1
|
||||
}
|
||||
if (dataVersion < 2) {
|
||||
devModePassword = p.getString("$s.devModePassword", null).fix()
|
||||
sync.tokenApp = p.getString("$s.fcmToken", null).fix()
|
||||
timetable.bellSyncMultiplier = p.getString("$s.bellSyncMultiplier", null)?.toIntOrNull() ?: 0
|
||||
sync.quietHoursStart = p.getString("$s.quietHoursStart", null)?.toLongOrNull() ?: 0
|
||||
appRateSnackbarTime = p.getString("$s.appRateSnackbarTime", null)?.toLongOrNull() ?: 0
|
||||
sync.quietHoursEnd = p.getString("$s.quietHoursEnd", null)?.toLongOrNull() ?: 0
|
||||
timetable.countInSeconds = p.getString("$s.countInSeconds", null)?.toBoolean() ?: false
|
||||
ui.headerBackground = p.getString("$s.headerBackground", null).fix()
|
||||
ui.appBackground = p.getString("$s.appBackground", null).fix()
|
||||
ui.language = p.getString("$s.language", null).fix()
|
||||
appVersion = p.getString("$s.lastAppVersion", null)?.toIntOrNull() ?: BuildConfig.VERSION_CODE
|
||||
appInstalledTime = p.getString("$s.appInstalledTime", null)?.toLongOrNull() ?: 0
|
||||
grades.orderBy = p.getString("$s.gradesOrderBy", null)?.toIntOrNull() ?: 0
|
||||
sync.quietDuringLessons = p.getString("$s.quietDuringLessons", null)?.toBoolean() ?: false
|
||||
ui.miniMenuVisible = p.getString("$s.miniDrawerVisible", null)?.toBoolean() ?: false
|
||||
loginFinished = p.getString("$s.loginFinished", null)?.toBoolean() ?: false
|
||||
sync.onlyWifi = p.getString("$s.registerSyncOnlyWifi", null)?.toBoolean() ?: false
|
||||
sync.notifyAboutUpdates = p.getString("$s.notifyAboutUpdates", null)?.toBoolean() ?: true
|
||||
timetable.bellSyncDiff = p.getString("$s.bellSyncDiff", null)?.let { Gson().fromJson(it, Time::class.java) }
|
||||
|
||||
sync.tokenMobidziennikList = listOf()
|
||||
sync.tokenVulcanList = listOf()
|
||||
sync.tokenLibrusList = listOf()
|
||||
val tokens = p.getString("$s.fcmTokens", null)?.let { Gson().fromJson<Map<Int, Pair<String, List<Int>>>>(it, object: TypeToken<Map<Int, Pair<String, List<Int>>>>(){}.type) }
|
||||
tokens?.forEach {
|
||||
val token = it.value.first
|
||||
when (it.key) {
|
||||
LOGIN_TYPE_MOBIDZIENNIK -> sync.tokenMobidziennik = token
|
||||
LOGIN_TYPE_VULCAN -> sync.tokenVulcan = token
|
||||
LOGIN_TYPE_LIBRUS -> sync.tokenLibrus = token
|
||||
}
|
||||
}
|
||||
dataVersion = 2
|
||||
}
|
||||
}}
|
||||
|
||||
private fun String?.fix(): String? {
|
||||
return this?.replace("\"", "")?.let { if (it == "null") null else it }
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-12-1.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.config.utils
|
||||
|
||||
import android.content.Context
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.config.Config
|
||||
|
||||
class ProfileConfigMigration(app: App, config: Config) {
|
||||
init { config.apply {
|
||||
val p = app.getSharedPreferences("pl.szczodrzynski.edziennik_profiles", Context.MODE_PRIVATE)
|
||||
val s = "app.appConfig"
|
||||
|
||||
if (dataVersion < 1) {
|
||||
|
||||
//dataVersion = 1
|
||||
}
|
||||
if (dataVersion < 2) {
|
||||
//gradesColorMode do profilu !
|
||||
//agendaViewType do profilu !
|
||||
// app.appConfig.dontCountZeroToAverage do profilu !
|
||||
}
|
||||
}}
|
||||
}
|
@ -10,6 +10,8 @@ import androidx.room.TypeConverters;
|
||||
import androidx.room.migration.Migration;
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase;
|
||||
|
||||
import pl.szczodrzynski.edziennik.config.db.ConfigDao;
|
||||
import pl.szczodrzynski.edziennik.config.db.ConfigEntry;
|
||||
import pl.szczodrzynski.edziennik.data.db.converters.ConverterDate;
|
||||
import pl.szczodrzynski.edziennik.data.db.converters.ConverterDateInt;
|
||||
import pl.szczodrzynski.edziennik.data.db.converters.ConverterJsonObject;
|
||||
@ -105,7 +107,8 @@ import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||
NoticeType.class,
|
||||
AttendanceType.class,
|
||||
pl.szczodrzynski.edziennik.data.db.modules.timetable.Lesson.class,
|
||||
Metadata.class}, version = 64)
|
||||
ConfigEntry.class,
|
||||
Metadata.class}, version = 66)
|
||||
@TypeConverters({
|
||||
ConverterTime.class,
|
||||
ConverterDate.class,
|
||||
@ -144,6 +147,7 @@ public abstract class AppDb extends RoomDatabase {
|
||||
public abstract NoticeTypeDao noticeTypeDao();
|
||||
public abstract AttendanceTypeDao attendanceTypeDao();
|
||||
public abstract TimetableDao timetableDao();
|
||||
public abstract ConfigDao configDao();
|
||||
public abstract MetadataDao metadataDao();
|
||||
|
||||
private static volatile AppDb INSTANCE;
|
||||
@ -763,6 +767,27 @@ public abstract class AppDb extends RoomDatabase {
|
||||
database.execSQL("CREATE INDEX index_lessons_profileId_type_oldDate ON timetable (profileId, type, oldDate);");
|
||||
}
|
||||
};
|
||||
private static final Migration MIGRATION_64_65 = new Migration(64, 65) {
|
||||
@Override
|
||||
public void migrate(@NonNull SupportSQLiteDatabase database) {
|
||||
database.execSQL("CREATE TABLE config (" +
|
||||
"profileId INTEGER NOT NULL DEFAULT -1," +
|
||||
"`key` TEXT NOT NULL," +
|
||||
"value TEXT NOT NULL," +
|
||||
"PRIMARY KEY(profileId, `key`));");
|
||||
}
|
||||
};
|
||||
private static final Migration MIGRATION_65_66 = new Migration(65, 66) {
|
||||
@Override
|
||||
public void migrate(@NonNull SupportSQLiteDatabase database) {
|
||||
database.execSQL("DROP TABLE config;");
|
||||
database.execSQL("CREATE TABLE config (" +
|
||||
"profileId INTEGER NOT NULL DEFAULT -1," +
|
||||
"`key` TEXT NOT NULL," +
|
||||
"value TEXT," +
|
||||
"PRIMARY KEY(profileId, `key`));");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public static AppDb getDatabase(final Context context) {
|
||||
@ -824,7 +849,9 @@ public abstract class AppDb extends RoomDatabase {
|
||||
MIGRATION_60_61,
|
||||
MIGRATION_61_62,
|
||||
MIGRATION_62_63,
|
||||
MIGRATION_63_64
|
||||
MIGRATION_63_64,
|
||||
MIGRATION_64_65,
|
||||
MIGRATION_65_66
|
||||
)
|
||||
.allowMainThreadQueries()
|
||||
//.fallbackToDestructiveMigration()
|
||||
|
@ -1,16 +1,17 @@
|
||||
package pl.szczodrzynski.edziennik.data.db.modules.events;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.sqlite.db.SimpleSQLiteQuery;
|
||||
import androidx.sqlite.db.SupportSQLiteQuery;
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.OnConflictStrategy;
|
||||
import androidx.room.Query;
|
||||
import androidx.room.RawQuery;
|
||||
import androidx.room.Transaction;
|
||||
import androidx.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
import androidx.sqlite.db.SimpleSQLiteQuery;
|
||||
import androidx.sqlite.db.SupportSQLiteQuery;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -130,6 +131,12 @@ public abstract class EventDao {
|
||||
@Query("DELETE FROM events WHERE profileId = :profileId AND eventAddedManually = 0 AND eventDate >= :todayDate")
|
||||
public abstract void removeFuture(int profileId, Date todayDate);
|
||||
|
||||
@Query("DELETE FROM events WHERE profileId = :profileId AND eventAddedManually = 0 AND eventDate >= :todayDate AND eventType = :type")
|
||||
public abstract void removeFutureWithType(int profileId, Date todayDate, int type);
|
||||
|
||||
@Query("DELETE FROM events WHERE profileId = :profileId AND eventAddedManually = 0 AND eventDate >= :todayDate AND eventType != :exceptType")
|
||||
public abstract void removeFutureExceptType(int profileId, Date todayDate, int exceptType);
|
||||
|
||||
@Query("UPDATE metadata SET seen = :seen WHERE profileId = :profileId AND (thingType = "+TYPE_EVENT+" OR thingType = "+TYPE_LESSON_CHANGE+" OR thingType = "+TYPE_HOMEWORK+") AND thingId IN (SELECT eventId FROM events WHERE profileId = :profileId AND eventDate = :date)")
|
||||
public abstract void setSeenByDate(int profileId, Date date, boolean seen);
|
||||
|
||||
|
@ -1,18 +1,16 @@
|
||||
package pl.szczodrzynski.edziennik.data.db.modules.grades;
|
||||
|
||||
import android.util.LongSparseArray;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.sqlite.db.SimpleSQLiteQuery;
|
||||
import androidx.sqlite.db.SupportSQLiteQuery;
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.OnConflictStrategy;
|
||||
import androidx.room.Query;
|
||||
import androidx.room.RawQuery;
|
||||
import androidx.room.Transaction;
|
||||
|
||||
import android.util.LongSparseArray;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseIntArray;
|
||||
import androidx.sqlite.db.SimpleSQLiteQuery;
|
||||
import androidx.sqlite.db.SupportSQLiteQuery;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -133,4 +131,8 @@ public abstract class GradeDao {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public LiveData<List<GradeFull>> getAllFromDate(int profileId, int semester, long date) {
|
||||
return getAllWhere(profileId, "gradeSemester = " + semester + " AND addedDate > " + date);
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,10 @@ public abstract class LuckyNumberDao {
|
||||
|
||||
@Nullable
|
||||
@Query("SELECT * FROM luckyNumbers WHERE profileId = :profileId AND luckyNumberDate >= :date ORDER BY luckyNumberDate DESC LIMIT 1")
|
||||
public abstract LuckyNumber getNearestFutureNow(int profileId, Date date);
|
||||
public abstract LuckyNumber getNearestFutureNow(int profileId, int date);
|
||||
|
||||
@Query("SELECT * FROM luckyNumbers WHERE profileId = :profileId AND luckyNumberDate >= :date ORDER BY luckyNumberDate DESC LIMIT 1")
|
||||
public abstract LiveData<LuckyNumber> getNearestFuture(int profileId, int date);
|
||||
|
||||
@RawQuery(observedEntities = {LuckyNumber.class})
|
||||
abstract LiveData<List<LuckyNumberFull>> getAll(SupportSQLiteQuery query);
|
||||
|
@ -9,7 +9,6 @@ import androidx.room.Transaction;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.notices.Notice;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.announcements.Announcement;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.attendance.Attendance;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event;
|
||||
@ -17,6 +16,7 @@ import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonChange;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonFull;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.notices.Notice;
|
||||
import pl.szczodrzynski.edziennik.utils.models.UnreadCounter;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata.TYPE_ANNOUNCEMENT;
|
||||
@ -85,6 +85,11 @@ public abstract class MetadataDao {
|
||||
updateSeen(profileId, TYPE_LESSON_CHANGE, ((LessonFull) o).changeId, seen);
|
||||
}
|
||||
}
|
||||
if (o instanceof pl.szczodrzynski.edziennik.data.db.modules.timetable.LessonFull) {
|
||||
if (add(new Metadata(profileId, TYPE_LESSON_CHANGE, ((pl.szczodrzynski.edziennik.data.db.modules.timetable.LessonFull) o).getId(), seen, false, 0)) == -1) {
|
||||
updateSeen(profileId, TYPE_LESSON_CHANGE, ((pl.szczodrzynski.edziennik.data.db.modules.timetable.LessonFull) o).getId(), seen);
|
||||
}
|
||||
}
|
||||
if (o instanceof Announcement) {
|
||||
if (add(new Metadata(profileId, TYPE_ANNOUNCEMENT, ((Announcement) o).id, seen, false, 0)) == -1) {
|
||||
updateSeen(profileId, TYPE_ANNOUNCEMENT, ((Announcement) o).id, seen);
|
||||
@ -129,6 +134,11 @@ public abstract class MetadataDao {
|
||||
updateNotified(profileId, TYPE_LESSON_CHANGE, ((LessonFull) o).changeId, notified);
|
||||
}
|
||||
}
|
||||
if (o instanceof pl.szczodrzynski.edziennik.data.db.modules.timetable.LessonFull) {
|
||||
if (add(new Metadata(profileId, TYPE_LESSON_CHANGE, ((pl.szczodrzynski.edziennik.data.db.modules.timetable.LessonFull) o).getId(), false, notified, 0)) == -1) {
|
||||
updateNotified(profileId, TYPE_LESSON_CHANGE, ((pl.szczodrzynski.edziennik.data.db.modules.timetable.LessonFull) o).getId(), notified);
|
||||
}
|
||||
}
|
||||
if (o instanceof Announcement) {
|
||||
if (add(new Metadata(profileId, TYPE_ANNOUNCEMENT, ((Announcement) o).id, false, notified, 0)) == -1) {
|
||||
updateNotified(profileId, TYPE_ANNOUNCEMENT, ((Announcement) o).id, notified);
|
||||
|
@ -21,7 +21,10 @@ interface NotificationDao {
|
||||
@Query("DELETE FROM notifications WHERE profileId = :profileId")
|
||||
fun clear(profileId: Int)
|
||||
|
||||
@Query("SELECT * FROM notifications")
|
||||
@Query("DELETE FROM notifications")
|
||||
fun clearAll()
|
||||
|
||||
@Query("SELECT * FROM notifications ORDER BY addedDate DESC")
|
||||
fun getAll(): LiveData<List<Notification>>
|
||||
|
||||
@Query("SELECT * FROM notifications")
|
||||
|
@ -1,5 +1,6 @@
|
||||
package pl.szczodrzynski.edziennik.data.db.modules.profiles;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Insert;
|
||||
@ -24,6 +25,7 @@ public interface ProfileDao {
|
||||
@Query("SELECT profiles.*, loginStores.loginStoreType, loginStores.loginStoreData FROM profiles LEFT JOIN loginStores ON profiles.loginStoreId = loginStores.loginStoreId WHERE profileId = :profileId")
|
||||
LiveData<ProfileFull> getById(int profileId);
|
||||
|
||||
@Nullable
|
||||
@Query("SELECT profiles.*, loginStores.loginStoreType, loginStores.loginStoreData FROM profiles LEFT JOIN loginStores ON profiles.loginStoreId = loginStores.loginStoreId WHERE profileId = :profileId")
|
||||
ProfileFull getFullByIdNow(int profileId);
|
||||
|
||||
|
@ -2,14 +2,15 @@ package pl.szczodrzynski.edziennik.data.db.modules.profiles
|
||||
|
||||
import android.content.Context
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Ignore
|
||||
import com.google.gson.JsonObject
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_AGENDA
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_ANNOUNCEMENTS
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_ATTENDANCE
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_BEHAVIOUR
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_GRADES
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOMEWORK
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_BEHAVIOUR
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_TIMETABLE
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore.*
|
||||
@ -74,6 +75,7 @@ class ProfileFull : Profile {
|
||||
fragmentIds.add(DRAWER_ITEM_AGENDA)
|
||||
fragmentIds.add(DRAWER_ITEM_GRADES)
|
||||
fragmentIds.add(DRAWER_ITEM_MESSAGES)
|
||||
fragmentIds.add(DRAWER_ITEM_HOMEWORK)
|
||||
fragmentIds.add(DRAWER_ITEM_BEHAVIOUR)
|
||||
fragmentIds.add(DRAWER_ITEM_ATTENDANCE)
|
||||
fragmentIds.add(DRAWER_ITEM_ANNOUNCEMENTS)
|
||||
@ -87,9 +89,7 @@ class ProfileFull : Profile {
|
||||
return fragmentIds
|
||||
}
|
||||
|
||||
constructor() : super() {
|
||||
|
||||
}
|
||||
constructor() : super()
|
||||
|
||||
constructor(profile: Profile, loginStore: LoginStore) {
|
||||
|
||||
@ -122,7 +122,10 @@ class ProfileFull : Profile {
|
||||
}*/
|
||||
}
|
||||
|
||||
constructor(context: Context) : super(context) {}
|
||||
constructor(context: Context) : super(context)
|
||||
|
||||
@Ignore
|
||||
constructor(id: Int, name: String, subname: String, loginStoreId: Int) : super(id, name, subname, loginStoreId)
|
||||
|
||||
fun canChangeLoginPassword(): Boolean {
|
||||
return loginStoreType == LOGIN_TYPE_MOBIDZIENNIK || loginStoreType == LOGIN_TYPE_LIBRUS || loginStoreType == LOGIN_TYPE_IUCZNIOWIE
|
||||
|
@ -15,7 +15,7 @@ import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
Index(value = ["profileId", "type", "date"]),
|
||||
Index(value = ["profileId", "type", "oldDate"])
|
||||
])
|
||||
open class Lesson(val profileId: Int, @PrimaryKey val id: Long) {
|
||||
open class Lesson(val profileId: Int, @PrimaryKey var id: Long) {
|
||||
companion object {
|
||||
const val TYPE_NO_LESSONS = -1
|
||||
const val TYPE_NORMAL = 0
|
||||
@ -45,6 +45,27 @@ open class Lesson(val profileId: Int, @PrimaryKey val id: Long) {
|
||||
var oldTeamId: Long? = null
|
||||
var oldClassroom: String? = null
|
||||
|
||||
val displayDate: Date?
|
||||
get() {
|
||||
if (type == TYPE_SHIFTED_SOURCE)
|
||||
return oldDate
|
||||
return date ?: oldDate
|
||||
}
|
||||
|
||||
val displayStartTime: Time?
|
||||
get() {
|
||||
if (type == TYPE_SHIFTED_SOURCE)
|
||||
return oldStartTime
|
||||
return startTime ?: oldStartTime
|
||||
}
|
||||
|
||||
val isCancelled
|
||||
get() = type == TYPE_CANCELLED || type == TYPE_SHIFTED_SOURCE
|
||||
val isChange
|
||||
get() = type == TYPE_CHANGE || type == TYPE_SHIFTED_TARGET
|
||||
|
||||
fun buildId(): Long = (displayDate?.combineWith(displayStartTime) ?: 0L) / 6L * 10L + (hashCode() and 0xFFFF)
|
||||
|
||||
override fun toString(): String {
|
||||
return "Lesson(profileId=$profileId, " +
|
||||
"id=$id, " +
|
||||
@ -66,32 +87,53 @@ open class Lesson(val profileId: Int, @PrimaryKey val id: Long) {
|
||||
"oldTeamId=$oldTeamId, " +
|
||||
"oldClassroom=$oldClassroom)"
|
||||
}
|
||||
}
|
||||
/*
|
||||
DROP TABLE lessons;
|
||||
DROP TABLE lessonChanges;
|
||||
CREATE TABLE lessons (
|
||||
profileId INTEGER NOT NULL,
|
||||
type INTEGER NOT NULL,
|
||||
|
||||
date TEXT DEFAULT NULL,
|
||||
lessonNumber INTEGER DEFAULT NULL,
|
||||
startTime TEXT DEFAULT NULL,
|
||||
endTime TEXT DEFAULT NULL,
|
||||
teacherId INTEGER DEFAULT NULL,
|
||||
subjectId INTEGER DEFAULT NULL,
|
||||
teamId INTEGER DEFAULT NULL,
|
||||
classroom TEXT DEFAULT NULL,
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is Lesson) return false
|
||||
|
||||
oldDate TEXT DEFAULT NULL,
|
||||
oldLessonNumber INTEGER DEFAULT NULL,
|
||||
oldStartTime TEXT DEFAULT NULL,
|
||||
oldEndTime TEXT DEFAULT NULL,
|
||||
oldTeacherId INTEGER DEFAULT NULL,
|
||||
oldSubjectId INTEGER DEFAULT NULL,
|
||||
oldTeamId INTEGER DEFAULT NULL,
|
||||
oldClassroom TEXT DEFAULT NULL,
|
||||
if (profileId != other.profileId) return false
|
||||
if (id != other.id) return false
|
||||
if (type != other.type) return false
|
||||
if (date != other.date) return false
|
||||
if (lessonNumber != other.lessonNumber) return false
|
||||
if (startTime != other.startTime) return false
|
||||
if (endTime != other.endTime) return false
|
||||
if (subjectId != other.subjectId) return false
|
||||
if (teacherId != other.teacherId) return false
|
||||
if (teamId != other.teamId) return false
|
||||
if (classroom != other.classroom) return false
|
||||
if (oldDate != other.oldDate) return false
|
||||
if (oldLessonNumber != other.oldLessonNumber) return false
|
||||
if (oldStartTime != other.oldStartTime) return false
|
||||
if (oldEndTime != other.oldEndTime) return false
|
||||
if (oldSubjectId != other.oldSubjectId) return false
|
||||
if (oldTeacherId != other.oldTeacherId) return false
|
||||
if (oldTeamId != other.oldTeamId) return false
|
||||
if (oldClassroom != other.oldClassroom) return false
|
||||
|
||||
PRIMARY KEY(profileId)
|
||||
);
|
||||
*/
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int { // intentionally ignoring ID and display* here
|
||||
var result = profileId
|
||||
result = 31 * result + type
|
||||
result = 31 * result + (date?.hashCode() ?: 0)
|
||||
result = 31 * result + (lessonNumber ?: 0)
|
||||
result = 31 * result + (startTime?.hashCode() ?: 0)
|
||||
result = 31 * result + (endTime?.hashCode() ?: 0)
|
||||
result = 31 * result + (subjectId?.hashCode() ?: 0)
|
||||
result = 31 * result + (teacherId?.hashCode() ?: 0)
|
||||
result = 31 * result + (teamId?.hashCode() ?: 0)
|
||||
result = 31 * result + (classroom?.hashCode() ?: 0)
|
||||
result = 31 * result + (oldDate?.hashCode() ?: 0)
|
||||
result = 31 * result + (oldLessonNumber ?: 0)
|
||||
result = 31 * result + (oldStartTime?.hashCode() ?: 0)
|
||||
result = 31 * result + (oldEndTime?.hashCode() ?: 0)
|
||||
result = 31 * result + (oldSubjectId?.hashCode() ?: 0)
|
||||
result = 31 * result + (oldTeacherId?.hashCode() ?: 0)
|
||||
result = 31 * result + (oldTeamId?.hashCode() ?: 0)
|
||||
result = 31 * result + (oldClassroom?.hashCode() ?: 0)
|
||||
return result
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package pl.szczodrzynski.edziennik.data.db.modules.timetable
|
||||
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import android.content.Context
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
|
||||
class LessonFull(profileId: Int, id: Long) : Lesson(profileId, id) {
|
||||
@ -11,24 +12,13 @@ class LessonFull(profileId: Int, id: Long) : Lesson(profileId, id) {
|
||||
var oldTeacherName: String? = null
|
||||
var oldTeamName: String? = null
|
||||
|
||||
val displayDate: Date?
|
||||
get() {
|
||||
if (type == TYPE_SHIFTED_SOURCE)
|
||||
return oldDate
|
||||
return date ?: oldDate
|
||||
}
|
||||
val displayLessonNumber: Int?
|
||||
get() {
|
||||
if (type == TYPE_SHIFTED_SOURCE)
|
||||
return oldLessonNumber
|
||||
return lessonNumber ?: oldLessonNumber
|
||||
}
|
||||
val displayStartTime: Time?
|
||||
get() {
|
||||
if (type == TYPE_SHIFTED_SOURCE)
|
||||
return oldStartTime
|
||||
return startTime ?: oldStartTime
|
||||
}
|
||||
|
||||
val displayEndTime: Time?
|
||||
get() {
|
||||
if (type == TYPE_SHIFTED_SOURCE)
|
||||
@ -42,12 +32,14 @@ class LessonFull(profileId: Int, id: Long) : Lesson(profileId, id) {
|
||||
return oldSubjectName
|
||||
return subjectName ?: oldSubjectName
|
||||
}
|
||||
|
||||
val displayTeacherName: String?
|
||||
get() {
|
||||
if (type == TYPE_SHIFTED_SOURCE)
|
||||
return oldTeacherName
|
||||
return teacherName ?: oldTeacherName
|
||||
}
|
||||
|
||||
val displayTeamName: String?
|
||||
get() {
|
||||
if (type == TYPE_SHIFTED_SOURCE)
|
||||
@ -68,12 +60,14 @@ class LessonFull(profileId: Int, id: Long) : Lesson(profileId, id) {
|
||||
return oldTeamId
|
||||
return teamId ?: oldTeamId
|
||||
}
|
||||
|
||||
val displaySubjectId: Long?
|
||||
get() {
|
||||
if (type == TYPE_SHIFTED_SOURCE)
|
||||
return oldSubjectId
|
||||
return subjectId ?: oldSubjectId
|
||||
}
|
||||
|
||||
val displayTeacherId: Long?
|
||||
get() {
|
||||
if (type == TYPE_SHIFTED_SOURCE)
|
||||
@ -81,8 +75,55 @@ class LessonFull(profileId: Int, id: Long) : Lesson(profileId, id) {
|
||||
return teacherId ?: oldTeacherId
|
||||
}
|
||||
|
||||
fun getDisplayChangeType(context: Context): String {
|
||||
return context.getString(when (type) {
|
||||
TYPE_CHANGE -> R.string.lesson_change
|
||||
TYPE_CANCELLED -> R.string.lesson_cancelled
|
||||
TYPE_SHIFTED_TARGET, TYPE_SHIFTED_SOURCE -> R.string.lesson_shifted
|
||||
else -> R.string.lesson_timetable_change
|
||||
})
|
||||
}
|
||||
|
||||
private fun changeText(actual: String?, old: String?): String {
|
||||
val first = when (type) {
|
||||
TYPE_CHANGE, TYPE_CANCELLED, TYPE_SHIFTED_SOURCE -> old
|
||||
else -> actual
|
||||
}
|
||||
|
||||
val second = when (type) {
|
||||
TYPE_CHANGE -> actual
|
||||
else -> null
|
||||
}
|
||||
|
||||
return when (second) {
|
||||
null -> first.orEmpty()
|
||||
first -> second
|
||||
else -> if (first != null) "$first -> $second" else second.orEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
val changeSubjectName: String
|
||||
get() = changeText(subjectName, oldSubjectName)
|
||||
|
||||
val isSubjectNameChanged: Boolean
|
||||
get() = type == TYPE_CHANGE && subjectName != oldSubjectName
|
||||
|
||||
|
||||
val changeTeacherName: String
|
||||
get() = changeText(teacherName, oldTeacherName)
|
||||
|
||||
val isTeacherNameChanged: Boolean
|
||||
get() = type == TYPE_CHANGE && teacherName != oldTeacherName
|
||||
|
||||
|
||||
val changeClassroom: String
|
||||
get() = changeText(classroom, oldClassroom)
|
||||
|
||||
val isClassroomChanged: Boolean
|
||||
get() = type == TYPE_CHANGE && classroom != oldClassroom
|
||||
|
||||
// metadata
|
||||
var seen: Boolean = false
|
||||
var notified: Boolean = false
|
||||
var addedDate: Long = 0
|
||||
}
|
||||
}
|
||||
|
@ -52,6 +52,13 @@ interface TimetableDao {
|
||||
""")
|
||||
fun getForDate(profileId: Int, date: Date) : LiveData<List<LessonFull>>
|
||||
|
||||
@Query("""
|
||||
$QUERY
|
||||
WHERE timetable.profileId = :profileId AND ((type != 3 AND date = :date) OR ((type = 3 OR type = 1) AND oldDate = :date))
|
||||
ORDER BY id, type
|
||||
""")
|
||||
fun getForDateNow(profileId: Int, date: Date) : List<LessonFull>
|
||||
|
||||
@Query("""
|
||||
$QUERY
|
||||
WHERE timetable.profileId = :profileId AND ((type != 3 AND date > :today) OR ((type = 3 OR type = 1) AND oldDate > :today)) AND timetable.subjectId = :subjectId
|
||||
@ -75,10 +82,23 @@ interface TimetableDao {
|
||||
""")
|
||||
fun getBetweenDatesNow(dateFrom: Date, dateTo: Date) : List<LessonFull>
|
||||
|
||||
@Query("""
|
||||
$QUERY
|
||||
WHERE (type != 3 AND date >= :dateFrom AND date <= :dateTo) OR ((type = 3 OR type = 1) AND oldDate >= :dateFrom AND oldDate <= :dateTo)
|
||||
ORDER BY profileId, id, type
|
||||
""")
|
||||
fun getBetweenDates(dateFrom: Date, dateTo: Date) : LiveData<List<LessonFull>>
|
||||
|
||||
@Query("""
|
||||
$QUERY
|
||||
WHERE timetable.profileId = :profileId AND timetable.id = :lessonId
|
||||
ORDER BY id, type
|
||||
""")
|
||||
fun getByIdNow(profileId: Int, lessonId: Long) : LessonFull?
|
||||
|
||||
@Query("""
|
||||
$QUERY
|
||||
WHERE timetable.profileId = :profileId AND timetable.type NOT IN (${Lesson.TYPE_NORMAL}, ${Lesson.TYPE_NO_LESSONS}, ${Lesson.TYPE_SHIFTED_SOURCE}) AND metadata.notified = 0
|
||||
""")
|
||||
fun getNotNotifiedNow(profileId: Int): List<LessonFull>
|
||||
}
|
||||
|
@ -90,12 +90,12 @@ public class ServerRequest {
|
||||
.addParameter("device_id", Settings.Secure.getString(app.getContext().getContentResolver(), Settings.Secure.ANDROID_ID))
|
||||
.addParameter("device_model", Build.MANUFACTURER+" "+Build.MODEL)
|
||||
.addParameter("device_os_version", Build.VERSION.RELEASE)
|
||||
.addParameter("fcm_token", app.appConfig.fcmToken)
|
||||
.addParameter("fcm_token", app.config.getSync().getTokenApp())
|
||||
.addParameter("signature", sign(app.signature, timestamp))
|
||||
.addParameter("signature_timestamp", timestamp)
|
||||
.addParameter("package_name", "pl.szczodrzynski.edziennik")
|
||||
.addParameter("source", source)
|
||||
.addParameter("update_frequency", app.appConfig.registerSyncEnabled ? app.appConfig.registerSyncInterval : -1)
|
||||
.addParameter("update_frequency", app.config.getSync().getEnabled() ? app.config.getSync().getInterval() : -1)
|
||||
.post()
|
||||
.callback(new JsonCallbackHandler() {
|
||||
@Override
|
||||
@ -127,12 +127,12 @@ public class ServerRequest {
|
||||
.addParameter("device_id", Settings.Secure.getString(app.getContext().getContentResolver(), Settings.Secure.ANDROID_ID))
|
||||
.addParameter("device_model", Build.MANUFACTURER+" "+Build.MODEL)
|
||||
.addParameter("device_os_version", Build.VERSION.RELEASE)
|
||||
.addParameter("fcm_token", app.appConfig.fcmToken)
|
||||
.addParameter("fcm_token", app.config.getSync().getTokenApp())
|
||||
.addParameter("signature", sign(app.signature, timestamp))
|
||||
.addParameter("signature_timestamp", timestamp)
|
||||
.addParameter("package_name", "pl.szczodrzynski.edziennik")
|
||||
.addParameter("source", source)
|
||||
.addParameter("update_frequency", app.appConfig.registerSyncEnabled ? app.appConfig.registerSyncInterval : -1)
|
||||
.addParameter("update_frequency", app.config.getSync().getEnabled() ? app.config.getSync().getInterval() : -1)
|
||||
.post()
|
||||
.build()
|
||||
.execute();
|
||||
|
@ -47,9 +47,8 @@ public class MyFirebaseMessagingService extends FirebaseMessagingService {
|
||||
|
||||
Log.d(TAG, "New token: "+s);
|
||||
App app = (App)getApplicationContext();
|
||||
if (app.appConfig.fcmToken == null || !app.appConfig.fcmToken.equals(s)) {
|
||||
app.appConfig.fcmToken = s;
|
||||
app.saveConfig();
|
||||
if (app.config.getSync().getTokenApp() == null || !app.config.getSync().getTokenApp().equals(s)) {
|
||||
app.config.getSync().setTokenApp(s);
|
||||
}
|
||||
}
|
||||
|
||||
@ -198,8 +197,7 @@ public class MyFirebaseMessagingService extends FirebaseMessagingService {
|
||||
else {
|
||||
feedbackMessage.sentTime = Long.parseLong(remoteMessage.getData().get("sent_time"));
|
||||
if (feedbackMessage.text.startsWith("devmode")) {
|
||||
app.appConfig.devModePassword = feedbackMessage.text.replace("devmode", "");
|
||||
app.saveConfig("devModePassword");
|
||||
app.config.setDevModePassword(feedbackMessage.text.replace("devmode", ""));
|
||||
app.checkDevModePassword();
|
||||
feedbackMessage.text = "devmode "+(App.devMode ? "allowed" : "disallowed");
|
||||
}
|
||||
|
@ -57,16 +57,16 @@ class SyncWorker(val context: Context, val params: WorkerParameters) : Worker(co
|
||||
/**
|
||||
* Cancel any existing sync jobs and schedule a new one.
|
||||
*
|
||||
* If [registerSyncEnabled] is not true, just cancel every job.
|
||||
* If [ConfigSync.enabled] is not true, just cancel every job.
|
||||
*/
|
||||
fun rescheduleNext(app: App) {
|
||||
cancelNext(app)
|
||||
val enableSync = app.appConfig.registerSyncEnabled
|
||||
val enableSync = app.config.sync.enabled
|
||||
if (!enableSync) {
|
||||
return
|
||||
}
|
||||
val onlyWifi = app.appConfig.registerSyncOnlyWifi
|
||||
val syncInterval = app.appConfig.registerSyncInterval.toLong()
|
||||
val onlyWifi = app.config.sync.onlyWifi
|
||||
val syncInterval = app.config.sync.interval.toLong()
|
||||
|
||||
val syncAt = System.currentTimeMillis() + syncInterval*1000
|
||||
d(TAG, "Scheduling work at ${syncAt.formatDate()}")
|
||||
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-11-30
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.dialogs.event
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.PorterDuffColorFilter
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.EventFull
|
||||
import pl.szczodrzynski.edziennik.databinding.RowDialogEventListItemBinding
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.bs
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class EventListAdapter(
|
||||
val context: Context,
|
||||
val parentDialog: EventListDialog
|
||||
) : RecyclerView.Adapter<EventListAdapter.ViewHolder>() {
|
||||
|
||||
private val app by lazy { context.applicationContext as App }
|
||||
|
||||
val eventList = mutableListOf<EventFull>()
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val inflater = LayoutInflater.from(parent.context)
|
||||
val view: RowDialogEventListItemBinding = DataBindingUtil.inflate(inflater, R.layout.row_dialog_event_list_item, parent, false)
|
||||
return ViewHolder(view)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val event = eventList[position]
|
||||
|
||||
holder.apply {
|
||||
b.eventListItemRoot.background.colorFilter = when (event.type) {
|
||||
Event.TYPE_HOMEWORK -> PorterDuffColorFilter((0xffffffff).toInt(), PorterDuff.Mode.CLEAR)
|
||||
else -> PorterDuffColorFilter(event.color, PorterDuff.Mode.MULTIPLY)
|
||||
}
|
||||
|
||||
b.eventListItemStartTime.text = if (event.startTime == null) app.getString(R.string.event_all_day) else event.startTime?.stringHM
|
||||
b.eventListItemTeamName.text = bs(event.teamName)
|
||||
b.eventListItemTeacherName.text = app.getString(R.string.concat_2_strings, bs(null, event.teacherFullName, "\n"), bs(event.subjectLongName))
|
||||
b.eventListItemAddedDate.text = Date.fromMillis(event.addedDate).formattedStringShort
|
||||
b.eventListItemType.text = event.typeName
|
||||
b.eventListItemTopic.text = event.topic
|
||||
b.eventListItemHomework.visibility = if (event.type == Event.TYPE_HOMEWORK) View.VISIBLE else View.GONE
|
||||
b.eventListItemSharedBy.text = app.getString(R.string.event_shared_by_format, if (event.sharedBy == "self") app.getString(R.string.event_shared_by_self) else event.sharedByName)
|
||||
b.eventListItemSharedBy.visibility = if (event.sharedByName.isNullOrBlank()) View.GONE else View.VISIBLE
|
||||
|
||||
b.eventListItemEdit.visibility = if (event.addedManually) View.VISIBLE else View.GONE
|
||||
b.eventListItemEdit.setOnClickListener {
|
||||
parentDialog.dismiss()
|
||||
|
||||
EventManualV2Dialog(
|
||||
context as MainActivity,
|
||||
event.profileId,
|
||||
editingEvent = event,
|
||||
onShowListener = parentDialog.onShowListener,
|
||||
onDismissListener = parentDialog.onDismissListener
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = eventList.size
|
||||
|
||||
class ViewHolder(val b: RowDialogEventListItemBinding) : RecyclerView.ViewHolder(b.root)
|
||||
}
|
@ -3,14 +3,15 @@ package pl.szczodrzynski.edziennik.ui.dialogs.event;
|
||||
import android.content.Context;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffColorFilter;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.mikepenz.iconics.view.IconicsImageView;
|
||||
import com.mikepenz.iconics.view.IconicsTextView;
|
||||
|
||||
@ -20,21 +21,21 @@ import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.EventFull;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||
import pl.szczodrzynski.edziennik.utils.Utils;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.data.db.modules.events.Event.TYPE_HOMEWORK;
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.bs;
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.d;
|
||||
|
||||
public class EventListAdapter extends RecyclerView.Adapter<EventListAdapter.ViewHolder> {
|
||||
private static final String TAG = "EventListAdapter";
|
||||
public class EventListAdapterOld extends RecyclerView.Adapter<EventListAdapterOld.ViewHolder> {
|
||||
private static final String TAG = "EventListAdapterOld";
|
||||
private Context context;
|
||||
private List<EventFull> examList;
|
||||
private EventListDialog parentDialog;
|
||||
private EventListDialogOld parentDialog;
|
||||
|
||||
//getting the context and product list with constructor
|
||||
public EventListAdapter(Context mCtx, List<EventFull> examList, EventListDialog parentDialog) {
|
||||
public EventListAdapterOld(Context mCtx, List<EventFull> examList, EventListDialogOld parentDialog) {
|
||||
this.context = mCtx;
|
||||
this.examList = examList;
|
||||
this.parentDialog = parentDialog;
|
||||
@ -42,15 +43,15 @@ public class EventListAdapter extends RecyclerView.Adapter<EventListAdapter.View
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public EventListAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
public EventListAdapterOld.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
//inflating and returning our view holder
|
||||
LayoutInflater inflater = LayoutInflater.from(context);
|
||||
View view = inflater.inflate(R.layout.row_dialog_event_list_item, parent, false);
|
||||
return new EventListAdapter.ViewHolder(view);
|
||||
return new EventListAdapterOld.ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull EventListAdapter.ViewHolder holder, int position) {
|
||||
public void onBindViewHolder(@NonNull EventListAdapterOld.ViewHolder holder, int position) {
|
||||
App app = (App) context.getApplicationContext();
|
||||
|
||||
EventFull event = examList.get(position);
|
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-11-30
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.dialogs.event
|
||||
|
||||
import android.graphics.Typeface
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.timetable.Lesson
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.timetable.LessonFull
|
||||
import pl.szczodrzynski.edziennik.databinding.DialogEventListBinding
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class EventListDialog(
|
||||
val activity: AppCompatActivity,
|
||||
val profileId: Int,
|
||||
val date: Date,
|
||||
val time: Time? = null,
|
||||
val onShowListener: ((tag: String) -> Unit)? = null,
|
||||
val onDismissListener: ((tag: String) -> Unit)? = null
|
||||
) : CoroutineScope {
|
||||
|
||||
companion object {
|
||||
const val TAG = "EventListDialog"
|
||||
}
|
||||
|
||||
private lateinit var job: Job
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Main
|
||||
|
||||
private val app by lazy { activity.application as App }
|
||||
private lateinit var b: DialogEventListBinding
|
||||
private lateinit var dialog: AlertDialog
|
||||
private lateinit var adapter: EventListAdapter
|
||||
|
||||
private var lesson: LessonFull? = null
|
||||
|
||||
init {
|
||||
run {
|
||||
if (activity.isFinishing)
|
||||
return@run
|
||||
job = Job()
|
||||
onShowListener?.invoke(TAG)
|
||||
b = DialogEventListBinding.inflate(activity.layoutInflater)
|
||||
|
||||
dialog = MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(date.formattedString + (time?.let { ", " + it.stringHM } ?: ""))
|
||||
.setView(b.root)
|
||||
.setPositiveButton(R.string.close) { dialog, _ -> dialog.dismiss() }
|
||||
.setNeutralButton(R.string.add) { _, _ ->
|
||||
EventManualV2Dialog(
|
||||
activity,
|
||||
lesson?.profileId ?: profileId,
|
||||
lesson,
|
||||
date,
|
||||
time,
|
||||
onShowListener = onShowListener,
|
||||
onDismissListener = onDismissListener
|
||||
)
|
||||
}
|
||||
.setOnDismissListener {
|
||||
onDismissListener?.invoke(TAG)
|
||||
}
|
||||
.show()
|
||||
|
||||
app.db.timetableDao().getForDate(profileId, date).observe(activity, Observer { lessons ->
|
||||
lesson = lessons.firstOrNull { it.displayStartTime == time }
|
||||
update()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fun dismiss() = dialog.dismiss()
|
||||
|
||||
private fun update() {
|
||||
b.eventListLessonDetails.visibility = if (lesson == null) View.GONE else View.VISIBLE
|
||||
|
||||
if (lesson != null) {
|
||||
dialog.setTitle(if (time == null) date.formattedString else (lesson?.displaySubjectName
|
||||
?: date.formattedString) + ", " + time.stringHM)
|
||||
|
||||
b.eventListLessonDate.text = app.getString(R.string.date_time_format, date.formattedString, "")
|
||||
|
||||
if (lesson?.type == Lesson.TYPE_CANCELLED) {
|
||||
b.eventListLessonChange.text = app.getString(R.string.lesson_cancelled)
|
||||
b.eventListLessonChange.setTypeface(null, Typeface.BOLD_ITALIC)
|
||||
b.eventListTeacher.visibility = View.GONE
|
||||
b.eventListClassroom.visibility = View.GONE
|
||||
} else {
|
||||
b.eventListLessonChange.text = lesson?.changeSubjectName
|
||||
b.eventListLessonChange.setTypeface(null, Typeface.ITALIC)
|
||||
b.eventListLessonChange.visibility = if (lesson?.isSubjectNameChanged == true) View.VISIBLE else View.GONE
|
||||
|
||||
b.eventListTeacher.text = lesson?.changeTeacherName
|
||||
b.eventListTeacher.setTypeface(null, if (lesson?.isTeacherNameChanged == true) Typeface.ITALIC else Typeface.NORMAL)
|
||||
|
||||
b.eventListClassroom.text = lesson?.changeClassroom
|
||||
b.eventListClassroom.setTypeface(null, if (lesson?.isClassroomChanged == true) Typeface.ITALIC else Typeface.NORMAL)
|
||||
}
|
||||
}
|
||||
|
||||
b.eventListView.apply {
|
||||
setHasFixedSize(false)
|
||||
isNestedScrollingEnabled = true
|
||||
layoutManager = LinearLayoutManager(activity)
|
||||
}
|
||||
|
||||
adapter = EventListAdapter(activity, this@EventListDialog)
|
||||
b.eventListView.adapter = adapter
|
||||
|
||||
app.db.eventDao().getAllByDateTime(profileId, date, time).observe(activity, Observer { events ->
|
||||
if (events.isNullOrEmpty()) {
|
||||
b.eventListView.visibility = View.GONE
|
||||
b.textNoEvents.visibility = View.VISIBLE
|
||||
} else {
|
||||
adapter.run {
|
||||
eventList.apply {
|
||||
clear()
|
||||
addAll(events)
|
||||
}
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -8,14 +8,14 @@ import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.cardview.widget.CardView;
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonChange;
|
||||
@ -26,16 +26,16 @@ import pl.szczodrzynski.edziennik.ui.dialogs.teacherabsence.TeacherAbsenceDialog
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time;
|
||||
|
||||
public class EventListDialog {
|
||||
public class EventListDialogOld {
|
||||
private App app;
|
||||
private Context context;
|
||||
private int profileId;
|
||||
|
||||
public EventListDialog(Context context) {
|
||||
public EventListDialogOld(Context context) {
|
||||
this.context = context;
|
||||
this.profileId = App.profileId;
|
||||
}
|
||||
public EventListDialog(Context context, int profileId) {
|
||||
public EventListDialogOld(Context context, int profileId) {
|
||||
this.context = context;
|
||||
this.profileId = profileId;
|
||||
}
|
||||
@ -47,7 +47,7 @@ public class EventListDialog {
|
||||
public boolean callDismissListener = true;
|
||||
private LessonFull lesson;
|
||||
|
||||
public EventListDialog withDismissListener(DialogInterface.OnDismissListener dismissListener) {
|
||||
public EventListDialogOld withDismissListener(DialogInterface.OnDismissListener dismissListener) {
|
||||
this.dismissListener = dismissListener;
|
||||
return this;
|
||||
}
|
||||
@ -222,7 +222,7 @@ public class EventListDialog {
|
||||
dialogView.findViewById(R.id.textNoEvents).setVisibility(View.VISIBLE);
|
||||
}
|
||||
else {
|
||||
EventListAdapter adapter = new EventListAdapter(context, events, this);
|
||||
EventListAdapterOld adapter = new EventListAdapterOld(context, events, this);
|
||||
examsView.setAdapter(adapter);
|
||||
}
|
||||
});
|
@ -517,7 +517,7 @@ public class EventManualDialog {
|
||||
|
||||
registerEventManualDateLayout = dialogView.findViewById(R.id.registerEventManualDateLayout);
|
||||
registerEventManualDate = dialogView.findViewById(R.id.registerEventManualDate);
|
||||
registerEventManualDate.setCompoundDrawablesWithIntrinsicBounds(null, null, new IconicsDrawable(context, CommunityMaterial.Icon.cmd_calendar).size(IconicsSize.dp(16)).color(IconicsColor.colorInt(primaryTextColor)), null);
|
||||
registerEventManualDate.setCompoundDrawablesWithIntrinsicBounds(null, null, new IconicsDrawable(context, CommunityMaterial.Icon.cmd_calendar_outline).size(IconicsSize.dp(16)).color(IconicsColor.colorInt(primaryTextColor)), null);
|
||||
//registerEventManualDate.setCompoundDrawablePadding(Utils.dpToPx(6));
|
||||
registerEventManualLessonLayout = dialogView.findViewById(R.id.registerEventManualLessonLayout);
|
||||
registerEventManualLesson = dialogView.findViewById(R.id.registerEventManualLesson);
|
||||
|
@ -6,7 +6,10 @@ package pl.szczodrzynski.edziennik.ui.dialogs.event
|
||||
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.PorterDuffColorFilter
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AlertDialog.BUTTON_POSITIVE
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.Observer
|
||||
import com.google.android.material.datepicker.MaterialDatePicker
|
||||
@ -17,7 +20,9 @@ import kotlinx.coroutines.*
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.EventType
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.subjects.Subject
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teams.Team
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.timetable.Lesson
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.timetable.LessonFull
|
||||
@ -67,25 +72,28 @@ class EventManualV2Dialog(
|
||||
.setTitle(R.string.dialog_event_manual_title)
|
||||
.setView(b.root)
|
||||
.setNegativeButton(R.string.cancel) { dialog, _ -> dialog.dismiss() }
|
||||
.setPositiveButton(R.string.save) { _, _ -> saveEvent() }
|
||||
.setPositiveButton(R.string.save, null)
|
||||
.setOnDismissListener {
|
||||
onDismissListener?.invoke(TAG)
|
||||
}
|
||||
.show()
|
||||
.create()
|
||||
.apply {
|
||||
setOnShowListener { dialog ->
|
||||
val positiveButton = (dialog as AlertDialog).getButton(BUTTON_POSITIVE)
|
||||
positiveButton.setOnClickListener {
|
||||
saveEvent()
|
||||
}
|
||||
}
|
||||
|
||||
show()
|
||||
}
|
||||
|
||||
event = editingEvent?.clone() ?: Event().also { event ->
|
||||
event.profileId = profileId
|
||||
/*defaultDate?.let {
|
||||
event.eventDate = it
|
||||
b.date = it
|
||||
}
|
||||
defaultTime?.let {
|
||||
event.startTime = it
|
||||
b.time = it
|
||||
}
|
||||
defaultType?.let {
|
||||
event.type = it
|
||||
}*/
|
||||
}
|
||||
b.shareSwitch.isChecked = event.sharedBy != null
|
||||
}
|
||||
|
||||
b.showMore.onClick { // TODO iconics is broken
|
||||
@ -99,9 +107,32 @@ class EventManualV2Dialog(
|
||||
}
|
||||
}
|
||||
|
||||
updateShareText()
|
||||
b.shareSwitch.onChange { _, isChecked ->
|
||||
updateShareText(isChecked)
|
||||
}
|
||||
|
||||
loadLists()
|
||||
}}
|
||||
|
||||
private fun updateShareText(checked: Boolean = b.shareSwitch.isChecked) {
|
||||
val editingShared = editingEvent?.sharedBy != null
|
||||
val editingOwn = editingEvent?.sharedBy == "self"
|
||||
|
||||
b.shareDetails.visibility = if (checked || editingShared)
|
||||
View.VISIBLE
|
||||
else View.GONE
|
||||
|
||||
val text = when {
|
||||
checked && editingShared && editingOwn -> R.string.dialog_event_manual_share_will_change
|
||||
checked && editingShared -> R.string.dialog_event_manual_share_will_request
|
||||
!checked && editingShared -> R.string.dialog_event_manual_share_will_remove
|
||||
else -> R.string.dialog_event_manual_share_first_notice
|
||||
}
|
||||
|
||||
b.shareDetails.setText(text)
|
||||
}
|
||||
|
||||
private fun loadLists() { launch {
|
||||
val deferred = async(Dispatchers.Default) {
|
||||
// get the team list
|
||||
@ -155,6 +186,8 @@ class EventManualV2Dialog(
|
||||
b.teamDropdown.select(it.teamId)
|
||||
b.subjectDropdown.select(it.subjectId)
|
||||
b.teacherDropdown.select(it.teacherId)
|
||||
b.topic.setText(it.topic)
|
||||
b.shareSwitch.isChecked = true
|
||||
b.typeDropdown.select(it.type)?.let { item ->
|
||||
customColor = (item.tag as EventType).color
|
||||
}
|
||||
@ -263,6 +296,16 @@ class EventManualV2Dialog(
|
||||
val dates = deferred.await()
|
||||
b.dateDropdown.clear().append(dates)
|
||||
|
||||
defaultDate?.let {
|
||||
event.eventDate = it
|
||||
if (b.dateDropdown.select(it) == null)
|
||||
b.dateDropdown.select(TextInputDropDown.Item(
|
||||
it.value.toLong(),
|
||||
it.formattedString,
|
||||
tag = it
|
||||
))
|
||||
}
|
||||
|
||||
editingEvent?.eventDate?.let {
|
||||
b.dateDropdown.select(TextInputDropDown.Item(
|
||||
it.value.toLong(),
|
||||
@ -400,6 +443,16 @@ class EventManualV2Dialog(
|
||||
b.teacherDropdown.deselect()
|
||||
}
|
||||
else {
|
||||
defaultTime?.let {
|
||||
event.startTime = it
|
||||
if (b.timeDropdown.select(it) == null)
|
||||
b.timeDropdown.select(TextInputDropDown.Item(
|
||||
it.value.toLong(),
|
||||
it.stringHM,
|
||||
tag = it
|
||||
))
|
||||
}
|
||||
|
||||
editingEvent?.let {
|
||||
b.timeDropdown.select(it.startTime?.value?.toLong())
|
||||
}
|
||||
@ -417,17 +470,16 @@ class EventManualV2Dialog(
|
||||
|
||||
// attach a listener to time dropdown
|
||||
b.timeDropdown.setOnChangeListener { item ->
|
||||
when {
|
||||
when (item.id) {
|
||||
// no lessons this day
|
||||
item.id == -2L -> {
|
||||
-2L -> {
|
||||
b.timeDropdown.deselect()
|
||||
return@setOnChangeListener false
|
||||
}
|
||||
// custom start hour
|
||||
item.id == -1L -> {
|
||||
|
||||
return@setOnChangeListener false
|
||||
}
|
||||
// custom start hour
|
||||
-1L -> return@setOnChangeListener false
|
||||
|
||||
// selected a specific lesson
|
||||
else -> {
|
||||
if (item.tag is LessonFull) {
|
||||
@ -436,7 +488,7 @@ class EventManualV2Dialog(
|
||||
b.teamDropdown.deselect()
|
||||
b.subjectDropdown.deselect()
|
||||
b.teacherDropdown.deselect()
|
||||
item.tag.displayTeamId?.let {
|
||||
item.tag.displayTeamId?.let {
|
||||
b.teamDropdown.select(it)
|
||||
}
|
||||
item.tag.displaySubjectId?.let {
|
||||
@ -454,6 +506,80 @@ class EventManualV2Dialog(
|
||||
}
|
||||
|
||||
private fun saveEvent() {
|
||||
val date = b.dateDropdown.selected?.tag.instanceOfOrNull<Date>()
|
||||
val lesson = b.timeDropdown.selected?.tag.instanceOfOrNull<LessonFull>()
|
||||
val team = b.teamDropdown.selected?.tag.instanceOfOrNull<Team>()
|
||||
val share = b.shareSwitch.isChecked
|
||||
val type = b.typeDropdown.selected?.tag.instanceOfOrNull<EventType>()
|
||||
val topic = b.topic.text?.toString()
|
||||
val subject = b.subjectDropdown.selected?.tag.instanceOfOrNull<Subject>()
|
||||
val teacher = b.teacherDropdown.selected?.tag.instanceOfOrNull<Teacher>()
|
||||
|
||||
b.teamDropdown.error = null
|
||||
b.typeDropdown.error = null
|
||||
b.topic.error = null
|
||||
|
||||
var isError = false
|
||||
|
||||
if (share && team == null) {
|
||||
b.teamDropdown.error = app.getString(R.string.dialog_event_manual_team_choose)
|
||||
isError = true
|
||||
}
|
||||
|
||||
if (type == null) {
|
||||
b.typeDropdown.error = app.getString(R.string.dialog_event_manual_type_choose)
|
||||
isError = true
|
||||
}
|
||||
|
||||
if (topic.isNullOrBlank()) {
|
||||
b.topic.error = app.getString(R.string.dialog_event_manual_topic_choose)
|
||||
isError = true
|
||||
}
|
||||
|
||||
if (isError) return
|
||||
|
||||
val id = System.currentTimeMillis()
|
||||
|
||||
val eventObject = Event(
|
||||
profileId,
|
||||
id,
|
||||
date,
|
||||
lesson?.displayStartTime,
|
||||
topic,
|
||||
customColor ?: -1,
|
||||
type?.id?.toInt() ?: Event.TYPE_DEFAULT,
|
||||
true,
|
||||
teacher?.id ?: -1,
|
||||
subject?.id ?: -1,
|
||||
team?.id ?: -1
|
||||
)
|
||||
|
||||
val metadataObject = Metadata(
|
||||
profileId,
|
||||
when (type?.id?.toInt()) {
|
||||
Event.TYPE_HOMEWORK -> Metadata.TYPE_HOMEWORK
|
||||
else -> Metadata.TYPE_EVENT
|
||||
},
|
||||
eventObject.id,
|
||||
true,
|
||||
true,
|
||||
System.currentTimeMillis()
|
||||
)
|
||||
|
||||
finishAdding(eventObject, metadataObject)
|
||||
}
|
||||
|
||||
private fun finishAdding(eventObject: Event, metadataObject: Metadata) {
|
||||
launch {
|
||||
val deferred = async(Dispatchers.Default) {
|
||||
app.db.eventDao().add(eventObject)
|
||||
app.db.metadataDao().add(metadataObject)
|
||||
}
|
||||
|
||||
deferred.await()
|
||||
}
|
||||
|
||||
dialog.dismiss()
|
||||
Toast.makeText(app, R.string.saved, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-11-24.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.dialogs.home
|
||||
|
||||
import android.text.InputType
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||
|
||||
class StudentNumberDialog(
|
||||
val activity: AppCompatActivity,
|
||||
val profile: Profile,
|
||||
val onShowListener: ((tag: String) -> Unit)? = null,
|
||||
val onDismissListener: ((tag: String) -> Unit)? = null
|
||||
) {
|
||||
companion object {
|
||||
private const val TAG = "StudentNumberDialog"
|
||||
}
|
||||
|
||||
private lateinit var dialog: AlertDialog
|
||||
|
||||
init { run {
|
||||
if (activity.isFinishing)
|
||||
return@run
|
||||
onShowListener?.invoke(TAG)
|
||||
MaterialDialog.Builder(activity)
|
||||
.title(R.string.card_lucky_number_set_title)
|
||||
.content(R.string.card_lucky_number_set_text)
|
||||
.inputType(InputType.TYPE_CLASS_NUMBER)
|
||||
.input(null, if (profile.studentNumber == -1) "" else profile.studentNumber.toString()) { _: MaterialDialog?, input: CharSequence ->
|
||||
try {
|
||||
profile.studentNumber = input.toString().toInt()
|
||||
} catch (e: Exception) {
|
||||
Toast.makeText(activity, R.string.incorrect_format, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
.dismissListener {
|
||||
onDismissListener?.invoke(TAG)
|
||||
}.show()
|
||||
}}
|
||||
}
|
@ -94,15 +94,23 @@ class SyncViewListDialog(
|
||||
listOfNotNull(*it.toTypedArray())
|
||||
}
|
||||
|
||||
if (selectedViewIds.isNotEmpty()) {
|
||||
activity.swipeRefreshLayout.isRefreshing = true
|
||||
EdziennikTask.syncProfile(
|
||||
App.profileId,
|
||||
selectedViewIds
|
||||
).enqueue(activity)
|
||||
}
|
||||
}
|
||||
.setNeutralButton(R.string.sync_feature_all) { _, _ ->
|
||||
dialog.dismiss()
|
||||
|
||||
activity.swipeRefreshLayout.isRefreshing = true
|
||||
EdziennikTask.syncProfile(
|
||||
App.profileId,
|
||||
selectedViewIds
|
||||
).enqueue(activity)
|
||||
EdziennikTask.syncProfile(App.profileId).enqueue(activity)
|
||||
}
|
||||
.setNegativeButton(R.string.cancel) { _, _ ->
|
||||
dialog.dismiss()
|
||||
}
|
||||
.show()
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ class LessonDetailsDialog(
|
||||
.setPositiveButton(R.string.close) { dialog, _ ->
|
||||
dialog.dismiss()
|
||||
}
|
||||
.setNeutralButton(R.string.add) { dialog, _ ->
|
||||
.setNeutralButton(R.string.add) { _, _ ->
|
||||
EventManualV2Dialog(
|
||||
activity,
|
||||
lesson.profileId,
|
||||
@ -120,7 +120,7 @@ class LessonDetailsDialog(
|
||||
dialog.dismiss()
|
||||
val dateStr = otherLessonDate?.stringY_m_d ?: return@setOnClickListener
|
||||
val intent = Intent(TimetableFragment.ACTION_SCROLL_TO_DATE).apply {
|
||||
putExtra("date", dateStr)
|
||||
putExtra("timetableDate", dateStr)
|
||||
}
|
||||
activity.sendBroadcast(intent)
|
||||
}
|
||||
@ -157,4 +157,4 @@ class LessonDetailsDialog(
|
||||
b.teamName = lesson.teamName
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,15 +6,16 @@ import android.graphics.drawable.Drawable;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.applandeo.materialcalendarview.CalendarView;
|
||||
import com.applandeo.materialcalendarview.EventDay;
|
||||
@ -27,6 +28,7 @@ import com.mikepenz.iconics.IconicsColor;
|
||||
import com.mikepenz.iconics.IconicsDrawable;
|
||||
import com.mikepenz.iconics.IconicsSize;
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial;
|
||||
import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
@ -34,13 +36,13 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.MainActivity;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.EventFull;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonFull;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.TeacherAbsenceFull;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentAgendaCalendarBinding;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentAgendaDefaultBinding;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.EventFull;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonFull;
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventListDialog;
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventManualDialog;
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.lessonchange.LessonChangeDialog;
|
||||
@ -51,11 +53,11 @@ import pl.szczodrzynski.edziennik.ui.modules.agenda.lessonchange.LessonChangeEve
|
||||
import pl.szczodrzynski.edziennik.ui.modules.agenda.teacherabsence.TeacherAbsenceCounter;
|
||||
import pl.szczodrzynski.edziennik.ui.modules.agenda.teacherabsence.TeacherAbsenceEvent;
|
||||
import pl.szczodrzynski.edziennik.ui.modules.agenda.teacherabsence.TeacherAbsenceEventRenderer;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time;
|
||||
import pl.szczodrzynski.edziennik.utils.Colors;
|
||||
import pl.szczodrzynski.edziennik.utils.Themes;
|
||||
import pl.szczodrzynski.edziennik.utils.Utils;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time;
|
||||
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem;
|
||||
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetSeparatorItem;
|
||||
|
||||
@ -82,7 +84,7 @@ public class AgendaFragment extends Fragment {
|
||||
if (app.profile == null)
|
||||
return inflater.inflate(R.layout.fragment_loading, container, false);
|
||||
// activity, context and profile is valid
|
||||
viewType = app.profile.getAgendaViewType();
|
||||
viewType = app.config.getUi().getAgendaViewType();
|
||||
if (viewType == AGENDA_DEFAULT) {
|
||||
b_default = DataBindingUtil.inflate(inflater, R.layout.fragment_agenda_default, container, false);
|
||||
return b_default.getRoot();
|
||||
@ -102,7 +104,7 @@ public class AgendaFragment extends Fragment {
|
||||
new BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_add_event)
|
||||
.withDescription(R.string.menu_add_event_desc)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_calendar_plus)
|
||||
.withIcon(SzkolnyFont.Icon.szf_calendar_plus_outline)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
new MaterialDialog.Builder(activity)
|
||||
@ -122,18 +124,17 @@ public class AgendaFragment extends Fragment {
|
||||
}),
|
||||
new BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_agenda_change_view)
|
||||
.withIcon(viewType == AGENDA_DEFAULT ? CommunityMaterial.Icon.cmd_calendar : CommunityMaterial.Icon2.cmd_view_list)
|
||||
.withIcon(viewType == AGENDA_DEFAULT ? CommunityMaterial.Icon.cmd_calendar_outline : CommunityMaterial.Icon.cmd_format_list_bulleted_square)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
viewType = viewType == AGENDA_DEFAULT ? AGENDA_CALENDAR : AGENDA_DEFAULT;
|
||||
app.profile.setAgendaViewType(viewType);
|
||||
app.profileSaveAsync();
|
||||
app.config.getUi().setAgendaViewType(viewType);
|
||||
activity.reloadTarget();
|
||||
}),
|
||||
new BottomSheetSeparatorItem(true),
|
||||
new BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_mark_as_read)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check_outline)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
AsyncTask.execute(() -> app.db.metadataDao().setAllSeen(App.profileId, TYPE_EVENT, true));
|
||||
@ -309,7 +310,7 @@ public class AgendaFragment extends Fragment {
|
||||
int scrolledDate = Date.fromCalendar(calendar).getValue();
|
||||
if (unreadEventDates.contains(scrolledDate)) {
|
||||
AsyncTask.execute(() -> app.db.eventDao().setSeenByDate(App.profileId, Date.fromYmd(intToStr(scrolledDate)), true));
|
||||
unreadEventDates.remove(unreadEventDates.indexOf(scrolledDate));
|
||||
unreadEventDates.remove((Integer) scrolledDate);
|
||||
}
|
||||
}
|
||||
|
||||
@ -317,9 +318,23 @@ public class AgendaFragment extends Fragment {
|
||||
public void onEventSelected(CalendarEvent calendarEvent) {
|
||||
if (calendarEvent instanceof BaseCalendarEvent) {
|
||||
if (!calendarEvent.isPlaceholder() && !calendarEvent.isAllDay()) {
|
||||
new EventListDialog(activity).show(app, Date.fromCalendar(calendarEvent.getInstanceDay()), Time.fromMillis(calendarEvent.getStartTime().getTimeInMillis()), true);
|
||||
// new EventListDialogOld(activity).show(app, Date.fromCalendar(calendarEvent.getInstanceDay()), Time.fromMillis(calendarEvent.getStartTime().getTimeInMillis()), true);
|
||||
new EventListDialog(
|
||||
activity,
|
||||
App.profileId,
|
||||
Date.fromCalendar(calendarEvent.getInstanceDay()),
|
||||
Time.fromMillis(calendarEvent.getStartTime().getTimeInMillis()),
|
||||
null,
|
||||
null);
|
||||
} else {
|
||||
new EventListDialog(activity).show(app, Date.fromCalendar(calendarEvent.getInstanceDay()));
|
||||
// new EventListDialogOld(activity).show(app, Date.fromCalendar(calendarEvent.getInstanceDay()));
|
||||
new EventListDialog(
|
||||
activity,
|
||||
App.profileId,
|
||||
Date.fromCalendar(calendarEvent.getInstanceDay()),
|
||||
null,
|
||||
null,
|
||||
null);
|
||||
}
|
||||
} else if (calendarEvent instanceof LessonChangeEvent) {
|
||||
new LessonChangeDialog(activity).show(app, Date.fromCalendar(calendarEvent.getInstanceDay()));
|
||||
@ -401,10 +416,18 @@ public class AgendaFragment extends Fragment {
|
||||
int scrolledDate = dayDate.getValue();
|
||||
if (unreadEventDates.contains(scrolledDate)) {
|
||||
AsyncTask.execute(() -> app.db.eventDao().setSeenByDate(App.profileId, Date.fromYmd(intToStr(scrolledDate)), true));
|
||||
unreadEventDates.remove(unreadEventDates.indexOf(scrolledDate));
|
||||
unreadEventDates.remove((Integer) scrolledDate);
|
||||
}
|
||||
|
||||
new EventListDialog(getContext()).show(app, dayDate);
|
||||
// new EventListDialogOld(getContext()).show(app, dayDate);
|
||||
new EventListDialog(
|
||||
activity,
|
||||
App.profileId,
|
||||
dayDate,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
);
|
||||
});
|
||||
b_calendar.progressBar.setVisibility(View.GONE);
|
||||
});
|
||||
|
@ -58,7 +58,7 @@ public class AnnouncementsFragment extends Fragment {
|
||||
activity.getBottomSheet().prependItems(
|
||||
new BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_mark_as_read)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check_outline)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
AsyncTask.execute(() -> app.db.metadataDao().setAllSeen(App.profileId, TYPE_ANNOUNCEMENT, true));
|
||||
|
@ -95,7 +95,7 @@ public class AttendanceFragment extends Fragment {
|
||||
activity.getBottomSheet().prependItems(
|
||||
new BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_mark_as_read)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check_outline)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
AsyncTask.execute(() -> app.db.metadataDao().setAllSeen(App.profileId, TYPE_ATTENDANCE, true));
|
||||
@ -133,7 +133,7 @@ public class AttendanceFragment extends Fragment {
|
||||
CafeBar.builder(activity)
|
||||
.to(activity.getNavView().getCoordinator())
|
||||
.content(R.string.sync_old_data_info)
|
||||
.icon(new IconicsDrawable(activity).icon(CommunityMaterial.Icon2.cmd_sync).size(IconicsSize.dp(20)).color(IconicsColor.colorInt(Themes.INSTANCE.getPrimaryTextColor(activity))))
|
||||
.icon(new IconicsDrawable(activity).icon(CommunityMaterial.Icon.cmd_download_outline).size(IconicsSize.dp(20)).color(IconicsColor.colorInt(Themes.INSTANCE.getPrimaryTextColor(activity))))
|
||||
.positiveText(R.string.refresh)
|
||||
.positiveColor(0xff4caf50)
|
||||
.negativeText(R.string.ok)
|
||||
|
@ -69,7 +69,7 @@ public class BehaviourFragment extends Fragment {
|
||||
activity.getBottomSheet().prependItems(
|
||||
new BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_mark_as_read)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check_outline)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
AsyncTask.execute(() -> app.db.metadataDao().setAllSeen(App.profileId, TYPE_NOTICE, true));
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user