mirror of
https://github.com/szkolny-eu/szkolny-android.git
synced 2025-06-16 15:31:54 +02:00
Compare commits
9 Commits
v4.13-rc.1
...
v4.13-rc.3
Author | SHA1 | Date | |
---|---|---|---|
26ad6373e6 | |||
cac8f94407 | |||
6628b97faf | |||
8424414317 | |||
d8bb927703 | |||
c8e8c172a2 | |||
0d4dee765a | |||
fd407b2b03 | |||
40ed5a221f |
1
.idea/codeStyles/Project.xml
generated
1
.idea/codeStyles/Project.xml
generated
@ -1,6 +1,7 @@
|
|||||||
<component name="ProjectCodeStyleConfiguration">
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
<code_scheme name="Project" version="173">
|
<code_scheme name="Project" version="173">
|
||||||
<JetCodeStyleSettings>
|
<JetCodeStyleSettings>
|
||||||
|
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />
|
||||||
<option name="ALLOW_TRAILING_COMMA" value="true" />
|
<option name="ALLOW_TRAILING_COMMA" value="true" />
|
||||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||||
</JetCodeStyleSettings>
|
</JetCodeStyleSettings>
|
||||||
|
@ -208,7 +208,7 @@ dependencies {
|
|||||||
implementation "com.daimajia.swipelayout:library:1.2.0@aar"
|
implementation "com.daimajia.swipelayout:library:1.2.0@aar"
|
||||||
implementation "com.github.Applandeo:Material-Calendar-View:15de569cbc" // https://github.com/Applandeo/Material-Calendar-View
|
implementation "com.github.Applandeo:Material-Calendar-View:15de569cbc" // https://github.com/Applandeo/Material-Calendar-View
|
||||||
implementation "com.github.CanHub:Android-Image-Cropper:2.2.2" // https://github.com/CanHub/Android-Image-Cropper
|
implementation "com.github.CanHub:Android-Image-Cropper:2.2.2" // https://github.com/CanHub/Android-Image-Cropper
|
||||||
implementation "com.github.ChuckerTeam.Chucker:library:3.0.1" // https://github.com/ChuckerTeam/chucker
|
implementation "com.github.ChuckerTeam.Chucker:library:3.5.2" // https://github.com/ChuckerTeam/chucker
|
||||||
implementation "com.github.antonKozyriatskyi:CircularProgressIndicator:1.2.2" // https://github.com/antonKozyriatskyi/CircularProgressIndicator
|
implementation "com.github.antonKozyriatskyi:CircularProgressIndicator:1.2.2" // https://github.com/antonKozyriatskyi/CircularProgressIndicator
|
||||||
implementation "com.github.bassaer:chatmessageview:2.0.1" // https://github.com/bassaer/ChatMessageView
|
implementation "com.github.bassaer:chatmessageview:2.0.1" // https://github.com/bassaer/ChatMessageView
|
||||||
implementation "com.github.hypertrack:hyperlog-android:0.0.10" // https://github.com/hypertrack/hyperlog-android
|
implementation "com.github.hypertrack:hyperlog-android:0.0.10" // https://github.com/hypertrack/hyperlog-android
|
||||||
|
4
app/proguard-rules.pro
vendored
4
app/proguard-rules.pro
vendored
@ -22,6 +22,7 @@
|
|||||||
-keep class android.support.v7.widget.** { *; }
|
-keep class android.support.v7.widget.** { *; }
|
||||||
|
|
||||||
-keep class pl.szczodrzynski.edziennik.utils.models.** { *; }
|
-keep class pl.szczodrzynski.edziennik.utils.models.** { *; }
|
||||||
|
-keep class pl.szczodrzynski.edziennik.data.db.enums.* { *; }
|
||||||
-keep class pl.szczodrzynski.edziennik.data.db.entity.Event { *; }
|
-keep class pl.szczodrzynski.edziennik.data.db.entity.Event { *; }
|
||||||
-keep class pl.szczodrzynski.edziennik.data.db.full.EventFull { *; }
|
-keep class pl.szczodrzynski.edziennik.data.db.full.EventFull { *; }
|
||||||
-keep class pl.szczodrzynski.edziennik.data.db.entity.FeedbackMessage { *; }
|
-keep class pl.szczodrzynski.edziennik.data.db.entity.FeedbackMessage { *; }
|
||||||
@ -31,6 +32,9 @@
|
|||||||
-keepnames class pl.szczodrzynski.edziennik.ui.widgets.timetable.WidgetTimetableProvider
|
-keepnames class pl.szczodrzynski.edziennik.ui.widgets.timetable.WidgetTimetableProvider
|
||||||
-keepnames class pl.szczodrzynski.edziennik.ui.widgets.notifications.WidgetNotificationsProvider
|
-keepnames class pl.szczodrzynski.edziennik.ui.widgets.notifications.WidgetNotificationsProvider
|
||||||
-keepnames class pl.szczodrzynski.edziennik.ui.widgets.luckynumber.WidgetLuckyNumberProvider
|
-keepnames class pl.szczodrzynski.edziennik.ui.widgets.luckynumber.WidgetLuckyNumberProvider
|
||||||
|
-keep class pl.szczodrzynski.edziennik.config.AppData { *; }
|
||||||
|
-keep class pl.szczodrzynski.edziennik.config.AppData$** { *; }
|
||||||
|
-keep class pl.szczodrzynski.edziennik.utils.managers.TextStylingManager$HtmlMode { *; }
|
||||||
|
|
||||||
-keepnames class androidx.appcompat.view.menu.MenuBuilder { setHeaderTitleInt(java.lang.CharSequence); }
|
-keepnames class androidx.appcompat.view.menu.MenuBuilder { setHeaderTitleInt(java.lang.CharSequence); }
|
||||||
-keepnames class androidx.appcompat.view.menu.MenuPopupHelper { showPopup(int, int, boolean, boolean); }
|
-keepnames class androidx.appcompat.view.menu.MenuPopupHelper { showPopup(int, int, boolean, boolean); }
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
<h3>Wersja 4.13-rc.1, 2022-10-22</h3>
|
<h3>Wersja 4.13-rc.3, 2022-10-23</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Poprawione powiadomienia na Androidzie 13. @santoni0</li>
|
<li>Poprawione powiadomienia na Androidzie 13. @santoni0</li>
|
||||||
<li>Możliwość dostosowania wyświetlania planu lekcji.</li>
|
<li>Możliwość dostosowania wyświetlania planu lekcji.</li>
|
||||||
<li>Opcja kolorowania bloków w planie lekcji.</li>
|
<li>Opcja kolorowania bloków w planie lekcji.</li>
|
||||||
<li><b>USOS</b> - pierwsza wersja obsługi systemu. Osobne rodzaje wydarzeń (oraz wygląd niektórych części aplikacji) lepiej dostosowany do nauki na studiach.</li>
|
<li><b>USOS</b> - pierwsza wersja obsługi systemu. Osobne rodzaje wydarzeń (oraz wygląd niektórych części aplikacji) lepiej dostosowany do nauki na studiach.</li>
|
||||||
<li>Poprawione opcje filtrowania powiadomień i wyboru przycisków menu bocznego.</li>
|
<li>Poprawione opcje filtrowania powiadomień i wyboru przycisków menu bocznego.</li>
|
||||||
|
<li>Ulepszony system pobierania aktualizacji aplikacji.</li>
|
||||||
</ul>
|
</ul>
|
||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
/*secret password - removed for source code publication*/
|
/*secret password - removed for source code publication*/
|
||||||
static toys AES_IV[16] = {
|
static toys AES_IV[16] = {
|
||||||
0xb7, 0x04, 0xed, 0xb5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
0x0f, 0x0d, 0x19, 0x4d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||||
|
|
||||||
unsigned char *agony(unsigned int laugh, unsigned char *box, unsigned char *heat);
|
unsigned char *agony(unsigned int laugh, unsigned char *box, unsigned char *heat);
|
||||||
|
|
||||||
|
@ -28,7 +28,11 @@ import com.google.gson.Gson
|
|||||||
import com.hypertrack.hyperlog.HyperLog
|
import com.hypertrack.hyperlog.HyperLog
|
||||||
import com.mikepenz.iconics.Iconics
|
import com.mikepenz.iconics.Iconics
|
||||||
import im.wangchao.mhttp.MHttp
|
import im.wangchao.mhttp.MHttp
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import me.leolin.shortcutbadger.ShortcutBadger
|
import me.leolin.shortcutbadger.ShortcutBadger
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import org.greenrobot.eventbus.EventBus
|
import org.greenrobot.eventbus.EventBus
|
||||||
@ -55,7 +59,19 @@ import pl.szczodrzynski.edziennik.utils.PermissionChecker
|
|||||||
import pl.szczodrzynski.edziennik.utils.Themes
|
import pl.szczodrzynski.edziennik.utils.Themes
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils
|
import pl.szczodrzynski.edziennik.utils.Utils
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
import pl.szczodrzynski.edziennik.utils.managers.*
|
import pl.szczodrzynski.edziennik.utils.managers.AttendanceManager
|
||||||
|
import pl.szczodrzynski.edziennik.utils.managers.AvailabilityManager
|
||||||
|
import pl.szczodrzynski.edziennik.utils.managers.BuildManager
|
||||||
|
import pl.szczodrzynski.edziennik.utils.managers.EventManager
|
||||||
|
import pl.szczodrzynski.edziennik.utils.managers.GradesManager
|
||||||
|
import pl.szczodrzynski.edziennik.utils.managers.MessageManager
|
||||||
|
import pl.szczodrzynski.edziennik.utils.managers.NoteManager
|
||||||
|
import pl.szczodrzynski.edziennik.utils.managers.NotificationChannelsManager
|
||||||
|
import pl.szczodrzynski.edziennik.utils.managers.PermissionManager
|
||||||
|
import pl.szczodrzynski.edziennik.utils.managers.TextStylingManager
|
||||||
|
import pl.szczodrzynski.edziennik.utils.managers.TimetableManager
|
||||||
|
import pl.szczodrzynski.edziennik.utils.managers.UpdateManager
|
||||||
|
import pl.szczodrzynski.edziennik.utils.managers.UserActionManager
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
import kotlin.system.exitProcess
|
import kotlin.system.exitProcess
|
||||||
@ -80,18 +96,19 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val api by lazy { SzkolnyApi(this) }
|
val api by lazy { SzkolnyApi(this) }
|
||||||
val notificationChannelsManager by lazy { NotificationChannelsManager(this) }
|
|
||||||
val userActionManager by lazy { UserActionManager(this) }
|
|
||||||
val gradesManager by lazy { GradesManager(this) }
|
|
||||||
val timetableManager by lazy { TimetableManager(this) }
|
|
||||||
val eventManager by lazy { EventManager(this) }
|
|
||||||
val permissionManager by lazy { PermissionManager(this) }
|
|
||||||
val attendanceManager by lazy { AttendanceManager(this) }
|
val attendanceManager by lazy { AttendanceManager(this) }
|
||||||
val buildManager by lazy { BuildManager(this) }
|
|
||||||
val availabilityManager by lazy { AvailabilityManager(this) }
|
val availabilityManager by lazy { AvailabilityManager(this) }
|
||||||
val textStylingManager by lazy { TextStylingManager(this) }
|
val buildManager by lazy { BuildManager(this) }
|
||||||
|
val eventManager by lazy { EventManager(this) }
|
||||||
|
val gradesManager by lazy { GradesManager(this) }
|
||||||
val messageManager by lazy { MessageManager(this) }
|
val messageManager by lazy { MessageManager(this) }
|
||||||
val noteManager by lazy { NoteManager(this) }
|
val noteManager by lazy { NoteManager(this) }
|
||||||
|
val notificationChannelsManager by lazy { NotificationChannelsManager(this) }
|
||||||
|
val permissionManager by lazy { PermissionManager(this) }
|
||||||
|
val textStylingManager by lazy { TextStylingManager(this) }
|
||||||
|
val timetableManager by lazy { TimetableManager(this) }
|
||||||
|
val updateManager by lazy { UpdateManager(this) }
|
||||||
|
val userActionManager by lazy { UserActionManager(this) }
|
||||||
|
|
||||||
val db
|
val db
|
||||||
get() = App.db
|
get() = App.db
|
||||||
@ -190,12 +207,6 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
|
|||||||
Iconics.init(applicationContext)
|
Iconics.init(applicationContext)
|
||||||
Iconics.respectFontBoundsDefault = true
|
Iconics.respectFontBoundsDefault = true
|
||||||
|
|
||||||
if (devMode) {
|
|
||||||
HyperLog.initialize(this)
|
|
||||||
HyperLog.setLogLevel(Log.VERBOSE)
|
|
||||||
HyperLog.setLogFormat(DebugLogFormat(this))
|
|
||||||
}
|
|
||||||
|
|
||||||
// initialize companion object values
|
// initialize companion object values
|
||||||
AppData.read(this)
|
AppData.read(this)
|
||||||
App.db = AppDb(this)
|
App.db = AppDb(this)
|
||||||
@ -204,6 +215,12 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
|
|||||||
devMode = config.devMode ?: debugMode
|
devMode = config.devMode ?: debugMode
|
||||||
enableChucker = config.enableChucker ?: devMode
|
enableChucker = config.enableChucker ?: devMode
|
||||||
|
|
||||||
|
if (devMode) {
|
||||||
|
HyperLog.initialize(this)
|
||||||
|
HyperLog.setLogLevel(Log.VERBOSE)
|
||||||
|
HyperLog.setLogFormat(DebugLogFormat(this))
|
||||||
|
}
|
||||||
|
|
||||||
if (!profileLoadById(config.lastProfileId)) {
|
if (!profileLoadById(config.lastProfileId)) {
|
||||||
val success = db.profileDao().firstId?.let { profileLoadById(it) }
|
val success = db.profileDao().firstId?.let { profileLoadById(it) }
|
||||||
if (success != true)
|
if (success != true)
|
||||||
|
@ -46,6 +46,7 @@ import pl.szczodrzynski.edziennik.databinding.ActivitySzkolnyBinding
|
|||||||
import pl.szczodrzynski.edziennik.ext.*
|
import pl.szczodrzynski.edziennik.ext.*
|
||||||
import pl.szczodrzynski.edziennik.sync.AppManagerDetectedEvent
|
import pl.szczodrzynski.edziennik.sync.AppManagerDetectedEvent
|
||||||
import pl.szczodrzynski.edziennik.sync.SyncWorker
|
import pl.szczodrzynski.edziennik.sync.SyncWorker
|
||||||
|
import pl.szczodrzynski.edziennik.sync.UpdateStateEvent
|
||||||
import pl.szczodrzynski.edziennik.sync.UpdateWorker
|
import pl.szczodrzynski.edziennik.sync.UpdateWorker
|
||||||
import pl.szczodrzynski.edziennik.ui.base.MainSnackbar
|
import pl.szczodrzynski.edziennik.ui.base.MainSnackbar
|
||||||
import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget
|
import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget
|
||||||
@ -56,6 +57,7 @@ import pl.szczodrzynski.edziennik.ui.dialogs.sync.RegisterUnavailableDialog
|
|||||||
import pl.szczodrzynski.edziennik.ui.dialogs.sync.ServerMessageDialog
|
import pl.szczodrzynski.edziennik.ui.dialogs.sync.ServerMessageDialog
|
||||||
import pl.szczodrzynski.edziennik.ui.dialogs.sync.SyncViewListDialog
|
import pl.szczodrzynski.edziennik.ui.dialogs.sync.SyncViewListDialog
|
||||||
import pl.szczodrzynski.edziennik.ui.dialogs.sync.UpdateAvailableDialog
|
import pl.szczodrzynski.edziennik.ui.dialogs.sync.UpdateAvailableDialog
|
||||||
|
import pl.szczodrzynski.edziennik.ui.dialogs.sync.UpdateProgressDialog
|
||||||
import pl.szczodrzynski.edziennik.ui.error.ErrorDetailsDialog
|
import pl.szczodrzynski.edziennik.ui.error.ErrorDetailsDialog
|
||||||
import pl.szczodrzynski.edziennik.ui.error.ErrorSnackbar
|
import pl.szczodrzynski.edziennik.ui.error.ErrorSnackbar
|
||||||
import pl.szczodrzynski.edziennik.ui.event.EventManualDialog
|
import pl.szczodrzynski.edziennik.ui.event.EventManualDialog
|
||||||
@ -536,6 +538,14 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
|||||||
UpdateAvailableDialog(this, event).show()
|
UpdateAvailableDialog(this, event).show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
|
||||||
|
fun onUpdateStateEvent(event: UpdateStateEvent) {
|
||||||
|
if (!event.running)
|
||||||
|
return
|
||||||
|
EventBus.getDefault().removeStickyEvent(event)
|
||||||
|
UpdateProgressDialog(this, event.update ?: return, event.downloadId).show()
|
||||||
|
}
|
||||||
|
|
||||||
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
|
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
|
||||||
fun onRegisterAvailabilityEvent(event: RegisterAvailabilityEvent) {
|
fun onRegisterAvailabilityEvent(event: RegisterAvailabilityEvent) {
|
||||||
EventBus.getDefault().removeStickyEvent(event)
|
EventBus.getDefault().removeStickyEvent(event)
|
||||||
@ -699,6 +709,10 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
|||||||
|
|
||||||
if (extras?.containsKey("action") == true) {
|
if (extras?.containsKey("action") == true) {
|
||||||
val handled = when (extras.getString("action")) {
|
val handled = when (extras.getString("action")) {
|
||||||
|
"updateRequest" -> {
|
||||||
|
UpdateAvailableDialog(this, app.config.update).show()
|
||||||
|
true
|
||||||
|
}
|
||||||
"serverMessage" -> {
|
"serverMessage" -> {
|
||||||
ServerMessageDialog(
|
ServerMessageDialog(
|
||||||
this,
|
this,
|
||||||
|
@ -24,7 +24,7 @@ class Config(db: AppDb) : BaseConfig(db) {
|
|||||||
val timetable by lazy { ConfigTimetable(this) }
|
val timetable by lazy { ConfigTimetable(this) }
|
||||||
val grades by lazy { ConfigGrades(this) }
|
val grades by lazy { ConfigGrades(this) }
|
||||||
|
|
||||||
var dataVersion by config<Int>(0)
|
var dataVersion by config<Int>(DATA_VERSION)
|
||||||
var hash by config<String>("")
|
var hash by config<String>("")
|
||||||
|
|
||||||
var lastProfileId by config<Int>(0)
|
var lastProfileId by config<Int>(0)
|
||||||
@ -39,6 +39,7 @@ class Config(db: AppDb) : BaseConfig(db) {
|
|||||||
|
|
||||||
var apiAvailabilityCheck by config<Boolean>(true)
|
var apiAvailabilityCheck by config<Boolean>(true)
|
||||||
var apiInvalidCert by config<String?>(null)
|
var apiInvalidCert by config<String?>(null)
|
||||||
|
var apiKeyCustom by config<String?>(null)
|
||||||
var appInstalledTime by config<Long>(0L)
|
var appInstalledTime by config<Long>(0L)
|
||||||
var appRateSnackbarTime by config<Long>(0L)
|
var appRateSnackbarTime by config<Long>(0L)
|
||||||
var appVersion by config<Int>(BuildConfig.VERSION_CODE)
|
var appVersion by config<Int>(BuildConfig.VERSION_CODE)
|
||||||
@ -49,7 +50,8 @@ class Config(db: AppDb) : BaseConfig(db) {
|
|||||||
var widgetConfigs by config<JsonObject> { JsonObject() }
|
var widgetConfigs by config<JsonObject> { JsonObject() }
|
||||||
|
|
||||||
fun migrate(app: App) {
|
fun migrate(app: App) {
|
||||||
if (dataVersion < DATA_VERSION)
|
if (dataVersion < DATA_VERSION || hash == "")
|
||||||
|
// migrate old data version OR freshly installed app (or updated from 3.x)
|
||||||
ConfigMigration(app, this)
|
ConfigMigration(app, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ class ProfileConfig(
|
|||||||
val timetable by lazy { ConfigTimetable(this) }
|
val timetable by lazy { ConfigTimetable(this) }
|
||||||
val grades by lazy { ConfigGrades(this) }*/
|
val grades by lazy { ConfigGrades(this) }*/
|
||||||
|
|
||||||
var dataVersion by config<Int>(0)
|
var dataVersion by config<Int>(DATA_VERSION)
|
||||||
var hash by config<String>("")
|
var hash by config<String>("")
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
@ -16,9 +16,9 @@ import pl.szczodrzynski.edziennik.utils.models.Time
|
|||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
|
||||||
class AppConfigMigrationV3(p: SharedPreferences, config: Config) {
|
class AppConfigMigrationV3(p: SharedPreferences, config: Config) {
|
||||||
init { config.apply {
|
init {
|
||||||
val s = "app.appConfig"
|
val s = "app.appConfig"
|
||||||
if (dataVersion < 1) {
|
config.apply {
|
||||||
ui.theme = p.getString("$s.appTheme", null)?.toIntOrNull() ?: 1
|
ui.theme = p.getString("$s.appTheme", null)?.toIntOrNull() ?: 1
|
||||||
sync.enabled = p.getString("$s.registerSyncEnabled", null)?.toBoolean() ?: true
|
sync.enabled = p.getString("$s.registerSyncEnabled", null)?.toBoolean() ?: true
|
||||||
sync.interval = p.getString("$s.registerSyncInterval", null)?.toIntOrNull() ?: 3600
|
sync.interval = p.getString("$s.registerSyncInterval", null)?.toIntOrNull() ?: 3600
|
||||||
@ -37,9 +37,6 @@ class AppConfigMigrationV3(p: SharedPreferences, config: Config) {
|
|||||||
NavTarget.HOMEWORK,
|
NavTarget.HOMEWORK,
|
||||||
NavTarget.SETTINGS
|
NavTarget.SETTINGS
|
||||||
)
|
)
|
||||||
dataVersion = 1
|
|
||||||
}
|
|
||||||
if (dataVersion < 2) {
|
|
||||||
devModePassword = p.getString("$s.devModePassword", null).fix()
|
devModePassword = p.getString("$s.devModePassword", null).fix()
|
||||||
sync.tokenApp = p.getString("$s.fcmToken", null).fix()
|
sync.tokenApp = p.getString("$s.fcmToken", null).fix()
|
||||||
timetable.bellSyncMultiplier = p.getString("$s.bellSyncMultiplier", null)?.toIntOrNull() ?: 0
|
timetable.bellSyncMultiplier = p.getString("$s.bellSyncMultiplier", null)?.toIntOrNull() ?: 0
|
||||||
@ -86,9 +83,8 @@ class AppConfigMigrationV3(p: SharedPreferences, config: Config) {
|
|||||||
LoginType.LIBRUS.id -> sync.tokenLibrus = token
|
LoginType.LIBRUS.id -> sync.tokenLibrus = token
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dataVersion = 2
|
|
||||||
}
|
}
|
||||||
}}
|
}
|
||||||
|
|
||||||
private fun String?.fix(): String? {
|
private fun String?.fix(): String? {
|
||||||
return this?.replace("\"", "")?.let { if (it == "null") null else it }
|
return this?.replace("\"", "")?.let { if (it == "null") null else it }
|
||||||
|
@ -5,12 +5,9 @@
|
|||||||
package pl.szczodrzynski.edziennik.config.utils
|
package pl.szczodrzynski.edziennik.config.utils
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import androidx.core.content.edit
|
||||||
import pl.szczodrzynski.edziennik.App
|
import pl.szczodrzynski.edziennik.App
|
||||||
import pl.szczodrzynski.edziennik.BuildConfig
|
|
||||||
import pl.szczodrzynski.edziennik.config.Config
|
import pl.szczodrzynski.edziennik.config.Config
|
||||||
import pl.szczodrzynski.edziennik.ext.HOUR
|
|
||||||
import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget
|
|
||||||
import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.ORDER_BY_DATE_DESC
|
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
|
||||||
@ -22,6 +19,9 @@ class ConfigMigration(app: App, config: Config) {
|
|||||||
// migrate appConfig from app version 3.x and lower.
|
// migrate appConfig from app version 3.x and lower.
|
||||||
// Updates dataVersion to level 2.
|
// Updates dataVersion to level 2.
|
||||||
AppConfigMigrationV3(p, config)
|
AppConfigMigrationV3(p, config)
|
||||||
|
p.edit {
|
||||||
|
remove("app.appConfig.appTheme")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dataVersion < 11) {
|
if (dataVersion < 11) {
|
||||||
@ -43,5 +43,7 @@ class ConfigMigration(app: App, config: Config) {
|
|||||||
|
|
||||||
dataVersion = 11
|
dataVersion = 11
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hash = "invalid"
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
@ -41,24 +41,18 @@ class UsosApiTerms(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun processResponse(json: JsonArray): Boolean {
|
private fun processResponse(json: JsonArray): Boolean {
|
||||||
val dates = mutableSetOf<Date>()
|
val today = Date.getToday()
|
||||||
for (term in json.asJsonObjectList()) {
|
for (term in json.asJsonObjectList()) {
|
||||||
if (!term.getBoolean("is_active", false))
|
if (!term.getBoolean("is_active", false))
|
||||||
continue
|
continue
|
||||||
val startDate = term.getString("start_date")?.let { Date.fromY_m_d(it) }
|
val startDate = term.getString("start_date")?.let { Date.fromY_m_d(it) } ?: continue
|
||||||
val finishDate = term.getString("finish_date")?.let { Date.fromY_m_d(it) }
|
val finishDate = term.getString("finish_date")?.let { Date.fromY_m_d(it) } ?: continue
|
||||||
if (startDate != null)
|
if (today in startDate..finishDate) {
|
||||||
dates += startDate
|
profile?.studentSchoolYearStart = startDate.year
|
||||||
if (finishDate != null)
|
profile?.dateSemester1Start = startDate
|
||||||
dates += finishDate
|
profile?.dateSemester2Start = finishDate
|
||||||
|
}
|
||||||
}
|
}
|
||||||
val datesSorted = dates.sorted()
|
|
||||||
if (datesSorted.size != 3)
|
|
||||||
return false
|
|
||||||
profile?.studentSchoolYearStart = datesSorted[0].year
|
|
||||||
profile?.dateSemester1Start = datesSorted[0]
|
|
||||||
profile?.dateSemester2Start = datesSorted[1]
|
|
||||||
profile?.dateYearEnd = datesSorted[2]
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,6 @@ import kotlinx.coroutines.Dispatchers
|
|||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import org.greenrobot.eventbus.EventBus
|
|
||||||
import pl.szczodrzynski.edziennik.*
|
import pl.szczodrzynski.edziennik.*
|
||||||
import pl.szczodrzynski.edziennik.data.api.ERROR_API_INVALID_SIGNATURE
|
import pl.szczodrzynski.edziennik.data.api.ERROR_API_INVALID_SIGNATURE
|
||||||
import pl.szczodrzynski.edziennik.data.api.szkolny.adapter.DateAdapter
|
import pl.szczodrzynski.edziennik.data.api.szkolny.adapter.DateAdapter
|
||||||
@ -128,16 +127,10 @@ class SzkolnyApi(val app: App) : CoroutineScope {
|
|||||||
response: Response<ApiResponse<T>>,
|
response: Response<ApiResponse<T>>,
|
||||||
updateDeviceHash: Boolean = false,
|
updateDeviceHash: Boolean = false,
|
||||||
): T {
|
): T {
|
||||||
app.config.update = response.body()?.update?.let { update ->
|
response.body()?.update?.let { update ->
|
||||||
if (update.versionCode > BuildConfig.VERSION_CODE) {
|
// do not process "null" update, as it might not mean there's no update
|
||||||
if (update.updateMandatory
|
// do not notify; silently check and show the home update card
|
||||||
&& EventBus.getDefault().hasSubscriberForEvent(update::class.java)) {
|
app.updateManager.process(update, notify = false)
|
||||||
EventBus.getDefault().postSticky(update)
|
|
||||||
}
|
|
||||||
update
|
|
||||||
}
|
|
||||||
else
|
|
||||||
null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
response.body()?.registerAvailability?.let { registerAvailability ->
|
response.body()?.registerAvailability?.let { registerAvailability ->
|
||||||
@ -431,8 +424,8 @@ class SzkolnyApi(val app: App) : CoroutineScope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
fun getUpdate(channel: String): List<Update> {
|
fun getUpdate(channel: Update.Type): List<Update> {
|
||||||
val response = api.updates(channel).execute()
|
val response = api.updates(channel.name.lowercase()).execute()
|
||||||
return parseResponse(response)
|
return parseResponse(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,10 +12,11 @@ import pl.szczodrzynski.edziennik.ext.bodyToString
|
|||||||
import pl.szczodrzynski.edziennik.ext.currentTimeUnix
|
import pl.szczodrzynski.edziennik.ext.currentTimeUnix
|
||||||
import pl.szczodrzynski.edziennik.ext.hmacSHA1
|
import pl.szczodrzynski.edziennik.ext.hmacSHA1
|
||||||
import pl.szczodrzynski.edziennik.ext.md5
|
import pl.szczodrzynski.edziennik.ext.md5
|
||||||
|
import pl.szczodrzynski.edziennik.ext.takeValue
|
||||||
|
|
||||||
class SignatureInterceptor(val app: App) : Interceptor {
|
class SignatureInterceptor(val app: App) : Interceptor {
|
||||||
companion object {
|
companion object {
|
||||||
private const val API_KEY = "szkolny_android_42a66f0842fc7da4e37c66732acf705a"
|
const val API_KEY = "szkolny_android_42a66f0842fc7da4e37c66732acf705a"
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun intercept(chain: Interceptor.Chain): Response {
|
override fun intercept(chain: Interceptor.Chain): Response {
|
||||||
@ -27,7 +28,7 @@ class SignatureInterceptor(val app: App) : Interceptor {
|
|||||||
|
|
||||||
return chain.proceed(
|
return chain.proceed(
|
||||||
request.newBuilder()
|
request.newBuilder()
|
||||||
.header("X-ApiKey", API_KEY)
|
.header("X-ApiKey", app.config.apiKeyCustom?.takeValue() ?: API_KEY)
|
||||||
.header("X-AppVersion", BuildConfig.VERSION_CODE.toString())
|
.header("X-AppVersion", BuildConfig.VERSION_CODE.toString())
|
||||||
.header("X-Timestamp", timestamp.toString())
|
.header("X-Timestamp", timestamp.toString())
|
||||||
.header("X-Signature", sign(timestamp, body, url))
|
.header("X-Signature", sign(timestamp, body, url))
|
||||||
|
@ -46,6 +46,6 @@ object Signing {
|
|||||||
|
|
||||||
/*fun provideKey(param1: String, param2: Long): ByteArray {*/
|
/*fun provideKey(param1: String, param2: Long): ByteArray {*/
|
||||||
fun pleaseStopRightNow(param1: String, param2: Long): ByteArray {
|
fun pleaseStopRightNow(param1: String, param2: Long): ByteArray {
|
||||||
return "$param1.MTIzNDU2Nzg5MDyDtdBKln===.$param2".sha256()
|
return "$param1.MTIzNDU2Nzg5MD7hH6ZvtD===.$param2".sha256()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,12 +5,21 @@
|
|||||||
package pl.szczodrzynski.edziennik.data.api.szkolny.response
|
package pl.szczodrzynski.edziennik.data.api.szkolny.response
|
||||||
|
|
||||||
data class Update(
|
data class Update(
|
||||||
val versionCode: Int,
|
val versionCode: Int,
|
||||||
val versionName: String,
|
val versionName: String,
|
||||||
val releaseDate: String,
|
val releaseDate: String,
|
||||||
val releaseNotes: String?,
|
val releaseNotes: String?,
|
||||||
val releaseType: String,
|
val releaseType: String,
|
||||||
val isOnGooglePlay: Boolean,
|
val isOnGooglePlay: Boolean,
|
||||||
val downloadUrl: String?,
|
val downloadUrl: String?,
|
||||||
val updateMandatory: Boolean
|
val updateMandatory: Boolean,
|
||||||
)
|
) {
|
||||||
|
|
||||||
|
enum class Type {
|
||||||
|
NIGHTLY,
|
||||||
|
DEV,
|
||||||
|
BETA,
|
||||||
|
RC,
|
||||||
|
RELEASE,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -6,7 +6,11 @@ package pl.szczodrzynski.edziennik.data.firebase
|
|||||||
|
|
||||||
import com.google.gson.JsonParser
|
import com.google.gson.JsonParser
|
||||||
import com.google.gson.reflect.TypeToken
|
import com.google.gson.reflect.TypeToken
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import org.greenrobot.eventbus.EventBus
|
import org.greenrobot.eventbus.EventBus
|
||||||
import pl.szczodrzynski.edziennik.App
|
import pl.szczodrzynski.edziennik.App
|
||||||
import pl.szczodrzynski.edziennik.data.api.events.FeedbackMessageEvent
|
import pl.szczodrzynski.edziennik.data.api.events.FeedbackMessageEvent
|
||||||
@ -14,14 +18,18 @@ import pl.szczodrzynski.edziennik.data.api.events.RegisterAvailabilityEvent
|
|||||||
import pl.szczodrzynski.edziennik.data.api.szkolny.response.RegisterAvailabilityStatus
|
import pl.szczodrzynski.edziennik.data.api.szkolny.response.RegisterAvailabilityStatus
|
||||||
import pl.szczodrzynski.edziennik.data.api.szkolny.response.Update
|
import pl.szczodrzynski.edziennik.data.api.szkolny.response.Update
|
||||||
import pl.szczodrzynski.edziennik.data.api.task.PostNotifications
|
import pl.szczodrzynski.edziennik.data.api.task.PostNotifications
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.*
|
import pl.szczodrzynski.edziennik.data.db.entity.Event
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.FeedbackMessage
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.Note
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.Notification
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||||
import pl.szczodrzynski.edziennik.data.db.enums.MetadataType
|
import pl.szczodrzynski.edziennik.data.db.enums.MetadataType
|
||||||
import pl.szczodrzynski.edziennik.data.db.enums.NotificationType
|
import pl.szczodrzynski.edziennik.data.db.enums.NotificationType
|
||||||
import pl.szczodrzynski.edziennik.ext.getInt
|
import pl.szczodrzynski.edziennik.ext.getInt
|
||||||
import pl.szczodrzynski.edziennik.ext.getLong
|
import pl.szczodrzynski.edziennik.ext.getLong
|
||||||
import pl.szczodrzynski.edziennik.ext.getString
|
import pl.szczodrzynski.edziennik.ext.getString
|
||||||
import pl.szczodrzynski.edziennik.ext.resolveString
|
import pl.szczodrzynski.edziennik.ext.resolveString
|
||||||
import pl.szczodrzynski.edziennik.sync.UpdateWorker
|
|
||||||
import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget
|
import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||||
@ -64,7 +72,10 @@ class SzkolnyAppFirebase(val app: App, val profiles: List<Profile>, val message:
|
|||||||
message.data.getString("title") ?: "",
|
message.data.getString("title") ?: "",
|
||||||
message.data.getString("message") ?: ""
|
message.data.getString("message") ?: ""
|
||||||
)
|
)
|
||||||
"appUpdate" -> launch { UpdateWorker.runNow(app, app.gson.fromJson(message.data.getString("update"), Update::class.java)) }
|
"appUpdate" -> {
|
||||||
|
val update = app.gson.fromJson(message.data.getString("update"), Update::class.java)
|
||||||
|
app.updateManager.process(update, notify = true)
|
||||||
|
}
|
||||||
"feedbackMessage" -> launch {
|
"feedbackMessage" -> launch {
|
||||||
val message = app.gson.fromJson(message.data.getString("message"), FeedbackMessage::class.java) ?: return@launch
|
val message = app.gson.fromJson(message.data.getString("message"), FeedbackMessage::class.java) ?: return@launch
|
||||||
feedbackMessage(message)
|
feedbackMessage(message)
|
||||||
|
@ -50,13 +50,13 @@ inline fun <reified E : Enum<E>> Int.toEnum() = when (E::class.java) {
|
|||||||
} as E
|
} as E
|
||||||
|
|
||||||
fun <E : Enum<E>> Int.toEnum(type: Class<*>) = when (type) {
|
fun <E : Enum<E>> Int.toEnum(type: Class<*>) = when (type) {
|
||||||
// enums commented out are not really used in Bundles
|
// this is used for Config so all enums are here
|
||||||
FeatureType::class.java -> this.asFeatureType()
|
FeatureType::class.java -> this.asFeatureType()
|
||||||
// LoginMethod::class.java -> this.asLoginMethod()
|
LoginMethod::class.java -> this.asLoginMethod()
|
||||||
LoginMode::class.java -> this.asLoginMode()
|
LoginMode::class.java -> this.asLoginMode()
|
||||||
LoginType::class.java -> this.asLoginType()
|
LoginType::class.java -> this.asLoginType()
|
||||||
// MetadataType::class.java -> this.asMetadataType()
|
MetadataType::class.java -> this.asMetadataType()
|
||||||
// NotificationType::class.java -> this.asNotificationType()
|
NotificationType::class.java -> this.asNotificationType()
|
||||||
NavTarget::class.java -> this.asNavTarget()
|
NavTarget::class.java -> this.asNavTarget()
|
||||||
else -> throw IllegalArgumentException("Unknown type $type")
|
else -> throw IllegalArgumentException("Unknown type $type")
|
||||||
} as E
|
} as E
|
||||||
|
@ -76,4 +76,6 @@ fun pendingIntentFlag(): Int {
|
|||||||
fun Int?.takeValue() = if (this == -1) null else this
|
fun Int?.takeValue() = if (this == -1) null else this
|
||||||
fun Int?.takePositive() = if (this == -1 || this == 0) null else this
|
fun Int?.takePositive() = if (this == -1 || this == 0) null else this
|
||||||
|
|
||||||
|
fun String?.takeValue() = if (this.isNullOrBlank()) null else this
|
||||||
|
|
||||||
fun Any?.ignore() = Unit
|
fun Any?.ignore() = Unit
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2022-10-22.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.sync
|
||||||
|
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.szkolny.response.Update
|
||||||
|
|
||||||
|
class UpdateStateEvent(val running: Boolean, val update: Update?, val downloadId: Long)
|
@ -5,25 +5,14 @@
|
|||||||
package pl.szczodrzynski.edziennik.sync
|
package pl.szczodrzynski.edziennik.sync
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.NotificationManager
|
|
||||||
import android.app.PendingIntent
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
|
||||||
import android.widget.Toast
|
|
||||||
import androidx.core.app.NotificationCompat
|
|
||||||
import androidx.work.*
|
import androidx.work.*
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import org.greenrobot.eventbus.EventBus
|
|
||||||
import pl.szczodrzynski.edziennik.*
|
import pl.szczodrzynski.edziennik.*
|
||||||
import pl.szczodrzynski.edziennik.R
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.szkolny.response.Update
|
import pl.szczodrzynski.edziennik.data.api.szkolny.response.Update
|
||||||
import pl.szczodrzynski.edziennik.ext.DAY
|
import pl.szczodrzynski.edziennik.ext.DAY
|
||||||
import pl.szczodrzynski.edziennik.ext.concat
|
|
||||||
import pl.szczodrzynski.edziennik.ext.formatDate
|
import pl.szczodrzynski.edziennik.ext.formatDate
|
||||||
import pl.szczodrzynski.edziennik.ext.pendingIntentFlag
|
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils
|
import pl.szczodrzynski.edziennik.utils.Utils
|
||||||
import pl.szczodrzynski.edziennik.utils.html.BetterHtml
|
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
@ -76,63 +65,6 @@ class UpdateWorker(val context: Context, val params: WorkerParameters) : Worker(
|
|||||||
Utils.d(TAG, "Cancelling work by tag $TAG")
|
Utils.d(TAG, "Cancelling work by tag $TAG")
|
||||||
WorkManager.getInstance(app).cancelAllWorkByTag(TAG)
|
WorkManager.getInstance(app).cancelAllWorkByTag(TAG)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun runNow(app: App, overrideUpdate: Update? = null) {
|
|
||||||
try {
|
|
||||||
val update = overrideUpdate
|
|
||||||
?: run {
|
|
||||||
withContext(Dispatchers.Default) {
|
|
||||||
SzkolnyApi(app).runCatching({
|
|
||||||
getUpdate("beta")
|
|
||||||
}, {
|
|
||||||
Toast.makeText(app, app.getString(R.string.notification_cant_check_update), Toast.LENGTH_SHORT).show()
|
|
||||||
})
|
|
||||||
} ?: return@run null
|
|
||||||
|
|
||||||
if (app.config.update == null
|
|
||||||
|| app.config.update?.versionCode ?: BuildConfig.VERSION_CODE <= BuildConfig.VERSION_CODE) {
|
|
||||||
app.config.update = null
|
|
||||||
Toast.makeText(app, app.getString(R.string.notification_no_update), Toast.LENGTH_SHORT).show()
|
|
||||||
return@run null
|
|
||||||
}
|
|
||||||
app.config.update
|
|
||||||
} ?: return
|
|
||||||
|
|
||||||
if (update.versionCode <= BuildConfig.VERSION_CODE) {
|
|
||||||
app.config.update = null
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (EventBus.getDefault().hasSubscriberForEvent(update::class.java)) {
|
|
||||||
if (!update.updateMandatory) // mandatory updates are posted by the SzkolnyApi
|
|
||||||
EventBus.getDefault().postSticky(update)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val notificationIntent = Intent(app, UpdateDownloaderService::class.java)
|
|
||||||
val pendingIntent = PendingIntent.getService(app, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT or pendingIntentFlag())
|
|
||||||
val notification = NotificationCompat.Builder(app, app.notificationChannelsManager.updates.key)
|
|
||||||
.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 { BetterHtml.fromHtml(context = null, it) }
|
|
||||||
).concat("\n")))
|
|
||||||
.setColor(0xff2196f3.toInt())
|
|
||||||
.setLights(0xFF00FFFF.toInt(), 2000, 2000)
|
|
||||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
|
||||||
.setDefaults(NotificationCompat.DEFAULT_ALL)
|
|
||||||
.setGroup(app.notificationChannelsManager.updates.key)
|
|
||||||
.setContentIntent(pendingIntent)
|
|
||||||
.setAutoCancel(false)
|
|
||||||
.build()
|
|
||||||
(app.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).notify(app.notificationChannelsManager.updates.id, notification)
|
|
||||||
|
|
||||||
} catch (ignore: Exception) { }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val job = Job()
|
private val job = Job()
|
||||||
@ -146,22 +78,13 @@ class UpdateWorker(val context: Context, val params: WorkerParameters) : Worker(
|
|||||||
return Result.success()
|
return Result.success()
|
||||||
}
|
}
|
||||||
|
|
||||||
launch {
|
val channel = if (App.devMode)
|
||||||
runNow(app)
|
Update.Type.BETA
|
||||||
}
|
else
|
||||||
|
Update.Type.RELEASE
|
||||||
|
app.updateManager.checkNowSync(channel, notify = true)
|
||||||
|
|
||||||
rescheduleNext(this.context)
|
rescheduleNext(this.context)
|
||||||
return Result.success()
|
return Result.success()
|
||||||
}
|
}
|
||||||
|
|
||||||
class JavaWrapper(app: App) : CoroutineScope {
|
|
||||||
private val job = Job()
|
|
||||||
override val coroutineContext: CoroutineContext
|
|
||||||
get() = job + Dispatchers.Main
|
|
||||||
init {
|
|
||||||
launch {
|
|
||||||
runNow(app)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import android.view.View
|
|||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.core.widget.doAfterTextChanged
|
||||||
import androidx.sqlite.db.SimpleSQLiteQuery
|
import androidx.sqlite.db.SimpleSQLiteQuery
|
||||||
import com.chuckerteam.chucker.api.Chucker
|
import com.chuckerteam.chucker.api.Chucker
|
||||||
import com.chuckerteam.chucker.api.Chucker.SCREEN_HTTP
|
import com.chuckerteam.chucker.api.Chucker.SCREEN_HTTP
|
||||||
@ -21,6 +22,7 @@ import kotlinx.coroutines.Job
|
|||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import pl.szczodrzynski.edziennik.*
|
import pl.szczodrzynski.edziennik.*
|
||||||
import pl.szczodrzynski.edziennik.config.Config
|
import pl.szczodrzynski.edziennik.config.Config
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.szkolny.interceptor.SignatureInterceptor
|
||||||
import pl.szczodrzynski.edziennik.databinding.LabFragmentBinding
|
import pl.szczodrzynski.edziennik.databinding.LabFragmentBinding
|
||||||
import pl.szczodrzynski.edziennik.ext.*
|
import pl.szczodrzynski.edziennik.ext.*
|
||||||
import pl.szczodrzynski.edziennik.ui.base.lazypager.LazyFragment
|
import pl.szczodrzynski.edziennik.ui.base.lazypager.LazyFragment
|
||||||
@ -141,6 +143,16 @@ class LabPageFragment : LazyFragment(), CoroutineScope {
|
|||||||
app.config.apiInvalidCert = null
|
app.config.apiInvalidCert = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b.apiKey.setText(app.config.apiKeyCustom ?: SignatureInterceptor.API_KEY)
|
||||||
|
b.apiKey.doAfterTextChanged {
|
||||||
|
it?.toString()?.let { key ->
|
||||||
|
if (key == SignatureInterceptor.API_KEY)
|
||||||
|
app.config.apiKeyCustom = null
|
||||||
|
else
|
||||||
|
app.config.apiKeyCustom = key.takeValue()?.trim()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
b.rebuildConfig.onClick {
|
b.rebuildConfig.onClick {
|
||||||
App.config = Config(App.db)
|
App.config = Config(App.db)
|
||||||
}
|
}
|
||||||
|
@ -43,11 +43,11 @@ class UpdateAvailableDialog(
|
|||||||
override suspend fun onShow() = Unit
|
override suspend fun onShow() = Unit
|
||||||
|
|
||||||
override suspend fun onPositiveClick(): Boolean {
|
override suspend fun onPositiveClick(): Boolean {
|
||||||
if (update == null)
|
if (update == null || update.isOnGooglePlay)
|
||||||
Utils.openGooglePlay(activity)
|
Utils.openGooglePlay(activity)
|
||||||
else
|
else
|
||||||
activity.startService(Intent(app, UpdateDownloaderService::class.java))
|
activity.startService(Intent(app, UpdateDownloaderService::class.java))
|
||||||
return NO_DISMISS
|
return DISMISS
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun onBeforeShow(): Boolean {
|
override suspend fun onBeforeShow(): Boolean {
|
||||||
|
@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2022-10-22.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.ui.dialogs.sync
|
||||||
|
|
||||||
|
import android.app.DownloadManager
|
||||||
|
import android.database.CursorIndexOutOfBoundsException
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.content.getSystemService
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
import org.greenrobot.eventbus.Subscribe
|
||||||
|
import org.greenrobot.eventbus.ThreadMode
|
||||||
|
import pl.szczodrzynski.edziennik.R
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.szkolny.response.Update
|
||||||
|
import pl.szczodrzynski.edziennik.databinding.UpdateProgressDialogBinding
|
||||||
|
import pl.szczodrzynski.edziennik.ext.getInt
|
||||||
|
import pl.szczodrzynski.edziennik.ext.startCoroutineTimer
|
||||||
|
import pl.szczodrzynski.edziennik.sync.UpdateStateEvent
|
||||||
|
import pl.szczodrzynski.edziennik.ui.dialogs.base.BindingDialog
|
||||||
|
import pl.szczodrzynski.edziennik.utils.Utils
|
||||||
|
|
||||||
|
class UpdateProgressDialog(
|
||||||
|
activity: AppCompatActivity,
|
||||||
|
private val update: Update,
|
||||||
|
private val downloadId: Long,
|
||||||
|
onShowListener: ((tag: String) -> Unit)? = null,
|
||||||
|
onDismissListener: ((tag: String) -> Unit)? = null,
|
||||||
|
) : BindingDialog<UpdateProgressDialogBinding>(activity, onShowListener, onDismissListener) {
|
||||||
|
|
||||||
|
override val TAG = "UpdateProgressDialog"
|
||||||
|
|
||||||
|
override fun getTitleRes() = R.string.notification_downloading_update
|
||||||
|
override fun inflate(layoutInflater: LayoutInflater) =
|
||||||
|
UpdateProgressDialogBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
|
override fun isCancelable() = false
|
||||||
|
override fun getNegativeButtonText() = R.string.cancel
|
||||||
|
|
||||||
|
private var timerJob: Job? = null
|
||||||
|
|
||||||
|
override suspend fun onShow() {
|
||||||
|
EventBus.getDefault().register(this)
|
||||||
|
b.update = update
|
||||||
|
b.progress.progress = 0
|
||||||
|
|
||||||
|
val downloadManager = app.getSystemService<DownloadManager>() ?: return
|
||||||
|
val query = DownloadManager.Query().setFilterById(downloadId)
|
||||||
|
|
||||||
|
timerJob?.cancel()
|
||||||
|
timerJob = startCoroutineTimer(repeatMillis = 100L) {
|
||||||
|
try {
|
||||||
|
val cursor = downloadManager.query(query)
|
||||||
|
cursor.moveToFirst()
|
||||||
|
val progress = cursor.getInt(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)
|
||||||
|
?.toFloat() ?: return@startCoroutineTimer
|
||||||
|
b.downloadedSize.text = Utils.readableFileSize(progress.toLong())
|
||||||
|
val total = cursor.getInt(DownloadManager.COLUMN_TOTAL_SIZE_BYTES)
|
||||||
|
?.toFloat() ?: return@startCoroutineTimer
|
||||||
|
b.totalSize.text = Utils.readableFileSize(total.toLong())
|
||||||
|
b.progress.progress = (progress / total * 100.0f).toInt()
|
||||||
|
} catch (_: CursorIndexOutOfBoundsException) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDismiss() {
|
||||||
|
EventBus.getDefault().unregister(this)
|
||||||
|
timerJob?.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun onNegativeClick(): Boolean {
|
||||||
|
val downloadManager = app.getSystemService<DownloadManager>() ?: return NO_DISMISS
|
||||||
|
downloadManager.remove(downloadId)
|
||||||
|
return DISMISS
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
|
||||||
|
fun onUpdateStateEvent(event: UpdateStateEvent) {
|
||||||
|
if (event.downloadId != downloadId)
|
||||||
|
return
|
||||||
|
EventBus.getDefault().removeStickyEvent(event)
|
||||||
|
if (!event.running)
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
}
|
@ -15,7 +15,10 @@ import coil.load
|
|||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import pl.szczodrzynski.edziennik.*
|
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.db.entity.Profile
|
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||||
import pl.szczodrzynski.edziennik.databinding.CardHomeAvailabilityBinding
|
import pl.szczodrzynski.edziennik.databinding.CardHomeAvailabilityBinding
|
||||||
import pl.szczodrzynski.edziennik.ext.Intent
|
import pl.szczodrzynski.edziennik.ext.Intent
|
||||||
@ -28,6 +31,7 @@ import pl.szczodrzynski.edziennik.ui.dialogs.sync.UpdateAvailableDialog
|
|||||||
import pl.szczodrzynski.edziennik.ui.home.HomeCard
|
import pl.szczodrzynski.edziennik.ui.home.HomeCard
|
||||||
import pl.szczodrzynski.edziennik.ui.home.HomeCardAdapter
|
import pl.szczodrzynski.edziennik.ui.home.HomeCardAdapter
|
||||||
import pl.szczodrzynski.edziennik.ui.home.HomeFragment
|
import pl.szczodrzynski.edziennik.ui.home.HomeFragment
|
||||||
|
import pl.szczodrzynski.edziennik.utils.Utils
|
||||||
import pl.szczodrzynski.edziennik.utils.html.BetterHtml
|
import pl.szczodrzynski.edziennik.utils.html.BetterHtml
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
@ -79,7 +83,7 @@ class HomeAvailabilityCard(
|
|||||||
else if (update != null && update.versionCode > BuildConfig.VERSION_CODE) {
|
else if (update != null && update.versionCode > BuildConfig.VERSION_CODE) {
|
||||||
b.homeAvailabilityTitle.setText(R.string.home_availability_title)
|
b.homeAvailabilityTitle.setText(R.string.home_availability_title)
|
||||||
b.homeAvailabilityText.setText(R.string.home_availability_text, update.versionName)
|
b.homeAvailabilityText.setText(R.string.home_availability_text, update.versionName)
|
||||||
b.homeAvailabilityUpdate.isVisible = true
|
b.homeAvailabilityUpdate.isVisible = !app.buildManager.isPlayRelease
|
||||||
b.homeAvailabilityIcon.setImageResource(R.drawable.ic_update)
|
b.homeAvailabilityIcon.setImageResource(R.drawable.ic_update)
|
||||||
onInfoClick = {
|
onInfoClick = {
|
||||||
UpdateAvailableDialog(activity, update).show()
|
UpdateAvailableDialog(activity, update).show()
|
||||||
@ -92,7 +96,10 @@ class HomeAvailabilityCard(
|
|||||||
b.homeAvailabilityUpdate.onClick {
|
b.homeAvailabilityUpdate.onClick {
|
||||||
if (update == null)
|
if (update == null)
|
||||||
return@onClick
|
return@onClick
|
||||||
activity.startService(Intent(app, UpdateDownloaderService::class.java))
|
if (update.isOnGooglePlay)
|
||||||
|
Utils.openGooglePlay(activity)
|
||||||
|
else
|
||||||
|
activity.startService(Intent(app, UpdateDownloaderService::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
b.homeAvailabilityInfo.onClick(onInfoClick)
|
b.homeAvailabilityInfo.onClick(onInfoClick)
|
||||||
|
@ -18,8 +18,8 @@ import kotlinx.coroutines.launch
|
|||||||
import pl.szczodrzynski.edziennik.App
|
import pl.szczodrzynski.edziennik.App
|
||||||
import pl.szczodrzynski.edziennik.BuildConfig
|
import pl.szczodrzynski.edziennik.BuildConfig
|
||||||
import pl.szczodrzynski.edziennik.R
|
import pl.szczodrzynski.edziennik.R
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.szkolny.response.Update
|
||||||
import pl.szczodrzynski.edziennik.ext.after
|
import pl.szczodrzynski.edziennik.ext.after
|
||||||
import pl.szczodrzynski.edziennik.sync.UpdateWorker
|
|
||||||
import pl.szczodrzynski.edziennik.ui.dialogs.ChangelogDialog
|
import pl.szczodrzynski.edziennik.ui.dialogs.ChangelogDialog
|
||||||
import pl.szczodrzynski.edziennik.ui.settings.SettingsCard
|
import pl.szczodrzynski.edziennik.ui.settings.SettingsCard
|
||||||
import pl.szczodrzynski.edziennik.ui.settings.SettingsLicenseActivity
|
import pl.szczodrzynski.edziennik.ui.settings.SettingsLicenseActivity
|
||||||
@ -113,7 +113,17 @@ class SettingsAboutCard(util: SettingsUtil) : SettingsCard(util), CoroutineScope
|
|||||||
icon = CommunityMaterial.Icon3.cmd_update
|
icon = CommunityMaterial.Icon3.cmd_update
|
||||||
) {
|
) {
|
||||||
launch {
|
launch {
|
||||||
UpdateWorker.runNow(app)
|
val channel = if (App.devMode)
|
||||||
|
Update.Type.BETA
|
||||||
|
else
|
||||||
|
Update.Type.RC
|
||||||
|
val result = app.updateManager.checkNow(channel, notify = false)
|
||||||
|
val update = result.getOrNull()
|
||||||
|
// the dialog is shown by MainActivity (EventBus)
|
||||||
|
when {
|
||||||
|
result.isFailure -> Toast.makeText(app, app.getString(R.string.notification_cant_check_update), Toast.LENGTH_SHORT).show()
|
||||||
|
update == null -> Toast.makeText(app, app.getString(R.string.notification_no_update), Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)),
|
)),
|
||||||
|
@ -9,11 +9,29 @@ import android.text.TextUtils
|
|||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import pl.szczodrzynski.edziennik.*
|
import pl.szczodrzynski.edziennik.App
|
||||||
|
import pl.szczodrzynski.edziennik.BuildConfig
|
||||||
|
import pl.szczodrzynski.edziennik.R
|
||||||
import pl.szczodrzynski.edziennik.data.api.szkolny.interceptor.Signing
|
import pl.szczodrzynski.edziennik.data.api.szkolny.interceptor.Signing
|
||||||
import pl.szczodrzynski.edziennik.ext.*
|
import pl.szczodrzynski.edziennik.data.api.szkolny.response.Update
|
||||||
|
import pl.szczodrzynski.edziennik.ext.Intent
|
||||||
|
import pl.szczodrzynski.edziennik.ext.asBoldSpannable
|
||||||
|
import pl.szczodrzynski.edziennik.ext.asColoredSpannable
|
||||||
|
import pl.szczodrzynski.edziennik.ext.concat
|
||||||
|
import pl.szczodrzynski.edziennik.ext.getJsonObject
|
||||||
|
import pl.szczodrzynski.edziennik.ext.getString
|
||||||
|
import pl.szczodrzynski.edziennik.ext.isNotNullNorBlank
|
||||||
|
import pl.szczodrzynski.edziennik.ext.join
|
||||||
|
import pl.szczodrzynski.edziennik.ext.md5
|
||||||
|
import pl.szczodrzynski.edziennik.ext.resolveAttr
|
||||||
|
import pl.szczodrzynski.edziennik.ext.resolveColor
|
||||||
|
import pl.szczodrzynski.edziennik.ext.toJsonObject
|
||||||
import pl.szczodrzynski.edziennik.ui.base.BuildInvalidActivity
|
import pl.szczodrzynski.edziennik.ui.base.BuildInvalidActivity
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils
|
import pl.szczodrzynski.edziennik.utils.Utils
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
@ -75,6 +93,14 @@ class BuildManager(val app: App) : CoroutineScope {
|
|||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val releaseType = when {
|
||||||
|
isNightly || isDaily -> Update.Type.NIGHTLY
|
||||||
|
BuildConfig.VERSION_BASE.endsWith("-dev") -> Update.Type.DEV
|
||||||
|
BuildConfig.VERSION_BASE.contains("-beta.") -> Update.Type.BETA
|
||||||
|
BuildConfig.VERSION_BASE.contains("-rc.") -> Update.Type.RC
|
||||||
|
else -> Update.Type.RELEASE
|
||||||
|
}
|
||||||
|
|
||||||
fun showVersionDialog(activity: AppCompatActivity) {
|
fun showVersionDialog(activity: AppCompatActivity) {
|
||||||
val yes = activity.getString(R.string.yes)
|
val yes = activity.getString(R.string.yes)
|
||||||
val no = activity.getString(R.string.no)
|
val no = activity.getString(R.string.no)
|
||||||
|
@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2022-10-22.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.utils.managers
|
||||||
|
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
import pl.szczodrzynski.edziennik.App
|
||||||
|
import pl.szczodrzynski.edziennik.BuildConfig
|
||||||
|
import pl.szczodrzynski.edziennik.R
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.szkolny.response.Update
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.task.PostNotifications
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.Notification
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.enums.NotificationType
|
||||||
|
import pl.szczodrzynski.edziennik.ext.concat
|
||||||
|
import pl.szczodrzynski.edziennik.ext.resolveString
|
||||||
|
import pl.szczodrzynski.edziennik.utils.html.BetterHtml
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
|
class UpdateManager(val app: App) : CoroutineScope {
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "UpdateManager"
|
||||||
|
}
|
||||||
|
|
||||||
|
private val job = Job()
|
||||||
|
override val coroutineContext: CoroutineContext
|
||||||
|
get() = job + Dispatchers.Default
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for updates on the specified [maxChannel].
|
||||||
|
* If the running build is of "more-unstable" type,
|
||||||
|
* that channel is used instead.
|
||||||
|
*
|
||||||
|
* Optionally, post a notification if [notify] is true.
|
||||||
|
*
|
||||||
|
* @return [Result] containing a newer update, or null if not available
|
||||||
|
*/
|
||||||
|
suspend fun checkNow(
|
||||||
|
maxChannel: Update.Type,
|
||||||
|
notify: Boolean,
|
||||||
|
): Result<Update?> = withContext(Dispatchers.IO) {
|
||||||
|
return@withContext checkNowSync(maxChannel, notify)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for updates on the specified [maxChannel].
|
||||||
|
* If the running build is of "more-unstable" type,
|
||||||
|
* that channel is used instead.
|
||||||
|
*
|
||||||
|
* Optionally, post a notification if [notify] is true.
|
||||||
|
*
|
||||||
|
* @return [Result] containing a newer update, or null if not available
|
||||||
|
*/
|
||||||
|
fun checkNowSync(
|
||||||
|
maxChannel: Update.Type,
|
||||||
|
notify: Boolean,
|
||||||
|
): Result<Update?> {
|
||||||
|
val channel = minOf(app.buildManager.releaseType, maxChannel)
|
||||||
|
val update = app.api.runCatching({
|
||||||
|
getUpdate(channel).firstOrNull()
|
||||||
|
}, {
|
||||||
|
return Result.failure(it)
|
||||||
|
})
|
||||||
|
return Result.success(process(update, notify))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process the update: check if the version is newer, and optionally
|
||||||
|
* post a notification.
|
||||||
|
*
|
||||||
|
* @return [update] if it's a newer version, null otherwise
|
||||||
|
*/
|
||||||
|
fun process(update: Update?, notify: Boolean): Update? {
|
||||||
|
if (update == null || update.versionCode <= BuildConfig.VERSION_CODE) {
|
||||||
|
app.config.update = null
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
app.config.update = update
|
||||||
|
|
||||||
|
if (EventBus.getDefault().hasSubscriberForEvent(update::class.java)) {
|
||||||
|
EventBus.getDefault().postSticky(update)
|
||||||
|
return update
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notify)
|
||||||
|
notify(update)
|
||||||
|
return update
|
||||||
|
}
|
||||||
|
|
||||||
|
fun notify(update: Update) {
|
||||||
|
val bigText = listOf(
|
||||||
|
app.getString(R.string.notification_updates_text, update.versionName),
|
||||||
|
update.releaseNotes?.let { BetterHtml.fromHtml(context = null, it) },
|
||||||
|
)
|
||||||
|
val notification = Notification(
|
||||||
|
id = System.currentTimeMillis(),
|
||||||
|
title = R.string.notification_updates_title.resolveString(app),
|
||||||
|
text = bigText.concat("\n").toString(),
|
||||||
|
type = NotificationType.UPDATE,
|
||||||
|
profileId = null,
|
||||||
|
profileName = R.string.notification_updates_title.resolveString(app),
|
||||||
|
).addExtra("action", "updateRequest")
|
||||||
|
app.db.notificationDao().add(notification)
|
||||||
|
PostNotifications(app, listOf(notification))
|
||||||
|
}
|
||||||
|
}
|
@ -133,6 +133,18 @@
|
|||||||
android:text="Reset API signature"
|
android:text="Reset API signature"
|
||||||
android:textAllCaps="false" />
|
android:textAllCaps="false" />
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp">
|
||||||
|
|
||||||
|
<pl.szczodrzynski.edziennik.utils.TextInputKeyboardEdit
|
||||||
|
android:id="@+id/apiKey"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="API Key" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/disableDebug"
|
android:id="@+id/disableDebug"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
90
app/src/main/res/layout/update_progress_dialog.xml
Normal file
90
app/src/main/res/layout/update_progress_dialog.xml
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright (c) Kuba Szczodrzyński 2022-10-22.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<data>
|
||||||
|
|
||||||
|
<import type="pl.szczodrzynski.edziennik.BuildConfig" />
|
||||||
|
|
||||||
|
<variable
|
||||||
|
name="update"
|
||||||
|
type="pl.szczodrzynski.edziennik.data.api.szkolny.response.Update" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingHorizontal="16dp"
|
||||||
|
android:paddingTop="24dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:text="@string/app_name"
|
||||||
|
android:textAppearance="@style/NavView.TextView.Medium" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@{BuildConfig.VERSION_BASE}"
|
||||||
|
android:textAppearance="@style/NavView.TextView.Medium"
|
||||||
|
tools:text="4.13-rc.1" />
|
||||||
|
|
||||||
|
<com.mikepenz.iconics.view.IconicsImageView
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
app:iiv_color="?android:textColorPrimary"
|
||||||
|
app:iiv_icon="cmd-chevron-right"
|
||||||
|
app:iiv_size="24dp"
|
||||||
|
tools:background="@drawable/ic_arrow_right" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@{update.versionName}"
|
||||||
|
android:textAppearance="@style/NavView.TextView.Medium"
|
||||||
|
tools:text="4.13-rc.1" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.progressindicator.LinearProgressIndicator
|
||||||
|
android:id="@+id/progress"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginVertical="8dp"
|
||||||
|
tools:progress="33" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="64dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/downloadedSize"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
tools:text="2.5 MiB" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/totalSize"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
tools:text="11.4 MiB" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</layout>
|
||||||
|
|
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"base": {
|
"base": {
|
||||||
|
"configOverrides": {},
|
||||||
"messagesConfig": {
|
"messagesConfig": {
|
||||||
"subjectLength": null,
|
"subjectLength": null,
|
||||||
"bodyLength": null,
|
"bodyLength": null,
|
||||||
@ -82,6 +83,7 @@
|
|||||||
},
|
},
|
||||||
"university": {
|
"university": {
|
||||||
"configOverrides": {
|
"configOverrides": {
|
||||||
|
"timetableTrimHourRange": true,
|
||||||
"timetableColorSubjectName": true
|
"timetableColorSubjectName": true
|
||||||
},
|
},
|
||||||
"uiConfig": {
|
"uiConfig": {
|
||||||
|
@ -15,6 +15,8 @@ import android.net.Uri
|
|||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.core.content.FileProvider
|
import androidx.core.content.FileProvider
|
||||||
|
import androidx.core.content.getSystemService
|
||||||
|
import org.greenrobot.eventbus.EventBus
|
||||||
import pl.szczodrzynski.edziennik.App
|
import pl.szczodrzynski.edziennik.App
|
||||||
import pl.szczodrzynski.edziennik.R
|
import pl.szczodrzynski.edziennik.R
|
||||||
import pl.szczodrzynski.edziennik.data.api.szkolny.response.Update
|
import pl.szczodrzynski.edziennik.data.api.szkolny.response.Update
|
||||||
@ -49,6 +51,8 @@ class UpdateDownloaderService : IntentService(UpdateDownloaderService::class.jav
|
|||||||
return
|
return
|
||||||
val app = context.applicationContext as App
|
val app = context.applicationContext as App
|
||||||
|
|
||||||
|
EventBus.getDefault().postSticky(UpdateStateEvent(running = false, update = null, downloadId))
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !app.permissionChecker.canRequestApkInstall()) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !app.permissionChecker.canRequestApkInstall()) {
|
||||||
app.permissionChecker.requestApkInstall()
|
app.permissionChecker.requestApkInstall()
|
||||||
return
|
return
|
||||||
@ -79,11 +83,14 @@ class UpdateDownloaderService : IntentService(UpdateDownloaderService::class.jav
|
|||||||
val app = application as App
|
val app = application as App
|
||||||
val update = App.config.update ?: return
|
val update = App.config.update ?: return
|
||||||
|
|
||||||
if (tryUpdateWithGooglePlay(update))
|
if (tryUpdateWithGooglePlay(update)) {
|
||||||
|
stopSelf()
|
||||||
return
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (update.downloadUrl == null) {
|
if (update.downloadUrl == null) {
|
||||||
Toast.makeText(app, "Nie można pobrać tej aktualizacji. Pobierz ręcznie z Google Play.", Toast.LENGTH_LONG).show()
|
Toast.makeText(app, "Nie można pobrać tej aktualizacji. Pobierz ręcznie z Google Play.", Toast.LENGTH_LONG).show()
|
||||||
|
stopSelf()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,7 +99,7 @@ class UpdateDownloaderService : IntentService(UpdateDownloaderService::class.jav
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
(app.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).cancel(app.notificationChannelsManager.updates.id)
|
app.getSystemService<NotificationManager>()?.cancel(app.notificationChannelsManager.updates.id)
|
||||||
|
|
||||||
val dir: File? = app.getExternalFilesDir(null)
|
val dir: File? = app.getExternalFilesDir(null)
|
||||||
if (dir?.isDirectory == true) {
|
if (dir?.isDirectory == true) {
|
||||||
@ -117,5 +124,6 @@ class UpdateDownloaderService : IntentService(UpdateDownloaderService::class.jav
|
|||||||
}
|
}
|
||||||
Toast.makeText(app, "Pobieranie aktualizacji Szkolny.eu ${update.versionName}", Toast.LENGTH_LONG).show()
|
Toast.makeText(app, "Pobieranie aktualizacji Szkolny.eu ${update.versionName}", Toast.LENGTH_LONG).show()
|
||||||
downloadId = downloadManager.enqueue(request)
|
downloadId = downloadManager.enqueue(request)
|
||||||
|
EventBus.getDefault().postSticky(UpdateStateEvent(running = true, update, downloadId))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,8 @@ buildscript {
|
|||||||
kotlin_version = '1.6.10'
|
kotlin_version = '1.6.10'
|
||||||
|
|
||||||
release = [
|
release = [
|
||||||
versionName: "4.13-rc.1",
|
versionName: "4.13-rc.3",
|
||||||
versionCode: 4130010
|
versionCode: 4130030
|
||||||
]
|
]
|
||||||
|
|
||||||
setup = [
|
setup = [
|
||||||
|
Reference in New Issue
Block a user