forked from github/szkolny
[Structure] Refactor App class to Kotlin. Rewrite SzkolnyTask and posting notifications. Remove dependency on AppConfig. Update libraries and gradle.
This commit is contained in:
parent
55c6e40d6d
commit
b7fc6fcc38
@ -2,7 +2,7 @@ apply plugin: 'com.android.library'
|
||||
//apply plugin: 'me.tatarka.retrolambda'
|
||||
|
||||
android {
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
compileSdkVersion setup.compileSdk
|
||||
|
||||
android {
|
||||
lintOptions {
|
||||
@ -12,7 +12,7 @@ android {
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 14
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
targetSdkVersion setup.targetSdk
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
}
|
||||
@ -43,9 +43,9 @@ android {
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
// Google libraries
|
||||
implementation "androidx.appcompat:appcompat:${androidXAppCompat}"
|
||||
implementation "androidx.recyclerview:recyclerview:${androidXRecyclerView}"
|
||||
implementation "com.google.android.material:material:${googleMaterial}"
|
||||
implementation "androidx.appcompat:appcompat:${versions.appcompat}"
|
||||
implementation "androidx.recyclerview:recyclerview:${versions.recyclerView}"
|
||||
implementation "com.google.android.material:material:${versions.material}"
|
||||
|
||||
// other libraries
|
||||
//implementation 'se.emilsjolander:stickylistheaders:2.7.0'
|
||||
|
@ -1,13 +1,14 @@
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
apply plugin: 'io.fabric'
|
||||
|
||||
android {
|
||||
signingConfigs {
|
||||
}
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
compileSdkVersion setup.compileSdk
|
||||
defaultConfig {
|
||||
applicationId 'pl.szczodrzynski.edziennik'
|
||||
minSdkVersion setup.minSdk
|
||||
@ -103,7 +104,7 @@ tasks.whenTaskAdded { task ->
|
||||
dependencies {
|
||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||
|
||||
annotationProcessor "androidx.room:room-compiler:${versions.room}"
|
||||
kapt "androidx.room:room-compiler:${versions.room}"
|
||||
debugImplementation "com.amitshekhar.android:debug-db:1.0.5"
|
||||
|
||||
implementation "android.arch.navigation:navigation-fragment-ktx:${versions.navigationFragment}"
|
||||
|
@ -28,7 +28,7 @@
|
||||
-keepclassmembers class pl.szczodrzynski.edziennik.ui.widgets.WidgetConfig { public *; }
|
||||
-keepnames class pl.szczodrzynski.edziennik.ui.widgets.timetable.WidgetTimetableProvider
|
||||
-keepnames class pl.szczodrzynski.edziennik.ui.widgets.notifications.WidgetNotificationsProvider
|
||||
-keepnames class pl.szczodrzynski.edziennik.widgets.luckynumber.WidgetLuckyNumber
|
||||
-keepnames class pl.szczodrzynski.edziennik.ui.widgets.luckynumber.WidgetLuckyNumberProvider
|
||||
|
||||
-keep class .R
|
||||
-keep class **.R$* {
|
||||
|
@ -80,6 +80,7 @@
|
||||
<service android:name=".ui.widgets.timetable.WidgetTimetableService"
|
||||
android:permission="android.permission.BIND_REMOTEVIEWS" />
|
||||
<activity android:name=".ui.widgets.LessonDialogActivity"
|
||||
android:label=""
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:excludeFromRecents="true"
|
||||
android:noHistory="true"
|
||||
@ -141,12 +142,8 @@
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme" />
|
||||
<activity android:name=".ui.modules.settings.SettingsLicenseActivity"
|
||||
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:theme="@style/AppTheme" />
|
||||
<activity android:name=".ui.modules.webpush.WebPushConfigActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:theme="@style/AppTheme.Dark" />
|
||||
<activity android:name=".ui.modules.webpush.QrScannerActivity" />
|
||||
<activity android:name="com.theartofdev.edmodo.cropper.CropImageActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
@ -165,20 +162,11 @@
|
||||
<action android:name="android.intent.action.USER_PRESENT" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<receiver android:name=".receivers.BootReceiver">
|
||||
<receiver android:name=".sync.UpdateDownloaderService$DownloadProgressReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
<action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
|
||||
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<!--<receiver android:name=".sync.FirebaseBroadcastReceiver"
|
||||
android:exported="true"
|
||||
android:permission="com.google.android.c2dm.permission.SEND">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
|
||||
</intent-filter>
|
||||
</receiver>-->
|
||||
<receiver android:name=".receivers.SzkolnyReceiver"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
@ -200,8 +188,6 @@
|
||||
<action android:name="com.google.firebase.MESSAGING_EVENT" />
|
||||
</intent-filter>
|
||||
</service>-->
|
||||
<service android:name=".receivers.BootReceiver$NotificationActionService" />
|
||||
<service android:name=".Notifier$GetDataRetryService" />
|
||||
<service android:name=".data.api.ApiService" />
|
||||
<service android:name=".data.firebase.MyFirebaseService"
|
||||
android:exported="false">
|
||||
@ -210,6 +196,7 @@
|
||||
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
<service android:name=".sync.UpdateDownloaderService" />
|
||||
|
||||
<!--
|
||||
_____ _ _
|
||||
|
@ -1,4 +1,4 @@
|
||||
<h3>Wersja 4.0-beta.3, 2020-01-10</h3>
|
||||
<h3>Wersja 4.0-beta.4, 2020-01-19</h3>
|
||||
<ul>
|
||||
<li><b>Przebudowaliśmy cały moduł synchronizacji</b>, co oznacza większą stabilność aplikacji, szybkosć oraz poprawność pobieranych danych.</li>
|
||||
<li><b><u>Wysyłanie wiadomości</u></b> - funkcja, na którą czekał każdy. Od teraz w Szkolnym można wysyłać oraz odpowiadać na wiadomości do nauczycieli 👏</li>
|
||||
@ -6,6 +6,7 @@
|
||||
<li>Nowa <b>Strona główna</b> - ładniejszy wygląd oraz możliwość przestawiania kart na każdym profilu</li>
|
||||
<li>Nowy <b>Plan lekcji</b> - z doskonałą obsługą lekcji przesuniętych oraz dwóch lekcji o tej samej godzinie</li>
|
||||
<li>Nowe okienka informacji o wydarzeniach oraz lekcjach</li>
|
||||
<li>Nowe, przyjemniejsze powiadomienia</li>
|
||||
<li>Łatwiejsze dodawanie własnych wydarzeń</li>
|
||||
<li>Dużo poprawek w widoku <b>Wiadomości</b> oraz <b>Ogłoszeń</b></li>
|
||||
<li>Częściowa <b>Obsługa dziennika EduDziennik</b></li>
|
||||
@ -14,7 +15,9 @@
|
||||
<li>Librus: obsługa Zadań domowych bez posiadania Mobilnych dodatków (przez system Synergia)</li>
|
||||
<li>Lepsze <b>przekazywanie powiadomień na komputer</b> oraz łatwiejsze parowanie</li>
|
||||
<li>Poprawiliśmy synchronizację w tle na niektórych telefonach</li>
|
||||
<li>Usunąłem denerwujący brak zaznaczenia w lewym menu</li>
|
||||
<li>Znaczna ilość błędów z poprzednich wersji już nie występuje</li>
|
||||
<li><strike>Występują natomiast nowe błędy, dlatego proszę o ich zgłaszanie :)</strike></li>
|
||||
</ul>
|
||||
<br>
|
||||
<br>
|
||||
|
@ -4,20 +4,93 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik
|
||||
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.pm.ShortcutInfo
|
||||
import android.content.pm.ShortcutManager
|
||||
import android.graphics.drawable.Icon
|
||||
import android.os.Build
|
||||
import android.provider.Settings
|
||||
import android.util.Log
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.multidex.MultiDexApplication
|
||||
import androidx.work.Configuration
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import cat.ereza.customactivityoncrash.config.CaocConfig
|
||||
import com.chuckerteam.chucker.api.ChuckerCollector
|
||||
import com.chuckerteam.chucker.api.ChuckerInterceptor
|
||||
import com.chuckerteam.chucker.api.RetentionManager
|
||||
import com.google.firebase.FirebaseApp
|
||||
import com.google.firebase.FirebaseOptions
|
||||
import com.google.firebase.iid.FirebaseInstanceId
|
||||
import com.google.firebase.messaging.FirebaseMessaging
|
||||
import com.google.gson.Gson
|
||||
import com.hypertrack.hyperlog.HyperLog
|
||||
import com.mikepenz.iconics.Iconics
|
||||
import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont
|
||||
import im.wangchao.mhttp.MHttp
|
||||
import im.wangchao.mhttp.internal.cookie.PersistentCookieJar
|
||||
import im.wangchao.mhttp.internal.cookie.cache.SetCookieCache
|
||||
import im.wangchao.mhttp.internal.cookie.persistence.SharedPrefsCookiePersistor
|
||||
import kotlinx.coroutines.*
|
||||
import me.leolin.shortcutbadger.ShortcutBadger
|
||||
import okhttp3.OkHttpClient
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import pl.szczodrzynski.edziennik.config.Config
|
||||
import pl.szczodrzynski.edziennik.data.api.events.ProfileListEmptyEvent
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.interceptor.Signing
|
||||
import pl.szczodrzynski.edziennik.data.db.AppDb
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.network.NetworkUtils
|
||||
import pl.szczodrzynski.edziennik.sync.SyncWorker
|
||||
import pl.szczodrzynski.edziennik.sync.UpdateWorker
|
||||
import pl.szczodrzynski.edziennik.ui.modules.base.CrashActivity
|
||||
import pl.szczodrzynski.edziennik.utils.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class Szkolny : /*MultiDexApplication(),*/ Configuration.Provider, CoroutineScope {
|
||||
class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
|
||||
companion object {
|
||||
@Volatile
|
||||
lateinit var db: AppDb
|
||||
val config: Config by lazy { Config(db) }
|
||||
var profile: Profile by mutableLazy { Profile(0, 0, 0, "") }
|
||||
val profileId
|
||||
get() = profile.id
|
||||
|
||||
var devMode = false
|
||||
}
|
||||
|
||||
//lateinit var db: AppDb
|
||||
//val config by lazy { Config(db); // TODO migrate }
|
||||
val notifications by lazy { Notifications() }
|
||||
inner class Notifications {
|
||||
val syncId = 1
|
||||
val syncKey = "pl.szczodrzynski.edziennik.SYNC"
|
||||
val syncChannelName: String by lazy { getString(R.string.notification_channel_get_data_name) }
|
||||
val syncChannelDesc: String by lazy { getString(R.string.notification_channel_get_data_desc) }
|
||||
val dataId = 50
|
||||
val dataKey = "pl.szczodrzynski.edziennik.DATA"
|
||||
val dataChannelName: String by lazy { getString(R.string.notification_channel_notifications_name) }
|
||||
val dataChannelDesc: String by lazy { getString(R.string.notification_channel_notifications_desc) }
|
||||
val dataQuietId = 60
|
||||
val dataQuietKey = "pl.szczodrzynski.edziennik.DATA_QUIET"
|
||||
val dataQuietChannelName: String by lazy { getString(R.string.notification_channel_notifications_quiet_name) }
|
||||
val dataQuietChannelDesc: String by lazy { getString(R.string.notification_channel_notifications_quiet_desc) }
|
||||
val updatesId = 100
|
||||
val updatesKey = "pl.szczodrzynski.edziennik.UPDATES"
|
||||
val updatesChannelName: String by lazy { getString(R.string.notification_channel_updates_name) }
|
||||
val updatesChannelDesc: String by lazy { getString(R.string.notification_channel_updates_desc) }
|
||||
}
|
||||
|
||||
val db
|
||||
get() = App.db
|
||||
val config
|
||||
get() = App.config
|
||||
val profile
|
||||
get() = App.profile
|
||||
val profileId
|
||||
get() = App.profileId
|
||||
|
||||
private val job = Job()
|
||||
override val coroutineContext: CoroutineContext
|
||||
@ -26,11 +99,10 @@ class Szkolny : /*MultiDexApplication(),*/ Configuration.Provider, CoroutineScop
|
||||
.setMinimumLoggingLevel(Log.VERBOSE)
|
||||
.build()
|
||||
|
||||
/*val preferences by lazy { getSharedPreferences(getString(R.string.preference_file), Context.MODE_PRIVATE) }
|
||||
val notifier by lazy { Notifier(this) }
|
||||
val preferences by lazy { getSharedPreferences(getString(R.string.preference_file), Context.MODE_PRIVATE) }
|
||||
val permissionChecker by lazy { PermissionChecker(this) }
|
||||
|
||||
lateinit var profile: ProfileFull
|
||||
val networkUtils by lazy { NetworkUtils(this) }
|
||||
val gson by lazy { Gson() }
|
||||
|
||||
/* _ _ _______ _______ _____
|
||||
| | | |__ __|__ __| __ \
|
||||
@ -48,13 +120,13 @@ class Szkolny : /*MultiDexApplication(),*/ Configuration.Provider, CoroutineScop
|
||||
.connectTimeout(20, TimeUnit.SECONDS)
|
||||
.writeTimeout(5, TimeUnit.SECONDS)
|
||||
.readTimeout(10, TimeUnit.SECONDS)
|
||||
builder.installHttpsSupport()
|
||||
builder.installHttpsSupport(this)
|
||||
|
||||
if (devMode || BuildConfig.DEBUG) {
|
||||
HyperLog.initialize(this)
|
||||
HyperLog.setLogLevel(Log.VERBOSE)
|
||||
HyperLog.setLogFormat(DebugLogFormat(this))
|
||||
val chuckerCollector = ChuckerCollector(this, true, Period.ONE_HOUR)
|
||||
val chuckerCollector = ChuckerCollector(this, true, RetentionManager.Period.ONE_HOUR)
|
||||
val chuckerInterceptor = ChuckerInterceptor(this, chuckerCollector)
|
||||
builder.addInterceptor(chuckerInterceptor)
|
||||
}
|
||||
@ -77,22 +149,7 @@ class Szkolny : /*MultiDexApplication(),*/ Configuration.Provider, CoroutineScop
|
||||
|_____/|_|\__, |_| |_|\__,_|\__|\__,_|_| \___|
|
||||
__/ |
|
||||
|__*/
|
||||
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
|
||||
}
|
||||
val deviceId: String by lazy { Settings.Secure.getString(contentResolver, Settings.Secure.ANDROID_ID) ?: "" }
|
||||
private var unreadBadgesAvailable = true
|
||||
|
||||
/* _____ _
|
||||
@ -118,193 +175,214 @@ class Szkolny : /*MultiDexApplication(),*/ Configuration.Provider, CoroutineScop
|
||||
.apply()
|
||||
Iconics.init(applicationContext)
|
||||
Iconics.registerFont(SzkolnyFont)
|
||||
db = AppDb.getDatabase(this)
|
||||
App.db = AppDb(this)
|
||||
Themes.themeInt = config.ui.theme
|
||||
MHttp.instance().customOkHttpClient(http)
|
||||
|
||||
if (!profileLoadById(config.lastProfileId)) {
|
||||
db.profileDao().firstId?.let { profileLoadById(it) }
|
||||
}
|
||||
|
||||
devMode = "f054761fbdb6a238" == deviceId || BuildConfig.DEBUG
|
||||
if (config.devModePassword != null)
|
||||
checkDevModePassword()
|
||||
|
||||
Signing.getCert(this)
|
||||
|
||||
launch { async(Dispatchers.Default) {
|
||||
if (config.sync.enabled) {
|
||||
scheduleNext(this@App, false)
|
||||
} else {
|
||||
cancelNext(this@App)
|
||||
launch {
|
||||
withContext(Dispatchers.Default) {
|
||||
config.migrate(this@App)
|
||||
|
||||
if (config.devModePassword != null)
|
||||
checkDevModePassword()
|
||||
|
||||
if (config.sync.enabled)
|
||||
SyncWorker.scheduleNext(this@App, false)
|
||||
else
|
||||
SyncWorker.cancelNext(this@App)
|
||||
|
||||
if (config.sync.notifyAboutUpdates)
|
||||
UpdateWorker.scheduleNext(this@App, false)
|
||||
else
|
||||
UpdateWorker.cancelNext(this@App)
|
||||
|
||||
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 (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
|
||||
notificationManager.createNotificationChannel(
|
||||
NotificationChannel(notifications.syncKey, notifications.syncChannelName, NotificationManager.IMPORTANCE_MIN).apply {
|
||||
description = notifications.syncChannelDesc
|
||||
})
|
||||
notificationManager.createNotificationChannel(
|
||||
NotificationChannel(notifications.dataKey, notifications.dataChannelName, NotificationManager.IMPORTANCE_HIGH).apply {
|
||||
description = notifications.dataChannelDesc
|
||||
enableLights(true)
|
||||
lightColor = 0xff2196f3.toInt()
|
||||
})
|
||||
notificationManager.createNotificationChannel(
|
||||
NotificationChannel(notifications.dataQuietKey, notifications.dataQuietChannelName, NotificationManager.IMPORTANCE_LOW).apply {
|
||||
description = notifications.dataQuietChannelDesc
|
||||
setSound(null, null)
|
||||
enableVibration(false)
|
||||
})
|
||||
notificationManager.createNotificationChannel(
|
||||
NotificationChannel(notifications.updatesKey, notifications.updatesChannelName, NotificationManager.IMPORTANCE_DEFAULT).apply {
|
||||
description = notifications.updatesChannelDesc
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
if (config.appInstalledTime == 0L)
|
||||
try {
|
||||
config.appInstalledTime = packageManager.getPackageInfo(packageName, 0).firstInstallTime
|
||||
config.appRateSnackbarTime = config.appInstalledTime + 7 * DAY * MS
|
||||
} catch (e: PackageManager.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()
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
private fun profileLoadById(profileId: Int): Boolean {
|
||||
db.profileDao().getByIdNow(profileId)?.also {
|
||||
App.profile = it
|
||||
App.config.lastProfileId = it.id
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
fun profileLoad(profileId: Int, onSuccess: (profile: Profile) -> Unit) {
|
||||
launch {
|
||||
val deferred = async(Dispatchers.Default) {
|
||||
profileLoad(profileId)
|
||||
val success = withContext(Dispatchers.Default) {
|
||||
profileLoadById(profileId)
|
||||
}
|
||||
deferred.await()
|
||||
onSuccess(profile)
|
||||
if (success)
|
||||
onSuccess(profile)
|
||||
else
|
||||
profileLoadLast(onSuccess)
|
||||
}
|
||||
}
|
||||
|
||||
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 profileLoadLast(onSuccess: (profile: Profile) -> Unit) {
|
||||
launch {
|
||||
val success = withContext(Dispatchers.Default) {
|
||||
profileLoadById(db.profileDao().lastId ?: return@withContext false)
|
||||
}
|
||||
if (!success) {
|
||||
EventBus.getDefault().post(ProfileListEmptyEvent())
|
||||
}
|
||||
}
|
||||
}
|
||||
fun profileSave() = profileSave(profile)
|
||||
fun profileSave(profile: Profile) {
|
||||
launch(Dispatchers.Default) {
|
||||
App.db.profileDao().add(profile)
|
||||
}
|
||||
}
|
||||
|
||||
@ -315,5 +393,5 @@ class Szkolny : /*MultiDexApplication(),*/ Configuration.Provider, CoroutineScop
|
||||
e.printStackTrace()
|
||||
false
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
@ -1,91 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-1-19.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.content.pm.ShortcutManager;
|
||||
import android.content.pm.Signature;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.provider.Settings;
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import androidx.work.Configuration;
|
||||
|
||||
import com.chuckerteam.chucker.api.ChuckerCollector;
|
||||
import com.chuckerteam.chucker.api.ChuckerInterceptor;
|
||||
import com.chuckerteam.chucker.api.RetentionManager;
|
||||
import com.google.android.gms.security.ProviderInstaller;
|
||||
import com.google.firebase.FirebaseApp;
|
||||
import com.google.firebase.FirebaseOptions;
|
||||
import com.google.firebase.iid.FirebaseInstanceId;
|
||||
import com.google.firebase.messaging.FirebaseMessaging;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import com.hypertrack.hyperlog.HyperLog;
|
||||
import com.mikepenz.iconics.Iconics;
|
||||
import com.mikepenz.iconics.IconicsColor;
|
||||
import com.mikepenz.iconics.IconicsDrawable;
|
||||
import com.mikepenz.iconics.IconicsSize;
|
||||
import com.mikepenz.iconics.typeface.IIcon;
|
||||
import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.security.KeyStore;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
|
||||
import cat.ereza.customactivityoncrash.config.CaocConfig;
|
||||
import im.wangchao.mhttp.MHttp;
|
||||
import im.wangchao.mhttp.internal.cookie.PersistentCookieJar;
|
||||
import im.wangchao.mhttp.internal.cookie.cache.SetCookieCache;
|
||||
import im.wangchao.mhttp.internal.cookie.persistence.SharedPrefsCookiePersistor;
|
||||
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.api.szkolny.interceptor.Signing;
|
||||
import pl.szczodrzynski.edziennik.data.api.task.EdziennikTask;
|
||||
import pl.szczodrzynski.edziennik.data.db.AppDb;
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.DebugLog;
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile;
|
||||
import pl.szczodrzynski.edziennik.network.NetworkUtils;
|
||||
import pl.szczodrzynski.edziennik.network.TLSSocketFactory;
|
||||
import pl.szczodrzynski.edziennik.sync.SyncWorker;
|
||||
import pl.szczodrzynski.edziennik.ui.modules.base.CrashActivity;
|
||||
import pl.szczodrzynski.edziennik.utils.DebugLogFormat;
|
||||
import pl.szczodrzynski.edziennik.utils.PermissionChecker;
|
||||
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.entity.LoginStore.LOGIN_TYPE_MOBIDZIENNIK;
|
||||
|
||||
public class App extends androidx.multidex.MultiDexApplication implements Configuration.Provider {
|
||||
/*public class AppOld extends androidx.multidex.MultiDexApplication implements Configuration.Provider {
|
||||
private static final String TAG = "App";
|
||||
public static int profileId = -1;
|
||||
private Context mContext;
|
||||
@ -379,36 +298,7 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
|
||||
}
|
||||
}
|
||||
|
||||
/*Task<CapabilityInfo> capabilityInfoTask =
|
||||
Wearable.getCapabilityClient(this)
|
||||
.getCapability("edziennik_wear_app", CapabilityClient.FILTER_REACHABLE);
|
||||
capabilityInfoTask.addOnCompleteListener((task) -> {
|
||||
if (task.isSuccessful()) {
|
||||
CapabilityInfo capabilityInfo = task.getResult();
|
||||
assert capabilityInfo != null;
|
||||
Set<Node> nodes;
|
||||
nodes = capabilityInfo.getNodes();
|
||||
Log.d(TAG, "Nodes "+nodes);
|
||||
|
||||
if (nodes.size() > 0) {
|
||||
Wearable.getMessageClient(this).sendMessage(
|
||||
nodes.toArray(new Node[]{})[0].getId(), "/ping", "Hello world".getBytes());
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG, "Capability request failed to return any results.");
|
||||
}
|
||||
});
|
||||
|
||||
Wearable.getDataClient(this).addListener(dataEventBuffer -> {
|
||||
Log.d(TAG, "onDataChanged(): " + dataEventBuffer);
|
||||
|
||||
for (DataEvent event : dataEventBuffer) {
|
||||
if (event.getType() == DataEvent.TYPE_CHANGED) {
|
||||
String path = event.getDataItem().getUri().getPath();
|
||||
Log.d(TAG, "Data "+path+ " :: "+Arrays.toString(event.getDataItem().getData()));
|
||||
}
|
||||
}
|
||||
});*/
|
||||
|
||||
FirebaseApp pushMobidziennikApp = FirebaseApp.initializeApp(
|
||||
this,
|
||||
@ -498,14 +388,7 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
|
||||
|
||||
if (appSharedPrefs.contains("profiles")) {
|
||||
SharedPreferences.Editor appSharedPrefsEditor = appSharedPrefs.edit();
|
||||
/*List<Integer> appProfileIds = gson.fromJson(appSharedPrefs.getString("profiles", ""), new TypeToken<List<Integer>>(){}.getType());
|
||||
for (int id: appProfileIds) {
|
||||
AppProfile appProfile = gson.fromJson(appSharedPrefs.getString("profile"+id, ""), AppProfile.class);
|
||||
if (appProfile != null) {
|
||||
appConfig.profiles.add(appProfile);
|
||||
}
|
||||
appSharedPrefsEditor.remove("profile"+id);
|
||||
}*/
|
||||
|
||||
appSharedPrefsEditor.remove("profiles");
|
||||
appSharedPrefsEditor.apply();
|
||||
//profilesSave();
|
||||
@ -539,16 +422,6 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
|
||||
}
|
||||
}
|
||||
|
||||
/*if (appConfig.lastAppVersion > BuildConfig.VERSION_CODE) {
|
||||
BootReceiver br = new BootReceiver();
|
||||
Intent i = new Intent();
|
||||
//i.putExtra("UserChecked", true);
|
||||
br.onReceive(getContext(), i);
|
||||
Toast.makeText(mContext, R.string.warning_older_version_running, Toast.LENGTH_LONG).show();
|
||||
//Toast.makeText(mContext, "Zaktualizuj aplikację.", Toast.LENGTH_LONG).show();
|
||||
//System.exit(0);
|
||||
}*/
|
||||
|
||||
if (appConfig == null) {
|
||||
appConfig = new AppConfig(this);
|
||||
}
|
||||
@ -564,15 +437,7 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
|
||||
for (Map.Entry<String, JsonElement> entry : appConfigJson.entrySet()) {
|
||||
String jsonObj;
|
||||
jsonObj = entry.getValue().toString();
|
||||
/*if (entry.getValue().isJsonObject()) {
|
||||
jsonObj = entry.getValue().getAsJsonObject().toString();
|
||||
}
|
||||
else if (entry.getValue().isJsonArray()) {
|
||||
jsonObj = entry.getValue().getAsJsonArray().toString();
|
||||
}
|
||||
else {
|
||||
jsonObj = entry.getValue().toString();
|
||||
}*/
|
||||
|
||||
appSharedPrefsEditor.putString("app.appConfig." + entry.getKey(), jsonObj);
|
||||
}
|
||||
|
||||
@ -628,18 +493,10 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
|
||||
}
|
||||
public void profileLoadById(int id, boolean loadedLast) {
|
||||
//Log.d(TAG, "Loading ID "+id);
|
||||
/*if (profile == null) {
|
||||
profile = profileNew();
|
||||
AppDb.profileId = profile.id;
|
||||
appSharedPrefs.edit().putInt("current_profile_id", profile.id).apply();
|
||||
return;
|
||||
}*/
|
||||
|
||||
if (profile == null || profile.getId() != id) {
|
||||
profile = db.profileDao().getByIdNow(id);
|
||||
/*if (profile == null) {
|
||||
profileLoadById(id);
|
||||
return;
|
||||
}*/
|
||||
|
||||
if (profile != null) {
|
||||
MainActivity.Companion.setUseOldMessages(profile.getLoginStoreType() == LOGIN_TYPE_MOBIDZIENNIK && appConfig.mobidziennikOldMessages == 1);
|
||||
profileId = profile.getId();
|
||||
@ -655,44 +512,6 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
|
||||
}
|
||||
}
|
||||
|
||||
/*public void profileRemove(int id)
|
||||
{
|
||||
Profile profile = db.profileDao().getFullByIdNow(id);
|
||||
|
||||
if (profile.id == profile.loginStoreId) {
|
||||
// this profile is the owner of the login store
|
||||
// we need to check if any other profile is using it
|
||||
List<Integer> transferProfileIds = db.profileDao().getIdsByLoginStoreIdNow(profile.loginStoreId);
|
||||
if (transferProfileIds.size() == 1) {
|
||||
// this login store is free of users, remove it along with the profile
|
||||
db.loginStoreDao().remove(profile.loginStoreId);
|
||||
// the current store is removed, we are ready to remove the profile
|
||||
}
|
||||
else if (transferProfileIds.size() > 1) {
|
||||
transferProfileIds.remove(transferProfileIds.indexOf(profile.id));
|
||||
// someone is using the store
|
||||
// we need to transfer it to the firstProfileId
|
||||
db.loginStoreDao().changeId(profile.loginStoreId, transferProfileIds.get(0));
|
||||
db.profileDao().changeStoreId(profile.loginStoreId, transferProfileIds.get(0));
|
||||
// the current store is removed, we are ready to remove the profile
|
||||
}
|
||||
}
|
||||
// else, the profile uses a store that it doesn't own
|
||||
// leave the store and go on with removing
|
||||
|
||||
Log.d(TAG, "Before removal: "+db.profileDao().getAllNow().toString());
|
||||
db.profileDao().remove(profile.id);
|
||||
Log.d(TAG, "After removal: "+db.profileDao().getAllNow().toString());
|
||||
|
||||
*//*int newId = 1;
|
||||
if (appConfig.profiles.size() > 0) {
|
||||
newId = appConfig.profiles.get(appConfig.profiles.size() - 1).id;
|
||||
}
|
||||
Log.d(TAG, "New ID: "+newId);
|
||||
//Toast.makeText(mContext, "selected new id "+newId, Toast.LENGTH_SHORT).show();
|
||||
profileLoadById(newId);*//*
|
||||
}*/
|
||||
|
||||
public int profileFirstId() {
|
||||
Integer id = db.profileDao().getFirstId();
|
||||
return id == null ? 1 : id;
|
||||
@ -719,4 +538,4 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}*/
|
@ -35,6 +35,7 @@ import androidx.core.util.forEach
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.Observer
|
||||
import com.google.android.gms.security.ProviderInstaller
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonObject
|
||||
@ -42,23 +43,31 @@ import im.wangchao.mhttp.Response
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import okhttp3.ConnectionSpec
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.RequestBody
|
||||
import okhttp3.TlsVersion
|
||||
import okio.Buffer
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Team
|
||||
import pl.szczodrzynski.edziennik.network.TLSSocketFactory
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
import java.io.PrintWriter
|
||||
import java.io.StringWriter
|
||||
import java.math.BigInteger
|
||||
import java.nio.charset.Charset
|
||||
import java.security.KeyStore
|
||||
import java.security.MessageDigest
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import java.util.zip.CRC32
|
||||
import javax.crypto.Mac
|
||||
import javax.crypto.spec.SecretKeySpec
|
||||
import javax.net.ssl.SSLContext
|
||||
import javax.net.ssl.TrustManagerFactory
|
||||
import javax.net.ssl.X509TrustManager
|
||||
import kotlin.Pair
|
||||
|
||||
|
||||
@ -643,6 +652,12 @@ fun Bundle(vararg properties: Pair<String, Any?>): Bundle {
|
||||
}
|
||||
}
|
||||
}
|
||||
fun Intent(action: String? = null, vararg properties: Pair<String, Any?>): Intent {
|
||||
return Intent(action).putExtras(Bundle(*properties))
|
||||
}
|
||||
fun Intent(packageContext: Context, cls: Class<*>, vararg properties: Pair<String, Any?>): Intent {
|
||||
return Intent(packageContext, cls).putExtras(Bundle(*properties))
|
||||
}
|
||||
|
||||
fun Bundle.toJsonObject(): JsonObject {
|
||||
val json = JsonObject()
|
||||
@ -957,6 +972,8 @@ fun Context.getNotificationTitle(type: Int): String {
|
||||
Notification.TYPE_NEW_EVENT -> R.string.notification_type_new_event
|
||||
Notification.TYPE_NEW_HOMEWORK -> R.string.notification_type_new_homework
|
||||
Notification.TYPE_NEW_SHARED_EVENT -> R.string.notification_type_new_shared_event
|
||||
Notification.TYPE_NEW_SHARED_HOMEWORK -> R.string.notification_type_new_shared_homework
|
||||
Notification.TYPE_REMOVED_SHARED_EVENT -> R.string.notification_type_removed_shared_event
|
||||
Notification.TYPE_NEW_MESSAGE -> R.string.notification_type_new_message
|
||||
Notification.TYPE_NEW_NOTICE -> R.string.notification_type_notice
|
||||
Notification.TYPE_NEW_ATTENDANCE -> R.string.notification_type_attendance
|
||||
@ -973,3 +990,37 @@ fun Context.getNotificationTitle(type: Int): String {
|
||||
fun Cursor?.getString(columnName: String) = this?.getStringOrNull(getColumnIndex(columnName))
|
||||
fun Cursor?.getInt(columnName: String) = this?.getIntOrNull(getColumnIndex(columnName))
|
||||
fun Cursor?.getLong(columnName: String) = this?.getLongOrNull(getColumnIndex(columnName))
|
||||
|
||||
fun OkHttpClient.Builder.installHttpsSupport(context: Context) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP_MR1) {
|
||||
try {
|
||||
try {
|
||||
ProviderInstaller.installIfNeeded(context)
|
||||
} 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
package pl.szczodrzynski.edziennik
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.ActivityManager
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
@ -9,7 +8,6 @@ import android.content.IntentFilter
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.os.AsyncTask
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
@ -41,15 +39,16 @@ import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
import pl.droidsonroids.gif.GifDrawable
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask
|
||||
import pl.szczodrzynski.edziennik.data.api.events.*
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.interceptor.Signing
|
||||
import pl.szczodrzynski.edziennik.data.api.task.EdziennikTask
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata.*
|
||||
import pl.szczodrzynski.edziennik.databinding.ActivitySzkolnyBinding
|
||||
import pl.szczodrzynski.edziennik.sync.AppManagerDetectedEvent
|
||||
import pl.szczodrzynski.edziennik.sync.SyncWorker
|
||||
import pl.szczodrzynski.edziennik.sync.UpdateWorker
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.changelog.ChangelogDialog
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.settings.ProfileRemoveDialog
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.sync.SyncViewListDialog
|
||||
@ -269,12 +268,21 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
d(TAG, "Activity created")
|
||||
|
||||
setTheme(Themes.appTheme)
|
||||
|
||||
app.config.ui.language?.let {
|
||||
setLanguage(it)
|
||||
}
|
||||
|
||||
if (App.profileId == 0) {
|
||||
onProfileListEmptyEvent(ProfileListEmptyEvent())
|
||||
return
|
||||
}
|
||||
|
||||
d(TAG, "Profile is valid, inflating views")
|
||||
|
||||
setContentView(b.root)
|
||||
|
||||
Log.d(TAG, Signing.appPassword)
|
||||
@ -344,8 +352,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
setAccountHeaderBackground(app.config.ui.headerBackground)
|
||||
|
||||
drawerProfileListEmptyListener = {
|
||||
app.config.loginFinished = false
|
||||
profileListEmptyListener()
|
||||
onProfileListEmptyEvent(ProfileListEmptyEvent())
|
||||
}
|
||||
drawerItemSelectedListener = { id, position, drawerItem ->
|
||||
loadTarget(id)
|
||||
@ -374,30 +381,19 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
|
||||
navTarget = navTargetList[0]
|
||||
|
||||
var profileListEmpty = drawer.profileListEmpty
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
intent?.putExtras(savedInstanceState)
|
||||
savedInstanceState.clear()
|
||||
}
|
||||
|
||||
if (!profileListEmpty) {
|
||||
handleIntent(intent?.extras)
|
||||
}
|
||||
app.db.profileDao().all.observe(this, Observer { profiles ->
|
||||
drawer.setProfileList(profiles.filter { it.id >= 0 }.toMutableList())
|
||||
if (profileListEmpty) {
|
||||
profileListEmpty = false
|
||||
handleIntent(intent?.extras)
|
||||
}
|
||||
else if (app.profile != null) {
|
||||
drawer.currentProfile = app.profile.id
|
||||
}
|
||||
drawer.currentProfile = App.profileId
|
||||
})
|
||||
|
||||
// if null, getAllFull will load a profile and update drawerItems
|
||||
if (app.profile != null)
|
||||
setDrawerItems()
|
||||
setDrawerItems()
|
||||
|
||||
handleIntent(intent?.extras)
|
||||
|
||||
app.db.metadataDao().unreadCounts.observe(this, Observer { unreadCounters ->
|
||||
unreadCounters.map {
|
||||
@ -417,6 +413,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
isStoragePermissionGranted()
|
||||
|
||||
SyncWorker.scheduleNext(app)
|
||||
UpdateWorker.scheduleNext(app)
|
||||
|
||||
// APP BACKGROUND
|
||||
if (app.config.ui.appBackground != null) {
|
||||
@ -521,13 +518,10 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
}
|
||||
}
|
||||
|
||||
var profileListEmptyListener = {
|
||||
startActivityForResult(Intent(this, LoginActivity::class.java), REQUEST_LOGIN_ACTIVITY)
|
||||
}
|
||||
private var profileSettingClickListener = { id: Int, view: View? ->
|
||||
when (id) {
|
||||
DRAWER_PROFILE_ADD_NEW -> {
|
||||
profileListEmptyListener()
|
||||
startActivityForResult(Intent(this, LoginActivity::class.java), REQUEST_LOGIN_ACTIVITY)
|
||||
}
|
||||
DRAWER_PROFILE_SYNC_ALL -> {
|
||||
EdziennikTask.sync().enqueue(this)
|
||||
@ -587,6 +581,13 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
}
|
||||
}
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onProfileListEmptyEvent(event: ProfileListEmptyEvent) {
|
||||
d(TAG, "Profile list is empty. Launch LoginActivity.")
|
||||
app.config.loginFinished = false
|
||||
startActivity(Intent(this, LoginActivity::class.java))
|
||||
finish()
|
||||
}
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onApiTaskProgressEvent(event: ApiTaskProgressEvent) {
|
||||
if (event.profileId == App.profileId) {
|
||||
navView.toolbar.apply {
|
||||
@ -630,7 +631,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
|
||||
fun onAppManagerDetectedEvent(event: AppManagerDetectedEvent) {
|
||||
EventBus.getDefault().removeStickyEvent(event)
|
||||
if (app.appConfig.dontShowAppManagerDialog)
|
||||
if (app.config.sync.dontShowAppManagerDialog)
|
||||
return
|
||||
MaterialAlertDialogBuilder(this)
|
||||
.setTitle(R.string.app_manager_dialog_title)
|
||||
@ -652,8 +653,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
}
|
||||
}
|
||||
.setNeutralButton(R.string.dont_ask_again) { dialog, which ->
|
||||
app.appConfig.dontShowAppManagerDialog = true
|
||||
app.saveConfig("dontShowAppManagerDialog")
|
||||
app.config.sync.dontShowAppManagerDialog = true
|
||||
}
|
||||
.setCancelable(false)
|
||||
.show()
|
||||
@ -698,7 +698,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
if (extras?.containsKey("reloadProfileId") == true) {
|
||||
val reloadProfileId = extras.getInt("reloadProfileId", -1)
|
||||
extras.remove("reloadProfileId")
|
||||
if (reloadProfileId == -1 || (app.profile != null && app.profile.id == reloadProfileId)) {
|
||||
if (reloadProfileId == -1 || app.profile.id == reloadProfileId) {
|
||||
reloadTarget()
|
||||
return
|
||||
}
|
||||
@ -728,9 +728,9 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
}
|
||||
|
||||
when {
|
||||
app.profile == null || app.profile.id == -1 -> {
|
||||
app.profile.id == 0 -> {
|
||||
if (intentProfileId == -1)
|
||||
intentProfileId = app.appSharedPrefs.getInt("current_profile_id", 1)
|
||||
intentProfileId = app.config.lastProfileId
|
||||
loadProfile(intentProfileId, intentTargetId, extras)
|
||||
}
|
||||
intentProfileId != -1 -> {
|
||||
@ -769,7 +769,16 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
startActivity(intent)
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
d(TAG, "Activity started")
|
||||
super.onStart()
|
||||
}
|
||||
override fun onStop() {
|
||||
d(TAG, "Activity stopped")
|
||||
super.onStop()
|
||||
}
|
||||
override fun onResume() {
|
||||
d(TAG, "Activity resumed")
|
||||
val filter = IntentFilter()
|
||||
filter.addAction(Intent.ACTION_MAIN)
|
||||
registerReceiver(intentReceiver, filter)
|
||||
@ -777,10 +786,15 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
super.onResume()
|
||||
}
|
||||
override fun onPause() {
|
||||
d(TAG, "Activity paused")
|
||||
unregisterReceiver(intentReceiver)
|
||||
EventBus.getDefault().unregister(this)
|
||||
super.onPause()
|
||||
}
|
||||
override fun onDestroy() {
|
||||
d(TAG, "Activity destroyed")
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
@ -794,15 +808,10 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (requestCode == REQUEST_LOGIN_ACTIVITY) {
|
||||
if (resultCode == Activity.RESULT_CANCELED && false) {
|
||||
if (!app.config.loginFinished)
|
||||
finish()
|
||||
}
|
||||
else {
|
||||
if (!app.config.loginFinished)
|
||||
finish()
|
||||
else {
|
||||
handleIntent(data?.extras)
|
||||
}
|
||||
handleIntent(data?.extras)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -823,34 +832,23 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
fun loadProfile(id: Int) = loadProfile(id, navTargetId)
|
||||
fun loadProfile(id: Int, arguments: Bundle?) = loadProfile(id, navTargetId, arguments)
|
||||
fun loadProfile(id: Int, drawerSelection: Int, arguments: Bundle? = null) {
|
||||
//d("NavDebug", "loadProfile(id = $id, drawerSelection = $drawerSelection)")
|
||||
if (app.profile != null && App.profileId == id) {
|
||||
if (App.profileId == id) {
|
||||
drawer.currentProfile = app.profile.id
|
||||
loadTarget(drawerSelection, arguments)
|
||||
return
|
||||
}
|
||||
AsyncTask.execute {
|
||||
app.profileLoadById(id)
|
||||
app.profileLoad(id) {
|
||||
MessagesFragment.pageSelection = -1
|
||||
MessagesListFragment.tapPositions = intArrayOf(RecyclerView.NO_POSITION, RecyclerView.NO_POSITION)
|
||||
MessagesListFragment.topPositions = intArrayOf(RecyclerView.NO_POSITION, RecyclerView.NO_POSITION)
|
||||
MessagesListFragment.bottomPositions = intArrayOf(RecyclerView.NO_POSITION, RecyclerView.NO_POSITION)
|
||||
|
||||
this.runOnUiThread {
|
||||
if (app.profile == null) {
|
||||
if (app.config.loginFinished) {
|
||||
// this shouldn't run
|
||||
profileListEmptyListener()
|
||||
}
|
||||
} else {
|
||||
setDrawerItems()
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
setDrawerItems()
|
||||
// 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.profileId
|
||||
loadTarget(drawerSelection, arguments)
|
||||
}
|
||||
}
|
||||
fun loadTarget(id: Int, arguments: Bundle? = null) {
|
||||
@ -995,7 +993,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
* that something has changed in the bottom sheet.
|
||||
*/
|
||||
fun gainAttention() {
|
||||
if (app.config.ui.bottomSheetOpened || true)
|
||||
if (app.config.ui.bottomSheetOpened)
|
||||
return
|
||||
b.navView.postDelayed({
|
||||
navView.gainAttentionOnBottomBar()
|
||||
@ -1044,12 +1042,11 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
}
|
||||
|
||||
fun setDrawerItems() {
|
||||
d("NavDebug", "setDrawerItems() app.profile = ${app.profile ?: "null"}")
|
||||
d("NavDebug", "setDrawerItems() app.profile = ${app.profile}")
|
||||
val drawerItems = arrayListOf<IDrawerItem<*>>()
|
||||
val drawerProfiles = arrayListOf<ProfileSettingDrawerItem>()
|
||||
|
||||
val supportedFragments = if (app.profile == null) arrayListOf<Int>()
|
||||
else app.profile.supportedFragments
|
||||
val supportedFragments = app.profile.supportedFragments
|
||||
|
||||
targetPopToHomeList.clear()
|
||||
|
||||
@ -1113,7 +1110,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
private var targetHomeId: Int = -1
|
||||
override fun onBackPressed() {
|
||||
if (!b.navView.onBackPressed()) {
|
||||
if (App.getConfig().ui.openDrawerOnBackPressed) {
|
||||
if (App.config.ui.openDrawerOnBackPressed) {
|
||||
b.navView.drawer.toggle()
|
||||
} else {
|
||||
navigateUp()
|
||||
|
@ -1,350 +0,0 @@
|
||||
package pl.szczodrzynski.edziennik;
|
||||
|
||||
import android.app.IntentService;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import pl.szczodrzynski.edziennik.receivers.BootReceiver;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time;
|
||||
|
||||
import static androidx.core.app.NotificationCompat.PRIORITY_DEFAULT;
|
||||
import static androidx.core.app.NotificationCompat.PRIORITY_MAX;
|
||||
|
||||
public class Notifier {
|
||||
|
||||
private static final String TAG = "Notifier";
|
||||
public static final int ID_GET_DATA = 1337000;
|
||||
public static final int ID_GET_DATA_ERROR = 1337001;
|
||||
private static String CHANNEL_GET_DATA_NAME;
|
||||
private static String CHANNEL_GET_DATA_DESC;
|
||||
private static final String GROUP_KEY_GET_DATA = "pl.szczodrzynski.edziennik.GET_DATA";
|
||||
|
||||
public static final int ID_NOTIFICATIONS = 1337002;
|
||||
public static String CHANNEL_NOTIFICATIONS_NAME;
|
||||
public static String CHANNEL_NOTIFICATIONS_DESC;
|
||||
public static final String GROUP_KEY_NOTIFICATIONS = "pl.szczodrzynski.edziennik.NOTIFICATIONS";
|
||||
|
||||
public static final int ID_NOTIFICATIONS_QUIET = 1337002;
|
||||
public static String CHANNEL_NOTIFICATIONS_QUIET_NAME;
|
||||
public static String CHANNEL_NOTIFICATIONS_QUIET_DESC;
|
||||
public static final String GROUP_KEY_NOTIFICATIONS_QUIET = "pl.szczodrzynski.edziennik.NOTIFICATIONS_QUIET";
|
||||
|
||||
private static final int ID_UPDATES = 1337003;
|
||||
private static String CHANNEL_UPDATES_NAME;
|
||||
private static String CHANNEL_UPDATES_DESC;
|
||||
private static final String GROUP_KEY_UPDATES = "pl.szczodrzynski.edziennik.UPDATES";
|
||||
|
||||
private App app;
|
||||
public NotificationManager notificationManager;
|
||||
private NotificationCompat.Builder getDataNotificationBuilder;
|
||||
public int notificationColor;
|
||||
|
||||
Notifier(App _app) {
|
||||
this.app = _app;
|
||||
|
||||
CHANNEL_GET_DATA_NAME = app.getString(R.string.notification_channel_get_data_name);
|
||||
CHANNEL_GET_DATA_DESC = app.getString(R.string.notification_channel_get_data_desc);
|
||||
CHANNEL_NOTIFICATIONS_NAME = app.getString(R.string.notification_channel_notifications_name);
|
||||
CHANNEL_NOTIFICATIONS_DESC = app.getString(R.string.notification_channel_notifications_desc);
|
||||
CHANNEL_NOTIFICATIONS_QUIET_NAME = app.getString(R.string.notification_channel_notifications_quiet_name);
|
||||
CHANNEL_NOTIFICATIONS_QUIET_DESC = app.getString(R.string.notification_channel_notifications_quiet_desc);
|
||||
CHANNEL_UPDATES_NAME = app.getString(R.string.notification_channel_updates_name);
|
||||
CHANNEL_UPDATES_DESC = app.getString(R.string.notification_channel_updates_desc);
|
||||
|
||||
notificationColor = ContextCompat.getColor(app.getContext(), R.color.colorPrimary);
|
||||
notificationManager = (NotificationManager) app.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
NotificationChannel channelGetData = new NotificationChannel(GROUP_KEY_GET_DATA, CHANNEL_GET_DATA_NAME, NotificationManager.IMPORTANCE_MIN);
|
||||
channelGetData.setDescription(CHANNEL_GET_DATA_DESC);
|
||||
notificationManager.createNotificationChannel(channelGetData);
|
||||
|
||||
NotificationChannel channelNotifications = new NotificationChannel(GROUP_KEY_NOTIFICATIONS, CHANNEL_NOTIFICATIONS_NAME, NotificationManager.IMPORTANCE_HIGH);
|
||||
channelNotifications.setDescription(CHANNEL_NOTIFICATIONS_DESC);
|
||||
channelNotifications.enableLights(true);
|
||||
channelNotifications.setLightColor(notificationColor);
|
||||
notificationManager.createNotificationChannel(channelNotifications);
|
||||
|
||||
NotificationChannel channelNotificationsQuiet = new NotificationChannel(GROUP_KEY_NOTIFICATIONS_QUIET, CHANNEL_NOTIFICATIONS_QUIET_NAME, NotificationManager.IMPORTANCE_DEFAULT);
|
||||
channelNotificationsQuiet.setDescription(CHANNEL_NOTIFICATIONS_QUIET_DESC);
|
||||
channelNotificationsQuiet.setSound(null, null);
|
||||
channelNotificationsQuiet.enableVibration(false);
|
||||
notificationManager.createNotificationChannel(channelNotificationsQuiet);
|
||||
|
||||
NotificationChannel channelUpdates = new NotificationChannel(GROUP_KEY_UPDATES, CHANNEL_UPDATES_NAME, NotificationManager.IMPORTANCE_HIGH);
|
||||
channelUpdates.setDescription(CHANNEL_UPDATES_DESC);
|
||||
notificationManager.createNotificationChannel(channelUpdates);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean shouldBeQuiet() {
|
||||
long now = Time.getNow().getInMillis();
|
||||
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");
|
||||
}
|
||||
if (start > now) {
|
||||
now += 1000 * 60 * 60 * 24;
|
||||
//Log.d(TAG, "Now is smaller");
|
||||
}
|
||||
//Log.d(TAG, "Start is "+start+", now is "+now+", end is "+end);
|
||||
return start > 0 && now >= start && now <= end;
|
||||
}
|
||||
|
||||
public int getNotificationDefaults() {
|
||||
return (shouldBeQuiet() ? 0 : Notification.DEFAULT_ALL);
|
||||
}
|
||||
public String getNotificationGroup() {
|
||||
return shouldBeQuiet() ? GROUP_KEY_NOTIFICATIONS_QUIET : GROUP_KEY_NOTIFICATIONS;
|
||||
}
|
||||
public int getNotificationPriority() {
|
||||
return shouldBeQuiet() ? PRIORITY_DEFAULT : PRIORITY_MAX;
|
||||
}
|
||||
|
||||
/* _____ _ _____ _
|
||||
| __ \ | | / ____| | |
|
||||
| | | | __ _| |_ __ _ | | __ ___| |_
|
||||
| | | |/ _` | __/ _` | | | |_ |/ _ \ __|
|
||||
| |__| | (_| | || (_| | | |__| | __/ |_
|
||||
|_____/ \__,_|\__\__,_| \_____|\___|\_*/
|
||||
public Notification notificationGetDataShow(int maxProgress) {
|
||||
/*Intent notificationIntent = new Intent(app.getContext(), SyncService.class);
|
||||
notificationIntent.setAction(ACTION_CANCEL);
|
||||
PendingIntent pendingIntent = PendingIntent.getService(app.getContext(), 0,
|
||||
notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);*/
|
||||
|
||||
getDataNotificationBuilder = new NotificationCompat.Builder(app, GROUP_KEY_GET_DATA)
|
||||
.setSmallIcon(android.R.drawable.stat_sys_download)
|
||||
.setColor(notificationColor)
|
||||
.setContentTitle(app.getString(R.string.notification_get_data_title))
|
||||
.setContentText(app.getString(R.string.notification_get_data_text))
|
||||
//.addAction(R.drawable.ic_notification, app.getString(R.string.notification_get_data_cancel), pendingIntent)
|
||||
//.setGroup(GROUP_KEY_GET_DATA)
|
||||
.setOngoing(true)
|
||||
.setProgress(maxProgress, 0, false)
|
||||
.setTicker(app.getString(R.string.notification_get_data_summary))
|
||||
.setPriority(NotificationCompat.PRIORITY_LOW);
|
||||
return getDataNotificationBuilder.build();
|
||||
}
|
||||
|
||||
public Notification notificationGetDataProgress(int progress, int maxProgress) {
|
||||
getDataNotificationBuilder.setProgress(maxProgress, progress, false);
|
||||
return getDataNotificationBuilder.build();
|
||||
}
|
||||
|
||||
public Notification notificationGetDataAction(int stringResId) {
|
||||
getDataNotificationBuilder.setContentTitle(app.getString(R.string.sync_action_format, app.getString(stringResId)));
|
||||
return getDataNotificationBuilder.build();
|
||||
}
|
||||
|
||||
public Notification notificationGetDataProfile(String profileName) {
|
||||
getDataNotificationBuilder.setContentText(profileName);
|
||||
return getDataNotificationBuilder.build();
|
||||
}
|
||||
|
||||
public Notification notificationGetDataError(String profileName, String error, int failedProfileId) {
|
||||
Intent notificationIntent = new Intent(app.getContext(), Notifier.GetDataRetryService.class);
|
||||
notificationIntent.putExtra("failedProfileId", failedProfileId);
|
||||
PendingIntent pendingIntent = PendingIntent.getService(app.getContext(), 0,
|
||||
notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
|
||||
getDataNotificationBuilder.mActions.clear();
|
||||
/*try {
|
||||
//Use reflection clean up old actions
|
||||
Field f = getDataNotificationBuilder.getClass().getDeclaredField("mActions");
|
||||
f.setAccessible(true);
|
||||
f.set(getDataNotificationBuilder, new ArrayList<NotificationCompat.Action>());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}*/
|
||||
|
||||
getDataNotificationBuilder.setProgress(0, 0, false)
|
||||
.setTicker(app.getString(R.string.notification_get_data_error_summary))
|
||||
.setSmallIcon(android.R.drawable.stat_sys_warning)
|
||||
.addAction(R.drawable.ic_notification, app.getString(R.string.notification_get_data_once_again), pendingIntent)
|
||||
.setContentTitle(app.getString(R.string.notification_get_data_error_title, profileName))
|
||||
.setContentText(error)
|
||||
.setStyle(new NotificationCompat.BigTextStyle().bigText(error))
|
||||
.setOngoing(false);
|
||||
return getDataNotificationBuilder.build();
|
||||
}
|
||||
|
||||
public void notificationPost(int id, Notification notification) {
|
||||
notificationManager.notify(id, notification);
|
||||
}
|
||||
|
||||
public void notificationCancel(int id) {
|
||||
notificationManager.cancel(id);
|
||||
}
|
||||
|
||||
//public void notificationGetDataHide() {
|
||||
// notificationManager.cancel(ID_GET_DATA);
|
||||
// }
|
||||
|
||||
public static class GetDataRetryService extends IntentService {
|
||||
private static final String TAG = "Notifier/GetDataRetry";
|
||||
|
||||
public GetDataRetryService() {
|
||||
super(Notifier.GetDataRetryService.class.getSimpleName());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onHandleIntent(Intent intent) {
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* _ _ _ _ __ _ _ _
|
||||
| \ | | | | (_)/ _(_) | | (_)
|
||||
| \| | ___ | |_ _| |_ _ ___ __ _| |_ _ ___ _ __
|
||||
| . ` |/ _ \| __| | _| |/ __/ _` | __| |/ _ \| '_ \
|
||||
| |\ | (_) | |_| | | | | (_| (_| | |_| | (_) | | | |
|
||||
|_| \_|\___/ \__|_|_| |_|\___\__,_|\__|_|\___/|_| |*/
|
||||
public void add(pl.szczodrzynski.edziennik.utils.models.Notification notification) {
|
||||
app.appConfig.notifications.add(notification);
|
||||
}
|
||||
|
||||
public void postAll() {
|
||||
Collections.sort(app.appConfig.notifications, (o1, o2) -> (o2.addedDate - o1.addedDate > 0) ? 1 : (o2.addedDate - o1.addedDate < 0) ? -1 : 0);
|
||||
|
||||
if (app.appConfig.notifications.size() > 40) {
|
||||
app.appConfig.notifications.subList(40, app.appConfig.notifications.size() - 1).clear();
|
||||
}
|
||||
|
||||
int unreadCount = 0;
|
||||
List<pl.szczodrzynski.edziennik.utils.models.Notification> notificationList = new ArrayList<>();
|
||||
for (pl.szczodrzynski.edziennik.utils.models.Notification notification: app.appConfig.notifications) {
|
||||
if (!notification.notified) {
|
||||
notification.seen = false;
|
||||
notification.notified = true;
|
||||
unreadCount++;
|
||||
if (notificationList.size() < 10) {
|
||||
notificationList.add(notification);
|
||||
}
|
||||
}
|
||||
else {
|
||||
notification.seen = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (pl.szczodrzynski.edziennik.utils.models.Notification notification: notificationList) {
|
||||
Intent intent = new Intent(app, MainActivity.class);
|
||||
notification.fillIntent(intent);
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(app, notification.id, intent, 0);
|
||||
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(app, getNotificationGroup())
|
||||
// title, text, type, date
|
||||
.setContentTitle(notification.title)
|
||||
.setContentText(notification.text)
|
||||
.setSubText(pl.szczodrzynski.edziennik.utils.models.Notification.stringType(app, notification.type))
|
||||
.setWhen(notification.addedDate)
|
||||
.setTicker(app.getString(R.string.notification_ticker_format, pl.szczodrzynski.edziennik.utils.models.Notification.stringType(app, notification.type)))
|
||||
// icon, color, lights, priority
|
||||
.setSmallIcon(R.drawable.ic_notification)
|
||||
.setColor(notificationColor)
|
||||
.setLights(0xFF00FFFF, 2000, 2000)
|
||||
.setPriority(getNotificationPriority())
|
||||
// channel, group, style
|
||||
.setChannelId(getNotificationGroup())
|
||||
.setGroup(getNotificationGroup())
|
||||
.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_SUMMARY)
|
||||
.setStyle(new NotificationCompat.BigTextStyle().bigText(notification.text))
|
||||
// intent, auto cancel
|
||||
.setContentIntent(pendingIntent)
|
||||
.setAutoCancel(true);
|
||||
if (!shouldBeQuiet()) {
|
||||
notificationBuilder.setDefaults(getNotificationDefaults());
|
||||
}
|
||||
notificationManager.notify(notification.id, notificationBuilder.build());
|
||||
}
|
||||
|
||||
if (notificationList.size() > 0 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
Intent intent = new Intent(app, MainActivity.class);
|
||||
intent.setAction("android.intent.action.MAIN");
|
||||
intent.putExtra("fragmentId", MainActivity.DRAWER_ITEM_NOTIFICATIONS);
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(app, ID_NOTIFICATIONS,
|
||||
intent, 0);
|
||||
|
||||
NotificationCompat.Builder groupBuilder =
|
||||
new NotificationCompat.Builder(app, getNotificationGroup())
|
||||
.setSmallIcon(R.drawable.ic_notification)
|
||||
.setColor(notificationColor)
|
||||
.setContentTitle(app.getString(R.string.notification_new_notification_title_format, unreadCount))
|
||||
.setGroupSummary(true)
|
||||
.setAutoCancel(true)
|
||||
.setChannelId(getNotificationGroup())
|
||||
.setGroup(getNotificationGroup())
|
||||
.setLights(0xFF00FFFF, 2000, 2000)
|
||||
.setPriority(getNotificationPriority())
|
||||
.setContentIntent(pendingIntent)
|
||||
.setStyle(new NotificationCompat.BigTextStyle());
|
||||
if (!shouldBeQuiet()) {
|
||||
groupBuilder.setDefaults(getNotificationDefaults());
|
||||
}
|
||||
notificationManager.notify(ID_NOTIFICATIONS, groupBuilder.build());
|
||||
}
|
||||
}
|
||||
|
||||
/* _ _ _ _
|
||||
| | | | | | | |
|
||||
| | | |_ __ __| | __ _| |_ ___ ___
|
||||
| | | | '_ \ / _` |/ _` | __/ _ \/ __|
|
||||
| |__| | |_) | (_| | (_| | || __/\__ \
|
||||
\____/| .__/ \__,_|\__,_|\__\___||___/
|
||||
| |
|
||||
|*/
|
||||
public void notificationUpdatesShow(String updateVersion, String updateUrl, String updateFilename, boolean updateDirect) {
|
||||
if (!app.config.getSync().getNotifyAboutUpdates())
|
||||
return;
|
||||
Intent notificationIntent = new Intent(app.getContext(), BootReceiver.NotificationActionService.class)
|
||||
.putExtra("update_version", updateVersion)
|
||||
.putExtra("update_url", updateUrl)
|
||||
.putExtra("update_filename", updateFilename)
|
||||
.putExtra("update_direct", updateDirect);
|
||||
|
||||
PendingIntent pendingIntent = PendingIntent.getService(app.getContext(), 0,
|
||||
notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
|
||||
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(app, GROUP_KEY_UPDATES)
|
||||
.setSmallIcon(android.R.drawable.stat_sys_download_done)
|
||||
.setColor(notificationColor)
|
||||
.setContentTitle(app.getString(R.string.notification_updates_title))
|
||||
.setContentText(app.getString(R.string.notification_updates_text, updateVersion))
|
||||
.setLights(0xFF00FFFF, 2000, 2000)
|
||||
.setContentIntent(pendingIntent)
|
||||
.setTicker(app.getString(R.string.notification_updates_summary))
|
||||
.setPriority(PRIORITY_MAX)
|
||||
.setAutoCancel(true);
|
||||
if (!shouldBeQuiet()) {
|
||||
notificationBuilder.setDefaults(getNotificationDefaults());
|
||||
}
|
||||
notificationManager.notify(ID_UPDATES, notificationBuilder.build());
|
||||
}
|
||||
|
||||
public void notificationUpdatesHide() {
|
||||
if (!app.config.getSync().getNotifyAboutUpdates())
|
||||
return;
|
||||
notificationManager.cancel(ID_UPDATES);
|
||||
}
|
||||
|
||||
public void dump() {
|
||||
for (pl.szczodrzynski.edziennik.utils.models.Notification notification: app.appConfig.notifications) {
|
||||
Log.d(TAG, "Profile"+notification.profileId+" Notification from "+ Date.fromMillis(notification.addedDate).getFormattedString()+" "+ Time.fromMillis(notification.addedDate).getStringHMS()+" - "+notification.text);
|
||||
}
|
||||
}
|
||||
}
|
@ -16,12 +16,13 @@ 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.api.szkolny.response.Update
|
||||
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
|
||||
const val DATA_VERSION = 10
|
||||
}
|
||||
|
||||
private val job = Job()
|
||||
@ -45,6 +46,20 @@ class Config(val db: AppDb) : CoroutineScope, AbstractConfig {
|
||||
get() { mHash = mHash ?: values.get("hash", ""); return mHash ?: "" }
|
||||
set(value) { set("hash", value); mHash = value }
|
||||
|
||||
private var mLastProfileId: Int? = null
|
||||
var lastProfileId: Int
|
||||
get() { mLastProfileId = mLastProfileId ?: values.get("lastProfileId", 0); return mLastProfileId ?: 0 }
|
||||
set(value) { set("lastProfileId", value); mLastProfileId = value }
|
||||
|
||||
private var mUpdatesChannel: String? = null
|
||||
var updatesChannel: String
|
||||
get() { mUpdatesChannel = mUpdatesChannel ?: values.get("updatesChannel", "release"); return mUpdatesChannel ?: "release" }
|
||||
set(value) { set("updatesChannel", value); mUpdatesChannel = value }
|
||||
private var mUpdate: Update? = null
|
||||
var update: Update?
|
||||
get() { mUpdate = mUpdate ?: values.get("update", null as Update?); return mUpdate ?: null as Update? }
|
||||
set(value) { set("update", value); mUpdate = value }
|
||||
|
||||
private var mAppVersion: Int? = null
|
||||
var appVersion: Int
|
||||
get() { mAppVersion = mAppVersion ?: values.get("appVersion", BuildConfig.VERSION_CODE); return mAppVersion ?: BuildConfig.VERSION_CODE }
|
||||
|
@ -17,6 +17,6 @@ class ConfigGrades(private val config: Config) {
|
||||
|
||||
private var mOrderBy: Int? = null
|
||||
var orderBy: Int
|
||||
get() { mOrderBy = mOrderBy ?: config.values.get("gradesOrderBy", 0); return mOrderBy ?: 0 }
|
||||
get() { mOrderBy = mOrderBy ?: config.values.get("gradesOrderBy", 0); return mOrderBy ?: ORDER_BY_DATE_DESC }
|
||||
set(value) { config.set("gradesOrderBy", value); mOrderBy = value }
|
||||
}
|
@ -9,6 +9,11 @@ import pl.szczodrzynski.edziennik.config.utils.getIntList
|
||||
import pl.szczodrzynski.edziennik.config.utils.set
|
||||
|
||||
class ConfigSync(private val config: Config) {
|
||||
private var mDontShowAppManagerDialog: Boolean? = null
|
||||
var dontShowAppManagerDialog: Boolean
|
||||
get() { mDontShowAppManagerDialog = mDontShowAppManagerDialog ?: config.values.get("dontShowAppManagerDialog", false); return mDontShowAppManagerDialog ?: false }
|
||||
set(value) { config.set("dontShowAppManagerDialog", value); mDontShowAppManagerDialog = value }
|
||||
|
||||
private var mSyncEnabled: Boolean? = null
|
||||
var enabled: Boolean
|
||||
get() { mSyncEnabled = mSyncEnabled ?: config.values.get("syncEnabled", true); return mSyncEnabled ?: true }
|
||||
|
@ -45,11 +45,6 @@ class ConfigUI(private val config: Config) {
|
||||
get() { mOpenDrawerOnBackPressed = mOpenDrawerOnBackPressed ?: config.values.get("openDrawerOnBackPressed", false); return mOpenDrawerOnBackPressed ?: false }
|
||||
set(value) { config.set("openDrawerOnBackPressed", value); mOpenDrawerOnBackPressed = 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() }
|
||||
|
@ -9,6 +9,7 @@ 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.ProfileConfigMigration
|
||||
import pl.szczodrzynski.edziennik.config.utils.get
|
||||
import pl.szczodrzynski.edziennik.config.utils.set
|
||||
import pl.szczodrzynski.edziennik.config.utils.toHashMap
|
||||
@ -27,6 +28,7 @@ class ProfileConfig(val db: AppDb, val profileId: Int, rawEntries: List<ConfigEn
|
||||
val values: HashMap<String, String?> = hashMapOf()
|
||||
|
||||
val grades by lazy { ProfileConfigGrades(this) }
|
||||
val ui by lazy { ProfileConfigUI(this) }
|
||||
/*
|
||||
val sync by lazy { ConfigSync(this) }
|
||||
val timetable by lazy { ConfigTimetable(this) }
|
||||
@ -44,8 +46,8 @@ class ProfileConfig(val db: AppDb, val profileId: Int, rawEntries: List<ConfigEn
|
||||
|
||||
init {
|
||||
rawEntries.toHashMap(profileId, values)
|
||||
/*if (dataVersion < DATA_VERSION)
|
||||
ProfileConfigMigration(this)*/
|
||||
if (dataVersion < DATA_VERSION)
|
||||
ProfileConfigMigration(this)
|
||||
}
|
||||
|
||||
override fun set(key: String, value: String?) {
|
||||
|
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-1-19.
|
||||
*/
|
||||
|
||||
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.entity.Profile.Companion.AGENDA_DEFAULT
|
||||
|
||||
class ProfileConfigUI(private val config: ProfileConfig) {
|
||||
private var mAgendaViewType: Int? = null
|
||||
var agendaViewType: Int
|
||||
get() { mAgendaViewType = mAgendaViewType ?: config.values.get("agendaViewType", 0); return mAgendaViewType ?: AGENDA_DEFAULT }
|
||||
set(value) { config.set("agendaViewType", value); mAgendaViewType = value }
|
||||
}
|
@ -22,4 +22,7 @@ interface ConfigDao {
|
||||
|
||||
@Query("SELECT * FROM config WHERE profileId = :profileId")
|
||||
fun getAllNow(profileId: Int): List<ConfigEntry>
|
||||
|
||||
@Query("DELETE FROM config WHERE profileId = :profileId")
|
||||
fun clear(profileId: Int)
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-1-19.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.config.utils
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import pl.szczodrzynski.edziennik.BuildConfig
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.config.Config
|
||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_LIBRUS
|
||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_MOBIDZIENNIK
|
||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_VULCAN
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
|
||||
class AppConfigMigrationV3(p: SharedPreferences, config: Config) {
|
||||
init { config.apply {
|
||||
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.registerSyncInterval", 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 }
|
||||
}
|
||||
}
|
@ -37,6 +37,9 @@ fun AbstractConfig.set(key: String, value: JsonElement?) {
|
||||
fun AbstractConfig.set(key: String, value: List<Any>?) {
|
||||
set(key, value?.let { gson.toJson(it) })
|
||||
}
|
||||
fun AbstractConfig.set(key: String, value: Any?) {
|
||||
set(key, value?.let { gson.toJson(it) })
|
||||
}
|
||||
fun AbstractConfig.setStringList(key: String, value: List<String>?) {
|
||||
set(key, value?.let { gson.toJson(it) })
|
||||
}
|
||||
@ -74,6 +77,9 @@ fun HashMap<String, String?>.get(key: String, default: JsonObject?): JsonObject?
|
||||
fun HashMap<String, String?>.get(key: String, default: JsonArray?): JsonArray? {
|
||||
return this[key]?.let { JsonParser().parse(it)?.asJsonArray } ?: default
|
||||
}
|
||||
inline fun <reified T> HashMap<String, String?>.get(key: String, default: T?): T? {
|
||||
return this[key]?.let { Gson().fromJson(it, T::class.java) } ?: 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
|
||||
|
@ -5,32 +5,32 @@
|
||||
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.HOUR
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_LIBRUS
|
||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_MOBIDZIENNIK
|
||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_VULCAN
|
||||
import pl.szczodrzynski.edziennik.config.Config
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
import pl.szczodrzynski.edziennik.config.ConfigGrades.Companion.ORDER_BY_DATE_DESC
|
||||
|
||||
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(
|
||||
val p = app.getSharedPreferences("pl.szczodrzynski.edziennik_profiles", Context.MODE_PRIVATE)
|
||||
if (p.contains("app.appConfig.appTheme")) {
|
||||
// migrate appConfig from app version 3.x and lower.
|
||||
// Updates dataVersion to level 2.
|
||||
AppConfigMigrationV3(p, config)
|
||||
}
|
||||
|
||||
if (dataVersion < 2) {
|
||||
appVersion = BuildConfig.VERSION_CODE
|
||||
loginFinished = false
|
||||
ui.language = null
|
||||
ui.theme = 1
|
||||
ui.appBackground = null
|
||||
ui.headerBackground = null
|
||||
ui.miniMenuVisible = false
|
||||
ui.miniMenuButtons = listOf(
|
||||
MainActivity.DRAWER_ITEM_HOME,
|
||||
MainActivity.DRAWER_ITEM_TIMETABLE,
|
||||
MainActivity.DRAWER_ITEM_AGENDA,
|
||||
@ -39,46 +39,36 @@ class ConfigMigration(app: App, config: Config) {
|
||||
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.enabled = true
|
||||
sync.interval = 1*HOUR.toInt()
|
||||
sync.notifyAboutUpdates = true
|
||||
sync.onlyWifi = false
|
||||
sync.quietHoursStart = 0
|
||||
sync.quietHoursEnd = 0
|
||||
sync.quietDuringLessons = false
|
||||
sync.tokenApp = null
|
||||
sync.tokenMobidziennik = null
|
||||
sync.tokenMobidziennikList = listOf()
|
||||
sync.tokenVulcanList = listOf()
|
||||
sync.tokenLibrus = null
|
||||
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
|
||||
}
|
||||
}
|
||||
sync.tokenVulcan = null
|
||||
sync.tokenVulcanList = listOf()
|
||||
timetable.bellSyncMultiplier = 0
|
||||
timetable.bellSyncDiff = null
|
||||
timetable.countInSeconds = false
|
||||
grades.orderBy = ORDER_BY_DATE_DESC
|
||||
|
||||
dataVersion = 2
|
||||
}
|
||||
}}
|
||||
|
||||
private fun String?.fix(): String? {
|
||||
return this?.replace("\"", "")?.let { if (it == "null") null else it }
|
||||
}
|
||||
if (dataVersion < 10) {
|
||||
ui.openDrawerOnBackPressed = false
|
||||
ui.homeCards = listOf()
|
||||
ui.snowfall = false
|
||||
ui.bottomSheetOpened = false
|
||||
sync.dontShowAppManagerDialog = false
|
||||
|
||||
dataVersion = 10
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
@ -4,23 +4,21 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.config.utils
|
||||
|
||||
import android.content.Context
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.config.Config
|
||||
import pl.szczodrzynski.edziennik.config.ProfileConfig
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile.Companion.AGENDA_DEFAULT
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile.Companion.COLOR_MODE_WEIGHTED
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile.Companion.YEAR_ALL_GRADES
|
||||
|
||||
class ProfileConfigMigration(app: App, config: Config) {
|
||||
class ProfileConfigMigration(config: ProfileConfig) {
|
||||
init { config.apply {
|
||||
val p = app.getSharedPreferences("pl.szczodrzynski.edziennik_profiles", Context.MODE_PRIVATE)
|
||||
val s = "app.appConfig"
|
||||
|
||||
if (dataVersion < 1) {
|
||||
grades.colorMode = COLOR_MODE_WEIGHTED
|
||||
grades.countZeroToAvg = true
|
||||
grades.yearAverageMode = YEAR_ALL_GRADES
|
||||
ui.agendaViewType = AGENDA_DEFAULT
|
||||
|
||||
//dataVersion = 1
|
||||
}
|
||||
if (dataVersion < 2) {
|
||||
//gradesColorMode do profilu !
|
||||
//agendaViewType do profilu !
|
||||
// app.appConfig.dontCountZeroToAverage do profilu !
|
||||
dataVersion = 1
|
||||
}
|
||||
}}
|
||||
}
|
@ -12,12 +12,15 @@ import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask
|
||||
import pl.szczodrzynski.edziennik.data.api.events.*
|
||||
import pl.szczodrzynski.edziennik.data.api.events.requests.ServiceCloseRequest
|
||||
import pl.szczodrzynski.edziennik.data.api.events.requests.TaskCancelRequest
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.api.task.*
|
||||
import pl.szczodrzynski.edziennik.data.api.task.ErrorReportTask
|
||||
import pl.szczodrzynski.edziennik.data.api.task.IApiTask
|
||||
import pl.szczodrzynski.edziennik.data.api.task.SzkolnyTask
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import kotlin.math.min
|
||||
@ -40,11 +43,8 @@ class ApiService : Service() {
|
||||
|
||||
private val syncingProfiles = mutableListOf<Profile>()
|
||||
|
||||
private val finishingTaskQueue = mutableListOf(
|
||||
SzkolnyTask.sync(syncingProfiles),
|
||||
NotifyTask()
|
||||
)
|
||||
private val allTaskList = mutableListOf<IApiTask>()
|
||||
private var szkolnyTaskFinished = false
|
||||
private val allTaskRequestList = mutableListOf<Any>()
|
||||
private val taskQueue = mutableListOf<IApiTask>()
|
||||
private val errorList = mutableListOf<ApiError>()
|
||||
|
||||
@ -132,14 +132,20 @@ class ApiService : Service() {
|
||||
checkIfTaskFrozen()
|
||||
if (taskIsRunning)
|
||||
return
|
||||
if (taskCancelled || serviceClosed || (taskQueue.isEmpty() && finishingTaskQueue.isEmpty())) {
|
||||
if (taskCancelled || serviceClosed || (taskQueue.isEmpty() && szkolnyTaskFinished)) {
|
||||
allCompleted()
|
||||
return
|
||||
}
|
||||
|
||||
lastEventTime = System.currentTimeMillis()
|
||||
|
||||
val task = if (taskQueue.isEmpty()) finishingTaskQueue.removeAt(0) else taskQueue.removeAt(0)
|
||||
val task = if (taskQueue.isNotEmpty()) {
|
||||
taskQueue.removeAt(0)
|
||||
} else {
|
||||
szkolnyTaskFinished = true
|
||||
SzkolnyTask(app, syncingProfiles)
|
||||
}
|
||||
|
||||
task.taskId = ++taskMaximumId
|
||||
task.prepare(app)
|
||||
taskIsRunning = true
|
||||
@ -162,9 +168,8 @@ class ApiService : Service() {
|
||||
try {
|
||||
when (task) {
|
||||
is EdziennikTask -> task.run(app, taskCallback)
|
||||
is NotifyTask -> task.run(app, taskCallback)
|
||||
is ErrorReportTask -> task.run(app, taskCallback, notification, errorList)
|
||||
is SzkolnyTask -> task.run(app, taskCallback)
|
||||
is SzkolnyTask -> task.run(taskCallback)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
taskCallback.onError(ApiError(TAG, EXCEPTION_API_TASK).withThrowable(e))
|
||||
@ -230,10 +235,12 @@ class ApiService : Service() {
|
||||
EventBus.getDefault().removeStickyEvent(task)
|
||||
d(TAG, task.toString())
|
||||
|
||||
// fix for duplicated tasks, thank you EventBus
|
||||
if (task in allTaskList)
|
||||
return
|
||||
allTaskList += task
|
||||
if (task is EdziennikTask) {
|
||||
// fix for duplicated tasks, thank you EventBus
|
||||
if (task.request in allTaskRequestList)
|
||||
return
|
||||
allTaskRequestList += task.request
|
||||
}
|
||||
|
||||
if (task is EdziennikTask) {
|
||||
when (task.request) {
|
||||
|
@ -1,206 +0,0 @@
|
||||
package pl.szczodrzynski.edziennik.data.api
|
||||
|
||||
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_HOME
|
||||
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_TIMETABLE
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.data.api.models.Data
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.*
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Grade.*
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification.Companion.TYPE_LUCKY_NUMBER
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification.Companion.TYPE_NEW_ANNOUNCEMENT
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification.Companion.TYPE_NEW_ATTENDANCE
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification.Companion.TYPE_NEW_EVENT
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification.Companion.TYPE_NEW_GRADE
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification.Companion.TYPE_NEW_HOMEWORK
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification.Companion.TYPE_NEW_MESSAGE
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification.Companion.TYPE_NEW_NOTICE
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification.Companion.TYPE_TIMETABLE_LESSON_CHANGE
|
||||
import pl.szczodrzynski.edziennik.getNotificationTitle
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class DataNotifications(val data: Data) {
|
||||
companion object {
|
||||
private const val TAG = "DataNotifications"
|
||||
}
|
||||
|
||||
val app = data.app
|
||||
val profileId = data.profile?.id ?: -1
|
||||
val profileName = data.profile?.name ?: ""
|
||||
val profile = data.profile
|
||||
val loginStore = data.loginStore
|
||||
|
||||
init { run {
|
||||
if (profile == null) {
|
||||
return@run
|
||||
}
|
||||
|
||||
val today = Date.getToday()
|
||||
val todayValue = today.value
|
||||
|
||||
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,
|
||||
type = TYPE_TIMETABLE_LESSON_CHANGE,
|
||||
profileId = profileId,
|
||||
profileName = profileName,
|
||||
viewId = DRAWER_ITEM_TIMETABLE,
|
||||
addedDate = lesson.addedDate
|
||||
).addExtra("timetableDate", lesson.displayDate?.stringY_m_d ?: "")
|
||||
}
|
||||
|
||||
for (event in app.db.eventDao().getNotNotifiedNow(profileId)) {
|
||||
val text = if (event.type == Event.TYPE_HOMEWORK)
|
||||
app.getString(
|
||||
if (event.subjectLongName.isNullOrEmpty())
|
||||
R.string.notification_homework_no_subject_format
|
||||
else
|
||||
R.string.notification_homework_format,
|
||||
event.subjectLongName,
|
||||
event.eventDate.formattedString
|
||||
)
|
||||
else
|
||||
app.getString(
|
||||
if (event.subjectLongName.isNullOrEmpty())
|
||||
R.string.notification_event_no_subject_format
|
||||
else
|
||||
R.string.notification_event_format,
|
||||
event.typeName,
|
||||
event.eventDate.formattedString,
|
||||
event.subjectLongName
|
||||
)
|
||||
val type = if (event.type == Event.TYPE_HOMEWORK) TYPE_NEW_HOMEWORK else TYPE_NEW_EVENT
|
||||
data.notifications += Notification(
|
||||
title = app.getNotificationTitle(type),
|
||||
text = text,
|
||||
type = type,
|
||||
profileId = profileId,
|
||||
profileName = profileName,
|
||||
viewId = if (event.type == Event.TYPE_HOMEWORK) DRAWER_ITEM_HOMEWORK else DRAWER_ITEM_AGENDA,
|
||||
addedDate = event.addedDate
|
||||
).addExtra("eventId", event.id).addExtra("eventDate", event.eventDate.value.toLong())
|
||||
}
|
||||
|
||||
for (grade in app.db.gradeDao().getNotNotifiedNow(profileId)) {
|
||||
val gradeName = when (grade.type) {
|
||||
TYPE_SEMESTER1_PROPOSED, TYPE_SEMESTER2_PROPOSED -> app.getString(R.string.grade_semester_proposed_format_2, grade.name)
|
||||
TYPE_SEMESTER1_FINAL, TYPE_SEMESTER2_FINAL -> app.getString(R.string.grade_semester_final_format_2, grade.name)
|
||||
TYPE_YEAR_PROPOSED -> app.getString(R.string.grade_year_proposed_format_2, grade.name)
|
||||
TYPE_YEAR_FINAL -> app.getString(R.string.grade_year_final_format_2, grade.name)
|
||||
else -> grade.name
|
||||
}
|
||||
val text = app.getString(R.string.notification_grade_format, gradeName, grade.subjectLongName)
|
||||
data.notifications += Notification(
|
||||
title = app.getNotificationTitle(TYPE_NEW_GRADE),
|
||||
text = text,
|
||||
type = TYPE_NEW_GRADE,
|
||||
profileId = profileId,
|
||||
profileName = profileName,
|
||||
viewId = DRAWER_ITEM_GRADES,
|
||||
addedDate = grade.addedDate
|
||||
).addExtra("gradeId", grade.id).addExtra("gradesSubjectId", grade.subjectId)
|
||||
}
|
||||
|
||||
for (notice in app.db.noticeDao().getNotNotifiedNow(profileId)) {
|
||||
val noticeTypeStr = if (notice.type == Notice.TYPE_POSITIVE) app.getString(R.string.notification_notice_praise) else if (notice.type == Notice.TYPE_NEGATIVE) app.getString(R.string.notification_notice_warning) else app.getString(R.string.notification_notice_new)
|
||||
val text = app.getString(R.string.notification_notice_format, noticeTypeStr, notice.teacherFullName, Date.fromMillis(notice.addedDate).formattedString)
|
||||
data.notifications += Notification(
|
||||
title = app.getNotificationTitle(TYPE_NEW_NOTICE),
|
||||
text = text,
|
||||
type = TYPE_NEW_NOTICE,
|
||||
profileId = profileId,
|
||||
profileName = profileName,
|
||||
viewId = DRAWER_ITEM_BEHAVIOUR,
|
||||
addedDate = notice.addedDate
|
||||
).addExtra("noticeId", notice.id)
|
||||
}
|
||||
|
||||
for (attendance in app.db.attendanceDao().getNotNotifiedNow(profileId)) {
|
||||
val attendanceTypeStr = when (attendance.type) {
|
||||
Attendance.TYPE_ABSENT -> app.getString(R.string.notification_absence)
|
||||
Attendance.TYPE_ABSENT_EXCUSED -> app.getString(R.string.notification_absence_excused)
|
||||
Attendance.TYPE_BELATED -> app.getString(R.string.notification_belated)
|
||||
Attendance.TYPE_BELATED_EXCUSED -> app.getString(R.string.notification_belated_excused)
|
||||
Attendance.TYPE_RELEASED -> app.getString(R.string.notification_release)
|
||||
Attendance.TYPE_DAY_FREE -> app.getString(R.string.notification_day_free)
|
||||
else -> app.getString(R.string.notification_type_attendance)
|
||||
}
|
||||
val text = app.getString(
|
||||
if (attendance.subjectLongName.isNullOrEmpty())
|
||||
R.string.notification_attendance_no_lesson_format
|
||||
else
|
||||
R.string.notification_attendance_format,
|
||||
attendanceTypeStr,
|
||||
attendance.subjectLongName,
|
||||
attendance.lessonDate.formattedString
|
||||
)
|
||||
data.notifications += Notification(
|
||||
title = app.getNotificationTitle(TYPE_NEW_ATTENDANCE),
|
||||
text = text,
|
||||
type = TYPE_NEW_ATTENDANCE,
|
||||
profileId = profileId,
|
||||
profileName = profileName,
|
||||
viewId = DRAWER_ITEM_ATTENDANCE,
|
||||
addedDate = attendance.addedDate
|
||||
).addExtra("attendanceId", attendance.id).addExtra("attendanceSubjectId", attendance.subjectId)
|
||||
}
|
||||
|
||||
for (announcement in app.db.announcementDao().getNotNotifiedNow(profileId)) {
|
||||
val text = app.context.getString(R.string.notification_announcement_format, announcement.subject)
|
||||
data.notifications += Notification(
|
||||
title = app.getNotificationTitle(TYPE_NEW_ANNOUNCEMENT),
|
||||
text = text,
|
||||
type = TYPE_NEW_ANNOUNCEMENT,
|
||||
profileId = profileId,
|
||||
profileName = profileName,
|
||||
viewId = DRAWER_ITEM_ANNOUNCEMENTS,
|
||||
addedDate = announcement.addedDate
|
||||
).addExtra("announcementId", announcement.id)
|
||||
}
|
||||
|
||||
for (message in app.db.messageDao().getReceivedNotNotifiedNow(profileId)) {
|
||||
val text = app.context.getString(R.string.notification_message_format, message.senderFullName, message.subject)
|
||||
data.notifications += Notification(
|
||||
title = app.getNotificationTitle(TYPE_NEW_MESSAGE),
|
||||
text = text,
|
||||
type = TYPE_NEW_MESSAGE,
|
||||
profileId = profileId,
|
||||
profileName = profileName,
|
||||
viewId = DRAWER_ITEM_MESSAGES,
|
||||
addedDate = message.addedDate
|
||||
).addExtra("messageType", Message.TYPE_RECEIVED.toLong()).addExtra("messageId", message.id)
|
||||
}
|
||||
|
||||
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
|
||||
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)
|
||||
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)
|
||||
}
|
||||
data.notifications += Notification(
|
||||
title = app.getNotificationTitle(TYPE_LUCKY_NUMBER),
|
||||
text = text,
|
||||
type = TYPE_LUCKY_NUMBER,
|
||||
profileId = profileId,
|
||||
profileName = profileName,
|
||||
viewId = DRAWER_ITEM_HOME,
|
||||
addedDate = luckyNumber.addedDate
|
||||
)
|
||||
}
|
||||
|
||||
data.db.metadataDao().setAllNotified(profileId, true)
|
||||
}}
|
||||
}
|
@ -1,4 +1,8 @@
|
||||
package pl.szczodrzynski.edziennik.data.api.task
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-1-16.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
@ -12,11 +16,12 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.template.Template
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.Vulcan
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
|
||||
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
|
||||
import pl.szczodrzynski.edziennik.data.api.task.IApiTask
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
|
||||
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
|
||||
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
|
||||
|
||||
open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTask(profileId) {
|
||||
companion object {
|
@ -15,12 +15,12 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.login.Edudzienn
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
|
||||
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
|
||||
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
|
||||
class Edudziennik(val app: App, val profile: Profile?, val loginStore: LoginStore, val callback: EdziennikCallback) : EdziennikInterface {
|
||||
@ -41,9 +41,7 @@ class Edudziennik(val app: App, val profile: Profile?, val loginStore: LoginStor
|
||||
|
||||
private fun completed() {
|
||||
data.saveData()
|
||||
data.notify {
|
||||
callback.onCompleted()
|
||||
}
|
||||
callback.onCompleted()
|
||||
}
|
||||
|
||||
/* _______ _ _ _ _ _
|
||||
|
@ -13,9 +13,9 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_EXAMS
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
@ -60,7 +60,7 @@ class EdudziennikWebExams(override val data: DataEdudziennik,
|
||||
startTime,
|
||||
topic,
|
||||
-1,
|
||||
eventType.id.toInt(),
|
||||
eventType.id,
|
||||
false,
|
||||
-1,
|
||||
subject.id,
|
||||
|
@ -17,12 +17,12 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.login.IdziennikLo
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
|
||||
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
|
||||
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
|
||||
class Idziennik(val app: App, val profile: Profile?, val loginStore: LoginStore, val callback: EdziennikCallback) : EdziennikInterface {
|
||||
@ -43,9 +43,7 @@ class Idziennik(val app: App, val profile: Profile?, val loginStore: LoginStore,
|
||||
|
||||
private fun completed() {
|
||||
data.saveData()
|
||||
data.notify {
|
||||
callback.onCompleted()
|
||||
}
|
||||
callback.onCompleted()
|
||||
}
|
||||
|
||||
/* _______ _ _ _ _ _
|
||||
|
@ -19,12 +19,12 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.login.LibrusLogin
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
|
||||
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
|
||||
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
|
||||
class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, val callback: EdziennikCallback) : EdziennikInterface {
|
||||
@ -45,9 +45,7 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
||||
|
||||
private fun completed() {
|
||||
data.saveData()
|
||||
data.notify {
|
||||
callback.onCompleted()
|
||||
}
|
||||
callback.onCompleted()
|
||||
}
|
||||
|
||||
/* _______ _ _ _ _ _
|
||||
|
@ -10,9 +10,9 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_EVENTS
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
|
||||
@ -34,7 +34,7 @@ class LibrusApiEvents(override val data: DataLibrus,
|
||||
val id = event.getLong("Id") ?: return@forEach
|
||||
val eventDate = Date.fromY_m_d(event.getString("Date"))
|
||||
val topic = event.getString("Content") ?: ""
|
||||
val type = event.getJsonObject("Category")?.getInt("Id") ?: -1
|
||||
val type = event.getJsonObject("Category")?.getLong("Id") ?: -1
|
||||
val teacherId = event.getJsonObject("CreatedBy")?.getLong("Id") ?: -1
|
||||
val subjectId = event.getJsonObject("Subject")?.getLong("Id") ?: -1
|
||||
val teamId = event.getJsonObject("Class")?.getLong("Id") ?: -1
|
||||
|
@ -17,12 +17,12 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.login.Mobidzie
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
|
||||
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
|
||||
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
|
||||
class Mobidziennik(val app: App, val profile: Profile?, val loginStore: LoginStore, val callback: EdziennikCallback) : EdziennikInterface {
|
||||
@ -45,9 +45,7 @@ class Mobidziennik(val app: App, val profile: Profile?, val loginStore: LoginSto
|
||||
|
||||
private fun completed() {
|
||||
data.saveData()
|
||||
data.notify {
|
||||
callback.onCompleted()
|
||||
}
|
||||
callback.onCompleted()
|
||||
}
|
||||
|
||||
/* _______ _ _ _ _ _
|
||||
|
@ -15,12 +15,12 @@ import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.api.prepare
|
||||
import pl.szczodrzynski.edziennik.data.api.templateLoginMethods
|
||||
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
|
||||
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
|
||||
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
|
||||
class Template(val app: App, val profile: Profile?, val loginStore: LoginStore, val callback: EdziennikCallback) : EdziennikInterface {
|
||||
@ -40,9 +40,7 @@ class Template(val app: App, val profile: Profile?, val loginStore: LoginStore,
|
||||
|
||||
private fun completed() {
|
||||
data.saveData()
|
||||
data.notify {
|
||||
callback.onCompleted()
|
||||
}
|
||||
callback.onCompleted()
|
||||
}
|
||||
|
||||
/* _______ _ _ _ _ _
|
||||
|
@ -18,12 +18,12 @@ import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.api.prepare
|
||||
import pl.szczodrzynski.edziennik.data.api.prepareFor
|
||||
import pl.szczodrzynski.edziennik.data.api.vulcanLoginMethods
|
||||
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
|
||||
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
|
||||
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
|
||||
class Vulcan(val app: App, val profile: Profile?, val loginStore: LoginStore, val callback: EdziennikCallback) : EdziennikInterface {
|
||||
@ -44,9 +44,7 @@ class Vulcan(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
||||
|
||||
private fun completed() {
|
||||
data.saveData()
|
||||
data.notify {
|
||||
callback.onCompleted()
|
||||
}
|
||||
callback.onCompleted()
|
||||
}
|
||||
|
||||
/* _______ _ _ _ _ _
|
||||
|
@ -0,0 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-1-18.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.events
|
||||
|
||||
class ProfileListEmptyEvent
|
@ -194,7 +194,6 @@ abstract class Data(val app: App, val profile: Profile?, val loginStore: LoginSt
|
||||
if (profile == null)
|
||||
return // return on first login
|
||||
|
||||
profile.empty = false
|
||||
profile.userCode = generateUserCode()
|
||||
|
||||
db.profileDao().add(profile)
|
||||
@ -294,21 +293,6 @@ abstract class Data(val app: App, val profile: Profile?, val loginStore: LoginSt
|
||||
db.messageRecipientDao().addAllIgnore(messageRecipientIgnoreList)
|
||||
}
|
||||
|
||||
fun notify(onSuccess: () -> Unit) {
|
||||
if (profile == null) {
|
||||
onSuccess()
|
||||
return
|
||||
}
|
||||
try {
|
||||
DataNotifications(this)
|
||||
db.notificationDao().addAll(notifications)
|
||||
onSuccess()
|
||||
} catch (e: Exception) {
|
||||
error(ApiError(TAG, EXCEPTION_NOTIFY)
|
||||
.withThrowable(e))
|
||||
}
|
||||
}
|
||||
|
||||
fun setSyncNext(endpointId: Int, syncIn: Long? = null, viewId: Int? = null, syncAt: Long? = null) {
|
||||
EndpointTimer(profile?.id
|
||||
?: -1, endpointId).apply {
|
||||
|
@ -47,11 +47,11 @@ open class DataRemoveModel {
|
||||
}
|
||||
}
|
||||
|
||||
class Events(private val type: Int?, private val exceptType: Int?, private val exceptTypes: List<Int>?) : DataRemoveModel() {
|
||||
class Events(private val type: Long?, private val exceptType: Long?, private val exceptTypes: List<Long>?) : DataRemoveModel() {
|
||||
companion object {
|
||||
fun futureExceptType(exceptType: Int) = Events(null, exceptType, null)
|
||||
fun futureExceptTypes(exceptTypes: List<Int>) = Events(null, null, exceptTypes)
|
||||
fun futureWithType(type: Int) = Events(type, null, null)
|
||||
fun futureExceptType(exceptType: Long) = Events(null, exceptType, null)
|
||||
fun futureExceptTypes(exceptTypes: List<Long>) = Events(null, null, exceptTypes)
|
||||
fun futureWithType(type: Long) = Events(type, null, null)
|
||||
}
|
||||
|
||||
fun commit(profileId: Int, dao: EventDao) {
|
||||
|
@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-13
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.szkolny
|
||||
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
|
||||
class Szkolny(val app: App, val callback: EdziennikCallback) {
|
||||
|
||||
private val api = SzkolnyApi(app)
|
||||
|
||||
fun sync(profileList: List<Profile>) {
|
||||
val profiles = profileList.filter { it.registration == Profile.REGISTRATION_ENABLED }
|
||||
if (profiles.isNotEmpty()) {
|
||||
val events = api.getEvents(profiles)
|
||||
|
||||
if (events.isNotEmpty()) {
|
||||
app.db.eventDao().addAll(events)
|
||||
app.db.metadataDao().addAllIgnore(events.map { event ->
|
||||
Metadata(
|
||||
event.profileId,
|
||||
Metadata.TYPE_EVENT,
|
||||
event.id,
|
||||
event.seen,
|
||||
event.notified,
|
||||
event.addedDate
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
completed()
|
||||
}
|
||||
|
||||
/*fun shareEvent(event: EventFull) {
|
||||
api.shareEvent(event)
|
||||
completed()
|
||||
}
|
||||
|
||||
fun unshareEvent(event: EventFull) {
|
||||
api.unshareEvent(event)
|
||||
completed()
|
||||
}*/
|
||||
|
||||
private fun completed() {
|
||||
callback.onCompleted()
|
||||
}
|
||||
}
|
@ -12,15 +12,14 @@ import pl.szczodrzynski.edziennik.BuildConfig
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.adapter.DateAdapter
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.adapter.TimeAdapter
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.interceptor.SignatureInterceptor
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.request.ErrorReportRequest
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.request.EventShareRequest
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.request.ServerSyncRequest
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.request.WebPushRequest
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.request.*
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.response.ApiResponse
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.response.Update
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.response.WebPushResponse
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.full.EventFull
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.data.db.full.EventFull
|
||||
import pl.szczodrzynski.edziennik.md5
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
@ -56,9 +55,8 @@ class SzkolnyApi(val app: App) {
|
||||
api = retrofit.create()
|
||||
}
|
||||
|
||||
fun getEvents(profiles: List<Profile>): List<EventFull> {
|
||||
fun getEvents(profiles: List<Profile>, notifications: List<Notification>, blacklistedIds: List<Long>): List<EventFull> {
|
||||
val teams = app.db.teamDao().allNow
|
||||
val notifications = app.db.notificationDao().getNotPostedNow()
|
||||
|
||||
val response = api.serverSync(ServerSyncRequest(
|
||||
deviceId = app.deviceId,
|
||||
@ -88,8 +86,8 @@ class SzkolnyApi(val app: App) {
|
||||
val config = app.config.getFor(profile.id)
|
||||
val user = ServerSyncRequest.User(
|
||||
profile.userCode,
|
||||
profile.studentNameLong ?: "",
|
||||
profile.studentNameShort ?: "",
|
||||
profile.studentNameLong,
|
||||
profile.studentNameShort,
|
||||
profile.loginStoreType,
|
||||
teams.filter { it.profileId == profile.id }.map { it.code }
|
||||
)
|
||||
@ -108,17 +106,19 @@ class SzkolnyApi(val app: App) {
|
||||
val events = mutableListOf<EventFull>()
|
||||
|
||||
response?.data?.events?.forEach { event ->
|
||||
teams.filter { it.code == event.teamCode }.forEach { team ->
|
||||
val profile = profiles.firstOrNull { it.id == team.profileId }
|
||||
if (event.id in blacklistedIds)
|
||||
return@forEach
|
||||
teams.filter { it.code == event.teamCode }.onEach { team ->
|
||||
val profile = profiles.firstOrNull { it.id == team.profileId } ?: return@onEach
|
||||
|
||||
events.add(event.apply {
|
||||
events.add(EventFull(event).apply {
|
||||
profileId = team.profileId
|
||||
teamId = team.id
|
||||
addedManually = true
|
||||
seen = profile?.empty ?: false
|
||||
notified = profile?.empty ?: false
|
||||
seen = profile.empty
|
||||
notified = profile.empty
|
||||
|
||||
if (profile?.userCode == event.sharedBy) sharedBy = "self"
|
||||
if (profile.userCode == event.sharedBy) sharedBy = "self"
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -193,4 +193,15 @@ class SzkolnyApi(val app: App) {
|
||||
errors = errors
|
||||
)).execute().body()
|
||||
}
|
||||
|
||||
fun unregisterAppUser(userCode: String): ApiResponse<Nothing>? {
|
||||
return api.appUser(AppUserRequest(
|
||||
deviceId = app.deviceId,
|
||||
userCode = userCode
|
||||
)).execute().body()
|
||||
}
|
||||
|
||||
fun getUpdate(): ApiResponse<List<Update>>? {
|
||||
return api.updates().execute().body()
|
||||
}
|
||||
}
|
||||
|
@ -4,16 +4,16 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.szkolny
|
||||
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.request.ErrorReportRequest
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.request.EventShareRequest
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.request.ServerSyncRequest
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.request.WebPushRequest
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.request.*
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.response.ApiResponse
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.response.ServerSyncResponse
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.response.Update
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.response.WebPushResponse
|
||||
import retrofit2.Call
|
||||
import retrofit2.http.Body
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.POST
|
||||
import retrofit2.http.Query
|
||||
|
||||
interface SzkolnyService {
|
||||
|
||||
@ -28,4 +28,10 @@ interface SzkolnyService {
|
||||
|
||||
@POST("errorReport")
|
||||
fun errorReport(@Body request: ErrorReportRequest): Call<ApiResponse<Nothing>>
|
||||
|
||||
@POST("appUser")
|
||||
fun appUser(@Body request: AppUserRequest): Call<ApiResponse<Nothing>>
|
||||
|
||||
@GET("updates/app")
|
||||
fun updates(@Query("channel") channel: String = "release"): Call<ApiResponse<List<Update>>>
|
||||
}
|
||||
|
@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-1-18.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.szkolny.request
|
||||
|
||||
data class AppUserRequest(
|
||||
val action: String = "unregister",
|
||||
|
||||
val deviceId: String,
|
||||
val userCode: String
|
||||
)
|
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-1-18.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.szkolny.response
|
||||
|
||||
data class Update(
|
||||
val versionCode: Int,
|
||||
val versionName: String,
|
||||
val releaseDate: String,
|
||||
val releaseNotes: String?,
|
||||
val releaseType: String,
|
||||
val isOnGooglePlay: Boolean,
|
||||
val downloadUrl: String?
|
||||
)
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-1-17.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.task
|
||||
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
|
||||
class AppSync(val app: App, val notifications: MutableList<Notification>, val profiles: List<Profile>, val api: SzkolnyApi) {
|
||||
companion object {
|
||||
private const val TAG = "AppSync"
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the app sync, sending all pending notifications
|
||||
* and retrieving a list of shared events.
|
||||
*
|
||||
* Events are automatically saved to app database,
|
||||
* along with corresponding metadata objects.
|
||||
*
|
||||
* @return a number of events inserted to DB, possibly needing a notification
|
||||
*/
|
||||
fun run(): Int {
|
||||
val profiles = profiles.filter { it.registration == Profile.REGISTRATION_ENABLED && !it.archived }
|
||||
if (profiles.isNotEmpty()) {
|
||||
val blacklistedIds = app.db.eventDao().blacklistedIds;
|
||||
val events = api.getEvents(profiles, notifications, blacklistedIds)
|
||||
|
||||
if (events.isNotEmpty()) {
|
||||
app.db.metadataDao().addAllIgnore(events.map { event ->
|
||||
Metadata(
|
||||
event.profileId,
|
||||
Metadata.TYPE_EVENT,
|
||||
event.id,
|
||||
event.seen,
|
||||
event.notified,
|
||||
event.addedDate
|
||||
)
|
||||
})
|
||||
return app.db.eventDao().addAll(events).size
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
@ -0,0 +1,277 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-1-16.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.task
|
||||
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.*
|
||||
import pl.szczodrzynski.edziennik.getNotificationTitle
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class Notifications(val app: App, val notifications: MutableList<Notification>, val profiles: List<Profile>) {
|
||||
companion object {
|
||||
private const val TAG = "Notifications"
|
||||
}
|
||||
|
||||
private val today by lazy { Date.getToday() }
|
||||
private val todayValue by lazy { today.value }
|
||||
|
||||
/**
|
||||
* Create a [Notification] from every possible
|
||||
* data type. Notifications are posted whenever
|
||||
* the object's metadata `notified` property is
|
||||
* set to false.
|
||||
*/
|
||||
fun run() {
|
||||
timetableNotifications()
|
||||
eventNotifications()
|
||||
gradeNotifications()
|
||||
behaviourNotifications()
|
||||
attendanceNotifications()
|
||||
announcementNotifications()
|
||||
messageNotifications()
|
||||
luckyNumberNotifications()
|
||||
}
|
||||
|
||||
private fun timetableNotifications() {
|
||||
for (lesson in app.db.timetableDao().getNotNotifiedNow()) {
|
||||
val text = app.getString(
|
||||
R.string.notification_lesson_change_format,
|
||||
lesson.getDisplayChangeType(app),
|
||||
if (lesson.displayDate == null) "" else lesson.displayDate!!.formattedString,
|
||||
lesson.changeSubjectName
|
||||
)
|
||||
notifications += Notification(
|
||||
id = Notification.buildId(lesson.profileId, Notification.TYPE_TIMETABLE_LESSON_CHANGE, lesson.id),
|
||||
title = app.getNotificationTitle(Notification.TYPE_TIMETABLE_LESSON_CHANGE),
|
||||
text = text,
|
||||
type = Notification.TYPE_TIMETABLE_LESSON_CHANGE,
|
||||
profileId = lesson.profileId,
|
||||
profileName = profiles.singleOrNull { it.id == lesson.profileId }?.name,
|
||||
viewId = MainActivity.DRAWER_ITEM_TIMETABLE,
|
||||
addedDate = lesson.addedDate
|
||||
).addExtra("timetableDate", lesson.displayDate?.stringY_m_d ?: "")
|
||||
}
|
||||
}
|
||||
|
||||
private fun eventNotifications() {
|
||||
for (event in app.db.eventDao().notNotifiedNow) {
|
||||
val text = if (event.type == Event.TYPE_HOMEWORK)
|
||||
app.getString(
|
||||
if (event.subjectLongName.isNullOrEmpty())
|
||||
R.string.notification_homework_no_subject_format
|
||||
else
|
||||
R.string.notification_homework_format,
|
||||
event.subjectLongName,
|
||||
event.eventDate.formattedString
|
||||
)
|
||||
else
|
||||
app.getString(
|
||||
if (event.subjectLongName.isNullOrEmpty())
|
||||
R.string.notification_event_no_subject_format
|
||||
else
|
||||
R.string.notification_event_format,
|
||||
event.typeName,
|
||||
event.eventDate.formattedString,
|
||||
event.subjectLongName
|
||||
)
|
||||
val type = if (event.type == Event.TYPE_HOMEWORK) Notification.TYPE_NEW_HOMEWORK else Notification.TYPE_NEW_EVENT
|
||||
notifications += Notification(
|
||||
id = Notification.buildId(event.profileId, type, event.id),
|
||||
title = app.getNotificationTitle(type),
|
||||
text = text,
|
||||
type = type,
|
||||
profileId = event.profileId,
|
||||
profileName = profiles.singleOrNull { it.id == event.profileId }?.name,
|
||||
viewId = if (event.type == Event.TYPE_HOMEWORK) MainActivity.DRAWER_ITEM_HOMEWORK else MainActivity.DRAWER_ITEM_AGENDA,
|
||||
addedDate = event.addedDate
|
||||
).addExtra("eventId", event.id).addExtra("eventDate", event.eventDate.value.toLong())
|
||||
}
|
||||
}
|
||||
|
||||
fun sharedEventNotifications() {
|
||||
for (event in app.db.eventDao().notNotifiedNow.filter { it.sharedBy != null }) {
|
||||
val text = app.getString(
|
||||
R.string.notification_shared_event_format,
|
||||
event.sharedByName,
|
||||
event.typeName ?: "wydarzenie",
|
||||
event.eventDate.formattedString,
|
||||
event.topic
|
||||
)
|
||||
val type = if (event.type == Event.TYPE_HOMEWORK) Notification.TYPE_NEW_HOMEWORK else Notification.TYPE_NEW_EVENT
|
||||
notifications += Notification(
|
||||
id = Notification.buildId(event.profileId, type, event.id),
|
||||
title = app.getNotificationTitle(type),
|
||||
text = text,
|
||||
type = type,
|
||||
profileId = event.profileId,
|
||||
profileName = profiles.singleOrNull { it.id == event.profileId }?.name,
|
||||
viewId = if (event.type == Event.TYPE_HOMEWORK) MainActivity.DRAWER_ITEM_HOMEWORK else MainActivity.DRAWER_ITEM_AGENDA,
|
||||
addedDate = event.addedDate
|
||||
).addExtra("eventId", event.id).addExtra("eventDate", event.eventDate.value.toLong())
|
||||
}
|
||||
}
|
||||
|
||||
private fun gradeNotifications() {
|
||||
for (grade in app.db.gradeDao().notNotifiedNow) {
|
||||
val gradeName = when (grade.type) {
|
||||
Grade.TYPE_SEMESTER1_PROPOSED, Grade.TYPE_SEMESTER2_PROPOSED -> app.getString(R.string.grade_semester_proposed_format_2, grade.name)
|
||||
Grade.TYPE_SEMESTER1_FINAL, Grade.TYPE_SEMESTER2_FINAL -> app.getString(R.string.grade_semester_final_format_2, grade.name)
|
||||
Grade.TYPE_YEAR_PROPOSED -> app.getString(R.string.grade_year_proposed_format_2, grade.name)
|
||||
Grade.TYPE_YEAR_FINAL -> app.getString(R.string.grade_year_final_format_2, grade.name)
|
||||
else -> grade.name
|
||||
}
|
||||
val text = app.getString(
|
||||
R.string.notification_grade_format,
|
||||
gradeName,
|
||||
grade.subjectLongName
|
||||
)
|
||||
notifications += Notification(
|
||||
id = Notification.buildId(grade.profileId, Notification.TYPE_NEW_GRADE, grade.id),
|
||||
title = app.getNotificationTitle(Notification.TYPE_NEW_GRADE),
|
||||
text = text,
|
||||
type = Notification.TYPE_NEW_GRADE,
|
||||
profileId = grade.profileId,
|
||||
profileName = profiles.singleOrNull { it.id == grade.profileId }?.name,
|
||||
viewId = MainActivity.DRAWER_ITEM_GRADES,
|
||||
addedDate = grade.addedDate
|
||||
).addExtra("gradeId", grade.id).addExtra("gradesSubjectId", grade.subjectId)
|
||||
}
|
||||
}
|
||||
|
||||
private fun behaviourNotifications() {
|
||||
for (notice in app.db.noticeDao().notNotifiedNow) {
|
||||
|
||||
val noticeTypeStr = when (notice.type) {
|
||||
Notice.TYPE_POSITIVE -> app.getString(R.string.notification_notice_praise)
|
||||
Notice.TYPE_NEGATIVE -> app.getString(R.string.notification_notice_warning)
|
||||
else -> app.getString(R.string.notification_notice_new)
|
||||
}
|
||||
|
||||
val text = app.getString(
|
||||
R.string.notification_notice_format,
|
||||
noticeTypeStr,
|
||||
notice.teacherFullName,
|
||||
Date.fromMillis(notice.addedDate).formattedString
|
||||
)
|
||||
notifications += Notification(
|
||||
id = Notification.buildId(notice.profileId, Notification.TYPE_NEW_NOTICE, notice.id),
|
||||
title = app.getNotificationTitle(Notification.TYPE_NEW_NOTICE),
|
||||
text = text,
|
||||
type = Notification.TYPE_NEW_NOTICE,
|
||||
profileId = notice.profileId,
|
||||
profileName = profiles.singleOrNull { it.id == notice.profileId }?.name,
|
||||
viewId = MainActivity.DRAWER_ITEM_BEHAVIOUR,
|
||||
addedDate = notice.addedDate
|
||||
).addExtra("noticeId", notice.id)
|
||||
}
|
||||
}
|
||||
|
||||
private fun attendanceNotifications() {
|
||||
for (attendance in app.db.attendanceDao().notNotifiedNow) {
|
||||
|
||||
val attendanceTypeStr = when (attendance.type) {
|
||||
Attendance.TYPE_ABSENT -> app.getString(R.string.notification_absence)
|
||||
Attendance.TYPE_ABSENT_EXCUSED -> app.getString(R.string.notification_absence_excused)
|
||||
Attendance.TYPE_BELATED -> app.getString(R.string.notification_belated)
|
||||
Attendance.TYPE_BELATED_EXCUSED -> app.getString(R.string.notification_belated_excused)
|
||||
Attendance.TYPE_RELEASED -> app.getString(R.string.notification_release)
|
||||
Attendance.TYPE_DAY_FREE -> app.getString(R.string.notification_day_free)
|
||||
else -> app.getString(R.string.notification_type_attendance)
|
||||
}
|
||||
|
||||
val text = app.getString(
|
||||
if (attendance.subjectLongName.isNullOrEmpty())
|
||||
R.string.notification_attendance_no_lesson_format
|
||||
else
|
||||
R.string.notification_attendance_format,
|
||||
attendanceTypeStr,
|
||||
attendance.subjectLongName,
|
||||
attendance.lessonDate.formattedString
|
||||
)
|
||||
notifications += Notification(
|
||||
id = Notification.buildId(attendance.profileId, Notification.TYPE_NEW_ATTENDANCE, attendance.id),
|
||||
title = app.getNotificationTitle(Notification.TYPE_NEW_ATTENDANCE),
|
||||
text = text,
|
||||
type = Notification.TYPE_NEW_ATTENDANCE,
|
||||
profileId = attendance.profileId,
|
||||
profileName = profiles.singleOrNull { it.id == attendance.profileId }?.name,
|
||||
viewId = MainActivity.DRAWER_ITEM_ATTENDANCE,
|
||||
addedDate = attendance.addedDate
|
||||
).addExtra("attendanceId", attendance.id).addExtra("attendanceSubjectId", attendance.subjectId)
|
||||
}
|
||||
}
|
||||
|
||||
private fun announcementNotifications() {
|
||||
for (announcement in app.db.announcementDao().notNotifiedNow) {
|
||||
val text = app.getString(
|
||||
R.string.notification_announcement_format,
|
||||
announcement.teacherFullName,
|
||||
announcement.subject
|
||||
)
|
||||
notifications += Notification(
|
||||
id = Notification.buildId(announcement.profileId, Notification.TYPE_NEW_ANNOUNCEMENT, announcement.id),
|
||||
title = app.getNotificationTitle(Notification.TYPE_NEW_ANNOUNCEMENT),
|
||||
text = text,
|
||||
type = Notification.TYPE_NEW_ANNOUNCEMENT,
|
||||
profileId = announcement.profileId,
|
||||
profileName = profiles.singleOrNull { it.id == announcement.profileId }?.name,
|
||||
viewId = MainActivity.DRAWER_ITEM_ANNOUNCEMENTS,
|
||||
addedDate = announcement.addedDate
|
||||
).addExtra("announcementId", announcement.id)
|
||||
}
|
||||
}
|
||||
|
||||
private fun messageNotifications() {
|
||||
for (message in app.db.messageDao().receivedNotNotifiedNow) {
|
||||
val text = app.getString(
|
||||
R.string.notification_message_format,
|
||||
message.senderFullName,
|
||||
message.subject
|
||||
)
|
||||
notifications += Notification(
|
||||
id = Notification.buildId(message.profileId, Notification.TYPE_NEW_MESSAGE, message.id),
|
||||
title = app.getNotificationTitle(Notification.TYPE_NEW_MESSAGE),
|
||||
text = text,
|
||||
type = Notification.TYPE_NEW_MESSAGE,
|
||||
profileId = message.profileId,
|
||||
profileName = profiles.singleOrNull { it.id == message.profileId }?.name,
|
||||
viewId = MainActivity.DRAWER_ITEM_MESSAGES,
|
||||
addedDate = message.addedDate
|
||||
).addExtra("messageType", Message.TYPE_RECEIVED.toLong()).addExtra("messageId", message.id)
|
||||
}
|
||||
}
|
||||
|
||||
private fun luckyNumberNotifications() {
|
||||
val luckyNumbers = app.db.luckyNumberDao().notNotifiedNow
|
||||
luckyNumbers?.removeAll { it.date < today }
|
||||
luckyNumbers?.forEach { luckyNumber ->
|
||||
val profile = profiles.singleOrNull { it.id == luckyNumber.profileId } ?: return@forEach
|
||||
val text = when (profile.studentNumber != -1 && profile.studentNumber == luckyNumber.number) {
|
||||
true -> when (luckyNumber.date.value) {
|
||||
todayValue -> R.string.notification_lucky_number_yours_format
|
||||
todayValue + 1 -> R.string.notification_lucky_number_yours_tomorrow_format
|
||||
else -> R.string.notification_lucky_number_yours_later_format
|
||||
}
|
||||
else -> when (luckyNumber.date.value) {
|
||||
todayValue -> R.string.notification_lucky_number_format
|
||||
todayValue + 1 -> R.string.notification_lucky_number_tomorrow_format
|
||||
else -> R.string.notification_lucky_number_later_format
|
||||
}
|
||||
}
|
||||
notifications += Notification(
|
||||
id = Notification.buildId(luckyNumber.profileId, Notification.TYPE_LUCKY_NUMBER, luckyNumber.date.value.toLong()),
|
||||
title = app.getNotificationTitle(Notification.TYPE_LUCKY_NUMBER),
|
||||
text = app.getString(text, luckyNumber.date.formattedString, luckyNumber.number),
|
||||
type = Notification.TYPE_LUCKY_NUMBER,
|
||||
profileId = luckyNumber.profileId,
|
||||
profileName = profile.name,
|
||||
viewId = MainActivity.DRAWER_ITEM_HOME,
|
||||
addedDate = luckyNumber.addedDate
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
package pl.szczodrzynski.edziennik.data.api.task
|
||||
|
||||
import android.app.PendingIntent
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import androidx.core.app.NotificationCompat
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.Notifier.ID_NOTIFICATIONS
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
|
||||
import pl.szczodrzynski.edziennik.getNotificationTitle
|
||||
import pl.szczodrzynski.edziennik.utils.models.Notification
|
||||
import kotlin.math.min
|
||||
|
||||
class NotifyTask : IApiTask(-1) {
|
||||
override fun prepare(app: App) {
|
||||
taskName = app.getString(R.string.edziennik_notification_api_notify_title)
|
||||
}
|
||||
|
||||
override fun cancel() {
|
||||
|
||||
}
|
||||
|
||||
fun run(app: App, taskCallback: EdziennikCallback) {
|
||||
val list = app.db.notificationDao().getNotPostedNow()
|
||||
val notificationList = list.subList(0, min(10, list.size))
|
||||
|
||||
val unreadCount = list.size
|
||||
|
||||
for (notification in notificationList) {
|
||||
val intent = Intent(app, MainActivity::class.java)
|
||||
notification.fillIntent(intent)
|
||||
val pendingIntent = PendingIntent.getActivity(app, notification.id, intent, 0)
|
||||
val notificationBuilder = NotificationCompat.Builder(app, app.notifier.notificationGroup)
|
||||
// title, text, type, date
|
||||
.setContentTitle(notification.profileName)
|
||||
.setContentText(notification.text)
|
||||
.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
|
||||
.setSmallIcon(R.drawable.ic_notification)
|
||||
.setColor(app.notifier.notificationColor)
|
||||
.setLights(-0xff0001, 2000, 2000)
|
||||
.setPriority(app.notifier.notificationPriority)
|
||||
// channel, group, style
|
||||
.setChannelId(app.notifier.notificationGroup)
|
||||
.setGroup(app.notifier.notificationGroup)
|
||||
.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_SUMMARY)
|
||||
.setStyle(NotificationCompat.BigTextStyle().bigText(notification.text))
|
||||
// intent, auto cancel
|
||||
.setContentIntent(pendingIntent)
|
||||
.setAutoCancel(true)
|
||||
if (!app.notifier.shouldBeQuiet()) {
|
||||
notificationBuilder.setDefaults(app.notifier.notificationDefaults)
|
||||
}
|
||||
app.notifier.notificationManager.notify(notification.id, notificationBuilder.build())
|
||||
}
|
||||
|
||||
if (notificationList.isNotEmpty() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
val intent = Intent(app, MainActivity::class.java)
|
||||
intent.action = "android.intent.action.MAIN"
|
||||
intent.putExtra("fragmentId", MainActivity.DRAWER_ITEM_NOTIFICATIONS)
|
||||
val pendingIntent = PendingIntent.getActivity(app, ID_NOTIFICATIONS,
|
||||
intent, 0)
|
||||
|
||||
val groupBuilder = NotificationCompat.Builder(app, app.notifier.notificationGroup)
|
||||
.setSmallIcon(R.drawable.ic_notification)
|
||||
.setColor(app.notifier.notificationColor)
|
||||
.setContentTitle(app.getString(R.string.notification_new_notification_title_format, unreadCount))
|
||||
.setGroupSummary(true)
|
||||
.setAutoCancel(true)
|
||||
.setChannelId(app.notifier.notificationGroup)
|
||||
.setGroup(app.notifier.notificationGroup)
|
||||
.setLights(-0xff0001, 2000, 2000)
|
||||
.setPriority(app.notifier.notificationPriority)
|
||||
.setContentIntent(pendingIntent)
|
||||
.setStyle(NotificationCompat.BigTextStyle())
|
||||
if (!app.notifier.shouldBeQuiet()) {
|
||||
groupBuilder.setDefaults(app.notifier.notificationDefaults)
|
||||
}
|
||||
app.notifier.notificationManager.notify(ID_NOTIFICATIONS, groupBuilder.build())
|
||||
}
|
||||
|
||||
app.db.notificationDao().setAllPosted()
|
||||
|
||||
taskCallback.onCompleted()
|
||||
}
|
||||
}
|
@ -0,0 +1,169 @@
|
||||
package pl.szczodrzynski.edziennik.data.api.task
|
||||
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.util.SparseIntArray
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.util.forEach
|
||||
import androidx.core.util.set
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification as AppNotification
|
||||
|
||||
class PostNotifications(val app: App, nList: MutableList<AppNotification>) {
|
||||
companion object {
|
||||
private const val TAG = "PostNotifications"
|
||||
}
|
||||
|
||||
/*public boolean shouldBeQuiet() {
|
||||
long now = Time.getNow().getInMillis();
|
||||
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");
|
||||
}
|
||||
if (start > now) {
|
||||
now += 1000 * 60 * 60 * 24;
|
||||
//Log.d(TAG, "Now is smaller");
|
||||
}
|
||||
//Log.d(TAG, "Start is "+start+", now is "+now+", end is "+end);
|
||||
return start > 0 && now >= start && now <= end;
|
||||
}*/
|
||||
fun shouldBeQuiet() = false
|
||||
|
||||
private fun buildSummaryText(summaryCounts: SparseIntArray): CharSequence {
|
||||
val summaryTexts = mutableListOf<String>()
|
||||
summaryCounts.forEach { key, value ->
|
||||
if (value <= 0)
|
||||
return@forEach
|
||||
val pluralRes = when (key) {
|
||||
AppNotification.TYPE_TIMETABLE_LESSON_CHANGE -> R.plurals.notification_new_timetable_change_format
|
||||
AppNotification.TYPE_NEW_GRADE -> R.plurals.notification_new_grades_format
|
||||
AppNotification.TYPE_NEW_EVENT -> R.plurals.notification_new_events_format
|
||||
AppNotification.TYPE_NEW_HOMEWORK -> R.plurals.notification_new_homework_format
|
||||
AppNotification.TYPE_NEW_SHARED_EVENT -> R.plurals.notification_new_shared_events_format
|
||||
AppNotification.TYPE_NEW_SHARED_HOMEWORK -> R.plurals.notification_new_shared_homework_format
|
||||
AppNotification.TYPE_NEW_MESSAGE -> R.plurals.notification_new_messages_format
|
||||
AppNotification.TYPE_NEW_NOTICE -> R.plurals.notification_new_notices_format
|
||||
AppNotification.TYPE_NEW_ATTENDANCE -> R.plurals.notification_new_attendance_format
|
||||
AppNotification.TYPE_LUCKY_NUMBER -> R.plurals.notification_new_lucky_number_format
|
||||
AppNotification.TYPE_NEW_ANNOUNCEMENT -> R.plurals.notification_new_announcements_format
|
||||
else -> R.plurals.notification_other_format
|
||||
}
|
||||
summaryTexts += app.resources.getQuantityString(pluralRes, value, value)
|
||||
}
|
||||
return summaryTexts.concat(", ")
|
||||
}
|
||||
|
||||
init {
|
||||
val notificationManager = app.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
val count = nList.size
|
||||
val summaryCounts = SparseIntArray()
|
||||
|
||||
val newNotificationsText = app.resources.getQuantityString(R.plurals.notification_count_format, count, count)
|
||||
val newNotificationsShortText = app.resources.getQuantityString(R.plurals.notification_count_short_format, count, count)
|
||||
|
||||
val intent = Intent(
|
||||
app,
|
||||
MainActivity::class.java,
|
||||
"fragmentId" to MainActivity.DRAWER_ITEM_NOTIFICATIONS
|
||||
)
|
||||
val summaryIntent = PendingIntent.getActivity(app, app.notifications.dataId, intent, PendingIntent.FLAG_ONE_SHOT)
|
||||
|
||||
// On Nougat or newer - show maximum 8 notifications
|
||||
// On Marshmallow or older - show maximum 4 notifications
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N && count > 4 || Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && count > 8) {
|
||||
val summaryList = mutableListOf<CharSequence>()
|
||||
nList.forEach {
|
||||
summaryCounts[it.type]++
|
||||
summaryList += listOf(
|
||||
it.profileName.asBoldSpannable(),
|
||||
it.text
|
||||
).concat(": ")
|
||||
}
|
||||
|
||||
// Create a summary to show *instead* of notifications
|
||||
val combined = NotificationCompat.Builder(app, app.notifications.dataKey)
|
||||
.setContentTitle(app.getString(R.string.app_name))
|
||||
.setContentText(buildSummaryText(summaryCounts))
|
||||
.setTicker(newNotificationsText)
|
||||
.setSmallIcon(R.drawable.ic_notification)
|
||||
.setStyle(NotificationCompat.InboxStyle()
|
||||
.also {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
it.setBigContentTitle(app.getString(R.string.app_name))
|
||||
it.setSummaryText(newNotificationsShortText)
|
||||
}
|
||||
else {
|
||||
it.setBigContentTitle(newNotificationsText)
|
||||
it.setSummaryText(app.getString(R.string.notification_click_to_see_all))
|
||||
}
|
||||
summaryList.forEach { line ->
|
||||
it.addLine(line)
|
||||
}
|
||||
})
|
||||
.setColor(0xff2196f3.toInt())
|
||||
.setLights(0xff2196f3.toInt(), 2000, 2000)
|
||||
.setPriority(NotificationCompat.PRIORITY_MAX)
|
||||
.setDefaults(NotificationCompat.DEFAULT_ALL)
|
||||
.setGroup(app.notifications.dataKey)
|
||||
.setContentIntent(summaryIntent)
|
||||
.setAutoCancel(true)
|
||||
.build()
|
||||
notificationManager.notify(System.currentTimeMillis().toInt(), combined)
|
||||
}
|
||||
else {
|
||||
// Less than 8 notifications
|
||||
val notifications = nList.map {
|
||||
summaryCounts[it.type]++
|
||||
NotificationCompat.Builder(app, app.notifications.dataKey)
|
||||
.setContentTitle(it.profileName ?: app.getString(R.string.app_name))
|
||||
.setContentText(it.text)
|
||||
.setSubText(it.title)
|
||||
.setTicker("${it.profileName}: ${it.title}")
|
||||
.setSmallIcon(R.drawable.ic_notification)
|
||||
.setStyle(NotificationCompat.BigTextStyle()
|
||||
.bigText(it.text))
|
||||
.setWhen(it.addedDate)
|
||||
.setColor(0xff2196f3.toInt())
|
||||
.setLights(0xff2196f3.toInt(), 2000, 2000)
|
||||
.setPriority(NotificationCompat.PRIORITY_MAX)
|
||||
.setDefaults(NotificationCompat.DEFAULT_ALL)
|
||||
.setGroup(app.notifications.dataKey)
|
||||
.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_SUMMARY)
|
||||
.setContentIntent(it.getPendingIntent(app))
|
||||
.setAutoCancel(true)
|
||||
.build()
|
||||
}
|
||||
|
||||
val time = System.currentTimeMillis()
|
||||
notificationManager.apply {
|
||||
notifications.forEachIndexed { index, it ->
|
||||
notificationManager.notify((time + index).toInt(), it)
|
||||
}
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
val summary = NotificationCompat.Builder(app, app.notifications.dataKey)
|
||||
.setContentTitle(newNotificationsText)
|
||||
.setContentText(buildSummaryText(summaryCounts))
|
||||
.setTicker(newNotificationsText)
|
||||
.setSmallIcon(R.drawable.ic_notification)
|
||||
.setColor(0xff2196f3.toInt())
|
||||
.setLights(0xff2196f3.toInt(), 2000, 2000)
|
||||
.setPriority(NotificationCompat.PRIORITY_MAX)
|
||||
.setDefaults(NotificationCompat.DEFAULT_ALL)
|
||||
.setGroup(app.notifications.dataKey)
|
||||
.setGroupSummary(true)
|
||||
.setContentIntent(summaryIntent)
|
||||
.setAutoCancel(true)
|
||||
.build()
|
||||
|
||||
notificationManager.notify(app.notifications.dataId, summary)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -7,39 +7,39 @@ package pl.szczodrzynski.edziennik.data.api.task
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.Szkolny
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
|
||||
class SzkolnyTask(val request: Any) : IApiTask(-1) {
|
||||
class SzkolnyTask(val app: App, val syncingProfiles: List<Profile>) : IApiTask(-1) {
|
||||
companion object {
|
||||
private const val TAG = "SzkolnyTask"
|
||||
|
||||
fun sync(profiles: List<Profile>) = SzkolnyTask(SyncRequest(profiles))
|
||||
/*fun shareEvent(event: EventFull) = SzkolnyTask(ShareEventRequest(event))
|
||||
fun unshareEvent(event: EventFull) = SzkolnyTask(UnshareEventRequest(event))*/
|
||||
}
|
||||
private val api by lazy { SzkolnyApi(app) }
|
||||
private val profiles by lazy { app.db.profileDao().allNow }
|
||||
override fun prepare(app: App) { taskName = app.getString(R.string.edziennik_szkolny_creating_notifications) }
|
||||
override fun cancel() {}
|
||||
|
||||
private lateinit var szkolny: Szkolny
|
||||
private val notificationList = mutableListOf<Notification>()
|
||||
|
||||
override fun prepare(app: App) {
|
||||
taskName = app.getString(R.string.edziennik_szkolny_api_sync_title)
|
||||
internal fun run(taskCallback: EdziennikCallback) {
|
||||
val startTime = System.currentTimeMillis()
|
||||
val notifications = Notifications(app, notificationList, profiles)
|
||||
// create all e-register data notifications
|
||||
notifications.run()
|
||||
// send notifications to web push, get shared events
|
||||
AppSync(app, notificationList, profiles, api).run()
|
||||
// create notifications for shared events (not present before app sync)
|
||||
notifications.sharedEventNotifications()
|
||||
d(TAG, "Created ${notificationList.count()} notifications.")
|
||||
// update the database
|
||||
app.db.metadataDao().setAllNotified(true)
|
||||
app.db.notificationDao().addAll(notificationList)
|
||||
app.db.profileDao().setAllNotEmpty()
|
||||
// post all notifications
|
||||
PostNotifications(app, notificationList)
|
||||
d(TAG, "SzkolnyTask: finished in ${System.currentTimeMillis()-startTime} ms.")
|
||||
taskCallback.onCompleted()
|
||||
}
|
||||
|
||||
override fun cancel() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
internal fun run(app: App, taskCallback: EdziennikCallback) {
|
||||
szkolny = Szkolny(app, taskCallback)
|
||||
|
||||
when (request) {
|
||||
is SyncRequest -> szkolny.sync(request.profiles)
|
||||
/*is ShareEventRequest -> szkolny.shareEvent(request.event)
|
||||
is UnshareEventRequest -> szkolny.unshareEvent(request.event)*/
|
||||
}
|
||||
}
|
||||
|
||||
data class SyncRequest(val profiles: List<Profile>)
|
||||
/*data class ShareEventRequest(val event: EventFull)
|
||||
data class UnshareEventRequest(val event: EventFull)*/
|
||||
}
|
||||
|
@ -16,8 +16,8 @@ import androidx.sqlite.db.SupportSQLiteQuery;
|
||||
import java.util.List;
|
||||
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Announcement;
|
||||
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull;
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata;
|
||||
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.data.db.entity.Metadata.TYPE_ANNOUNCEMENT;
|
||||
|
||||
@ -69,4 +69,14 @@ public abstract class AnnouncementDao {
|
||||
public List<AnnouncementFull> getNotNotifiedNow(int profileId) {
|
||||
return getAllNow(profileId, "notified = 0");
|
||||
}
|
||||
|
||||
@Query("SELECT " +
|
||||
"*, " +
|
||||
"teachers.teacherName || ' ' || teachers.teacherSurname AS teacherFullName " +
|
||||
"FROM announcements " +
|
||||
"LEFT JOIN teachers USING(profileId, teacherId) " +
|
||||
"LEFT JOIN metadata ON announcementId = thingId AND thingType = "+TYPE_ANNOUNCEMENT+" AND metadata.profileId = announcements.profileId " +
|
||||
"WHERE notified = 0 " +
|
||||
"ORDER BY addedDate DESC")
|
||||
public abstract List<AnnouncementFull> getNotNotifiedNow();
|
||||
}
|
||||
|
@ -5,20 +5,20 @@
|
||||
package pl.szczodrzynski.edziennik.data.db.dao;
|
||||
|
||||
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.sqlite.db.SimpleSQLiteQuery;
|
||||
import androidx.sqlite.db.SupportSQLiteQuery;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Attendance;
|
||||
import pl.szczodrzynski.edziennik.data.db.full.AttendanceFull;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.data.db.entity.Metadata.TYPE_ATTENDANCE;
|
||||
|
||||
@Dao
|
||||
@ -72,6 +72,13 @@ public abstract class AttendanceDao {
|
||||
return getAllNow(profileId, "notified = 0");
|
||||
}
|
||||
|
||||
@Query("SELECT * FROM attendances " +
|
||||
"LEFT JOIN subjects USING(profileId, subjectId) " +
|
||||
"LEFT JOIN metadata ON attendanceId = thingId AND thingType = " + TYPE_ATTENDANCE + " AND metadata.profileId = attendances.profileId " +
|
||||
"WHERE notified = 0 " +
|
||||
"ORDER BY attendanceLessonDate DESC, attendanceStartTime DESC")
|
||||
public abstract List<AttendanceFull> getNotNotifiedNow();
|
||||
|
||||
// only absent and absent_excused count as absences
|
||||
// all the other types are counted as being present
|
||||
@Query("SELECT \n" +
|
||||
|
@ -34,7 +34,7 @@ public abstract class EventDao {
|
||||
public abstract long add(Event event);
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
public abstract void addAll(List<Event> eventList);
|
||||
public abstract long[] addAll(List<Event> eventList);
|
||||
|
||||
@Query("DELETE FROM events WHERE profileId = :profileId")
|
||||
public abstract void clear(int profileId);
|
||||
@ -44,7 +44,7 @@ public abstract class EventDao {
|
||||
@Query("DELETE FROM metadata WHERE profileId = :profileId AND thingType = :thingType AND thingId = :thingId")
|
||||
public abstract void removeMetadata(int profileId, int thingType, long thingId);
|
||||
@Transaction
|
||||
public void remove(int profileId, int type, long id) {
|
||||
public void remove(int profileId, long type, long id) {
|
||||
remove(profileId, id);
|
||||
removeMetadata(profileId, type == Event.TYPE_HOMEWORK ? TYPE_HOMEWORK : TYPE_EVENT, id);
|
||||
}
|
||||
@ -88,7 +88,7 @@ public abstract class EventDao {
|
||||
public LiveData<List<EventFull>> getAllWhere(int profileId, String filter) {
|
||||
return getAll(profileId, filter);
|
||||
}
|
||||
public LiveData<List<EventFull>> getAllByType(int profileId, int type, String filter) {
|
||||
public LiveData<List<EventFull>> getAllByType(int profileId, long type, String filter) {
|
||||
return getAll(profileId, "eventType = "+type+" AND "+filter);
|
||||
}
|
||||
public LiveData<List<EventFull>> getAllByDate(int profileId, @NonNull Date date) {
|
||||
@ -125,6 +125,24 @@ public abstract class EventDao {
|
||||
return getAllNow(profileId, "notified = 0");
|
||||
}
|
||||
|
||||
@Query("SELECT eventId FROM events WHERE profileId = :profileId AND eventBlacklisted = 1")
|
||||
public abstract List<Long> getBlacklistedIds(int profileId);
|
||||
@Query("SELECT eventId FROM events WHERE eventBlacklisted = 1")
|
||||
public abstract List<Long> getBlacklistedIds();
|
||||
|
||||
@Query("SELECT " +
|
||||
"*, " +
|
||||
"eventTypes.eventTypeName AS typeName, " +
|
||||
"eventTypes.eventTypeColor AS typeColor " +
|
||||
"FROM events " +
|
||||
"LEFT JOIN subjects USING(profileId, subjectId) " +
|
||||
"LEFT JOIN eventTypes USING(profileId, eventType) " +
|
||||
"LEFT JOIN metadata ON eventId = thingId AND (thingType = " + TYPE_EVENT + " OR thingType = " + TYPE_HOMEWORK + ") AND metadata.profileId = events.profileId " +
|
||||
"WHERE events.eventBlacklisted = 0 AND notified = 0 " +
|
||||
"GROUP BY eventId " +
|
||||
"ORDER BY addedDate ASC")
|
||||
public abstract List<EventFull> getNotNotifiedNow();
|
||||
|
||||
public EventFull getByIdNow(int profileId, long eventId) {
|
||||
List<EventFull> eventList = getAllNow(profileId, "eventId = "+eventId);
|
||||
return eventList.size() == 0 ? null : eventList.get(0);
|
||||
@ -146,13 +164,13 @@ public abstract class EventDao {
|
||||
}
|
||||
|
||||
@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);
|
||||
public abstract void removeFutureWithType(int profileId, Date todayDate, long 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);
|
||||
public abstract void removeFutureExceptType(int profileId, Date todayDate, long exceptType);
|
||||
|
||||
@Transaction
|
||||
public void removeFutureExceptTypes(int profileId, Date todayDate, List<Integer> exceptTypes) {
|
||||
public void removeFutureExceptTypes(int profileId, Date todayDate, List<Long> exceptTypes) {
|
||||
removeFuture(profileId, todayDate, "eventType NOT IN " + exceptTypes.toString().replace('[', '(').replace(']', ')'));
|
||||
}
|
||||
|
||||
|
@ -4,14 +4,14 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.db.dao;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.OnConflictStrategy;
|
||||
import androidx.room.Query;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.EventType;
|
||||
|
||||
@Dao
|
||||
@ -26,11 +26,14 @@ public interface EventTypeDao {
|
||||
void clear(int profileId);
|
||||
|
||||
@Query("SELECT * FROM eventTypes WHERE profileId = :profileId AND eventType = :typeId")
|
||||
EventType getByIdNow(int profileId, int typeId);
|
||||
EventType getByIdNow(int profileId, long typeId);
|
||||
|
||||
@Query("SELECT * FROM eventTypes WHERE profileId = :profileId")
|
||||
LiveData<List<EventType>> getAll(int profileId);
|
||||
|
||||
@Query("SELECT * FROM eventTypes WHERE profileId = :profileId")
|
||||
List<EventType> getAllNow(int profileId);
|
||||
|
||||
@Query("SELECT * FROM eventTypes")
|
||||
List<EventType> getAllNow();
|
||||
}
|
||||
|
@ -83,6 +83,13 @@ public abstract class GradeDao {
|
||||
return getAllNow(profileId, "gradeParentId = "+parentId);
|
||||
}
|
||||
|
||||
@Query("SELECT * FROM grades " +
|
||||
"LEFT JOIN subjects USING(profileId, subjectId) " +
|
||||
"LEFT JOIN metadata ON gradeId = thingId AND thingType = " + TYPE_GRADE + " AND metadata.profileId = grades.profileId " +
|
||||
"WHERE notified = 0 " +
|
||||
"ORDER BY addedDate DESC")
|
||||
public abstract List<GradeFull> getNotNotifiedNow();
|
||||
|
||||
@RawQuery
|
||||
abstract GradeFull getNow(SupportSQLiteQuery query);
|
||||
public GradeFull getNow(int profileId, String filter) {
|
||||
|
@ -20,4 +20,7 @@ interface LibrusLessonDao {
|
||||
|
||||
@Query("SELECT * FROM librusLessons WHERE profileId = :profileId")
|
||||
fun getAllNow(profileId: Int): List<LibrusLesson>
|
||||
|
||||
@Query("DELETE FROM librusLessons WHERE profileId = :profileId")
|
||||
fun clear(profileId: Int)
|
||||
}
|
||||
|
@ -17,9 +17,9 @@ import androidx.sqlite.db.SupportSQLiteQuery;
|
||||
import java.util.List;
|
||||
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.LuckyNumber;
|
||||
import pl.szczodrzynski.edziennik.data.db.full.LuckyNumberFull;
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata;
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notice;
|
||||
import pl.szczodrzynski.edziennik.data.db.full.LuckyNumberFull;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.data.db.entity.Metadata.TYPE_LUCKY_NUMBER;
|
||||
@ -78,4 +78,10 @@ public abstract class LuckyNumberDao {
|
||||
public List<LuckyNumberFull> getNotNotifiedNow(int profileId) {
|
||||
return getAllNow(profileId, "notified = 0");
|
||||
}
|
||||
|
||||
@Query("SELECT * FROM luckyNumbers\n" +
|
||||
"LEFT JOIN metadata ON luckyNumberDate = thingId AND thingType = "+TYPE_LUCKY_NUMBER+" AND metadata.profileId = luckyNumbers.profileId " +
|
||||
"WHERE notified = 0 " +
|
||||
"ORDER BY addedDate DESC")
|
||||
public abstract List<LuckyNumberFull> getNotNotifiedNow();
|
||||
}
|
||||
|
@ -17,8 +17,8 @@ import androidx.sqlite.db.SupportSQLiteQuery;
|
||||
import java.util.List;
|
||||
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Message;
|
||||
import pl.szczodrzynski.edziennik.data.db.full.MessageFull;
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata;
|
||||
import pl.szczodrzynski.edziennik.data.db.full.MessageFull;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.data.db.entity.Message.TYPE_DELETED;
|
||||
import static pl.szczodrzynski.edziennik.data.db.entity.Message.TYPE_RECEIVED;
|
||||
@ -101,4 +101,14 @@ public abstract class MessageDao {
|
||||
public List<MessageFull> getReceivedNotNotifiedNow(int profileId) {
|
||||
return getReceivedNow(profileId, "notified = 0");
|
||||
}
|
||||
|
||||
@Query("SELECT " +
|
||||
"*, " +
|
||||
"teachers.teacherName || ' ' || teachers.teacherSurname AS senderFullName " +
|
||||
"FROM messages " +
|
||||
"LEFT JOIN teachers ON teachers.profileId = messages.profileId AND teacherId = senderId " +
|
||||
"LEFT JOIN metadata ON messageId = thingId AND thingType = "+TYPE_MESSAGE+" AND metadata.profileId = messages.profileId " +
|
||||
"WHERE messageType = 0 AND notified = 0 " +
|
||||
"ORDER BY addedDate DESC")
|
||||
public abstract List<MessageFull> getReceivedNotNotifiedNow();
|
||||
}
|
||||
|
@ -40,6 +40,9 @@ public abstract class MetadataDao {
|
||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||
public abstract void addAllIgnore(List<Metadata> metadataList);
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
public abstract void addAllReplace(List<Metadata> metadataList);
|
||||
|
||||
@Query("UPDATE metadata SET seen = :seen WHERE thingId = :thingId AND thingType = :thingType AND profileId = :profileId")
|
||||
abstract void updateSeen(int profileId, int thingType, long thingId, boolean seen);
|
||||
|
||||
@ -165,6 +168,9 @@ public abstract class MetadataDao {
|
||||
@Query("UPDATE metadata SET notified = :notified WHERE profileId = :profileId")
|
||||
public abstract void setAllNotified(int profileId, boolean notified);
|
||||
|
||||
@Query("UPDATE metadata SET notified = :notified")
|
||||
public abstract void setAllNotified(boolean notified);
|
||||
|
||||
|
||||
|
||||
@Query("SELECT count() FROM metadata WHERE profileId = :profileId AND thingType = :thingType AND seen = 0")
|
||||
|
@ -5,13 +5,13 @@
|
||||
package pl.szczodrzynski.edziennik.data.db.dao;
|
||||
|
||||
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.sqlite.db.SimpleSQLiteQuery;
|
||||
import androidx.sqlite.db.SupportSQLiteQuery;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -69,4 +69,14 @@ public abstract class NoticeDao {
|
||||
public List<NoticeFull> getNotNotifiedNow(int profileId) {
|
||||
return getAllNow(profileId, "notified = 0");
|
||||
}
|
||||
|
||||
@Query("SELECT " +
|
||||
"*, " +
|
||||
"teachers.teacherName || ' ' || teachers.teacherSurname AS teacherFullName " +
|
||||
"FROM notices " +
|
||||
"LEFT JOIN teachers USING(profileId, teacherId) " +
|
||||
"LEFT JOIN metadata ON noticeId = thingId AND thingType = "+TYPE_NOTICE+" AND metadata.profileId = notices.profileId " +
|
||||
"WHERE notified = 0 " +
|
||||
"ORDER BY addedDate DESC")
|
||||
public abstract List<NoticeFull> getNotNotifiedNow();
|
||||
}
|
||||
|
@ -52,9 +52,12 @@ interface ProfileDao {
|
||||
@Query("SELECT profiles.* FROM teams JOIN profiles USING(profileId) WHERE teamCode = :teamCode AND registration = " + Profile.REGISTRATION_ENABLED + " AND enableSharedEvents = 1")
|
||||
fun getByTeamCodeNowWithRegistration(teamCode: String?): List<Profile>
|
||||
|
||||
@get:Query("SELECT profileId FROM profiles WHERE profileId >= 0 ORDER BY profileId ASC LIMIT 1")
|
||||
@get:Query("SELECT profileId FROM profiles WHERE profileId > 0 ORDER BY profileId ASC LIMIT 1")
|
||||
val firstId: Int?
|
||||
|
||||
@get:Query("SELECT profileId FROM profiles WHERE profileId >= 0 ORDER BY profileId DESC LIMIT 1")
|
||||
@get:Query("SELECT profileId FROM profiles WHERE profileId > 0 ORDER BY profileId DESC LIMIT 1")
|
||||
val lastId: Int?
|
||||
|
||||
@Query("UPDATE profiles SET empty = 0")
|
||||
fun setAllNotEmpty()
|
||||
}
|
||||
|
@ -107,4 +107,18 @@ interface TimetableDao {
|
||||
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>
|
||||
|
||||
@Query("""
|
||||
SELECT
|
||||
timetable.*,
|
||||
teachers.teacherName ||" "|| teachers.teacherSurname AS teacherName,
|
||||
oldT.teacherName ||" "|| oldT.teacherSurname AS oldTeacherName,
|
||||
metadata.seen, metadata.notified, metadata.addedDate
|
||||
FROM timetable
|
||||
LEFT JOIN teachers USING(profileId, teacherId)
|
||||
LEFT JOIN teachers AS oldT ON timetable.profileId = oldT.profileId AND timetable.oldTeacherId = oldT.teacherId
|
||||
LEFT JOIN metadata ON id = thingId AND thingType = ${Metadata.TYPE_LESSON_CHANGE} AND metadata.profileId = timetable.profileId
|
||||
WHERE timetable.type NOT IN (${Lesson.TYPE_NORMAL}, ${Lesson.TYPE_NO_LESSONS}, ${Lesson.TYPE_SHIFTED_SOURCE}) AND metadata.notified = 0
|
||||
""")
|
||||
fun getNotNotifiedNow(): List<LessonFull>
|
||||
}
|
||||
|
@ -32,19 +32,19 @@ public class Event {
|
||||
public String topic;
|
||||
@ColumnInfo(name = "eventColor")
|
||||
public int color = -1;
|
||||
public static final int TYPE_UNDEFINED = -2;
|
||||
public static final int TYPE_HOMEWORK = -1;
|
||||
public static final int TYPE_DEFAULT = 0;
|
||||
public static final int TYPE_EXAM = 1;
|
||||
public static final int TYPE_SHORT_QUIZ = 2;
|
||||
public static final int TYPE_ESSAY = 3;
|
||||
public static final int TYPE_PROJECT = 4;
|
||||
public static final int TYPE_PT_MEETING = 5;
|
||||
public static final int TYPE_EXCURSION = 6;
|
||||
public static final int TYPE_READING = 7;
|
||||
public static final int TYPE_CLASS_EVENT = 8;
|
||||
public static final int TYPE_INFORMATION = 9;
|
||||
public static final int TYPE_TEACHER_ABSENCE = 10;
|
||||
public static final long TYPE_UNDEFINED = -2;
|
||||
public static final long TYPE_HOMEWORK = -1;
|
||||
public static final long TYPE_DEFAULT = 0;
|
||||
public static final long TYPE_EXAM = 1;
|
||||
public static final long TYPE_SHORT_QUIZ = 2;
|
||||
public static final long TYPE_ESSAY = 3;
|
||||
public static final long TYPE_PROJECT = 4;
|
||||
public static final long TYPE_PT_MEETING = 5;
|
||||
public static final long TYPE_EXCURSION = 6;
|
||||
public static final long TYPE_READING = 7;
|
||||
public static final long TYPE_CLASS_EVENT = 8;
|
||||
public static final long TYPE_INFORMATION = 9;
|
||||
public static final long TYPE_TEACHER_ABSENCE = 10;
|
||||
public static final int COLOR_HOMEWORK = 0xff795548;
|
||||
public static final int COLOR_DEFAULT = 0xffffc107;
|
||||
public static final int COLOR_EXAM = 0xfff44336;
|
||||
@ -58,7 +58,7 @@ public class Event {
|
||||
public static final int COLOR_INFORMATION = 0xff039be5;
|
||||
public static final int COLOR_TEACHER_ABSENCE = 0xff039be5;
|
||||
@ColumnInfo(name = "eventType")
|
||||
public int type = TYPE_DEFAULT;
|
||||
public long type = TYPE_DEFAULT;
|
||||
@ColumnInfo(name = "eventAddedManually")
|
||||
public boolean addedManually;
|
||||
@ColumnInfo(name = "eventSharedBy")
|
||||
@ -76,7 +76,7 @@ public class Event {
|
||||
@Ignore
|
||||
public Event() {}
|
||||
|
||||
public Event(int profileId, long id, Date eventDate, @Nullable Time startTime, String topic, int color, int type, boolean addedManually, long teacherId, long subjectId, long teamId)
|
||||
public Event(int profileId, long id, Date eventDate, @Nullable Time startTime, String topic, int color, long type, boolean addedManually, long teacherId, long subjectId, long teamId)
|
||||
{
|
||||
this.profileId = profileId;
|
||||
this.id = id;
|
||||
@ -97,8 +97,8 @@ public class Event {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Event clone() throws CloneNotSupportedException {
|
||||
return new Event(
|
||||
public Event clone() {
|
||||
Event event = new Event(
|
||||
profileId,
|
||||
id,
|
||||
eventDate.clone(),
|
||||
@ -111,6 +111,10 @@ public class Event {
|
||||
teacherId,
|
||||
teamId
|
||||
);
|
||||
event.sharedBy = sharedBy;
|
||||
event.sharedByName = sharedByName;
|
||||
event.blacklisted = blacklisted;
|
||||
return event;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -4,34 +4,18 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.db.entity
|
||||
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import com.google.gson.JsonObject
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification.Companion.TYPE_AUTO_ARCHIVING
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification.Companion.TYPE_ERROR
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification.Companion.TYPE_FEEDBACK_MESSAGE
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification.Companion.TYPE_GENERAL
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification.Companion.TYPE_LUCKY_NUMBER
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification.Companion.TYPE_NEW_ANNOUNCEMENT
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification.Companion.TYPE_NEW_ATTENDANCE
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification.Companion.TYPE_NEW_EVENT
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification.Companion.TYPE_NEW_GRADE
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification.Companion.TYPE_NEW_HOMEWORK
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification.Companion.TYPE_NEW_MESSAGE
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification.Companion.TYPE_NEW_NOTICE
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification.Companion.TYPE_NEW_SHARED_EVENT
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification.Companion.TYPE_SERVER_MESSAGE
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification.Companion.TYPE_TIMETABLE_CHANGED
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification.Companion.TYPE_TIMETABLE_LESSON_CHANGE
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification.Companion.TYPE_UPDATE
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
|
||||
@Entity(tableName = "notifications")
|
||||
data class Notification(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
val id: Int = 0,
|
||||
val id: Long = 0,
|
||||
|
||||
val title: String,
|
||||
val text: String,
|
||||
@ -41,7 +25,7 @@ data class Notification(
|
||||
val profileId: Int?,
|
||||
val profileName: String?,
|
||||
|
||||
var posted: Boolean = false,
|
||||
var posted: Boolean = true,
|
||||
|
||||
var viewId: Int? = null,
|
||||
var extras: JsonObject? = null,
|
||||
@ -59,6 +43,7 @@ data class Notification(
|
||||
const val TYPE_NEW_HOMEWORK = 10
|
||||
const val TYPE_NEW_SHARED_EVENT = 7
|
||||
const val TYPE_NEW_SHARED_HOMEWORK = 12
|
||||
const val TYPE_REMOVED_SHARED_EVENT = 18
|
||||
const val TYPE_NEW_MESSAGE = 8
|
||||
const val TYPE_NEW_NOTICE = 9
|
||||
const val TYPE_NEW_ATTENDANCE = 13
|
||||
@ -67,6 +52,10 @@ data class Notification(
|
||||
const val TYPE_NEW_ANNOUNCEMENT = 15
|
||||
const val TYPE_FEEDBACK_MESSAGE = 16
|
||||
const val TYPE_AUTO_ARCHIVING = 17
|
||||
|
||||
fun buildId(profileId: Int, type: Int, itemId: Long): Long {
|
||||
return 1000000000000 + profileId*10000000000 + type*100000000 + itemId;
|
||||
}
|
||||
}
|
||||
|
||||
fun addExtra(key: String, value: Long?): Notification {
|
||||
@ -100,4 +89,10 @@ data class Notification(
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
fun getPendingIntent(context: Context): PendingIntent {
|
||||
val intent = Intent(context, MainActivity::class.java)
|
||||
fillIntent(intent)
|
||||
return PendingIntent.getActivity(context, id.toInt(), intent, PendingIntent.FLAG_ONE_SHOT)
|
||||
}
|
||||
}
|
||||
|
@ -30,21 +30,21 @@ open class Profile(
|
||||
val loginStoreId: Int,
|
||||
val loginStoreType: Int,
|
||||
|
||||
override var name: String,
|
||||
override var subname: String?,
|
||||
override var name: String = "",
|
||||
override var subname: String? = null,
|
||||
|
||||
/**
|
||||
* The name of the student.
|
||||
* This doesn't change, no matter if it's a parent or student account.
|
||||
*/
|
||||
var studentNameLong: String,
|
||||
var studentNameShort: String,
|
||||
var studentNameLong: String = "",
|
||||
var studentNameShort: String = "",
|
||||
/**
|
||||
* A full name of the account owner.
|
||||
* If null, then it's a student account.
|
||||
* If not null, then it's a parent account with this name.
|
||||
*/
|
||||
var accountName: String?,
|
||||
var accountName: String? = null,
|
||||
|
||||
val studentData: JsonObject = JsonObject()
|
||||
|
||||
|
@ -45,6 +45,35 @@ public class EventFull extends Event {
|
||||
this.sharedByName = event.sharedByName;
|
||||
this.blacklisted = event.blacklisted;
|
||||
}
|
||||
public EventFull(EventFull event) {
|
||||
super(
|
||||
event.profileId,
|
||||
event.id,
|
||||
event.eventDate.clone(),
|
||||
event.startTime == null ? null : event.startTime.clone(),
|
||||
event.topic,
|
||||
event.color,
|
||||
event.type,
|
||||
event.addedManually,
|
||||
event.teacherId,
|
||||
event.subjectId,
|
||||
event.teamId
|
||||
);
|
||||
|
||||
this.sharedBy = event.sharedBy;
|
||||
this.sharedByName = event.sharedByName;
|
||||
this.blacklisted = event.blacklisted;
|
||||
this.typeName = event.typeName;
|
||||
this.typeColor = event.typeColor;
|
||||
this.teacherFullName = event.teacherFullName;
|
||||
this.subjectLongName = event.subjectLongName;
|
||||
this.subjectShortName = event.subjectShortName;
|
||||
this.teamName = event.teamName;
|
||||
this.teamCode = event.teamCode;
|
||||
this.seen = event.seen;
|
||||
this.notified = event.notified;
|
||||
this.addedDate = event.addedDate;
|
||||
}
|
||||
|
||||
public EventFull(Event event, Metadata metadata) {
|
||||
this(event);
|
||||
|
@ -11,11 +11,14 @@ import android.content.Intent
|
||||
import android.util.Log
|
||||
import com.google.firebase.iid.zzaq
|
||||
import com.google.firebase.iid.zzv
|
||||
import com.google.firebase.messaging.MessagingAnalytics
|
||||
import com.google.firebase.messaging.zzc
|
||||
import com.google.gson.JsonObject
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import java.util.*
|
||||
import com.google.firebase.messaging.zzo.zza as logNotificationOpen
|
||||
import com.google.firebase.messaging.zzo.zza as logNotificationReceived
|
||||
import com.google.firebase.messaging.zzo.zzb as logNotificationDismiss
|
||||
import com.google.firebase.messaging.zzo.zzd as shouldUploadMetrics
|
||||
|
||||
@SuppressLint("Registered")
|
||||
open class FirebaseService : zzc() {
|
||||
@ -45,8 +48,8 @@ open class FirebaseService : zzc() {
|
||||
}
|
||||
}
|
||||
|
||||
if (MessagingAnalytics.shouldUploadMetrics(intent)) {
|
||||
MessagingAnalytics.logNotificationOpen(intent)
|
||||
if (shouldUploadMetrics(intent)) {
|
||||
logNotificationOpen(intent)
|
||||
}
|
||||
|
||||
return true
|
||||
@ -62,8 +65,8 @@ open class FirebaseService : zzc() {
|
||||
|
||||
when (action) {
|
||||
"com.google.firebase.messaging.NOTIFICATION_DISMISS" -> {
|
||||
if (MessagingAnalytics.shouldUploadMetrics(intent)) {
|
||||
MessagingAnalytics.logNotificationDismiss(intent)
|
||||
if (shouldUploadMetrics(intent)) {
|
||||
logNotificationDismiss(intent)
|
||||
}
|
||||
}
|
||||
"com.google.firebase.messaging.NEW_TOKEN" -> {
|
||||
@ -106,8 +109,8 @@ open class FirebaseService : zzc() {
|
||||
// get the message type
|
||||
when (val it = json.getString("message_type") ?: "gcm") {
|
||||
"gcm" -> { // 0
|
||||
if (MessagingAnalytics.shouldUploadMetrics(intent)) {
|
||||
MessagingAnalytics.logNotificationReceived(intent)
|
||||
if (shouldUploadMetrics(intent)) {
|
||||
logNotificationReceived(intent, null)
|
||||
}
|
||||
|
||||
onMessageReceived(Message(messageId, json))
|
||||
|
@ -5,36 +5,19 @@
|
||||
package pl.szczodrzynski.edziennik.data.firebase;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.firebase.messaging.FirebaseMessagingService;
|
||||
import com.google.firebase.messaging.RemoteMessage;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.BuildConfig;
|
||||
import pl.szczodrzynski.edziennik.MainActivity;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.data.api.task.EdziennikTask;
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event;
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.EventType;
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.FeedbackMessage;
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask;
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore;
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile;
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Team;
|
||||
import pl.szczodrzynski.edziennik.data.db.full.EventFull;
|
||||
import pl.szczodrzynski.edziennik.network.ServerRequest;
|
||||
import pl.szczodrzynski.edziennik.ui.modules.base.DebugFragment;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Notification;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.App.APP_URL;
|
||||
import static pl.szczodrzynski.edziennik.data.db.entity.Event.TYPE_HOMEWORK;
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.d;
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.strToInt;
|
||||
|
||||
@ -45,16 +28,16 @@ public class MyFirebaseMessagingService extends FirebaseMessagingService {
|
||||
public void onNewToken(String s) {
|
||||
super.onNewToken(s);
|
||||
|
||||
Log.d(TAG, "New token: "+s);
|
||||
/* Log.d(TAG, "New token: "+s);
|
||||
App app = (App)getApplicationContext();
|
||||
if (app.config.getSync().getTokenApp() == null || !app.config.getSync().getTokenApp().equals(s)) {
|
||||
app.config.getSync().setTokenApp(s);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessageReceived(RemoteMessage remoteMessage) {
|
||||
App app = ((App) getApplicationContext());
|
||||
/*App app = ((App) getApplicationContext());
|
||||
// Not getting messages here? See why this may be: https://goo.gl/39bRNJ
|
||||
|
||||
String from = remoteMessage.getFrom();
|
||||
@ -78,7 +61,7 @@ public class MyFirebaseMessagingService extends FirebaseMessagingService {
|
||||
processVulcanPush(app, remoteMessage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
private void processMobidziennikPush(App app, RemoteMessage remoteMessage) {
|
||||
@ -102,14 +85,7 @@ public class MyFirebaseMessagingService extends FirebaseMessagingService {
|
||||
|
||||
if (profile != null) {
|
||||
if (remoteMessage.getData().get("id_wiadomosci") != null) {
|
||||
/*app.notifier.add(new Notification(app.getContext(), remoteMessage.getData().get("message"))
|
||||
.withProfileData(profile.id, profile.name)
|
||||
.withTitle(remoteMessage.getData().get("title"))
|
||||
.withType(Notification.TYPE_NEW_MESSAGE)
|
||||
.withFragmentRedirect(MainActivity.DRAWER_ITEM_MESSAGES)
|
||||
);
|
||||
app.notifier.postAll(profile);
|
||||
app.saveConfig("notifications");*/
|
||||
|
||||
d(TAG, "Syncing profile " + profile.getId());
|
||||
EdziennikTask.Companion.syncProfile(profile.getId(), null, null).enqueue(app);
|
||||
} else {
|
||||
@ -141,7 +117,7 @@ public class MyFirebaseMessagingService extends FirebaseMessagingService {
|
||||
|
||||
private void processAppPush(App app, RemoteMessage remoteMessage) {
|
||||
// Check if message contains a data payload.
|
||||
String type = remoteMessage.getData().get("type");
|
||||
/*String type = remoteMessage.getData().get("type");
|
||||
if (remoteMessage.getData().size() > 0
|
||||
&& type != null) {
|
||||
//Log.d(TAG, "Message data payload: " + remoteMessage.sync());
|
||||
@ -239,90 +215,8 @@ public class MyFirebaseMessagingService extends FirebaseMessagingService {
|
||||
break;
|
||||
case "ping":
|
||||
// just a ping
|
||||
break;
|
||||
/* ______ _ _
|
||||
| ____| | | | |
|
||||
| |____ _____ _ __ | |_ ______ ___| |__ __ _ _ __ ___
|
||||
| __\ \ / / _ \ '_ \| __| |______| / __| '_ \ / _` | '__/ _ \
|
||||
| |___\ V / __/ | | | |_ \__ \ | | | (_| | | | __/
|
||||
|______\_/ \___|_| |_|\__| |___/_| |_|\__,_|_| \__*/
|
||||
case "event":
|
||||
case "event_removed":
|
||||
AsyncTask.execute(() -> {
|
||||
String teamCode = remoteMessage.getData().get("team");
|
||||
String teamUnshareCode = remoteMessage.getData().get("team_unshare");
|
||||
while (teamCode != null || teamUnshareCode != null) {
|
||||
d(TAG, "Got an event for teamCode " + teamCode + " and teamUnshareCode " + teamUnshareCode);
|
||||
// get the target Profile by the corresponding teamCode
|
||||
List<Profile> profiles = app.db.profileDao().getByTeamCodeNowWithRegistration(teamCode == null ? teamUnshareCode : teamCode);
|
||||
for (Profile profile : profiles) {
|
||||
d(TAG, "Matched profile " + profile.getName());
|
||||
if (teamCode != null) {
|
||||
// SHARING
|
||||
JsonObject jEvent = new JsonParser().parse(remoteMessage.getData().get("data")).getAsJsonObject();
|
||||
d(TAG, "An event is there! " + jEvent.toString());
|
||||
// get the target Team from teamCode
|
||||
Team team = app.db.teamDao().getByCodeNow(profile.getId(), teamCode);
|
||||
if (team != null) {
|
||||
d(TAG, "The target team is " + team.name + ", ID " + team.id);
|
||||
// create the event from Json. Add the missing teamId and !!profileId!!
|
||||
Event event = app.gson.fromJson(jEvent.toString(), Event.class);
|
||||
if (jEvent.get("colorDefault") != null) {
|
||||
event.color = -1;
|
||||
}
|
||||
event.profileId = profile.getId();
|
||||
event.teamId = team.id;
|
||||
d(TAG, "Created the event! " + event);
|
||||
|
||||
// TODO? i guess
|
||||
Event oldEvent = app.db.eventDao().getByIdNow(profile.getId(), event.id);
|
||||
if (event.sharedBy != null && event.sharedBy.equals(profile.getUserCode())) {
|
||||
d(TAG, "Shared by self! Changing name");
|
||||
event.sharedBy = "self";
|
||||
event.sharedByName = profile.getStudentNameLong();
|
||||
}
|
||||
d(TAG, "Old event found? " + oldEvent);
|
||||
EventType eventType = app.db.eventTypeDao().getByIdNow(profile.getId(), event.type);
|
||||
app.notifier.add(new Notification(app.getContext(), app.getString((oldEvent == null ? R.string.notification_shared_event_format : R.string.notification_shared_event_modified_format), event.sharedByName, eventType == null ? "wydarzenie" : eventType.name, event.eventDate.getFormattedString(), event.topic))
|
||||
.withProfileData(profile.getId(), profile.getName())
|
||||
.withType(event.type == TYPE_HOMEWORK ? pl.szczodrzynski.edziennik.data.db.entity.Notification.TYPE_NEW_SHARED_HOMEWORK : pl.szczodrzynski.edziennik.data.db.entity.Notification.TYPE_NEW_SHARED_EVENT)
|
||||
.withFragmentRedirect(event.type == TYPE_HOMEWORK ? MainActivity.DRAWER_ITEM_HOMEWORK : MainActivity.DRAWER_ITEM_AGENDA)
|
||||
.withLongExtra("eventDate", event.eventDate.getValue())
|
||||
);
|
||||
d(TAG, "Finishing adding event " + event);
|
||||
app.db.eventDao().add(event);
|
||||
try {
|
||||
app.db.metadataDao().setBoth(profile.getId(), event, false, true, jEvent.get("addedDate").getAsLong());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// UNSHARING
|
||||
long eventId = Long.parseLong(remoteMessage.getData().get("remove_id"));
|
||||
EventFull oldEvent = app.db.eventDao().getByIdNow(profile.getId(), eventId);
|
||||
if (oldEvent != null) {
|
||||
app.notifier.add(new Notification(app.getContext(), app.getString(R.string.notification_shared_event_removed_format, oldEvent.sharedByName, oldEvent.typeName, oldEvent.eventDate.getFormattedString(), oldEvent.topic))
|
||||
.withProfileData(profile.getId(), profile.getName())
|
||||
.withType(oldEvent.type == TYPE_HOMEWORK ? pl.szczodrzynski.edziennik.data.db.entity.Notification.TYPE_NEW_SHARED_HOMEWORK : pl.szczodrzynski.edziennik.data.db.entity.Notification.TYPE_NEW_SHARED_EVENT)
|
||||
.withFragmentRedirect(oldEvent.type == TYPE_HOMEWORK ? MainActivity.DRAWER_ITEM_HOMEWORK : MainActivity.DRAWER_ITEM_AGENDA)
|
||||
.withLongExtra("eventDate", oldEvent.eventDate.getValue())
|
||||
);
|
||||
app.db.eventDao().remove(oldEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (teamCode != null) {
|
||||
teamCode = null;
|
||||
} else {
|
||||
teamUnshareCode = null;
|
||||
}
|
||||
}
|
||||
app.notifier.postAll();
|
||||
app.saveConfig();
|
||||
});
|
||||
break;
|
||||
break
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
@ -4,11 +4,129 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.firebase
|
||||
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import com.google.gson.JsonParser
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.api.task.PostNotifications
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
|
||||
class SzkolnyAppFirebase(val app: App, val profiles: List<Profile>, val message: FirebaseService.Message) {
|
||||
init {
|
||||
|
||||
run {
|
||||
val type = message.data.getString("type") ?: return@run
|
||||
when (type) {
|
||||
"sharedEvent" -> sharedEvent(
|
||||
message.data.getString("shareTeamCode") ?: return@run,
|
||||
message.data.getString("event") ?: return@run,
|
||||
message.data.getString("message") ?: return@run
|
||||
)
|
||||
"unsharedEvent" -> unsharedEvent(
|
||||
message.data.getString("unshareTeamCode") ?: return@run,
|
||||
message.data.getLong("eventId") ?: return@run,
|
||||
message.data.getString("message") ?: return@run
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun sharedEvent(teamCode: String, jsonStr: String, message: String) {
|
||||
val json = JsonParser().parse(jsonStr).asJsonObject
|
||||
val teams = app.db.teamDao().allNow
|
||||
val eventTypes = app.db.eventTypeDao().allNow
|
||||
|
||||
val events = mutableListOf<Event>()
|
||||
val metadataList = mutableListOf<Metadata>()
|
||||
val notificationList = mutableListOf<Notification>()
|
||||
|
||||
teams.filter { it.code == teamCode }.distinctBy { it.profileId }.forEach { team ->
|
||||
val profile = profiles.firstOrNull { it.id == team.profileId }
|
||||
val event = Event(
|
||||
team.profileId,
|
||||
json.getLong("id") ?: return,
|
||||
json.getInt("eventDate")?.let { Date.fromValue(it) } ?: return,
|
||||
json.getInt("startTime")?.let { Time.fromValue(it) },
|
||||
json.getString("topic") ?: "",
|
||||
json.getInt("color") ?: -1,
|
||||
json.getLong("type") ?: 0,
|
||||
true,
|
||||
json.getLong("teacherId") ?: -1,
|
||||
json.getLong("subjectId") ?: -1,
|
||||
team.id
|
||||
)
|
||||
|
||||
// TODO? i guess - this comment is here for like a year
|
||||
//val oldEvent: Event? = app.db.eventDao().getByIdNow(profile?.id ?: -1, event.id)
|
||||
|
||||
event.sharedBy = json.getString("sharedBy")
|
||||
event.sharedByName = json.getString("sharedByName")
|
||||
if (profile?.userCode == event.sharedBy) event.sharedBy = "self"
|
||||
|
||||
val metadata = Metadata(
|
||||
event.profileId,
|
||||
if (event.type == Event.TYPE_HOMEWORK) Metadata.TYPE_HOMEWORK else Metadata.TYPE_EVENT,
|
||||
event.id,
|
||||
false,
|
||||
true,
|
||||
json.getLong("addedDate") ?: System.currentTimeMillis()
|
||||
)
|
||||
|
||||
//val eventType = eventTypes.firstOrNull { it.profileId == profile?.id && it.id == event.type }
|
||||
|
||||
/*val text = app.getString(
|
||||
if (oldEvent == null)
|
||||
R.string.notification_shared_event_format
|
||||
else
|
||||
R.string.notification_shared_event_modified_format,
|
||||
event.sharedByName,
|
||||
eventType?.name ?: "wydarzenie",
|
||||
event.eventDate.formattedString,
|
||||
event.topic
|
||||
)*/
|
||||
val type = if (event.type == Event.TYPE_HOMEWORK) Notification.TYPE_NEW_SHARED_HOMEWORK else Notification.TYPE_NEW_SHARED_EVENT
|
||||
val notification = Notification(
|
||||
id = Notification.buildId(event.profileId, type, event.id),
|
||||
title = app.getNotificationTitle(type),
|
||||
text = message,
|
||||
type = type,
|
||||
profileId = profile?.id,
|
||||
profileName = profile?.name,
|
||||
viewId = if (event.type == Event.TYPE_HOMEWORK) MainActivity.DRAWER_ITEM_HOMEWORK else MainActivity.DRAWER_ITEM_AGENDA,
|
||||
addedDate = metadata.addedDate
|
||||
).addExtra("eventId", event.id).addExtra("eventDate", event.eventDate.value.toLong())
|
||||
|
||||
events += event
|
||||
metadataList += metadata
|
||||
notificationList += notification
|
||||
}
|
||||
app.db.eventDao().addAll(events)
|
||||
app.db.metadataDao().addAllReplace(metadataList)
|
||||
app.db.notificationDao().addAll(notificationList)
|
||||
PostNotifications(app, notificationList)
|
||||
}
|
||||
|
||||
private fun unsharedEvent(teamCode: String, eventId: Long, message: String) {
|
||||
val teams = app.db.teamDao().allNow
|
||||
val notificationList = mutableListOf<Notification>()
|
||||
|
||||
teams.filter { it.code == teamCode }.distinctBy { it.profileId }.forEach { team ->
|
||||
val profile = profiles.firstOrNull { it.id == team.profileId }
|
||||
val notification = Notification(
|
||||
id = Notification.buildId(profile?.id ?: 0, Notification.TYPE_REMOVED_SHARED_EVENT, eventId),
|
||||
title = app.getNotificationTitle(Notification.TYPE_REMOVED_SHARED_EVENT),
|
||||
text = message,
|
||||
type = Notification.TYPE_REMOVED_SHARED_EVENT,
|
||||
profileId = profile?.id,
|
||||
profileName = profile?.name,
|
||||
viewId = MainActivity.DRAWER_ITEM_AGENDA
|
||||
)
|
||||
notificationList += notification
|
||||
app.db.eventDao().remove(team.profileId, eventId)
|
||||
}
|
||||
app.db.notificationDao().addAll(notificationList)
|
||||
PostNotifications(app, notificationList)
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@
|
||||
package pl.szczodrzynski.edziennik.data.firebase
|
||||
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.data.api.task.EdziennikTask
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask
|
||||
import pl.szczodrzynski.edziennik.data.api.task.IApiTask
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.getString
|
||||
|
@ -9,7 +9,7 @@ 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_MESSAGES
|
||||
import pl.szczodrzynski.edziennik.data.api.task.EdziennikTask
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask
|
||||
import pl.szczodrzynski.edziennik.data.api.task.IApiTask
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Message.TYPE_RECEIVED
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
|
@ -22,7 +22,7 @@ public class NetworkUtils {
|
||||
public boolean isOnline() {
|
||||
assert app != null;
|
||||
ConnectivityManager cm =
|
||||
(ConnectivityManager) app.getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
(ConnectivityManager) app.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
assert cm != null;
|
||||
NetworkInfo netInfo = cm.getActiveNetworkInfo();
|
||||
return netInfo != null && netInfo.isConnectedOrConnecting();
|
||||
@ -30,7 +30,7 @@ public class NetworkUtils {
|
||||
|
||||
public int checkBackgroundDataRestricted() {
|
||||
|
||||
ConnectivityManager connMgr = (ConnectivityManager) app.getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
ConnectivityManager connMgr = (ConnectivityManager) app.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
assert connMgr != null;
|
||||
|
@ -29,7 +29,7 @@ public class ServerRequest {
|
||||
private String source = "";
|
||||
|
||||
public ServerRequest(App app, String url, String source) {
|
||||
this(app, url, source, app.profile);
|
||||
this(app, url, source, App.Companion.getProfile());
|
||||
}
|
||||
|
||||
public ServerRequest(App app, String url, String source, Profile profileFull) {
|
||||
@ -40,7 +40,7 @@ public class ServerRequest {
|
||||
this.app = app;
|
||||
this.url = url;
|
||||
this.params = new ArrayList<>();
|
||||
this.username = (profile != null && profile.getRegistration() == REGISTRATION_ENABLED ? usernameId : app.deviceId);
|
||||
this.username = (profile != null && profile.getRegistration() == REGISTRATION_ENABLED ? usernameId : app.getDeviceId());
|
||||
this.source = source;
|
||||
if (profile != null && profile.getRegistration() == REGISTRATION_ENABLED) {
|
||||
this.setBodyParameter("login_type", Integer.toString(loginStoreType));
|
||||
@ -51,7 +51,7 @@ public class ServerRequest {
|
||||
this.setBodyParameter("team_ids", "UI_THREAD");
|
||||
}
|
||||
else {
|
||||
this.setBodyParameter("team_ids", app.gson.toJson(app.db.teamDao().getAllCodesNow(profile.getId())));
|
||||
this.setBodyParameter("team_ids", app.getGson().toJson(App.db.teamDao().getAllCodesNow(profile.getId())));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -86,15 +86,15 @@ public class ServerRequest {
|
||||
.addParameter("app_version_build_type", BuildConfig.BUILD_TYPE)
|
||||
.addParameter("app_version_code", Integer.toString(BuildConfig.VERSION_CODE))
|
||||
.addParameter("app_version", BuildConfig.VERSION_NAME + " " + BuildConfig.BUILD_TYPE + " (" + BuildConfig.VERSION_CODE + ")")
|
||||
.addParameter("device_id", Settings.Secure.getString(app.getContext().getContentResolver(), Settings.Secure.ANDROID_ID))
|
||||
.addParameter("device_id", Settings.Secure.getString(app.getContentResolver(), Settings.Secure.ANDROID_ID))
|
||||
.addParameter("device_model", Build.MANUFACTURER+" "+Build.MODEL)
|
||||
.addParameter("device_os_version", Build.VERSION.RELEASE)
|
||||
.addParameter("fcm_token", app.config.getSync().getTokenApp())
|
||||
.addParameter("signature", sign(app.signature, timestamp))
|
||||
.addParameter("fcm_token", app.getConfig().getSync().getTokenApp())
|
||||
.addParameter("signature", "TODO")
|
||||
.addParameter("signature_timestamp", timestamp)
|
||||
.addParameter("package_name", "pl.szczodrzynski.edziennik")
|
||||
.addParameter("source", source)
|
||||
.addParameter("update_frequency", app.config.getSync().getEnabled() ? app.config.getSync().getInterval() : -1)
|
||||
.addParameter("update_frequency", app.getConfig().getSync().getEnabled() ? app.getConfig().getSync().getInterval() : -1)
|
||||
.post()
|
||||
.callback(new JsonCallbackHandler() {
|
||||
@Override
|
||||
@ -123,15 +123,15 @@ public class ServerRequest {
|
||||
.addParameter("app_version_build_type", BuildConfig.BUILD_TYPE)
|
||||
.addParameter("app_version_code", Integer.toString(BuildConfig.VERSION_CODE))
|
||||
.addParameter("app_version", BuildConfig.VERSION_NAME + " " + BuildConfig.BUILD_TYPE + " (" + BuildConfig.VERSION_CODE + ")")
|
||||
.addParameter("device_id", Settings.Secure.getString(app.getContext().getContentResolver(), Settings.Secure.ANDROID_ID))
|
||||
.addParameter("device_id", Settings.Secure.getString(app.getContentResolver(), Settings.Secure.ANDROID_ID))
|
||||
.addParameter("device_model", Build.MANUFACTURER+" "+Build.MODEL)
|
||||
.addParameter("device_os_version", Build.VERSION.RELEASE)
|
||||
.addParameter("fcm_token", app.config.getSync().getTokenApp())
|
||||
.addParameter("signature", sign(app.signature, timestamp))
|
||||
.addParameter("fcm_token", app.getConfig().getSync().getTokenApp())
|
||||
.addParameter("signature", "TODO")
|
||||
.addParameter("signature_timestamp", timestamp)
|
||||
.addParameter("package_name", "pl.szczodrzynski.edziennik")
|
||||
.addParameter("source", source)
|
||||
.addParameter("update_frequency", app.config.getSync().getEnabled() ? app.config.getSync().getInterval() : -1)
|
||||
.addParameter("update_frequency", app.getConfig().getSync().getEnabled() ? app.getConfig().getSync().getInterval() : -1)
|
||||
.post()
|
||||
.build()
|
||||
.execute();
|
||||
|
@ -1,287 +0,0 @@
|
||||
package pl.szczodrzynski.edziennik.receivers;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.DownloadManager;
|
||||
import android.app.IntentService;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.core.content.FileProvider;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.network.ServerRequest;
|
||||
import pl.szczodrzynski.edziennik.sync.SyncWorker;
|
||||
import pl.szczodrzynski.edziennik.utils.Utils;
|
||||
|
||||
import static android.content.Context.DOWNLOAD_SERVICE;
|
||||
import static pl.szczodrzynski.edziennik.App.APP_URL;
|
||||
import static pl.szczodrzynski.edziennik.App.UPDATES_ON_PLAY_STORE;
|
||||
|
||||
public class BootReceiver extends BroadcastReceiver {
|
||||
|
||||
private static final int NO_INTERNET_RETRY_TIMEOUT = 60;
|
||||
private static boolean alarmSet = false;
|
||||
public static long update_download_id;
|
||||
public static String update_url;
|
||||
public static String update_filename;
|
||||
private static final String TAG = "receivers.BootReceiver";
|
||||
private App app;
|
||||
|
||||
@Override
|
||||
public void onReceive(final Context context, final Intent intent) {
|
||||
app = (App)context.getApplicationContext();
|
||||
if (intent.getBooleanExtra("ExecutedByAlarm", false))
|
||||
{
|
||||
alarmSet = false;
|
||||
}
|
||||
if (intent.getAction() != null && intent.getAction().equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE))
|
||||
{
|
||||
long referenceId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
|
||||
if(referenceId == update_download_id) {
|
||||
Intent downloadIntent;
|
||||
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
if (!app.permissionChecker.canRequestApkInstall()) {
|
||||
app.permissionChecker.requestApkInstall();
|
||||
return;
|
||||
}
|
||||
}
|
||||
File fileLocation = new File(app.getContext().getExternalFilesDir(null), update_filename);
|
||||
Uri apkUri = FileProvider.getUriForFile(app.getContext(), app.getContext().getApplicationContext().getPackageName() + ".provider", fileLocation);
|
||||
|
||||
downloadIntent = new Intent(Intent.ACTION_VIEW);
|
||||
downloadIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
downloadIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
downloadIntent.setDataAndType(apkUri, "application/vnd.android.package-archive");
|
||||
|
||||
List<ResolveInfo> resInfoList = app.getContext().getPackageManager().queryIntentActivities(downloadIntent, PackageManager.MATCH_DEFAULT_ONLY);
|
||||
for (ResolveInfo resolveInfo : resInfoList) {
|
||||
String packageName = resolveInfo.activityInfo.packageName;
|
||||
app.getContext().grantUriPermission(packageName, apkUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
}
|
||||
|
||||
} else {
|
||||
File fileLocation = new File(app.getContext().getExternalFilesDir(null), update_filename);
|
||||
downloadIntent = new Intent(Intent.ACTION_VIEW);
|
||||
downloadIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
downloadIntent.setDataAndType(Uri.fromFile(fileLocation), "application/vnd.android.package-archive");
|
||||
}
|
||||
app.getContext().startActivity(downloadIntent);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SyncWorker.Companion.scheduleNext(app, false);
|
||||
if (app.networkUtils.isOnline())
|
||||
{
|
||||
checkUpdate(context, intent);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Toast.makeText(context, "No internet, retrying in "+NO_INTERNET_RETRY_TIMEOUT+" seconds", Toast.LENGTH_SHORT).show();
|
||||
scheduleUpdateCheck(context, NO_INTERNET_RETRY_TIMEOUT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean scheduleUpdateCheck(Context context, int secondsLater)
|
||||
{
|
||||
Intent alarmIntent = new Intent(context, BootReceiver.class);
|
||||
alarmIntent.putExtra("ExecutedByAlarm", true);
|
||||
PendingIntent alarmPendingIntent = PendingIntent.getBroadcast(context, 234324243, alarmIntent, 0);
|
||||
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||
if (alarmManager != null) {
|
||||
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (secondsLater * 1000), alarmPendingIntent);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void checkUpdate(final Context context, final Intent intent)
|
||||
{
|
||||
if (!alarmSet) {
|
||||
//Toast.makeText(context, "Update scheduled for 48 hours since now", Toast.LENGTH_SHORT).show();
|
||||
alarmSet = scheduleUpdateCheck(context, 48 * 60 * 60);
|
||||
}
|
||||
|
||||
//app.networkUtils.setSelfSignedSSL(app.getContext(), null);
|
||||
|
||||
new ServerRequest(app, app.requestScheme + APP_URL + "main.php?get_update", "BootReceiver/UPD")
|
||||
.run(((e, result) -> {
|
||||
if (result != null) {
|
||||
if (result.get("update_available").getAsBoolean()) {
|
||||
String updateVersion = result.get("update_version").getAsString();
|
||||
String updateUrl = result.get("update_url").getAsString();
|
||||
String updateFilename = result.get("update_filename").getAsString();
|
||||
boolean updateMandatory = result.get("update_mandatory").getAsBoolean();
|
||||
boolean updateDirect = result.get("update_direct").getAsBoolean();
|
||||
|
||||
if (app.appConfig.updateVersion == null || !app.appConfig.updateVersion.equals(updateVersion)) {
|
||||
app.appConfig.updateVersion = updateVersion;
|
||||
app.appConfig.updateUrl = updateUrl;
|
||||
app.appConfig.updateFilename = updateFilename;
|
||||
app.appConfig.updateMandatory = updateMandatory;
|
||||
app.appConfig.updateDirect = updateDirect;
|
||||
app.saveConfig();
|
||||
}
|
||||
if (!UPDATES_ON_PLAY_STORE || intent.getBooleanExtra("UserChecked", false)) {
|
||||
app.notifier.notificationUpdatesShow(
|
||||
updateVersion,
|
||||
updateUrl,
|
||||
updateFilename,
|
||||
updateDirect);
|
||||
}
|
||||
} else {
|
||||
if (app.appConfig.updateVersion == null || !app.appConfig.updateVersion.equals("")) {
|
||||
app.appConfig.updateVersion = "";
|
||||
app.appConfig.updateMandatory = false;
|
||||
app.saveConfig();
|
||||
}
|
||||
app.notifier.notificationUpdatesHide();
|
||||
|
||||
if (intent.getBooleanExtra("UserChecked", false)) {
|
||||
Toast.makeText(context, context.getString(R.string.notification_no_update), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Toast.makeText(context, "Server returned nothing, retrying in "+NO_INTERNET_RETRY_TIMEOUT+" seconds", Toast.LENGTH_SHORT).show();
|
||||
scheduleUpdateCheck(context, NO_INTERNET_RETRY_TIMEOUT);
|
||||
}
|
||||
}));
|
||||
/*Ion.with(app.getContext())
|
||||
.load(app.requestScheme + APP_URL + "main.php?get_update")
|
||||
.setBodyParameter("username", (app.profile.autoRegistrationAllowed ? app.profile.registrationUsername : app.appConfig.deviceId))
|
||||
.setBodyParameter("app_version_build_type", BuildConfig.BUILD_TYPE)
|
||||
.setBodyParameter("app_version_code", Integer.toString(BuildConfig.VERSION_CODE))
|
||||
.setBodyParameter("app_version", BuildConfig.VERSION_NAME + " " + BuildConfig.BUILD_TYPE + " (" + BuildConfig.VERSION_CODE + ")")
|
||||
.setBodyParameter("device_id", Settings.Secure.getString(app.getContext().getContentResolver(), Settings.Secure.ANDROID_ID))
|
||||
.setBodyParameter("device_model", Build.MANUFACTURER+" "+Build.MODEL)
|
||||
.setBodyParameter("device_os_version", Build.VERSION.RELEASE)
|
||||
.setBodyParameter("fcm_token", app.appConfig.fcmToken)
|
||||
.asJsonObject()
|
||||
.setCallback((e, result) -> {
|
||||
// do stuff with the result or error
|
||||
if (result != null) {
|
||||
if (result.get("update_available").getAsBoolean()) {
|
||||
String updateVersion = result.get("update_version").getAsString();
|
||||
String updateUrl = result.get("update_url").getAsString();
|
||||
String updateFilename = result.get("update_filename").getAsString();
|
||||
|
||||
if (app.appConfig.updateVersion == null || !app.appConfig.updateVersion.equals(updateVersion)) {
|
||||
app.appConfig.updateVersion = updateVersion;
|
||||
app.appConfig.updateUrl = updateUrl;
|
||||
app.appConfig.updateFilename = updateFilename;
|
||||
app.saveConfig();
|
||||
}
|
||||
app.notifier.notificationUpdatesShow(
|
||||
updateVersion,
|
||||
updateUrl,
|
||||
updateFilename);
|
||||
} else {
|
||||
if (app.appConfig.updateVersion == null || !app.appConfig.updateVersion.equals("")) {
|
||||
app.appConfig.updateVersion = "";
|
||||
app.saveConfig();
|
||||
}
|
||||
app.notifier.notificationUpdatesHide();
|
||||
|
||||
if (intent.getBooleanExtra("UserChecked", false)) {
|
||||
Toast.makeText(context, context.getString(R.string.notification_no_update), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Toast.makeText(context, "Server returned nothing, retrying in "+NO_INTERNET_RETRY_TIMEOUT+" seconds", Toast.LENGTH_SHORT).show();
|
||||
scheduleUpdateCheck(context, NO_INTERNET_RETRY_TIMEOUT);
|
||||
}
|
||||
});*/
|
||||
}
|
||||
|
||||
private static DownloadManager downloadManager;
|
||||
|
||||
public static long downloadFile(Context context) {
|
||||
Toast.makeText(context, R.string.downloading, Toast.LENGTH_SHORT).show();
|
||||
File dir = new File(context.getExternalFilesDir(null)+""/*, update_filename*/);
|
||||
/*if (existingFile.exists())
|
||||
{
|
||||
existingFile.delete();
|
||||
}*/
|
||||
if (dir.isDirectory())
|
||||
{
|
||||
String[] children = dir.list();
|
||||
for (int i = 0; i < children.length; i++)
|
||||
{
|
||||
new File(dir, children[i]).delete();
|
||||
}
|
||||
}
|
||||
|
||||
Uri uri = Uri.parse(update_url);
|
||||
long downloadReference;
|
||||
// Create request for android download manager
|
||||
downloadManager = (DownloadManager)context.getSystemService(DOWNLOAD_SERVICE);
|
||||
DownloadManager.Request request = new DownloadManager.Request(uri);
|
||||
//Setting title of request
|
||||
request.setTitle(context.getString(R.string.app_name));
|
||||
//Setting description of request
|
||||
request.setDescription(context.getString(R.string.notification_downloading_update));
|
||||
//Set the local destination for the downloaded file to a path within the application's external files directory
|
||||
try {
|
||||
request.setDestinationInExternalFilesDir(context, null, update_filename);
|
||||
}
|
||||
catch (java.lang.IllegalStateException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
Toast.makeText(context, "Failed to get external storage files directory", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
//Enqueue download and save into referenceId
|
||||
downloadReference = downloadManager.enqueue(request);
|
||||
return downloadReference;
|
||||
}
|
||||
|
||||
public static class NotificationActionService extends IntentService {
|
||||
private static final String TAG = "BootReceiver/NAS";
|
||||
|
||||
public NotificationActionService() {
|
||||
super(NotificationActionService.class.getSimpleName());
|
||||
//IntentFilter filter = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
|
||||
//registerReceiver(downloadReceiver, filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onHandleIntent(Intent intent) {
|
||||
if (UPDATES_ON_PLAY_STORE && !intent.getBooleanExtra("update_direct", false)) {
|
||||
Utils.openGooglePlay(this, "pl.szczodrzynski.edziennik");
|
||||
return;
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
App app = (App)getApplication();
|
||||
if (!app.permissionChecker.canRequestApkInstall()) {
|
||||
app.permissionChecker.requestApkInstall();
|
||||
app.notifier.notificationUpdatesShow(
|
||||
intent.getStringExtra("update_version"),
|
||||
intent.getStringExtra("update_url"),
|
||||
intent.getStringExtra("update_filename"),
|
||||
intent.getBooleanExtra("update_direct", false));
|
||||
return;
|
||||
}
|
||||
}
|
||||
update_url = intent.getStringExtra("update_url");
|
||||
update_filename = intent.getStringExtra("update_filename");
|
||||
//update_filename = "Edziennik_update.apk";
|
||||
update_download_id = downloadFile(this);
|
||||
}
|
||||
}
|
||||
}
|
@ -8,9 +8,9 @@ import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import pl.szczodrzynski.edziennik.data.api.ApiService
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask
|
||||
import pl.szczodrzynski.edziennik.data.api.events.requests.ServiceCloseRequest
|
||||
import pl.szczodrzynski.edziennik.data.api.events.requests.TaskCancelRequest
|
||||
import pl.szczodrzynski.edziennik.data.api.task.EdziennikTask
|
||||
|
||||
class SzkolnyReceiver : BroadcastReceiver() {
|
||||
companion object {
|
||||
|
@ -2,13 +2,9 @@ package pl.szczodrzynski.edziennik.sync
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.os.AsyncTask
|
||||
import androidx.work.*
|
||||
import androidx.work.impl.WorkManagerImpl
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.MINUTE
|
||||
import pl.szczodrzynski.edziennik.data.api.task.EdziennikTask
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask
|
||||
import pl.szczodrzynski.edziennik.formatDate
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import java.util.concurrent.TimeUnit
|
||||
@ -22,35 +18,8 @@ class SyncWorker(val context: Context, val params: WorkerParameters) : Worker(co
|
||||
*/
|
||||
@SuppressLint("RestrictedApi")
|
||||
fun scheduleNext(app: App, rescheduleIfFailedFound: Boolean = true) {
|
||||
AsyncTask.execute {
|
||||
val workManager = WorkManager.getInstance(app) as WorkManagerImpl
|
||||
val scheduledWork = workManager.workDatabase.workSpecDao().scheduledWork
|
||||
scheduledWork.forEach {
|
||||
d(TAG, "Work: ${it.id} at ${(it.periodStartTime+it.initialDelay).formatDate()}. State = ${it.state} (finished = ${it.state.isFinished})")
|
||||
}
|
||||
// remove finished work and other than SyncWorker
|
||||
scheduledWork.removeAll { it.workerClassName != SyncWorker::class.java.canonicalName || it.isPeriodic || it.state.isFinished }
|
||||
d(TAG, "Found ${scheduledWork.size} unfinished work")
|
||||
// remove all enqueued work that had to (but didn't) run at some point in the past (at least 1min ago)
|
||||
val failedWork = scheduledWork.filter { it.state == WorkInfo.State.ENQUEUED && it.periodStartTime+it.initialDelay < System.currentTimeMillis() - 1*MINUTE*1000 }
|
||||
d(TAG, "${failedWork.size} work requests failed to start (out of ${scheduledWork.size} requests)")
|
||||
if (rescheduleIfFailedFound) {
|
||||
if (failedWork.isNotEmpty()) {
|
||||
d(TAG, "App Manager detected!")
|
||||
EventBus.getDefault().postSticky(AppManagerDetectedEvent(failedWork.map { it.periodStartTime + it.initialDelay }))
|
||||
}
|
||||
if (scheduledWork.size - failedWork.size < 1) {
|
||||
d(TAG, "No pending work found, scheduling next:")
|
||||
rescheduleNext(app)
|
||||
}
|
||||
}
|
||||
else {
|
||||
d(TAG, "NOT rescheduling: waiting to open the activity")
|
||||
if (scheduledWork.size < 1) {
|
||||
d(TAG, "No work found *at all*, scheduling next:")
|
||||
rescheduleNext(app)
|
||||
}
|
||||
}
|
||||
WorkerUtils.scheduleNext(app, rescheduleIfFailedFound) {
|
||||
rescheduleNext(app)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-1-18.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.sync
|
||||
|
||||
import android.app.DownloadManager
|
||||
import android.app.IntentService
|
||||
import android.app.NotificationManager
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.widget.Toast
|
||||
import androidx.core.content.FileProvider
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.response.Update
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
import java.io.File
|
||||
|
||||
class UpdateDownloaderService : IntentService(UpdateDownloaderService::class.java.simpleName) {
|
||||
companion object {
|
||||
private const val TAG = "UpdateDownloaderService"
|
||||
private var downloadId = 0L
|
||||
private var downloadFilename = ""
|
||||
}
|
||||
|
||||
private fun tryUpdateWithGooglePlay(update: Update): Boolean {
|
||||
if (!update.isOnGooglePlay)
|
||||
return false
|
||||
return try {
|
||||
Utils.openGooglePlay(this, application.packageName)
|
||||
true
|
||||
}
|
||||
catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
class DownloadProgressReceiver : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent?) {
|
||||
if (intent?.action != DownloadManager.ACTION_DOWNLOAD_COMPLETE)
|
||||
return
|
||||
if (intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1) != downloadId)
|
||||
return
|
||||
val app = context.applicationContext as App
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !app.permissionChecker.canRequestApkInstall()) {
|
||||
app.permissionChecker.requestApkInstall()
|
||||
return
|
||||
}
|
||||
|
||||
val file = File(app.getExternalFilesDir(null), downloadFilename)
|
||||
val installIntent = Intent(Intent.ACTION_VIEW)
|
||||
installIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
installIntent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive")
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
val apkUri = FileProvider.getUriForFile(app, "${app.packageName}.provider", file)
|
||||
installIntent.setDataAndType(apkUri, "application/vnd.android.package-archive")
|
||||
|
||||
val resInfoList = app.packageManager.queryIntentActivities(installIntent, PackageManager.MATCH_DEFAULT_ONLY)
|
||||
for (resolveInfo in resInfoList) {
|
||||
val packageName = resolveInfo.activityInfo.packageName
|
||||
app.grantUriPermission(packageName, apkUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
}
|
||||
}
|
||||
|
||||
app.startActivity(installIntent)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onHandleIntent(intent: Intent?) {
|
||||
val app = application as App
|
||||
val update = App.config.update ?: return
|
||||
|
||||
if (tryUpdateWithGooglePlay(update))
|
||||
return
|
||||
|
||||
if (update.downloadUrl == null) {
|
||||
Toast.makeText(app, "Nie można pobrać tej aktualizacji. Pobierz ręcznie z Google Play.", Toast.LENGTH_LONG).show()
|
||||
return
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !app.permissionChecker.canRequestApkInstall()) {
|
||||
app.permissionChecker.requestApkInstall()
|
||||
return
|
||||
}
|
||||
|
||||
(app.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).cancel(app.notifications.updatesId)
|
||||
|
||||
val dir: File? = app.getExternalFilesDir(null)
|
||||
if (dir?.isDirectory == true) {
|
||||
dir.listFiles()?.forEach {
|
||||
it.delete()
|
||||
}
|
||||
}
|
||||
|
||||
val uri = Uri.parse(update.downloadUrl)
|
||||
downloadFilename = "${update.versionName}.apk"
|
||||
|
||||
val downloadManager = app.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
|
||||
val request = DownloadManager.Request(uri)
|
||||
request.setTitle(app.getString(R.string.app_name)+" "+update.versionName)
|
||||
request.setDescription(app.getString(R.string.notification_downloading_update))
|
||||
try {
|
||||
request.setDestinationInExternalFilesDir(app, null, downloadFilename)
|
||||
} catch (e: IllegalStateException) {
|
||||
e.printStackTrace()
|
||||
Toast.makeText(app, "Nie można znaleźć katalogu docelowego. Pobierz aktualizację ręcznie z Google Play.", Toast.LENGTH_LONG).show()
|
||||
return
|
||||
}
|
||||
downloadId = downloadManager.enqueue(request)
|
||||
}
|
||||
}
|
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-1-18.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.sync
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.text.Html
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.work.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class UpdateWorker(val context: Context, val params: WorkerParameters) : Worker(context, params), CoroutineScope {
|
||||
companion object {
|
||||
const val TAG = "UpdateWorker"
|
||||
|
||||
/**
|
||||
* Schedule the sync job only if it's not already scheduled.
|
||||
*/
|
||||
@SuppressLint("RestrictedApi")
|
||||
fun scheduleNext(app: App, rescheduleIfFailedFound: Boolean = true) {
|
||||
WorkerUtils.scheduleNext(app, rescheduleIfFailedFound) {
|
||||
rescheduleNext(app)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel any existing sync jobs and schedule a new one.
|
||||
*
|
||||
* If [ConfigSync.enabled] is not true, just cancel every job.
|
||||
*/
|
||||
fun rescheduleNext(app: App) {
|
||||
cancelNext(app)
|
||||
if (!app.config.sync.notifyAboutUpdates) {
|
||||
return
|
||||
}
|
||||
val syncInterval = 4 * DAY;
|
||||
|
||||
val syncAt = System.currentTimeMillis() + syncInterval*1000
|
||||
Utils.d(TAG, "Scheduling work at ${syncAt.formatDate()}")
|
||||
|
||||
val constraints = Constraints.Builder()
|
||||
.setRequiredNetworkType(NetworkType.CONNECTED)
|
||||
.build()
|
||||
|
||||
val syncWorkRequest = OneTimeWorkRequestBuilder<UpdateWorker>()
|
||||
.setInitialDelay(syncInterval, TimeUnit.SECONDS)
|
||||
.setConstraints(constraints)
|
||||
.addTag(TAG)
|
||||
.build()
|
||||
|
||||
WorkManager.getInstance(app).enqueue(syncWorkRequest)
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel any scheduled sync job.
|
||||
*/
|
||||
fun cancelNext(app: App) {
|
||||
Utils.d(TAG, "Cancelling work by tag $TAG")
|
||||
WorkManager.getInstance(app).cancelAllWorkByTag(TAG)
|
||||
}
|
||||
|
||||
fun runNow(app: App) {
|
||||
try {
|
||||
val api = SzkolnyApi(app)
|
||||
val response = api.getUpdate()
|
||||
if (response?.success != true)
|
||||
return
|
||||
val updates = response.data
|
||||
if (updates?.isNotEmpty() != true)
|
||||
return
|
||||
val update = updates[0]
|
||||
|
||||
app.config.update = update
|
||||
|
||||
val notificationIntent = Intent(app, UpdateDownloaderService::class.java)
|
||||
val pendingIntent = PendingIntent.getService(app, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
val notification = NotificationCompat.Builder(app, app.notifications.updatesKey)
|
||||
.setContentTitle(app.getString(R.string.notification_updates_title))
|
||||
.setContentText(app.getString(R.string.notification_updates_text, update.versionName))
|
||||
.setTicker(app.getString(R.string.notification_updates_summary))
|
||||
.setSmallIcon(R.drawable.ic_notification)
|
||||
.setStyle(NotificationCompat.BigTextStyle()
|
||||
.bigText(listOf(
|
||||
app.getString(R.string.notification_updates_text, update.versionName),
|
||||
update.releaseNotes?.let { Html.fromHtml(it) }
|
||||
).concat("\n")))
|
||||
.setColor(0xff2196f3.toInt())
|
||||
.setLights(0xFF00FFFF.toInt(), 2000, 2000)
|
||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||
.setDefaults(NotificationCompat.DEFAULT_ALL)
|
||||
.setGroup(app.notifications.updatesKey)
|
||||
.setContentIntent(pendingIntent)
|
||||
.setAutoCancel(false)
|
||||
.build()
|
||||
(app.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).notify(app.notifications.updatesId, notification)
|
||||
|
||||
} catch (ignore: Exception) { }
|
||||
}
|
||||
}
|
||||
|
||||
private val job = Job()
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Default
|
||||
|
||||
override fun doWork(): Result {
|
||||
Utils.d(TAG, "Running worker ID ${params.id}")
|
||||
val app = context as App
|
||||
if (!app.config.sync.notifyAboutUpdates) {
|
||||
return Result.success()
|
||||
}
|
||||
|
||||
launch {
|
||||
runNow(app)
|
||||
}
|
||||
|
||||
rescheduleNext(this.context)
|
||||
return Result.success()
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-1-18.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.sync
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.AsyncTask
|
||||
import androidx.work.WorkInfo
|
||||
import androidx.work.WorkManager
|
||||
import androidx.work.impl.WorkManagerImpl
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.MINUTE
|
||||
import pl.szczodrzynski.edziennik.formatDate
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
|
||||
object WorkerUtils {
|
||||
/**
|
||||
* Schedule the sync job only if it's not already scheduled.
|
||||
*/
|
||||
@SuppressLint("RestrictedApi")
|
||||
inline fun scheduleNext(app: App, rescheduleIfFailedFound: Boolean = true, crossinline onReschedule: () -> Unit) {
|
||||
AsyncTask.execute {
|
||||
val workManager = WorkManager.getInstance(app) as WorkManagerImpl
|
||||
val scheduledWork = workManager.workDatabase.workSpecDao().scheduledWork
|
||||
scheduledWork.forEach {
|
||||
Utils.d("WorkerUtils", "Work: ${it.id} at ${(it.periodStartTime + it.initialDelay).formatDate()}. State = ${it.state} (finished = ${it.state.isFinished})")
|
||||
}
|
||||
// remove finished work and other than SyncWorker
|
||||
scheduledWork.removeAll { it.workerClassName != SyncWorker::class.java.canonicalName || it.isPeriodic || it.state.isFinished }
|
||||
Utils.d("WorkerUtils", "Found ${scheduledWork.size} unfinished work")
|
||||
// remove all enqueued work that had to (but didn't) run at some point in the past (at least 1min ago)
|
||||
val failedWork = scheduledWork.filter { it.state == WorkInfo.State.ENQUEUED && it.periodStartTime + it.initialDelay < System.currentTimeMillis() - 1 * MINUTE * 1000 }
|
||||
Utils.d("WorkerUtils", "${failedWork.size} work requests failed to start (out of ${scheduledWork.size} requests)")
|
||||
if (rescheduleIfFailedFound) {
|
||||
if (failedWork.isNotEmpty()) {
|
||||
Utils.d("WorkerUtils", "App Manager detected!")
|
||||
EventBus.getDefault().postSticky(AppManagerDetectedEvent(failedWork.map { it.periodStartTime + it.initialDelay }))
|
||||
}
|
||||
if (scheduledWork.size - failedWork.size < 1) {
|
||||
Utils.d("WorkerUtils", "No pending work found, scheduling next:")
|
||||
onReschedule()
|
||||
}
|
||||
} else {
|
||||
Utils.d("WorkerUtils", "NOT rescheduling: waiting to open the activity")
|
||||
if (scheduledWork.size < 1) {
|
||||
Utils.d("WorkerUtils", "No work found *at all*, scheduling next:")
|
||||
onReschedule()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -44,7 +44,7 @@ class ChangelogDialog(
|
||||
|
||||
val text = app.assets.open("pl-changelog.html").bufferedReader().use {
|
||||
it.readText()
|
||||
}
|
||||
}.replace("<li>", "<br><li> - ")
|
||||
textView.text = Html.fromHtml(text)
|
||||
|
||||
val scrollView = ScrollView(activity)
|
||||
|
@ -21,13 +21,8 @@ import kotlinx.coroutines.*
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_AGENDA
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.*
|
||||
import pl.szczodrzynski.edziennik.data.db.full.EventFull
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.EventType
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Subject
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Team
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Lesson
|
||||
import pl.szczodrzynski.edziennik.data.db.full.LessonFull
|
||||
import pl.szczodrzynski.edziennik.databinding.DialogEventManualV2Binding
|
||||
import pl.szczodrzynski.edziennik.utils.Anim
|
||||
@ -43,7 +38,7 @@ class EventManualDialog(
|
||||
val defaultLesson: LessonFull? = null,
|
||||
val defaultDate: Date? = null,
|
||||
val defaultTime: Time? = null,
|
||||
val defaultType: Int? = null,
|
||||
val defaultType: Long? = null,
|
||||
val editingEvent: EventFull? = null,
|
||||
val onShowListener: ((tag: String) -> Unit)? = null,
|
||||
val onDismissListener: ((tag: String) -> Unit)? = null
|
||||
@ -149,7 +144,7 @@ class EventManualDialog(
|
||||
else -> R.string.dialog_event_manual_share_first_notice
|
||||
}
|
||||
|
||||
b.shareDetails.setText(text)
|
||||
b.shareDetails.setText(text, event.sharedByName ?: "")
|
||||
}
|
||||
|
||||
private fun loadLists() { launch {
|
||||
@ -588,8 +583,7 @@ class EventManualDialog(
|
||||
startTime,
|
||||
topic,
|
||||
customColor ?: -1,
|
||||
type?.toInt()
|
||||
?: Event.TYPE_DEFAULT,
|
||||
type ?: Event.TYPE_DEFAULT,
|
||||
true,
|
||||
teacherId ?: -1,
|
||||
subjectId ?: -1,
|
||||
@ -598,7 +592,7 @@ class EventManualDialog(
|
||||
|
||||
val metadataObject = Metadata(
|
||||
profileId,
|
||||
when (type?.toInt()) {
|
||||
when (type) {
|
||||
Event.TYPE_HOMEWORK -> Metadata.TYPE_HOMEWORK
|
||||
else -> Metadata.TYPE_EVENT
|
||||
},
|
||||
|
@ -32,7 +32,7 @@ public class GradeDetailsDialog {
|
||||
|
||||
public GradeDetailsDialog(Context context) {
|
||||
this.context = context;
|
||||
this.profileId = App.profileId;
|
||||
this.profileId = App.Companion.getProfileId();
|
||||
}
|
||||
public GradeDetailsDialog(Context context, int profileId) {
|
||||
this.context = context;
|
||||
@ -74,7 +74,7 @@ public class GradeDetailsDialog {
|
||||
b.setGrade(grade);
|
||||
|
||||
int gradeColor;
|
||||
if (App.getConfig().getFor(profileId).getGrades().getColorMode() == COLOR_MODE_DEFAULT) {
|
||||
if (App.Companion.getConfig().getFor(profileId).getGrades().getColorMode() == COLOR_MODE_DEFAULT) {
|
||||
gradeColor = grade.color;
|
||||
}
|
||||
else {
|
||||
@ -103,7 +103,7 @@ public class GradeDetailsDialog {
|
||||
|
||||
b.setCommentVisible(false);
|
||||
|
||||
b.setDevMode(App.devMode);
|
||||
b.setDevMode(App.Companion.getDevMode());
|
||||
|
||||
b.gradeName.setTextColor(ColorUtils.calculateLuminance(gradeColor) > 0.25 ? 0xff000000 : 0xffffffff);
|
||||
b.gradeName.getBackground().setColorFilter(new PorterDuffColorFilter(gradeColor, PorterDuff.Mode.MULTIPLY));
|
||||
|
@ -19,7 +19,7 @@ public class LessonChangeDialog {
|
||||
|
||||
public LessonChangeDialog(Context context) {
|
||||
this.context = context;
|
||||
this.profileId = App.profileId;
|
||||
this.profileId = App.Companion.getProfileId();
|
||||
}
|
||||
public LessonChangeDialog(Context context, int profileId) {
|
||||
this.context = context;
|
||||
|
@ -12,8 +12,6 @@ import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.databinding.DialogLessonDetailsBinding
|
||||
import pl.szczodrzynski.edziennik.utils.models.Notification
|
||||
import java.util.*
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class ProfileRemoveDialog(
|
||||
@ -52,26 +50,35 @@ class ProfileRemoveDialog(
|
||||
val profileObject = app.db.profileDao().getByIdNow(profileId) ?: return@async
|
||||
app.db.announcementDao().clear(profileId)
|
||||
app.db.attendanceDao().clear(profileId)
|
||||
app.db.eventDao().clear(profileId)
|
||||
app.db.eventTypeDao().clear(profileId)
|
||||
app.db.gradeDao().clear(profileId)
|
||||
app.db.gradeCategoryDao().clear(profileId)
|
||||
app.db.luckyNumberDao().clear(profileId)
|
||||
app.db.noticeDao().clear(profileId)
|
||||
app.db.subjectDao().clear(profileId)
|
||||
app.db.teacherDao().clear(profileId)
|
||||
app.db.teamDao().clear(profileId)
|
||||
app.db.messageRecipientDao().clear(profileId)
|
||||
app.db.messageDao().clear(profileId)
|
||||
app.db.endpointTimerDao().clear(profileId)
|
||||
app.db.attendanceTypeDao().clear(profileId)
|
||||
app.db.classroomDao().clear(profileId)
|
||||
app.db.configDao().clear(profileId)
|
||||
app.db.endpointTimerDao().clear(profileId)
|
||||
app.db.eventDao().clear(profileId)
|
||||
app.db.eventTypeDao().clear(profileId)
|
||||
app.db.gradeCategoryDao().clear(profileId)
|
||||
app.db.gradeDao().clear(profileId)
|
||||
app.db.lessonRangeDao().clear(profileId)
|
||||
app.db.librusLessonDao().clear(profileId)
|
||||
app.db.luckyNumberDao().clear(profileId)
|
||||
app.db.messageDao().clear(profileId)
|
||||
app.db.messageRecipientDao().clear(profileId)
|
||||
app.db.noticeDao().clear(profileId)
|
||||
app.db.noticeTypeDao().clear(profileId)
|
||||
app.db.noticeTypeDao().clear(profileId)
|
||||
app.db.notificationDao().clear(profileId)
|
||||
app.db.subjectDao().clear(profileId)
|
||||
app.db.teacherAbsenceDao().clear(profileId)
|
||||
app.db.teacherAbsenceDao().clear(profileId)
|
||||
app.db.teacherAbsenceTypeDao().clear(profileId)
|
||||
app.db.teacherDao().clear(profileId)
|
||||
app.db.teamDao().clear(profileId)
|
||||
app.db.timetableDao().clear(profileId)
|
||||
|
||||
val homeCards = app.config.ui.homeCards.toMutableList()
|
||||
homeCards.removeAll { it.profileId == profileId }
|
||||
app.config.ui.homeCards = homeCards
|
||||
|
||||
val loginStoreId = profileObject.loginStoreId
|
||||
val profilesUsingLoginStore = app.db.profileDao().getIdsByLoginStoreIdNow(loginStoreId)
|
||||
if (profilesUsingLoginStore.size == 1) {
|
||||
@ -80,18 +87,9 @@ class ProfileRemoveDialog(
|
||||
app.db.profileDao().remove(profileId)
|
||||
app.db.metadataDao().deleteAll(profileId)
|
||||
|
||||
val toRemove = ArrayList<Notification>()
|
||||
for (notification in app.appConfig.notifications) {
|
||||
if (notification.profileId == profileId) {
|
||||
toRemove.add(notification)
|
||||
}
|
||||
if (App.profileId == profileId) {
|
||||
app.profileLoadLast { }
|
||||
}
|
||||
app.appConfig.notifications.removeAll(toRemove)
|
||||
|
||||
app.profile = null
|
||||
App.profileId = -1
|
||||
|
||||
app.profileLoadById(app.profileLastId())
|
||||
}
|
||||
deferred.await()
|
||||
dialog.dismiss()
|
||||
|
@ -12,7 +12,7 @@ import kotlinx.coroutines.Job
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.data.api.task.EdziennikTask
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask
|
||||
import pl.szczodrzynski.edziennik.databinding.DialogLessonDetailsBinding
|
||||
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesFragment
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
@ -77,6 +77,9 @@ class LessonDetailsDialog(
|
||||
)
|
||||
}
|
||||
|
||||
if (App.devMode)
|
||||
b.lessonId.visibility = View.VISIBLE
|
||||
|
||||
update()
|
||||
}}
|
||||
|
||||
|
@ -78,10 +78,10 @@ public class AgendaFragment extends Fragment {
|
||||
return null;
|
||||
app = (App) activity.getApplication();
|
||||
getContext().getTheme().applyStyle(Themes.INSTANCE.getAppTheme(), true);
|
||||
if (app.profile == null)
|
||||
if (app.getProfile() == null)
|
||||
return inflater.inflate(R.layout.fragment_loading, container, false);
|
||||
// activity, context and profile is valid
|
||||
viewType = app.config.getUi().getAgendaViewType();
|
||||
viewType = app.getConfig().forProfile().getUi().getAgendaViewType();
|
||||
if (viewType == AGENDA_DEFAULT) {
|
||||
b_default = DataBindingUtil.inflate(inflater, R.layout.fragment_agenda_default, container, false);
|
||||
return b_default.getRoot();
|
||||
@ -94,7 +94,7 @@ public class AgendaFragment extends Fragment {
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
if (app == null || app.profile == null || activity == null || (b_default == null && b_calendar == null) || !isAdded())
|
||||
if (app == null || activity == null || b_default == null && b_calendar == null || !isAdded())
|
||||
return;
|
||||
|
||||
activity.getBottomSheet().prependItems(
|
||||
@ -106,7 +106,7 @@ public class AgendaFragment extends Fragment {
|
||||
activity.getBottomSheet().close();
|
||||
new EventManualDialog(
|
||||
activity,
|
||||
App.profileId,
|
||||
App.Companion.getProfileId(),
|
||||
null,
|
||||
actualDate,
|
||||
null,
|
||||
@ -122,7 +122,7 @@ public class AgendaFragment extends Fragment {
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
viewType = viewType == AGENDA_DEFAULT ? AGENDA_CALENDAR : AGENDA_DEFAULT;
|
||||
app.config.getUi().setAgendaViewType(viewType);
|
||||
app.getConfig().forProfile().getUi().setAgendaViewType(viewType);
|
||||
activity.reloadTarget();
|
||||
}),
|
||||
new BottomSheetSeparatorItem(true),
|
||||
@ -131,7 +131,7 @@ public class AgendaFragment extends Fragment {
|
||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check_outline)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
AsyncTask.execute(() -> app.db.metadataDao().setAllSeen(App.profileId, TYPE_EVENT, true));
|
||||
AsyncTask.execute(() -> App.db.metadataDao().setAllSeen(App.Companion.getProfileId(), TYPE_EVENT, true));
|
||||
Toast.makeText(activity, R.string.main_menu_mark_as_read_success, Toast.LENGTH_SHORT).show();
|
||||
})
|
||||
);
|
||||
@ -141,7 +141,7 @@ public class AgendaFragment extends Fragment {
|
||||
activity.getNavView().bottomBar.setFabIcon(CommunityMaterial.Icon2.cmd_plus);
|
||||
activity.getNavView().setFabOnClickListener(v -> new EventManualDialog(
|
||||
activity,
|
||||
App.profileId,
|
||||
App.Companion.getProfileId(),
|
||||
null,
|
||||
actualDate,
|
||||
null,
|
||||
@ -167,7 +167,7 @@ public class AgendaFragment extends Fragment {
|
||||
|
||||
final Handler handler = new Handler();
|
||||
handler.postDelayed(() -> AsyncTask.execute(() -> {
|
||||
if (app == null || app.profile == null || activity == null || b_default == null || !isAdded())
|
||||
if (app == null || activity == null || b_default == null || !isAdded())
|
||||
return;
|
||||
|
||||
List<CalendarEvent> eventList = new ArrayList<>();
|
||||
@ -193,8 +193,8 @@ public class AgendaFragment extends Fragment {
|
||||
));
|
||||
} TODO: Implement new timetable lesson changes */
|
||||
|
||||
if (app.profile.getStudentData("showTeacherAbsences", true)) {
|
||||
List<TeacherAbsenceFull> teacherAbsenceList = app.db.teacherAbsenceDao().getAllFullNow(App.profileId);
|
||||
if (app.getProfile().getStudentData("showTeacherAbsences", true)) {
|
||||
List<TeacherAbsenceFull> teacherAbsenceList = App.db.teacherAbsenceDao().getAllFullNow(App.Companion.getProfileId());
|
||||
List<TeacherAbsenceCounter> teacherAbsenceCounters = new ArrayList<>();
|
||||
|
||||
for (TeacherAbsenceFull absence : teacherAbsenceList) {
|
||||
@ -226,7 +226,7 @@ public class AgendaFragment extends Fragment {
|
||||
Colors.legibleTextColor(0xffff1744),
|
||||
startTime,
|
||||
endTime,
|
||||
App.profileId,
|
||||
App.Companion.getProfileId(),
|
||||
date,
|
||||
counter.getTeacherAbsenceCount()
|
||||
));
|
||||
@ -234,7 +234,7 @@ public class AgendaFragment extends Fragment {
|
||||
}
|
||||
|
||||
|
||||
List<EventFull> events = app.db.eventDao().getAllNow(App.profileId);
|
||||
List<EventFull> events = App.db.eventDao().getAllNow(App.Companion.getProfileId());
|
||||
for (EventFull event : events) {
|
||||
Calendar startTime = Calendar.getInstance();
|
||||
Calendar endTime = Calendar.getInstance();
|
||||
@ -321,7 +321,7 @@ public class AgendaFragment extends Fragment {
|
||||
actualDate = Date.fromCalendar(calendar);
|
||||
int scrolledDate = actualDate.getValue();
|
||||
if (unreadEventDates.contains(scrolledDate)) {
|
||||
AsyncTask.execute(() -> app.db.eventDao().setSeenByDate(App.profileId, Date.fromYmd(intToStr(scrolledDate)), true));
|
||||
AsyncTask.execute(() -> App.db.eventDao().setSeenByDate(App.Companion.getProfileId(), Date.fromYmd(intToStr(scrolledDate)), true));
|
||||
unreadEventDates.remove((Integer) scrolledDate);
|
||||
}
|
||||
}
|
||||
@ -342,7 +342,7 @@ public class AgendaFragment extends Fragment {
|
||||
// new EventListDialogOld(activity).show(app, Date.fromCalendar(calendarEvent.getInstanceDay()));
|
||||
new DayDialog(
|
||||
activity,
|
||||
App.profileId,
|
||||
App.Companion.getProfileId(),
|
||||
Date.fromCalendar(calendarEvent.getInstanceDay()),
|
||||
null,
|
||||
null
|
||||
@ -373,7 +373,7 @@ public class AgendaFragment extends Fragment {
|
||||
|
||||
final Handler handler = new Handler();
|
||||
handler.postDelayed(() -> AsyncTask.execute(() -> {
|
||||
if (app == null || app.profile == null || activity == null || b_calendar == null || !isAdded())
|
||||
if (app == null || activity == null || b_calendar == null || !isAdded())
|
||||
return;
|
||||
Context c = getContext();
|
||||
Activity a = getActivity();
|
||||
@ -385,7 +385,7 @@ public class AgendaFragment extends Fragment {
|
||||
|
||||
List<EventDay> eventList = new ArrayList<>();
|
||||
|
||||
List<EventFull> events = app.db.eventDao().getAllNow(App.profileId);
|
||||
List<EventFull> events = App.db.eventDao().getAllNow(App.Companion.getProfileId());
|
||||
for (EventFull event : events) {
|
||||
if (event.eventDate == null)
|
||||
continue;
|
||||
@ -434,13 +434,13 @@ public class AgendaFragment extends Fragment {
|
||||
Date dayDate = Date.fromCalendar(eventDay.getCalendar());
|
||||
int scrolledDate = dayDate.getValue();
|
||||
if (unreadEventDates.contains(scrolledDate)) {
|
||||
AsyncTask.execute(() -> app.db.eventDao().setSeenByDate(App.profileId, Date.fromYmd(intToStr(scrolledDate)), true));
|
||||
AsyncTask.execute(() -> App.db.eventDao().setSeenByDate(App.Companion.getProfileId(), Date.fromYmd(intToStr(scrolledDate)), true));
|
||||
unreadEventDates.remove((Integer) scrolledDate);
|
||||
}
|
||||
|
||||
new DayDialog(
|
||||
activity,
|
||||
App.profileId,
|
||||
App.Companion.getProfileId(),
|
||||
dayDate,
|
||||
null,
|
||||
null
|
||||
|
@ -24,8 +24,8 @@ import org.greenrobot.eventbus.ThreadMode;
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.MainActivity;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask;
|
||||
import pl.szczodrzynski.edziennik.data.api.events.AnnouncementGetEvent;
|
||||
import pl.szczodrzynski.edziennik.data.api.task.EdziennikTask;
|
||||
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull;
|
||||
import pl.szczodrzynski.edziennik.databinding.DialogAnnouncementBinding;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentAnnouncementsBinding;
|
||||
@ -49,8 +49,6 @@ public class AnnouncementsFragment extends Fragment {
|
||||
return null;
|
||||
app = (App) activity.getApplication();
|
||||
getContext().getTheme().applyStyle(Themes.INSTANCE.getAppTheme(), true);
|
||||
if (app.profile == null)
|
||||
return inflater.inflate(R.layout.fragment_loading, container, false);
|
||||
// activity, context and profile is valid
|
||||
b = DataBindingUtil.inflate(inflater, R.layout.fragment_announcements, container, false);
|
||||
b.refreshLayout.setParent(activity.getSwipeRefreshLayout());
|
||||
@ -61,7 +59,7 @@ public class AnnouncementsFragment extends Fragment {
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
|
||||
if (app == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
activity.getBottomSheet().prependItems(
|
||||
@ -70,10 +68,10 @@ public class AnnouncementsFragment extends Fragment {
|
||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check_outline)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
if (app.profile.getLoginStoreType() == LOGIN_TYPE_LIBRUS) {
|
||||
EdziennikTask.Companion.announcementsRead(App.profileId).enqueue(requireContext());
|
||||
if (app.getProfile().getLoginStoreType() == LOGIN_TYPE_LIBRUS) {
|
||||
EdziennikTask.Companion.announcementsRead(App.Companion.getProfileId()).enqueue(requireContext());
|
||||
} else {
|
||||
AsyncTask.execute(() -> app.db.metadataDao().setAllSeen(App.profileId, TYPE_ANNOUNCEMENT, true));
|
||||
AsyncTask.execute(() -> App.db.metadataDao().setAllSeen(App.Companion.getProfileId(), TYPE_ANNOUNCEMENT, true));
|
||||
Toast.makeText(activity, R.string.main_menu_mark_as_read_success, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
})
|
||||
@ -92,8 +90,8 @@ public class AnnouncementsFragment extends Fragment {
|
||||
recyclerView.setLayoutManager(linearLayoutManager);
|
||||
recyclerView.addItemDecoration(new SimpleDividerItemDecoration(view.getContext()));
|
||||
|
||||
app.db.announcementDao().getAll(App.profileId).observe(this, announcements -> {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
|
||||
app.db.announcementDao().getAll(App.Companion.getProfileId()).observe(this, announcements -> {
|
||||
if (app == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
if (announcements == null) {
|
||||
@ -109,8 +107,8 @@ public class AnnouncementsFragment extends Fragment {
|
||||
return;
|
||||
}*/
|
||||
AnnouncementsAdapter announcementsAdapter = new AnnouncementsAdapter(activity, announcements, (v, announcement) -> {
|
||||
if (announcement.text == null || (app.profile.getLoginStoreType() == LOGIN_TYPE_LIBRUS && !announcement.seen && app.networkUtils.isOnline())) {
|
||||
EdziennikTask.Companion.announcementGet(App.profileId, announcement).enqueue(requireContext());
|
||||
if (announcement.text == null || (app.getProfile().getLoginStoreType() == LOGIN_TYPE_LIBRUS && !announcement.seen && app.getNetworkUtils().isOnline())) {
|
||||
EdziennikTask.Companion.announcementGet(App.Companion.getProfileId(), announcement).enqueue(requireContext());
|
||||
} else {
|
||||
showAnnouncementDetailsDialog(announcement);
|
||||
}
|
||||
@ -157,9 +155,9 @@ public class AnnouncementsFragment extends Fragment {
|
||||
.show();
|
||||
DialogAnnouncementBinding b = DialogAnnouncementBinding.bind(dialog.getCustomView());
|
||||
b.text.setText(announcement.teacherFullName+"\n\n"+ (announcement.startDate != null ? announcement.startDate.getFormattedString() : "-") + (announcement.endDate != null ? " do " + announcement.endDate.getFormattedString() : "")+"\n\n" +announcement.text);
|
||||
if (!announcement.seen && app.profile.getLoginStoreType() != LOGIN_TYPE_LIBRUS) {
|
||||
if (!announcement.seen && app.getProfile().getLoginStoreType() != LOGIN_TYPE_LIBRUS) {
|
||||
announcement.seen = true;
|
||||
AsyncTask.execute(() -> app.db.metadataDao().setSeen(App.profileId, announcement, true));
|
||||
AsyncTask.execute(() -> App.db.metadataDao().setSeen(App.Companion.getProfileId(), announcement, true));
|
||||
if (recyclerView.getAdapter() != null)
|
||||
recyclerView.getAdapter().notifyDataSetChanged();
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ public class AttendanceAdapter extends RecyclerView.Adapter<AttendanceAdapter.Vi
|
||||
holder.attendanceLessonTopic.getBackground().setColorFilter(new PorterDuffColorFilter(0x692196f3, PorterDuff.Mode.MULTIPLY));
|
||||
attendance.seen = true;
|
||||
AsyncTask.execute(() -> {
|
||||
app.db.metadataDao().setSeen(App.profileId, attendance, true);
|
||||
App.db.metadataDao().setSeen(App.Companion.getProfileId(), attendance, true);
|
||||
//Intent i = new Intent("android.intent.action.MAIN").putExtra(MainActivity.ACTION_UPDATE_BADGES, "yes, sure");
|
||||
//context.sendBroadcast(i);
|
||||
});
|
||||
|
@ -33,8 +33,8 @@ import antonkozyriatskyi.circularprogressindicator.CircularProgressIndicator;
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.MainActivity;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.data.db.full.AttendanceFull;
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Subject;
|
||||
import pl.szczodrzynski.edziennik.data.db.full.AttendanceFull;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentAttendanceBinding;
|
||||
import pl.szczodrzynski.edziennik.utils.Themes;
|
||||
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem;
|
||||
@ -73,8 +73,6 @@ public class AttendanceFragment extends Fragment {
|
||||
return null;
|
||||
app = (App) activity.getApplication();
|
||||
getContext().getTheme().applyStyle(Themes.INSTANCE.getAppTheme(), true);
|
||||
if (app.profile == null)
|
||||
return inflater.inflate(R.layout.fragment_loading, container, false);
|
||||
// activity, context and profile is valid
|
||||
b = DataBindingUtil.inflate(inflater, R.layout.fragment_attendance, container, false);
|
||||
b.refreshLayout.setParent(activity.getSwipeRefreshLayout());
|
||||
@ -83,7 +81,7 @@ public class AttendanceFragment extends Fragment {
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
|
||||
if (app == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
activity.getBottomSheet().prependItems(
|
||||
@ -92,7 +90,7 @@ public class AttendanceFragment extends Fragment {
|
||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check_outline)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
AsyncTask.execute(() -> app.db.metadataDao().setAllSeen(App.profileId, TYPE_ATTENDANCE, true));
|
||||
AsyncTask.execute(() -> App.db.metadataDao().setAllSeen(App.Companion.getProfileId(), TYPE_ATTENDANCE, true));
|
||||
Toast.makeText(activity, R.string.main_menu_mark_as_read_success, Toast.LENGTH_SHORT).show();
|
||||
})
|
||||
);
|
||||
@ -149,13 +147,13 @@ public class AttendanceFragment extends Fragment {
|
||||
}
|
||||
}*/
|
||||
|
||||
if (app.profile.getLoginStoreType() == LOGIN_TYPE_MOBIDZIENNIK) {
|
||||
if (app.getProfile().getLoginStoreType() == LOGIN_TYPE_MOBIDZIENNIK) {
|
||||
b.attendanceSummarySubject.setVisibility(View.GONE);
|
||||
}
|
||||
else {
|
||||
b.attendanceSummarySubject.setOnClickListener((v -> {
|
||||
AsyncTask.execute(() -> {
|
||||
List<Subject> subjectList = app.db.subjectDao().getAllNow(App.profileId);
|
||||
List<Subject> subjectList = App.db.subjectDao().getAllNow(App.Companion.getProfileId());
|
||||
PopupMenu popupMenu = new PopupMenu(activity, b.attendanceSummarySubject, Gravity.END);
|
||||
popupMenu.getMenu().add(0, -1, 0, R.string.subject_filter_disabled);
|
||||
int index = 0;
|
||||
@ -187,8 +185,8 @@ public class AttendanceFragment extends Fragment {
|
||||
b.attendanceView.setHasFixedSize(true);
|
||||
b.attendanceView.setLayoutManager(linearLayoutManager);
|
||||
|
||||
app.db.attendanceDao().getAll(App.profileId).observe(this, attendance -> {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
|
||||
App.db.attendanceDao().getAll(App.Companion.getProfileId()).observe(this, attendance -> {
|
||||
if (app == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
if (attendance == null) {
|
||||
@ -209,7 +207,7 @@ public class AttendanceFragment extends Fragment {
|
||||
subjectTotalCount = new LongSparseArray<>();
|
||||
subjectAbsentCount = new LongSparseArray<>();
|
||||
for (AttendanceFull attendance: attendanceList) {
|
||||
if (app.profile.getLoginStoreType() == LOGIN_TYPE_VULCAN && attendance.type == TYPE_RELEASED)
|
||||
if (app.getProfile().getLoginStoreType() == LOGIN_TYPE_VULCAN && attendance.type == TYPE_RELEASED)
|
||||
continue;
|
||||
int[] subjectTotal = subjectTotalCount.get(attendance.subjectId, new int[3]);
|
||||
int[] subjectAbsent = subjectAbsentCount.get(attendance.subjectId, new int[3]);
|
||||
@ -228,7 +226,7 @@ public class AttendanceFragment extends Fragment {
|
||||
}
|
||||
|
||||
private void updateList() {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
|
||||
if (app == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
int presentCount = 0;
|
||||
@ -306,7 +304,7 @@ public class AttendanceFragment extends Fragment {
|
||||
float attendancePercentage;
|
||||
|
||||
// in Mobidziennik there are no TYPE_PRESENT records so we cannot calculate the percentage
|
||||
if (app.profile.getLoginStoreType() == LOGIN_TYPE_VULCAN) {
|
||||
if (app.getProfile().getLoginStoreType() == LOGIN_TYPE_VULCAN) {
|
||||
float allCount = presentCount + absentCount + belatedCount; // do not count releases
|
||||
float present = allCount - absentCount;
|
||||
attendancePercentage = present / allCount * 100.0f;
|
||||
|
@ -2,9 +2,9 @@ package pl.szczodrzynski.edziennik.ui.modules.base;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
|
||||
public class CrashGtfoActivity extends AppCompatActivity {
|
||||
@ -12,7 +12,7 @@ public class CrashGtfoActivity extends AppCompatActivity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setTheme((((App)getApplication()).getContext()
|
||||
setTheme((getApplication()
|
||||
.getSharedPreferences(getString(R.string.preference_file_global), Context.MODE_PRIVATE)
|
||||
.getBoolean("dark_theme", false) ? R.style.AppTheme_Dark : R.style.AppTheme));
|
||||
setContentView(R.layout.activity_gtfo);
|
||||
|
@ -1,15 +1,15 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.base;
|
||||
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.google.android.material.textfield.TextInputEditText;
|
||||
import com.google.gson.Gson;
|
||||
@ -100,7 +100,7 @@ public class DebugFragment extends Fragment {
|
||||
forceType = "i";
|
||||
parameter = parameter.substring(0, parameter.length()-1);
|
||||
}
|
||||
SimpleObj obj = app.gson.fromJson("{\"value\":"+parameter+"}", SimpleObj.class);
|
||||
SimpleObj obj = app.getGson().fromJson("{\"value\":"+parameter+"}", SimpleObj.class);
|
||||
Class type = obj.value.getClass();
|
||||
Object value = obj.value;
|
||||
if ("d".equals(forceType)) {
|
||||
@ -180,7 +180,7 @@ public class DebugFragment extends Fragment {
|
||||
getByPath(app, target, path, true);
|
||||
// set the value if specified
|
||||
if (valueToSet != null) {
|
||||
targetField.set(target, app.gson.fromJson(valueToSet, targetField.getGenericType()));
|
||||
targetField.set(target, app.getGson().fromJson(valueToSet, targetField.getGenericType()));
|
||||
targetField = null;
|
||||
}
|
||||
if (targetField != null) {
|
||||
@ -194,7 +194,7 @@ public class DebugFragment extends Fragment {
|
||||
return Log.getStackTraceString(e);
|
||||
}
|
||||
}
|
||||
return app.gson.toJson(target);
|
||||
return app.getGson().toJson(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -218,13 +218,13 @@ public class DebugFragment extends Fragment {
|
||||
getView().findViewById(R.id.debugAppconfig).setOnClickListener(v -> {
|
||||
JsonRecyclerView mRecyclerView = getView().findViewById(R.id.rv_json);
|
||||
// bind json
|
||||
mRecyclerView.bindJson(new Gson().toJson(app.appConfig));
|
||||
mRecyclerView.bindJson(new Gson().toJson(app.getConfig()));
|
||||
mRecyclerView.setTextSize(20);
|
||||
});
|
||||
getView().findViewById(R.id.debugAppprofile).setOnClickListener(v -> {
|
||||
JsonRecyclerView mRecyclerView = getView().findViewById(R.id.rv_json);
|
||||
// bind json
|
||||
mRecyclerView.bindJson(new Gson().toJson(app.profile));
|
||||
mRecyclerView.bindJson(new Gson().toJson(app.getProfile()));
|
||||
mRecyclerView.setTextSize(20);
|
||||
});
|
||||
}
|
||||
|
@ -53,8 +53,6 @@ public class BehaviourFragment extends Fragment {
|
||||
return null;
|
||||
app = (App) activity.getApplication();
|
||||
getContext().getTheme().applyStyle(Themes.INSTANCE.getAppTheme(), true);
|
||||
if (app.profile == null)
|
||||
return inflater.inflate(R.layout.fragment_loading, container, false);
|
||||
// activity, context and profile is valid
|
||||
b = DataBindingUtil.inflate(inflater, R.layout.fragment_behaviour, container, false);
|
||||
b.refreshLayout.setParent(activity.getSwipeRefreshLayout());
|
||||
@ -63,7 +61,7 @@ public class BehaviourFragment extends Fragment {
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
|
||||
if (app == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
activity.getBottomSheet().prependItems(
|
||||
@ -72,7 +70,7 @@ public class BehaviourFragment extends Fragment {
|
||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check_outline)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
AsyncTask.execute(() -> app.db.metadataDao().setAllSeen(App.profileId, TYPE_NOTICE, true));
|
||||
AsyncTask.execute(() -> App.db.metadataDao().setAllSeen(App.Companion.getProfileId(), TYPE_NOTICE, true));
|
||||
Toast.makeText(activity, R.string.main_menu_mark_as_read_success, Toast.LENGTH_SHORT).show();
|
||||
})
|
||||
);
|
||||
@ -99,8 +97,8 @@ public class BehaviourFragment extends Fragment {
|
||||
b.noticesView.setHasFixedSize(true);
|
||||
b.noticesView.setLayoutManager(linearLayoutManager);
|
||||
|
||||
app.db.noticeDao().getAll(App.profileId).observe(this, notices -> {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
|
||||
app.db.noticeDao().getAll(App.Companion.getProfileId()).observe(this, notices -> {
|
||||
if (app == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
if (notices == null) {
|
||||
|
@ -1,18 +1,5 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.feedback;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.databinding.ActivityFeedbackBinding;
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.FeedbackMessage;
|
||||
import pl.szczodrzynski.edziennik.data.db.full.FeedbackMessageWithCount;
|
||||
import pl.szczodrzynski.edziennik.network.ServerRequest;
|
||||
import pl.szczodrzynski.edziennik.utils.Anim;
|
||||
import pl.szczodrzynski.edziennik.utils.Themes;
|
||||
import pl.szczodrzynski.edziennik.utils.Utils;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@ -28,6 +15,9 @@ import android.view.animation.Animation;
|
||||
import android.widget.PopupMenu;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.github.bassaer.chatmessageview.model.IChatUser;
|
||||
import com.github.bassaer.chatmessageview.model.Message;
|
||||
@ -36,7 +26,16 @@ import com.github.bassaer.chatmessageview.view.ChatView;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.App.APP_URL;
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.FeedbackMessage;
|
||||
import pl.szczodrzynski.edziennik.data.db.full.FeedbackMessageWithCount;
|
||||
import pl.szczodrzynski.edziennik.databinding.ActivityFeedbackBinding;
|
||||
import pl.szczodrzynski.edziennik.network.ServerRequest;
|
||||
import pl.szczodrzynski.edziennik.utils.Anim;
|
||||
import pl.szczodrzynski.edziennik.utils.Themes;
|
||||
import pl.szczodrzynski.edziennik.utils.Utils;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.crc16;
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.openUrl;
|
||||
|
||||
@ -101,7 +100,7 @@ public class FeedbackActivity extends AppCompatActivity {
|
||||
.content(R.string.sending_message)
|
||||
.negativeText(R.string.cancel)
|
||||
.show();
|
||||
new ServerRequest(app, app.requestScheme + APP_URL + "main.php?feedback_message", "FeedbackSend")
|
||||
new ServerRequest(app, "https://edziennik.szczodrzynski.pl/app/main.php?feedback_message", "FeedbackSend")
|
||||
.setBodyParameter("message_text", text)
|
||||
.setBodyParameter("target_device", deviceToSend == null ? "null" : deviceToSend)
|
||||
.run(((e, result) -> {
|
||||
@ -199,7 +198,7 @@ public class FeedbackActivity extends AppCompatActivity {
|
||||
receiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
FeedbackMessage message = app.gson.fromJson(intent.getStringExtra("message"), FeedbackMessage.class);
|
||||
FeedbackMessage message = app.getGson().fromJson(intent.getStringExtra("message"), FeedbackMessage.class);
|
||||
Calendar c = Calendar.getInstance();
|
||||
c.setTimeInMillis(message.sentTime);
|
||||
Message chatMessage = new Message.Builder()
|
||||
@ -238,7 +237,7 @@ public class FeedbackActivity extends AppCompatActivity {
|
||||
mChatView.setMessageMarginTop(5);
|
||||
mChatView.setMessageMarginBottom(5);
|
||||
|
||||
if (App.devMode && app.deviceId.equals("f054761fbdb6a238")) {
|
||||
if (App.Companion.getDevMode() && app.getDeviceId().equals("f054761fbdb6a238")) {
|
||||
b.targetDeviceLayout.setVisibility(View.VISIBLE);
|
||||
b.targetDeviceDropDown.setOnClickListener((v -> {
|
||||
AsyncTask.execute(() -> {
|
||||
|
@ -21,11 +21,10 @@ import com.github.bassaer.chatmessageview.model.IChatUser
|
||||
import com.github.bassaer.chatmessageview.model.Message
|
||||
import com.github.bassaer.chatmessageview.view.ChatView
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.App.APP_URL
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentFeedbackBinding
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.FeedbackMessage
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentFeedbackBinding
|
||||
import pl.szczodrzynski.edziennik.network.ServerRequest
|
||||
import pl.szczodrzynski.edziennik.utils.Anim
|
||||
import pl.szczodrzynski.edziennik.utils.Themes
|
||||
@ -248,7 +247,7 @@ class FeedbackFragment : Fragment() {
|
||||
.content(R.string.sending_message)
|
||||
.negativeText(R.string.cancel)
|
||||
.show()
|
||||
ServerRequest(app, app.requestScheme + APP_URL + "main.php?feedback_message", "FeedbackSend")
|
||||
ServerRequest(app, "https://edziennik.szczodrzynski.pl/app/main.php?feedback_message", "FeedbackSend")
|
||||
.setBodyParameter("message_text", text)
|
||||
.setBodyParameter("target_device", if (deviceToSend == null) "null" else deviceToSend)
|
||||
.run { e, result ->
|
||||
|
@ -16,7 +16,6 @@ import androidx.fragment.app.Fragment;
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@ -25,8 +24,8 @@ import pl.szczodrzynski.edziennik.MainActivity;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.config.ProfileConfigGrades;
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Grade;
|
||||
import pl.szczodrzynski.edziennik.data.db.full.GradeFull;
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Subject;
|
||||
import pl.szczodrzynski.edziennik.data.db.full.GradeFull;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentGradesBinding;
|
||||
import pl.szczodrzynski.edziennik.utils.Themes;
|
||||
import pl.szczodrzynski.edziennik.utils.models.ItemGradesSubjectModel;
|
||||
@ -56,8 +55,6 @@ public class GradesFragment extends Fragment {
|
||||
return null;
|
||||
app = (App) activity.getApplication();
|
||||
getContext().getTheme().applyStyle(Themes.INSTANCE.getAppTheme(), true);
|
||||
if (app.profile == null)
|
||||
return inflater.inflate(R.layout.fragment_loading, container, false);
|
||||
// activity, context and profile is valid
|
||||
b = DataBindingUtil.inflate(inflater, R.layout.fragment_grades, container, false);
|
||||
b.refreshLayout.setParent(activity.getSwipeRefreshLayout());
|
||||
@ -68,10 +65,8 @@ public class GradesFragment extends Fragment {
|
||||
ListView listView;
|
||||
List<ItemGradesSubjectModel> subjectList;
|
||||
|
||||
private boolean sortModeChanged = false;
|
||||
|
||||
private String getRegisterCardAverageModeSubText() {
|
||||
switch (App.getConfig().forProfile().getGrades().getYearAverageMode()) {
|
||||
switch (App.Companion.getConfig().forProfile().getGrades().getYearAverageMode()) {
|
||||
default:
|
||||
case YEAR_1_AVG_2_AVG:
|
||||
return getString(R.string.settings_register_avg_mode_0_short);
|
||||
@ -88,7 +83,7 @@ public class GradesFragment extends Fragment {
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
|
||||
if (app == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
/*activity.getBottomSheet().setToggleGroupEnabled(true);
|
||||
@ -136,7 +131,7 @@ public class GradesFragment extends Fragment {
|
||||
.withIcon(CommunityMaterial.Icon2.cmd_palette_outline)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
ProfileConfigGrades config = app.config.getFor(App.profileId).getGrades();
|
||||
ProfileConfigGrades config = app.getConfig().getFor(App.Companion.getProfileId()).getGrades();
|
||||
new MaterialDialog.Builder(activity)
|
||||
.title(R.string.dialog_grades_color_mode_title)
|
||||
.items(R.array.dialog_grades_color_modes)
|
||||
@ -155,8 +150,8 @@ public class GradesFragment extends Fragment {
|
||||
new MaterialDialog.Builder(activity)
|
||||
.title(R.string.dialog_grades_sort_title)
|
||||
.items(R.array.dialog_grades_sort_modes)
|
||||
.itemsCallbackSingleChoice(app.config.getGrades().getOrderBy(), (dialog, view1, which, text) -> {
|
||||
app.config.getGrades().setOrderBy(which);
|
||||
.itemsCallbackSingleChoice(app.getConfig().getGrades().getOrderBy(), (dialog, view1, which, text) -> {
|
||||
app.getConfig().getGrades().setOrderBy(which);
|
||||
activity.reloadTarget();
|
||||
return true;
|
||||
})
|
||||
@ -184,8 +179,8 @@ public class GradesFragment extends Fragment {
|
||||
.title(getString(R.string.settings_register_avg_mode_dialog_title))
|
||||
.content(getString(R.string.settings_register_avg_mode_dialog_text))
|
||||
.items(modeNames)
|
||||
.itemsCallbackSingleChoice(modeIds.indexOf(App.getConfig().forProfile().getGrades().getYearAverageMode()), (dialog, itemView, which, text) -> {
|
||||
App.getConfig().forProfile().getGrades().setYearAverageMode(modeIds.get(which));
|
||||
.itemsCallbackSingleChoice(modeIds.indexOf(App.Companion.getConfig().forProfile().getGrades().getYearAverageMode()), (dialog, itemView, which, text) -> {
|
||||
App.Companion.getConfig().forProfile().getGrades().setYearAverageMode(modeIds.get(which));
|
||||
activity.reloadTarget();
|
||||
return true;
|
||||
})
|
||||
@ -197,7 +192,7 @@ public class GradesFragment extends Fragment {
|
||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check_outline)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
AsyncTask.execute(() -> app.db.metadataDao().setAllSeen(App.profileId, TYPE_GRADE, true));
|
||||
AsyncTask.execute(() -> App.db.metadataDao().setAllSeen(App.Companion.getProfileId(), TYPE_GRADE, true));
|
||||
Toast.makeText(activity, R.string.main_menu_mark_as_read_success, Toast.LENGTH_SHORT).show();
|
||||
})
|
||||
);
|
||||
@ -227,41 +222,41 @@ public class GradesFragment extends Fragment {
|
||||
|
||||
long finalExpandSubjectId = expandSubjectId;
|
||||
String orderBy;
|
||||
if (app.config.getGrades().getOrderBy() == ORDER_BY_SUBJECT_ASC) {
|
||||
if (app.getConfig().getGrades().getOrderBy() == ORDER_BY_SUBJECT_ASC) {
|
||||
orderBy = "subjectLongName ASC, addedDate DESC";
|
||||
}
|
||||
else if (app.config.getGrades().getOrderBy() == ORDER_BY_DATE_DESC) {
|
||||
else if (app.getConfig().getGrades().getOrderBy() == ORDER_BY_DATE_DESC) {
|
||||
orderBy = "addedDate DESC";
|
||||
}
|
||||
else if (app.config.getGrades().getOrderBy() == ORDER_BY_DATE_ASC) {
|
||||
else if (app.getConfig().getGrades().getOrderBy() == ORDER_BY_DATE_ASC) {
|
||||
orderBy = "addedDate ASC";
|
||||
}
|
||||
else {
|
||||
orderBy = "subjectLongName DESC, addedDate DESC";
|
||||
}
|
||||
|
||||
app.db.gradeDao().getAllOrderBy(App.profileId, orderBy).observe(this, grades -> {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
|
||||
App.db.gradeDao().getAllOrderBy(App.Companion.getProfileId(), orderBy).observe(this, grades -> {
|
||||
if (app == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
subjectList = new ArrayList<>();
|
||||
|
||||
ProfileConfigGrades config = app.config.getFor(App.profileId).getGrades();
|
||||
ProfileConfigGrades config = app.getConfig().getFor(App.Companion.getProfileId()).getGrades();
|
||||
|
||||
// now we have all grades from the newest to the oldest
|
||||
for (GradeFull grade: grades) {
|
||||
ItemGradesSubjectModel model = ItemGradesSubjectModel.searchModelBySubjectId(subjectList, grade.subjectId);
|
||||
if (model == null) {
|
||||
model = new ItemGradesSubjectModel(app.profile,
|
||||
new Subject(App.profileId, grade.subjectId, grade.subjectLongName, grade.subjectShortName),
|
||||
model = new ItemGradesSubjectModel(app.getProfile(),
|
||||
new Subject(App.Companion.getProfileId(), grade.subjectId, grade.subjectLongName, grade.subjectShortName),
|
||||
new ArrayList<>(),
|
||||
new ArrayList<>());
|
||||
subjectList.add(model);
|
||||
if (model.subject != null && model.subject.id == finalExpandSubjectId) {
|
||||
model.expandView = true;
|
||||
}
|
||||
model.colorMode = App.getConfig().forProfile().getGrades().getColorMode();
|
||||
model.yearAverageMode = App.getConfig().forProfile().getGrades().getYearAverageMode();
|
||||
model.colorMode = App.Companion.getConfig().forProfile().getGrades().getColorMode();
|
||||
model.yearAverageMode = App.Companion.getConfig().forProfile().getGrades().getYearAverageMode();
|
||||
}
|
||||
if (!grade.seen && grade.semester == 1) {
|
||||
model.semester1Unread++;
|
||||
@ -380,7 +375,7 @@ public class GradesFragment extends Fragment {
|
||||
else if (!model.isBehaviourSubject && model.isNormalSubject) {
|
||||
// applies for normal grades & normal+descriptive grades
|
||||
// calculate the normal grade average based on the user's setting
|
||||
switch (App.getConfig().forProfile().getGrades().getYearAverageMode()) {
|
||||
switch (App.Companion.getConfig().forProfile().getGrades().getYearAverageMode()) {
|
||||
case YEAR_1_AVG_2_AVG:
|
||||
model.yearAverage = (model.semester1Average + model.semester2Average) / 2;
|
||||
break;
|
||||
@ -433,7 +428,7 @@ public class GradesFragment extends Fragment {
|
||||
}
|
||||
|
||||
public void showAverages() {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded() || subjectList == null)
|
||||
if (app == null || activity == null || b == null || !isAdded() || subjectList == null)
|
||||
return;
|
||||
|
||||
float semester1Sum = 0;
|
||||
@ -529,8 +524,6 @@ public class GradesFragment extends Fragment {
|
||||
}
|
||||
}
|
||||
|
||||
DecimalFormat df = new DecimalFormat("0.00");
|
||||
|
||||
String semester1ExpectedAverageStr = semester1Count > semester1ProposedCount || semester1Count > semester1FinalCount ? getString(R.string.dialog_averages_expected_format, 1, semester1Sum / semester1Count) : "";
|
||||
String semester1ProposedAverageStr = semester1ProposedCount > 0 ? getString(R.string.dialog_averages_proposed_format, 1, semester1ProposedSum / semester1ProposedCount) : "";
|
||||
String semester1FinalAverageStr = semester1FinalCount > 0 ? getString(R.string.dialog_averages_final_format, 1, semester1FinalSum / semester1FinalCount) : "";
|
||||
|
@ -52,11 +52,11 @@ public class GradesListAdapter extends RecyclerView.Adapter<GradesListAdapter.Vi
|
||||
GradeFull grade = gradeList.get(position);
|
||||
|
||||
holder.root.setOnClickListener((v -> {
|
||||
new GradeDetailsDialog(v.getContext(), App.profileId).show(app, grade);
|
||||
new GradeDetailsDialog(v.getContext(), App.Companion.getProfileId()).show(app, grade);
|
||||
}));
|
||||
|
||||
int gradeColor;
|
||||
if (App.getConfig().forProfile().getGrades().getColorMode() == COLOR_MODE_DEFAULT) {
|
||||
if (App.Companion.getConfig().forProfile().getGrades().getColorMode() == COLOR_MODE_DEFAULT) {
|
||||
gradeColor = grade.color;
|
||||
}
|
||||
else {
|
||||
|
@ -31,8 +31,8 @@ import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.MainActivity;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.data.db.AppDb;
|
||||
import pl.szczodrzynski.edziennik.data.db.full.GradeFull;
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Subject;
|
||||
import pl.szczodrzynski.edziennik.data.db.full.GradeFull;
|
||||
import pl.szczodrzynski.edziennik.utils.Anim;
|
||||
import pl.szczodrzynski.edziennik.utils.Colors;
|
||||
import pl.szczodrzynski.edziennik.utils.Utils;
|
||||
@ -86,34 +86,34 @@ public class GradesSubjectAdapter extends ArrayAdapter<ItemGradesSubjectModel> i
|
||||
|
||||
private boolean gradesSetAsRead(ViewHolder holder, ItemGradesSubjectModel model, int semester) {
|
||||
boolean somethingChanged = false;
|
||||
AppDb db = AppDb.getDatabase(null);
|
||||
AppDb db = App.Companion.getDb();
|
||||
if (semester == 1) {
|
||||
model.semester1Unread = 0;
|
||||
for (GradeFull grade : model.grades1) {
|
||||
if (!grade.seen) {
|
||||
db.metadataDao().setSeen(App.profileId, grade, somethingChanged = true);
|
||||
db.metadataDao().setSeen(App.Companion.getProfileId(), grade, somethingChanged = true);
|
||||
}
|
||||
}
|
||||
if (model.semester1Proposed != null && !model.semester1Proposed.seen)
|
||||
db.metadataDao().setSeen(App.profileId, model.semester1Proposed, somethingChanged = true);
|
||||
db.metadataDao().setSeen(App.Companion.getProfileId(), model.semester1Proposed, somethingChanged = true);
|
||||
if (model.semester1Final != null && !model.semester1Final.seen)
|
||||
db.metadataDao().setSeen(App.profileId, model.semester1Final, somethingChanged = true);
|
||||
db.metadataDao().setSeen(App.Companion.getProfileId(), model.semester1Final, somethingChanged = true);
|
||||
}
|
||||
else if (semester == 2) {
|
||||
model.semester2Unread = 0;
|
||||
for (GradeFull grade : model.grades2) {
|
||||
if (!grade.seen) {
|
||||
db.metadataDao().setSeen(App.profileId, grade, somethingChanged = true);
|
||||
db.metadataDao().setSeen(App.Companion.getProfileId(), grade, somethingChanged = true);
|
||||
}
|
||||
}
|
||||
if (model.semester2Proposed != null && !model.semester2Proposed.seen)
|
||||
db.metadataDao().setSeen(App.profileId, model.semester2Proposed, somethingChanged = true);
|
||||
db.metadataDao().setSeen(App.Companion.getProfileId(), model.semester2Proposed, somethingChanged = true);
|
||||
if (model.semester2Final != null && !model.semester2Final.seen)
|
||||
db.metadataDao().setSeen(App.profileId, model.semester2Final, somethingChanged = true);
|
||||
db.metadataDao().setSeen(App.Companion.getProfileId(), model.semester2Final, somethingChanged = true);
|
||||
if (model.yearProposed != null && !model.yearProposed.seen)
|
||||
db.metadataDao().setSeen(App.profileId, model.yearProposed, somethingChanged = true);
|
||||
db.metadataDao().setSeen(App.Companion.getProfileId(), model.yearProposed, somethingChanged = true);
|
||||
if (model.yearFinal != null && !model.yearFinal.seen)
|
||||
db.metadataDao().setSeen(App.profileId, model.yearFinal, somethingChanged = true);
|
||||
db.metadataDao().setSeen(App.Companion.getProfileId(), model.yearFinal, somethingChanged = true);
|
||||
}
|
||||
if (somethingChanged) updateSubjectSemesterBadges(holder, model);
|
||||
return somethingChanged;
|
||||
@ -219,7 +219,7 @@ public class GradesSubjectAdapter extends ArrayAdapter<ItemGradesSubjectModel> i
|
||||
layoutParams.setMargins(0, 0, _5dp, 0);
|
||||
|
||||
DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics();
|
||||
int maxWidthPx = displayMetrics.widthPixels - Utils.dpToPx((app.config.getUi().getMiniMenuVisible() ? 72 : 0)/*miniDrawer size*/ + 8 + 8/*left and right offsets*/ + 24/*ellipsize width*/);
|
||||
int maxWidthPx = displayMetrics.widthPixels - Utils.dpToPx((app.getConfig().getUi().getMiniMenuVisible() ? 72 : 0)/*miniDrawer size*/ + 8 + 8/*left and right offsets*/ + 24/*ellipsize width*/);
|
||||
int totalWidthPx = 0;
|
||||
boolean ellipsized = false;
|
||||
|
||||
|
@ -40,11 +40,11 @@ class HomeFragment : Fragment(), CoroutineScope {
|
||||
private const val TAG = "HomeFragment"
|
||||
|
||||
fun swapCards(fromPosition: Int, toPosition: Int, cardAdapter: HomeCardAdapter) {
|
||||
val homeCards = App.getConfig().ui.homeCards.toMutableList()
|
||||
val homeCards = App.config.ui.homeCards.toMutableList()
|
||||
val fromPair = homeCards[fromPosition]
|
||||
homeCards[fromPosition] = homeCards[toPosition]
|
||||
homeCards[toPosition] = fromPair
|
||||
App.getConfig().ui.homeCards = homeCards
|
||||
App.config.ui.homeCards = homeCards
|
||||
|
||||
val fromCard = cardAdapter.items[fromPosition]
|
||||
cardAdapter.items[fromPosition] = cardAdapter.items[toPosition]
|
||||
|
@ -20,7 +20,7 @@ import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.data.api.task.EdziennikTask
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.databinding.CardHomeDebugBinding
|
||||
import pl.szczodrzynski.edziennik.dp
|
||||
|
@ -29,9 +29,9 @@ import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Grade.*
|
||||
import pl.szczodrzynski.edziennik.data.db.full.GradeFull
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Subject
|
||||
import pl.szczodrzynski.edziennik.data.db.full.GradeFull
|
||||
import pl.szczodrzynski.edziennik.databinding.CardHomeGradesBinding
|
||||
import pl.szczodrzynski.edziennik.dp
|
||||
import pl.szczodrzynski.edziennik.ui.modules.home.HomeCard
|
||||
@ -121,7 +121,7 @@ class HomeGradesCard(
|
||||
16 /*ellipsize width*/)) / 1.5f
|
||||
|
||||
subject.grades1.onEach { grade ->
|
||||
val gradeColor = when (App.getConfig().forProfile().grades.colorMode) {
|
||||
val gradeColor = when (App.config.forProfile().grades.colorMode) {
|
||||
Profile.COLOR_MODE_DEFAULT -> grade.color
|
||||
else -> Colors.gradeToColor(grade)
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ class HomeLuckyNumberCard(
|
||||
|
||||
holder.root.onClick {
|
||||
StudentNumberDialog(activity, profile, onDismissListener = {
|
||||
app.profileSaveAsync(profile)
|
||||
app.profileSave(profile)
|
||||
val newSubTextRes = if (profile.studentNumber == -1)
|
||||
R.string.home_lucky_number_details_click_to_set
|
||||
else
|
||||
|
@ -22,11 +22,11 @@ import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask
|
||||
import pl.szczodrzynski.edziennik.data.api.events.ApiTaskAllFinishedEvent
|
||||
import pl.szczodrzynski.edziennik.data.api.task.EdziennikTask
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Lesson
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.data.db.full.LessonFull
|
||||
import pl.szczodrzynski.edziennik.databinding.CardHomeTimetableBinding
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.bell.BellSyncTimeChooseDialog
|
||||
|
@ -85,7 +85,7 @@ public class HomeworkAdapter extends RecyclerView.Adapter<HomeworkAdapter.ViewHo
|
||||
holder.homeworkItemTopic.getBackground().setColorFilter(new PorterDuffColorFilter(0x692196f3, PorterDuff.Mode.MULTIPLY));
|
||||
homework.seen = true;
|
||||
AsyncTask.execute(() -> {
|
||||
app.db.metadataDao().setSeen(App.profileId, homework, true);
|
||||
App.db.metadataDao().setSeen(App.Companion.getProfileId(), homework, true);
|
||||
});
|
||||
}
|
||||
else {
|
||||
|
@ -78,6 +78,6 @@ public class ChangelogIntroActivity extends IntroActivity {
|
||||
.build());
|
||||
}*/
|
||||
|
||||
app.config.setAppVersion(BuildConfig.VERSION_CODE);
|
||||
app.getConfig().setAppVersion(BuildConfig.VERSION_CODE);
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user