mirror of
https://github.com/szkolny-eu/szkolny-android.git
synced 2025-01-31 05:48:19 +01:00
Merge branch 'develop'
This commit is contained in:
commit
41217190bb
@ -172,10 +172,10 @@ dependencies {
|
|||||||
kapt "eu.szkolny.selective-dao:codegen:27f8f3f194"
|
kapt "eu.szkolny.selective-dao:codegen:27f8f3f194"
|
||||||
|
|
||||||
// Iconics & related
|
// Iconics & related
|
||||||
implementation "com.mikepenz:iconics-core:5.3.0-b01"
|
implementation "com.mikepenz:iconics-core:5.3.1"
|
||||||
implementation "com.mikepenz:iconics-views:5.3.0-b01"
|
implementation "com.mikepenz:iconics-views:5.3.1"
|
||||||
implementation "com.mikepenz:community-material-typeface:5.8.55.0-kotlin@aar"
|
implementation "com.mikepenz:community-material-typeface:5.8.55.0-kotlin@aar"
|
||||||
implementation "eu.szkolny:szkolny-font:1.3"
|
implementation "eu.szkolny:szkolny-font:77e33acc2a"
|
||||||
|
|
||||||
// Other dependencies
|
// Other dependencies
|
||||||
implementation "cat.ereza:customactivityoncrash:2.3.0"
|
implementation "cat.ereza:customactivityoncrash:2.3.0"
|
||||||
|
@ -1,13 +1,6 @@
|
|||||||
<h3>Wersja 4.9, 2021-09-11</h3>
|
<h3>Wersja 4.10, 2021-09-22</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Vulcan: naprawiono brakujące lekcje w planie. @Antoni-Czaplicki</li>
|
<li>Dodano wyświetlanie informacji o frekwencji w planie lekcji. @Antoni-Czaplicki</li>
|
||||||
<li>Vulcan: naprawiono wysyłanie wiadomości. @Antoni-Czaplicki</li>
|
|
||||||
<li>Vulcan: naprawiono brak frekwencji.</li>
|
|
||||||
<li>Naprawiono eksportowanie planu lekcji oraz pobieranie załączników. @doteq</li>
|
|
||||||
<li>Mobidziennik: naprawiono możliwość pobierania przyszłego planu lekcji.</li>
|
|
||||||
<li>Mobidziennik: poprawiono brak nowych linii w wysłanej wiadomości.</li>
|
|
||||||
<li>Dodano ekran "Twórcy aplikacji" w Ustawieniach. @Pengwius</li>
|
|
||||||
<li>Zmieniono domyślne tło nagłówka menu. 😋</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] = {
|
||||||
0x36, 0x60, 0xb0, 0x4b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
0xda, 0x2a, 0x5f, 0xbe, 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);
|
||||||
|
|
||||||
|
@ -71,6 +71,7 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
|
|||||||
val permissionManager by lazy { PermissionManager(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 buildManager by lazy { BuildManager(this) }
|
||||||
|
val availabilityManager by lazy { AvailabilityManager(this) }
|
||||||
|
|
||||||
val db
|
val db
|
||||||
get() = App.db
|
get() = App.db
|
||||||
@ -174,8 +175,8 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
|
|||||||
App.config = Config(App.db)
|
App.config = Config(App.db)
|
||||||
App.profile = Profile(0, 0, 0, "")
|
App.profile = Profile(0, 0, 0, "")
|
||||||
debugMode = BuildConfig.DEBUG
|
debugMode = BuildConfig.DEBUG
|
||||||
devMode = config.debugMode || debugMode
|
devMode = config.devMode ?: debugMode
|
||||||
enableChucker = config.enableChucker || devMode
|
enableChucker = config.enableChucker ?: devMode
|
||||||
|
|
||||||
if (!profileLoadById(config.lastProfileId)) {
|
if (!profileLoadById(config.lastProfileId)) {
|
||||||
db.profileDao().firstId?.let { profileLoadById(it) }
|
db.profileDao().firstId?.let { profileLoadById(it) }
|
||||||
|
@ -85,6 +85,8 @@ import pl.szczodrzynski.edziennik.ui.modules.webpush.WebPushFragment
|
|||||||
import pl.szczodrzynski.edziennik.utils.*
|
import pl.szczodrzynski.edziennik.utils.*
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils.dpToPx
|
import pl.szczodrzynski.edziennik.utils.Utils.dpToPx
|
||||||
|
import pl.szczodrzynski.edziennik.utils.managers.AvailabilityManager
|
||||||
|
import pl.szczodrzynski.edziennik.utils.managers.AvailabilityManager.Error.Type
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
import pl.szczodrzynski.edziennik.utils.models.NavTarget
|
import pl.szczodrzynski.edziennik.utils.models.NavTarget
|
||||||
import pl.szczodrzynski.navlib.*
|
import pl.szczodrzynski.navlib.*
|
||||||
@ -634,45 +636,23 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
app.profile.registerName?.let { registerName ->
|
val error = withContext(Dispatchers.IO) {
|
||||||
var status = app.config.sync.registerAvailability[registerName]
|
app.availabilityManager.check(app.profile)
|
||||||
if (status == null || status.nextCheckAt < currentTimeUnix()) {
|
|
||||||
val api = SzkolnyApi(app)
|
|
||||||
val result = withContext(Dispatchers.IO) {
|
|
||||||
return@withContext api.runCatching({
|
|
||||||
val availability = getRegisterAvailability()
|
|
||||||
app.config.sync.registerAvailability = availability
|
|
||||||
availability[registerName]
|
|
||||||
}, onError = {
|
|
||||||
if (it.toErrorCode() == ERROR_API_INVALID_SIGNATURE) {
|
|
||||||
return@withContext false
|
|
||||||
}
|
}
|
||||||
return@withContext it
|
when (error?.type) {
|
||||||
})
|
Type.NOT_AVAILABLE -> {
|
||||||
}
|
|
||||||
|
|
||||||
when (result) {
|
|
||||||
false -> {
|
|
||||||
Toast.makeText(this@MainActivity, R.string.error_no_api_access, Toast.LENGTH_SHORT).show()
|
|
||||||
return@let
|
|
||||||
}
|
|
||||||
is Throwable -> {
|
|
||||||
errorSnackbar.addError(result.toApiError(TAG)).show()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
is RegisterAvailabilityStatus -> {
|
|
||||||
status = result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status?.available != true || status.minVersionCode > BuildConfig.VERSION_CODE) {
|
|
||||||
swipeRefreshLayout.isRefreshing = false
|
swipeRefreshLayout.isRefreshing = false
|
||||||
loadTarget(DRAWER_ITEM_HOME)
|
loadTarget(DRAWER_ITEM_HOME)
|
||||||
if (status != null)
|
RegisterUnavailableDialog(this, error.status!!)
|
||||||
RegisterUnavailableDialog(this, status)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
Type.API_ERROR -> {
|
||||||
|
errorSnackbar.addError(error.apiError!!).show()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
Type.NO_API_ACCESS -> {
|
||||||
|
Toast.makeText(this, R.string.error_no_api_access, Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
swipeRefreshLayout.isRefreshing = true
|
swipeRefreshLayout.isRefreshing = true
|
||||||
@ -699,10 +679,9 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
|||||||
@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)
|
||||||
app.profile.registerName?.let { registerName ->
|
val error = app.availabilityManager.check(app.profile, cacheOnly = true)
|
||||||
event.data[registerName]?.let {
|
if (error != null) {
|
||||||
RegisterUnavailableDialog(this, it)
|
RegisterUnavailableDialog(this, error.status!!)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
|
@ -12,10 +12,7 @@ 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.config.db.ConfigEntry
|
import pl.szczodrzynski.edziennik.config.db.ConfigEntry
|
||||||
import pl.szczodrzynski.edziennik.config.utils.ConfigMigration
|
import pl.szczodrzynski.edziennik.config.utils.*
|
||||||
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.api.szkolny.response.Update
|
||||||
import pl.szczodrzynski.edziennik.data.db.AppDb
|
import pl.szczodrzynski.edziennik.data.db.AppDb
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
@ -75,15 +72,15 @@ class Config(val db: AppDb) : CoroutineScope, AbstractConfig {
|
|||||||
get() { mPrivacyPolicyAccepted = mPrivacyPolicyAccepted ?: values.get("privacyPolicyAccepted", false); return mPrivacyPolicyAccepted ?: false }
|
get() { mPrivacyPolicyAccepted = mPrivacyPolicyAccepted ?: values.get("privacyPolicyAccepted", false); return mPrivacyPolicyAccepted ?: false }
|
||||||
set(value) { set("privacyPolicyAccepted", value); mPrivacyPolicyAccepted = value }
|
set(value) { set("privacyPolicyAccepted", value); mPrivacyPolicyAccepted = value }
|
||||||
|
|
||||||
private var mDebugMode: Boolean? = null
|
private var mDevMode: Boolean? = null
|
||||||
var debugMode: Boolean
|
var devMode: Boolean?
|
||||||
get() { mDebugMode = mDebugMode ?: values.get("debugMode", false); return mDebugMode ?: false }
|
get() { mDevMode = mDevMode ?: values.getBooleanOrNull("debugMode"); return mDevMode }
|
||||||
set(value) { set("debugMode", value); mDebugMode = value }
|
set(value) { set("debugMode", value?.toString()); mDevMode = value }
|
||||||
|
|
||||||
private var mEnableChucker: Boolean? = null
|
private var mEnableChucker: Boolean? = null
|
||||||
var enableChucker: Boolean
|
var enableChucker: Boolean?
|
||||||
get() { mEnableChucker = mEnableChucker ?: values.get("enableChucker", false); return mEnableChucker ?: false }
|
get() { mEnableChucker = mEnableChucker ?: values.getBooleanOrNull("enableChucker"); return mEnableChucker }
|
||||||
set(value) { set("enableChucker", value); mEnableChucker = value }
|
set(value) { set("enableChucker", value?.toString()); mEnableChucker = value }
|
||||||
|
|
||||||
private var mDevModePassword: String? = null
|
private var mDevModePassword: String? = null
|
||||||
var devModePassword: String?
|
var devModePassword: String?
|
||||||
@ -125,6 +122,11 @@ class Config(val db: AppDb) : CoroutineScope, AbstractConfig {
|
|||||||
get() { mApiInvalidCert = mApiInvalidCert ?: values["apiInvalidCert"]; return mApiInvalidCert }
|
get() { mApiInvalidCert = mApiInvalidCert ?: values["apiInvalidCert"]; return mApiInvalidCert }
|
||||||
set(value) { set("apiInvalidCert", value); mApiInvalidCert = value }
|
set(value) { set("apiInvalidCert", value); mApiInvalidCert = value }
|
||||||
|
|
||||||
|
private var mApiAvailabilityCheck: Boolean? = null
|
||||||
|
var apiAvailabilityCheck: Boolean
|
||||||
|
get() { mApiAvailabilityCheck = mApiAvailabilityCheck ?: values.get("apiAvailabilityCheck", true); return mApiAvailabilityCheck ?: true }
|
||||||
|
set(value) { set("apiAvailabilityCheck", value); mApiAvailabilityCheck = value }
|
||||||
|
|
||||||
private var rawEntries: List<ConfigEntry> = db.configDao().getAllNow()
|
private var rawEntries: List<ConfigEntry> = db.configDao().getAllNow()
|
||||||
private val profileConfigs: HashMap<Int, ProfileConfig> = hashMapOf()
|
private val profileConfigs: HashMap<Int, ProfileConfig> = hashMapOf()
|
||||||
init {
|
init {
|
||||||
|
@ -59,6 +59,9 @@ fun HashMap<String, String?>.get(key: String, default: String?): String? {
|
|||||||
fun HashMap<String, String?>.get(key: String, default: Boolean): Boolean {
|
fun HashMap<String, String?>.get(key: String, default: Boolean): Boolean {
|
||||||
return this[key]?.toBoolean() ?: default
|
return this[key]?.toBoolean() ?: default
|
||||||
}
|
}
|
||||||
|
fun HashMap<String, String?>.getBooleanOrNull(key: String): Boolean? {
|
||||||
|
return this[key]?.toBooleanStrictOrNull()
|
||||||
|
}
|
||||||
fun HashMap<String, String?>.get(key: String, default: Int): Int {
|
fun HashMap<String, String?>.get(key: String, default: Int): Int {
|
||||||
return this[key]?.toIntOrNull() ?: default
|
return this[key]?.toIntOrNull() ?: default
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,7 @@ class ConfigMigration(app: App, config: Config) {
|
|||||||
if (dataVersion < 3) {
|
if (dataVersion < 3) {
|
||||||
update = null
|
update = null
|
||||||
privacyPolicyAccepted = false
|
privacyPolicyAccepted = false
|
||||||
debugMode = false
|
devMode = null
|
||||||
devModePassword = null
|
devModePassword = null
|
||||||
appInstalledTime = 0L
|
appInstalledTime = 0L
|
||||||
appRateSnackbarTime = 0L
|
appRateSnackbarTime = 0L
|
||||||
|
@ -18,7 +18,6 @@ import pl.szczodrzynski.edziennik.data.api.events.RegisterAvailabilityEvent
|
|||||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
|
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
|
||||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
|
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||||
import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.task.IApiTask
|
import pl.szczodrzynski.edziennik.data.api.task.IApiTask
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||||
@ -27,6 +26,7 @@ import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
|
|||||||
import pl.szczodrzynski.edziennik.data.db.full.EventFull
|
import pl.szczodrzynski.edziennik.data.db.full.EventFull
|
||||||
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
|
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
|
import pl.szczodrzynski.edziennik.utils.managers.AvailabilityManager.Error.Type
|
||||||
|
|
||||||
open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTask(profileId) {
|
open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTask(profileId) {
|
||||||
companion object {
|
companion object {
|
||||||
@ -90,35 +90,21 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
profile.registerName?.also { registerName ->
|
val error = app.availabilityManager.check(profile)
|
||||||
var status = app.config.sync.registerAvailability[registerName]
|
when (error?.type) {
|
||||||
if (status == null || status.nextCheckAt < currentTimeUnix()) {
|
Type.NOT_AVAILABLE -> {
|
||||||
val api = SzkolnyApi(app)
|
|
||||||
api.runCatching({
|
|
||||||
val availability = getRegisterAvailability()
|
|
||||||
app.config.sync.registerAvailability = availability
|
|
||||||
status = availability[registerName]
|
|
||||||
}, onError = {
|
|
||||||
val apiError = it.toApiError(TAG)
|
|
||||||
if (apiError.errorCode == ERROR_API_INVALID_SIGNATURE) {
|
|
||||||
return@also
|
|
||||||
}
|
|
||||||
taskCallback.onError(apiError)
|
|
||||||
return
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status?.available != true
|
|
||||||
|| status?.minVersionCode ?: BuildConfig.VERSION_CODE > BuildConfig.VERSION_CODE) {
|
|
||||||
if (EventBus.getDefault().hasSubscriberForEvent(RegisterAvailabilityEvent::class.java)) {
|
if (EventBus.getDefault().hasSubscriberForEvent(RegisterAvailabilityEvent::class.java)) {
|
||||||
EventBus.getDefault().postSticky(
|
EventBus.getDefault().postSticky(RegisterAvailabilityEvent())
|
||||||
RegisterAvailabilityEvent(app.config.sync.registerAvailability)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
cancel()
|
cancel()
|
||||||
taskCallback.onCompleted()
|
taskCallback.onCompleted()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
Type.API_ERROR -> {
|
||||||
|
taskCallback.onError(error.apiError!!)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
else -> return@let
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,8 +4,4 @@
|
|||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.events
|
package pl.szczodrzynski.edziennik.data.api.events
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.szkolny.response.RegisterAvailabilityStatus
|
class RegisterAvailabilityEvent()
|
||||||
|
|
||||||
data class RegisterAvailabilityEvent(
|
|
||||||
val data: Map< String, RegisterAvailabilityStatus>
|
|
||||||
)
|
|
||||||
|
@ -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.MTIzNDU2Nzg5MDkdkClKMQ===.$param2".sha256()
|
return "$param1.MTIzNDU2Nzg5MDY8+Uq3So===.$param2".sha256()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,6 +64,8 @@ abstract class AttendanceDao : BaseDao<Attendance, AttendanceFull> {
|
|||||||
getRawNow("$QUERY WHERE notified = 0 $ORDER_BY")
|
getRawNow("$QUERY WHERE notified = 0 $ORDER_BY")
|
||||||
fun getNotNotifiedNow(profileId: Int) =
|
fun getNotNotifiedNow(profileId: Int) =
|
||||||
getRawNow("$QUERY WHERE attendances.profileId = $profileId AND notified = 0 $ORDER_BY")
|
getRawNow("$QUERY WHERE attendances.profileId = $profileId AND notified = 0 $ORDER_BY")
|
||||||
|
fun getAllByDateNow(profileId: Int, date: Date) =
|
||||||
|
getRawNow("$QUERY WHERE attendances.profileId = $profileId AND attendanceDate = '${date.stringY_m_d}' $ORDER_BY")
|
||||||
|
|
||||||
// GET ONE - NOW
|
// GET ONE - NOW
|
||||||
fun getByIdNow(profileId: Int, id: Long) =
|
fun getByIdNow(profileId: Int, id: Long) =
|
||||||
|
@ -140,7 +140,7 @@ open class Profile(
|
|||||||
LOGIN_TYPE_MOBIDZIENNIK -> "mobidziennik"
|
LOGIN_TYPE_MOBIDZIENNIK -> "mobidziennik"
|
||||||
LOGIN_TYPE_PODLASIE -> "podlasie"
|
LOGIN_TYPE_PODLASIE -> "podlasie"
|
||||||
LOGIN_TYPE_EDUDZIENNIK -> "edudziennik"
|
LOGIN_TYPE_EDUDZIENNIK -> "edudziennik"
|
||||||
else -> null
|
else -> "unknown"
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getImageDrawable(context: Context): Drawable {
|
override fun getImageDrawable(context: Context): Drawable {
|
||||||
|
@ -60,7 +60,7 @@ class SzkolnyAppFirebase(val app: App, val profiles: List<Profile>, val message:
|
|||||||
) ?: return@launch
|
) ?: return@launch
|
||||||
app.config.sync.registerAvailability = data
|
app.config.sync.registerAvailability = data
|
||||||
if (EventBus.getDefault().hasSubscriberForEvent(RegisterAvailabilityEvent::class.java)) {
|
if (EventBus.getDefault().hasSubscriberForEvent(RegisterAvailabilityEvent::class.java)) {
|
||||||
EventBus.getDefault().postSticky(RegisterAvailabilityEvent(data))
|
EventBus.getDefault().postSticky(RegisterAvailabilityEvent())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,8 +42,6 @@ class RegisterUnavailableDialog(
|
|||||||
init { run {
|
init { run {
|
||||||
if (activity.isFinishing)
|
if (activity.isFinishing)
|
||||||
return@run
|
return@run
|
||||||
if (status.available && status.minVersionCode <= BuildConfig.VERSION_CODE)
|
|
||||||
return@run
|
|
||||||
onShowListener?.invoke(TAG)
|
onShowListener?.invoke(TAG)
|
||||||
app = activity.applicationContext as App
|
app = activity.applicationContext as App
|
||||||
|
|
||||||
|
@ -8,15 +8,20 @@ import android.content.Intent
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.view.isVisible
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import com.mikepenz.iconics.IconicsDrawable
|
||||||
|
import com.mikepenz.iconics.utils.colorInt
|
||||||
|
import com.mikepenz.iconics.utils.sizeDp
|
||||||
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.App
|
import pl.szczodrzynski.edziennik.App
|
||||||
import pl.szczodrzynski.edziennik.R
|
import pl.szczodrzynski.edziennik.R
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Lesson
|
import pl.szczodrzynski.edziennik.data.db.entity.Lesson
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.full.AttendanceFull
|
||||||
import pl.szczodrzynski.edziennik.data.db.full.LessonFull
|
import pl.szczodrzynski.edziennik.data.db.full.LessonFull
|
||||||
import pl.szczodrzynski.edziennik.databinding.DialogLessonDetailsBinding
|
import pl.szczodrzynski.edziennik.databinding.DialogLessonDetailsBinding
|
||||||
import pl.szczodrzynski.edziennik.onClick
|
import pl.szczodrzynski.edziennik.onClick
|
||||||
@ -24,6 +29,7 @@ import pl.szczodrzynski.edziennik.setText
|
|||||||
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventDetailsDialog
|
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventDetailsDialog
|
||||||
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventListAdapter
|
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventListAdapter
|
||||||
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventManualDialog
|
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventManualDialog
|
||||||
|
import pl.szczodrzynski.edziennik.ui.modules.attendance.AttendanceDetailsDialog
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.timetable.TimetableFragment
|
import pl.szczodrzynski.edziennik.ui.modules.timetable.TimetableFragment
|
||||||
import pl.szczodrzynski.edziennik.utils.BetterLink
|
import pl.szczodrzynski.edziennik.utils.BetterLink
|
||||||
import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
|
import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
|
||||||
@ -34,6 +40,7 @@ import kotlin.coroutines.CoroutineContext
|
|||||||
class LessonDetailsDialog(
|
class LessonDetailsDialog(
|
||||||
val activity: AppCompatActivity,
|
val activity: AppCompatActivity,
|
||||||
val lesson: LessonFull,
|
val lesson: LessonFull,
|
||||||
|
val attendance: AttendanceFull? = null,
|
||||||
val onShowListener: ((tag: String) -> Unit)? = null,
|
val onShowListener: ((tag: String) -> Unit)? = null,
|
||||||
val onDismissListener: ((tag: String) -> Unit)? = null
|
val onDismissListener: ((tag: String) -> Unit)? = null
|
||||||
) : CoroutineScope {
|
) : CoroutineScope {
|
||||||
@ -52,6 +59,8 @@ class LessonDetailsDialog(
|
|||||||
private lateinit var adapter: EventListAdapter
|
private lateinit var adapter: EventListAdapter
|
||||||
private val manager
|
private val manager
|
||||||
get() = app.timetableManager
|
get() = app.timetableManager
|
||||||
|
private val attendanceManager
|
||||||
|
get() = app.attendanceManager
|
||||||
|
|
||||||
init { run {
|
init { run {
|
||||||
if (activity.isFinishing)
|
if (activity.isFinishing)
|
||||||
@ -170,6 +179,27 @@ class LessonDetailsDialog(
|
|||||||
b.teamName = lesson.teamName
|
b.teamName = lesson.teamName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b.attendanceDivider.isVisible = attendance != null
|
||||||
|
b.attendanceLayout.isVisible = attendance != null
|
||||||
|
if (attendance != null) {
|
||||||
|
b.attendanceView.setAttendance(attendance, app.attendanceManager, bigView = true)
|
||||||
|
b.attendanceType.text = attendance.typeName
|
||||||
|
b.attendanceIcon.isVisible = attendance.let {
|
||||||
|
val icon = attendanceManager.getAttendanceIcon(it) ?: return@let false
|
||||||
|
val color = attendanceManager.getAttendanceColor(it)
|
||||||
|
b.attendanceIcon.setImageDrawable(
|
||||||
|
IconicsDrawable(activity, icon).apply {
|
||||||
|
colorInt = color
|
||||||
|
sizeDp = 24
|
||||||
|
}
|
||||||
|
)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
b.attendanceDetails.onClick {
|
||||||
|
AttendanceDetailsDialog(activity, attendance, onShowListener, onDismissListener)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
adapter = EventListAdapter(
|
adapter = EventListAdapter(
|
||||||
activity,
|
activity,
|
||||||
showWeekDay = false,
|
showWeekDay = false,
|
||||||
|
@ -41,6 +41,7 @@ class LabFragment : Fragment(), CoroutineScope {
|
|||||||
app = activity.application as App
|
app = activity.application as App
|
||||||
b = TemplateFragmentBinding.inflate(inflater)
|
b = TemplateFragmentBinding.inflate(inflater)
|
||||||
b.refreshLayout.setParent(activity.swipeRefreshLayout)
|
b.refreshLayout.setParent(activity.swipeRefreshLayout)
|
||||||
|
b.refreshLayout.isEnabled = false
|
||||||
return b.root
|
return b.root
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ import kotlinx.coroutines.Dispatchers
|
|||||||
import kotlinx.coroutines.Job
|
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.data.db.entity.Event
|
import pl.szczodrzynski.edziennik.data.db.entity.Event
|
||||||
import pl.szczodrzynski.edziennik.databinding.LabFragmentBinding
|
import pl.szczodrzynski.edziennik.databinding.LabFragmentBinding
|
||||||
import pl.szczodrzynski.edziennik.ui.dialogs.profile.ProfileRemoveDialog
|
import pl.szczodrzynski.edziennik.ui.dialogs.profile.ProfileRemoveDialog
|
||||||
@ -78,10 +79,10 @@ class LabPageFragment : LazyFragment(), CoroutineScope {
|
|||||||
app.db.eventDao().getRawNow("UPDATE events SET homeworkBody = NULL WHERE profileId = ${App.profileId}")
|
app.db.eventDao().getRawNow("UPDATE events SET homeworkBody = NULL WHERE profileId = ${App.profileId}")
|
||||||
}
|
}
|
||||||
|
|
||||||
b.chucker.isChecked = app.config.enableChucker
|
b.chucker.isChecked = App.enableChucker
|
||||||
|
|
||||||
b.chucker.onChange { _, isChecked ->
|
b.chucker.onChange { _, isChecked ->
|
||||||
app.config.enableChucker = isChecked
|
app.config.enableChucker = isChecked
|
||||||
|
App.enableChucker = isChecked
|
||||||
MaterialAlertDialogBuilder(activity)
|
MaterialAlertDialogBuilder(activity)
|
||||||
.setTitle("Restart")
|
.setTitle("Restart")
|
||||||
.setMessage("Wymagany restart aplikacji")
|
.setMessage("Wymagany restart aplikacji")
|
||||||
@ -94,9 +95,9 @@ class LabPageFragment : LazyFragment(), CoroutineScope {
|
|||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
b.disableDebug.onClick {
|
b.disableDebug.onClick {
|
||||||
app.config.debugMode = false
|
app.config.devMode = false
|
||||||
|
App.devMode = false
|
||||||
MaterialAlertDialogBuilder(activity)
|
MaterialAlertDialogBuilder(activity)
|
||||||
.setTitle("Restart")
|
.setTitle("Restart")
|
||||||
.setMessage("Wymagany restart aplikacji")
|
.setMessage("Wymagany restart aplikacji")
|
||||||
@ -115,6 +116,14 @@ class LabPageFragment : LazyFragment(), CoroutineScope {
|
|||||||
app.profileSave()
|
app.profileSave()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b.resetCert.onClick {
|
||||||
|
app.config.apiInvalidCert = null
|
||||||
|
}
|
||||||
|
|
||||||
|
b.rebuildConfig.onClick {
|
||||||
|
App.config = Config(App.db)
|
||||||
|
}
|
||||||
|
|
||||||
val profiles = app.db.profileDao().allNow
|
val profiles = app.db.profileDao().allNow
|
||||||
b.profile.clear()
|
b.profile.clear()
|
||||||
b.profile += profiles.map { TextInputDropDown.Item(it.id.toLong(), "${it.id} ${it.name} archived ${it.archived}", tag = it) }
|
b.profile += profiles.map { TextInputDropDown.Item(it.id.toLong(), "${it.id} ${it.name} archived ${it.archived}", tag = it) }
|
||||||
|
@ -163,10 +163,9 @@ class HomeFragment : Fragment(), CoroutineScope {
|
|||||||
if (app.profile.archived)
|
if (app.profile.archived)
|
||||||
items.add(0, HomeArchiveCard(101, app, activity, this, app.profile))
|
items.add(0, HomeArchiveCard(101, app, activity, this, app.profile))
|
||||||
|
|
||||||
val status = app.config.sync.registerAvailability[app.profile.registerName]
|
val status = app.availabilityManager.check(app.profile, cacheOnly = true)?.status
|
||||||
val update = app.config.update
|
val update = app.config.update
|
||||||
if (update != null && update.versionCode > BuildConfig.VERSION_CODE
|
if (update != null && update.versionCode > BuildConfig.VERSION_CODE || status?.userMessage != null) {
|
||||||
|| status != null && (!status.available || status.minVersionCode > BuildConfig.VERSION_CODE)) {
|
|
||||||
items.add(0, HomeAvailabilityCard(102, app, activity, this, app.profile))
|
items.add(0, HomeAvailabilityCard(102, app, activity, this, app.profile))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +50,8 @@ class HomeAvailabilityCard(
|
|||||||
}
|
}
|
||||||
holder.root += b.root
|
holder.root += b.root
|
||||||
|
|
||||||
val status = app.config.sync.registerAvailability[profile.registerName]
|
val error = app.availabilityManager.check(profile, cacheOnly = true)
|
||||||
|
val status = error?.status
|
||||||
val update = app.config.update
|
val update = app.config.update
|
||||||
|
|
||||||
if (update == null && status == null)
|
if (update == null && status == null)
|
||||||
@ -58,7 +59,8 @@ class HomeAvailabilityCard(
|
|||||||
|
|
||||||
var onInfoClick = { _: View -> }
|
var onInfoClick = { _: View -> }
|
||||||
|
|
||||||
if (status != null && !status.available && status.userMessage != null) {
|
// show "register unavailable" only when disabled
|
||||||
|
if (status?.userMessage != null) {
|
||||||
b.homeAvailabilityTitle.text = HtmlCompat.fromHtml(status.userMessage.title, HtmlCompat.FROM_HTML_MODE_LEGACY)
|
b.homeAvailabilityTitle.text = HtmlCompat.fromHtml(status.userMessage.title, HtmlCompat.FROM_HTML_MODE_LEGACY)
|
||||||
b.homeAvailabilityText.text = HtmlCompat.fromHtml(status.userMessage.contentShort, HtmlCompat.FROM_HTML_MODE_LEGACY)
|
b.homeAvailabilityText.text = HtmlCompat.fromHtml(status.userMessage.contentShort, HtmlCompat.FROM_HTML_MODE_LEGACY)
|
||||||
b.homeAvailabilityUpdate.isVisible = false
|
b.homeAvailabilityUpdate.isVisible = false
|
||||||
@ -69,6 +71,7 @@ class HomeAvailabilityCard(
|
|||||||
RegisterUnavailableDialog(activity, status)
|
RegisterUnavailableDialog(activity, status)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// show "update available" when available OR version too old for the register
|
||||||
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)
|
||||||
@ -78,6 +81,9 @@ class HomeAvailabilityCard(
|
|||||||
UpdateAvailableDialog(activity, update)
|
UpdateAvailableDialog(activity, update)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
b.root.isVisible = false
|
||||||
|
}
|
||||||
|
|
||||||
b.homeAvailabilityUpdate.onClick {
|
b.homeAvailabilityUpdate.onClick {
|
||||||
if (update == null)
|
if (update == null)
|
||||||
|
@ -26,13 +26,12 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
|||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import pl.szczodrzynski.edziennik.*
|
import pl.szczodrzynski.edziennik.*
|
||||||
import pl.szczodrzynski.edziennik.data.api.*
|
import pl.szczodrzynski.edziennik.data.api.*
|
||||||
import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.szkolny.response.RegisterAvailabilityStatus
|
|
||||||
import pl.szczodrzynski.edziennik.databinding.LoginChooserFragmentBinding
|
import pl.szczodrzynski.edziennik.databinding.LoginChooserFragmentBinding
|
||||||
import pl.szczodrzynski.edziennik.ui.dialogs.RegisterUnavailableDialog
|
import pl.szczodrzynski.edziennik.ui.dialogs.RegisterUnavailableDialog
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.feedback.FeedbackActivity
|
import pl.szczodrzynski.edziennik.ui.modules.feedback.FeedbackActivity
|
||||||
import pl.szczodrzynski.edziennik.utils.BetterLinkMovementMethod
|
import pl.szczodrzynski.edziennik.utils.BetterLinkMovementMethod
|
||||||
import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
|
import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
|
||||||
|
import pl.szczodrzynski.edziennik.utils.managers.AvailabilityManager.Error.Type
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
@ -269,52 +268,23 @@ class LoginChooserFragment : Fragment(), CoroutineScope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun checkAvailability(loginType: Int): Boolean {
|
private suspend fun checkAvailability(loginType: Int): Boolean {
|
||||||
when (loginType) {
|
val error = withContext(Dispatchers.IO) {
|
||||||
LOGIN_TYPE_LIBRUS -> "librus"
|
app.availabilityManager.check(loginType)
|
||||||
LOGIN_TYPE_VULCAN -> "vulcan"
|
} ?: return true
|
||||||
LOGIN_TYPE_IDZIENNIK -> "idziennik"
|
|
||||||
LOGIN_TYPE_MOBIDZIENNIK -> "mobidziennik"
|
|
||||||
LOGIN_TYPE_PODLASIE -> "podlasie"
|
|
||||||
LOGIN_TYPE_EDUDZIENNIK -> "edudziennik"
|
|
||||||
else -> null
|
|
||||||
}?.let { registerName ->
|
|
||||||
var status = app.config.sync.registerAvailability[registerName]
|
|
||||||
if (status == null || status.nextCheckAt < currentTimeUnix()) {
|
|
||||||
val api = SzkolnyApi(app)
|
|
||||||
val result = withContext(Dispatchers.IO) {
|
|
||||||
return@withContext api.runCatching({
|
|
||||||
val availability = getRegisterAvailability()
|
|
||||||
app.config.sync.registerAvailability = availability
|
|
||||||
availability[registerName]
|
|
||||||
}, onError = {
|
|
||||||
if (it.toErrorCode() == ERROR_API_INVALID_SIGNATURE) {
|
|
||||||
return@withContext false
|
|
||||||
}
|
|
||||||
return@withContext it
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
when (result) {
|
return when (error.type) {
|
||||||
false -> {
|
Type.NOT_AVAILABLE -> {
|
||||||
|
RegisterUnavailableDialog(activity, error.status!!)
|
||||||
|
false
|
||||||
|
}
|
||||||
|
Type.API_ERROR -> {
|
||||||
|
activity.errorSnackbar.addError(error.apiError!!).show()
|
||||||
|
false
|
||||||
|
}
|
||||||
|
Type.NO_API_ACCESS -> {
|
||||||
Toast.makeText(activity, R.string.error_no_api_access, Toast.LENGTH_SHORT).show()
|
Toast.makeText(activity, R.string.error_no_api_access, Toast.LENGTH_SHORT).show()
|
||||||
return@let
|
true
|
||||||
}
|
|
||||||
is Throwable -> {
|
|
||||||
activity.errorSnackbar.addError(result.toApiError(TAG)).show()
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
is RegisterAvailabilityStatus -> {
|
|
||||||
status = result
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status?.available != true || status.minVersionCode > BuildConfig.VERSION_CODE) {
|
|
||||||
if (status != null)
|
|
||||||
RegisterUnavailableDialog(activity, status)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ class LoginPrizeFragment : Fragment(), CoroutineScope {
|
|||||||
.setTitle(R.string.are_you_sure)
|
.setTitle(R.string.are_you_sure)
|
||||||
.setMessage(R.string.dev_mode_enable_warning)
|
.setMessage(R.string.dev_mode_enable_warning)
|
||||||
.setPositiveButton(R.string.yes) { _, _ ->
|
.setPositiveButton(R.string.yes) { _, _ ->
|
||||||
app.config.debugMode = true
|
app.config.devMode = true
|
||||||
App.devMode = true
|
App.devMode = true
|
||||||
MaterialAlertDialogBuilder(activity)
|
MaterialAlertDialogBuilder(activity)
|
||||||
.setTitle("Restart")
|
.setTitle("Restart")
|
||||||
@ -67,8 +67,8 @@ class LoginPrizeFragment : Fragment(), CoroutineScope {
|
|||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
.setNegativeButton(R.string.no) { _, _ ->
|
.setNegativeButton(R.string.no) { _, _ ->
|
||||||
app.config.debugMode = false
|
app.config.devMode = App.debugMode
|
||||||
App.devMode = false
|
App.devMode = App.debugMode
|
||||||
activity.finish()
|
activity.finish()
|
||||||
}
|
}
|
||||||
.show()
|
.show()
|
||||||
|
@ -9,19 +9,24 @@ import android.view.LayoutInflater
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
|
import android.widget.LinearLayout
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.asynclayoutinflater.view.AsyncLayoutInflater
|
import androidx.asynclayoutinflater.view.AsyncLayoutInflater
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.*
|
||||||
import androidx.core.view.marginTop
|
|
||||||
import androidx.core.view.setPadding
|
|
||||||
import androidx.core.view.updateLayoutParams
|
|
||||||
import com.linkedin.android.tachyon.DayView
|
import com.linkedin.android.tachyon.DayView
|
||||||
import com.linkedin.android.tachyon.DayViewConfig
|
import com.linkedin.android.tachyon.DayViewConfig
|
||||||
|
import com.mikepenz.iconics.IconicsDrawable
|
||||||
|
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||||
|
import com.mikepenz.iconics.utils.colorInt
|
||||||
|
import com.mikepenz.iconics.utils.sizeDp
|
||||||
|
import eu.szkolny.font.SzkolnyFont
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import pl.szczodrzynski.edziennik.*
|
import pl.szczodrzynski.edziennik.*
|
||||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_TIMETABLE
|
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_TIMETABLE
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask
|
import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.Attendance
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Lesson
|
import pl.szczodrzynski.edziennik.data.db.entity.Lesson
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.full.AttendanceFull
|
||||||
import pl.szczodrzynski.edziennik.data.db.full.EventFull
|
import pl.szczodrzynski.edziennik.data.db.full.EventFull
|
||||||
import pl.szczodrzynski.edziennik.data.db.full.LessonFull
|
import pl.szczodrzynski.edziennik.data.db.full.LessonFull
|
||||||
import pl.szczodrzynski.edziennik.databinding.TimetableDayFragmentBinding
|
import pl.szczodrzynski.edziennik.databinding.TimetableDayFragmentBinding
|
||||||
@ -61,6 +66,8 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope {
|
|||||||
|
|
||||||
private val manager
|
private val manager
|
||||||
get() = app.timetableManager
|
get() = app.timetableManager
|
||||||
|
private val attendanceManager
|
||||||
|
get() = app.attendanceManager
|
||||||
|
|
||||||
// find SwipeRefreshLayout in the hierarchy
|
// find SwipeRefreshLayout in the hierarchy
|
||||||
private val refreshLayout by lazy { view?.findParentById(R.id.refreshLayout) }
|
private val refreshLayout by lazy { view?.findParentById(R.id.refreshLayout) }
|
||||||
@ -102,14 +109,17 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope {
|
|||||||
val events = withContext(Dispatchers.Default) {
|
val events = withContext(Dispatchers.Default) {
|
||||||
app.db.eventDao().getAllByDateNow(App.profileId, date)
|
app.db.eventDao().getAllByDateNow(App.profileId, date)
|
||||||
}
|
}
|
||||||
processLessonList(lessons, events)
|
val attendanceList = withContext(Dispatchers.Default) {
|
||||||
|
app.db.attendanceDao().getAllByDateNow(App.profileId, date)
|
||||||
|
}
|
||||||
|
processLessonList(lessons, events, attendanceList)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun processLessonList(lessons: List<LessonFull>, events: List<EventFull>) {
|
private fun processLessonList(lessons: List<LessonFull>, events: List<EventFull>, attendanceList: List<AttendanceFull>) {
|
||||||
// no lessons - timetable not downloaded yet
|
// no lessons - timetable not downloaded yet
|
||||||
if (lessons.isEmpty()) {
|
if (lessons.isEmpty()) {
|
||||||
inflater.inflate(R.layout.timetable_no_timetable, b.root) { view, _, _ ->
|
inflater.inflate(R.layout.timetable_no_timetable, b.root) { view, _, _ ->
|
||||||
@ -172,10 +182,10 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope {
|
|||||||
|
|
||||||
lessons.forEach { it.showAsUnseen = !it.seen }
|
lessons.forEach { it.showAsUnseen = !it.seen }
|
||||||
|
|
||||||
buildLessonViews(lessons.filter { it.type != Lesson.TYPE_NO_LESSONS }, events)
|
buildLessonViews(lessons.filter { it.type != Lesson.TYPE_NO_LESSONS }, events, attendanceList)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildLessonViews(lessons: List<LessonFull>, events: List<EventFull>) {
|
private fun buildLessonViews(lessons: List<LessonFull>, events: List<EventFull>, attendanceList: List<AttendanceFull>) {
|
||||||
if (!isAdded)
|
if (!isAdded)
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -192,6 +202,7 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope {
|
|||||||
val colorSecondary = android.R.attr.textColorSecondary.resolveAttr(activity)
|
val colorSecondary = android.R.attr.textColorSecondary.resolveAttr(activity)
|
||||||
|
|
||||||
for (lesson in lessons) {
|
for (lesson in lessons) {
|
||||||
|
val attendance = attendanceList.find { it.startTime == lesson.startTime }
|
||||||
val startTime = lesson.displayStartTime ?: continue
|
val startTime = lesson.displayStartTime ?: continue
|
||||||
val endTime = lesson.displayEndTime ?: continue
|
val endTime = lesson.displayEndTime ?: continue
|
||||||
|
|
||||||
@ -208,11 +219,17 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope {
|
|||||||
val lb = TimetableLessonBinding.bind(eventView)
|
val lb = TimetableLessonBinding.bind(eventView)
|
||||||
eventViews += eventView
|
eventViews += eventView
|
||||||
|
|
||||||
eventView.tag = lesson
|
eventView.tag = lesson to attendance
|
||||||
|
|
||||||
eventView.setOnClickListener {
|
eventView.setOnClickListener {
|
||||||
if (isAdded && it.tag is LessonFull)
|
if (isAdded && it.tag is Pair<*, *>) {
|
||||||
LessonDetailsDialog(activity, it.tag as LessonFull)
|
val (lessonObj, attendanceObj) = it.tag as Pair<*, *>
|
||||||
|
LessonDetailsDialog(
|
||||||
|
activity = activity,
|
||||||
|
lesson = lessonObj as LessonFull,
|
||||||
|
attendance = attendanceObj as AttendanceFull?
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val eventList = events.filter { it.time != null && it.time == lesson.displayStartTime }.take(3)
|
val eventList = events.filter { it.time != null && it.time == lesson.displayStartTime }.take(3)
|
||||||
@ -276,6 +293,18 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope {
|
|||||||
lb.detailsFirst.text = listOfNotEmpty(timeRange, classroomInfo).concat(bullet)
|
lb.detailsFirst.text = listOfNotEmpty(timeRange, classroomInfo).concat(bullet)
|
||||||
lb.detailsSecond.text = listOfNotEmpty(teacherInfo, teamInfo).concat(bullet)
|
lb.detailsSecond.text = listOfNotEmpty(teacherInfo, teamInfo).concat(bullet)
|
||||||
|
|
||||||
|
lb.attendanceIcon.isVisible = attendance?.let {
|
||||||
|
val icon = attendanceManager.getAttendanceIcon(it) ?: return@let false
|
||||||
|
val color = attendanceManager.getAttendanceColor(it)
|
||||||
|
lb.attendanceIcon.setImageDrawable(
|
||||||
|
IconicsDrawable(activity, icon).apply {
|
||||||
|
colorInt = color
|
||||||
|
sizeDp = 24
|
||||||
|
}
|
||||||
|
)
|
||||||
|
true
|
||||||
|
} ?: false
|
||||||
|
|
||||||
lb.unread = lesson.type != Lesson.TYPE_NORMAL && lesson.showAsUnseen
|
lb.unread = lesson.type != Lesson.TYPE_NORMAL && lesson.showAsUnseen
|
||||||
if (!lesson.seen) {
|
if (!lesson.seen) {
|
||||||
manager.markAsSeen(lesson)
|
manager.markAsSeen(lesson)
|
||||||
@ -283,6 +312,12 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope {
|
|||||||
|
|
||||||
//lb.subjectName.typeface = Typeface.create("sans-serif-light", Typeface.BOLD)
|
//lb.subjectName.typeface = Typeface.create("sans-serif-light", Typeface.BOLD)
|
||||||
lb.annotationVisible = manager.getAnnotation(activity, lesson, lb.annotation)
|
lb.annotationVisible = manager.getAnnotation(activity, lesson, lb.annotation)
|
||||||
|
val lessonNumberMargin =
|
||||||
|
if (lb.annotationVisible) (-8).dp
|
||||||
|
else 0
|
||||||
|
lb.lessonNumberText.updateLayoutParams<LinearLayout.LayoutParams> {
|
||||||
|
updateMargins(top = lessonNumberMargin, bottom = lessonNumberMargin)
|
||||||
|
}
|
||||||
|
|
||||||
// The day view needs the event time ranges in the start minute/end minute format,
|
// The day view needs the event time ranges in the start minute/end minute format,
|
||||||
// so calculate those here
|
// so calculate those here
|
||||||
|
@ -4,6 +4,9 @@
|
|||||||
|
|
||||||
package pl.szczodrzynski.edziennik.utils.managers
|
package pl.szczodrzynski.edziennik.utils.managers
|
||||||
|
|
||||||
|
import com.mikepenz.iconics.typeface.IIcon
|
||||||
|
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||||
|
import eu.szkolny.font.SzkolnyFont
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
@ -63,6 +66,17 @@ class AttendanceManager(val app: App) : CoroutineScope {
|
|||||||
else getAttendanceColor(attendance.baseType)
|
else getAttendanceColor(attendance.baseType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getAttendanceIcon(attendance: Attendance): IIcon? = when (attendance.baseType) {
|
||||||
|
Attendance.TYPE_PRESENT, Attendance.TYPE_PRESENT_CUSTOM -> CommunityMaterial.Icon.cmd_check
|
||||||
|
Attendance.TYPE_ABSENT -> CommunityMaterial.Icon.cmd_close
|
||||||
|
Attendance.TYPE_ABSENT_EXCUSED -> CommunityMaterial.Icon3.cmd_progress_close
|
||||||
|
Attendance.TYPE_RELEASED -> CommunityMaterial.Icon.cmd_account_arrow_right_outline
|
||||||
|
Attendance.TYPE_BELATED -> CommunityMaterial.Icon.cmd_clock_alert_outline
|
||||||
|
Attendance.TYPE_BELATED_EXCUSED -> CommunityMaterial.Icon.cmd_clock_check_outline
|
||||||
|
Attendance.TYPE_DAY_FREE -> SzkolnyFont.Icon.szf_umbrella_beach_outline
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
/* _ _ _____ _____ _ __ _
|
/* _ _ _____ _____ _ __ _
|
||||||
| | | |_ _| / ____| (_)/ _(_)
|
| | | |_ _| / ____| (_)/ _(_)
|
||||||
| | | | | | | (___ _ __ ___ ___ _| |_ _ ___
|
| | | | | | | (___ _ __ ___ ___ _| |_ _ ___
|
||||||
|
@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2021-9-18.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.utils.managers
|
||||||
|
|
||||||
|
import pl.szczodrzynski.edziennik.App
|
||||||
|
import pl.szczodrzynski.edziennik.BuildConfig
|
||||||
|
import pl.szczodrzynski.edziennik.currentTimeUnix
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.*
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.szkolny.response.RegisterAvailabilityStatus
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||||
|
import pl.szczodrzynski.edziennik.toApiError
|
||||||
|
|
||||||
|
class AvailabilityManager(val app: App) {
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "AvailabilityManager"
|
||||||
|
}
|
||||||
|
|
||||||
|
private val api = SzkolnyApi(app)
|
||||||
|
|
||||||
|
data class Error(
|
||||||
|
val type: Type,
|
||||||
|
val status: RegisterAvailabilityStatus?,
|
||||||
|
val apiError: ApiError?
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
fun notAvailable(status: RegisterAvailabilityStatus) =
|
||||||
|
Error(Type.NOT_AVAILABLE, status, null)
|
||||||
|
|
||||||
|
fun apiError(apiError: ApiError) =
|
||||||
|
Error(Type.API_ERROR, null, apiError)
|
||||||
|
|
||||||
|
fun noApiAccess() =
|
||||||
|
Error(Type.NO_API_ACCESS, null, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class Type {
|
||||||
|
NOT_AVAILABLE,
|
||||||
|
API_ERROR,
|
||||||
|
NO_API_ACCESS,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun check(profile: Profile, cacheOnly: Boolean = false): Error? {
|
||||||
|
return check(profile.registerName, cacheOnly)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun check(loginType: Int, cacheOnly: Boolean = false): Error? {
|
||||||
|
val registerName = when (loginType) {
|
||||||
|
LOGIN_TYPE_LIBRUS -> "librus"
|
||||||
|
LOGIN_TYPE_VULCAN -> "vulcan"
|
||||||
|
LOGIN_TYPE_IDZIENNIK -> "idziennik"
|
||||||
|
LOGIN_TYPE_MOBIDZIENNIK -> "mobidziennik"
|
||||||
|
LOGIN_TYPE_PODLASIE -> "podlasie"
|
||||||
|
LOGIN_TYPE_EDUDZIENNIK -> "edudziennik"
|
||||||
|
else -> "unknown"
|
||||||
|
}
|
||||||
|
return check(registerName, cacheOnly)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun check(registerName: String, cacheOnly: Boolean = false): Error? {
|
||||||
|
if (!app.config.apiAvailabilityCheck)
|
||||||
|
return null
|
||||||
|
val status = app.config.sync.registerAvailability[registerName]
|
||||||
|
if (status != null && status.nextCheckAt > currentTimeUnix()) {
|
||||||
|
return reportStatus(status)
|
||||||
|
}
|
||||||
|
if (cacheOnly) {
|
||||||
|
return reportStatus(status)
|
||||||
|
}
|
||||||
|
|
||||||
|
return try {
|
||||||
|
val availability = api.getRegisterAvailability()
|
||||||
|
app.config.sync.registerAvailability = availability
|
||||||
|
reportStatus(availability[registerName])
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
reportApiError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun reportStatus(status: RegisterAvailabilityStatus?): Error? {
|
||||||
|
if (status == null)
|
||||||
|
return null
|
||||||
|
if (!status.available || status.minVersionCode > BuildConfig.VERSION_CODE)
|
||||||
|
return Error.notAvailable(status)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun reportApiError(throwable: Throwable): Error {
|
||||||
|
val apiError = throwable.toApiError(TAG)
|
||||||
|
if (apiError.errorCode == ERROR_API_INVALID_SIGNATURE) {
|
||||||
|
app.config.sync.registerAvailability = mapOf()
|
||||||
|
return Error.noApiAccess()
|
||||||
|
}
|
||||||
|
return Error.apiError(apiError)
|
||||||
|
}
|
||||||
|
}
|
@ -134,7 +134,8 @@
|
|||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:baselineAligned="false"
|
android:baselineAligned="false"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/shiftedText"
|
android:id="@+id/shiftedText"
|
||||||
@ -290,6 +291,60 @@
|
|||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/attendanceDivider"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:background="@drawable/divider"/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/attendanceLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="8dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<pl.szczodrzynski.edziennik.ui.modules.attendance.AttendanceView
|
||||||
|
android:id="@+id/attendanceView"
|
||||||
|
android:layout_width="36dp"
|
||||||
|
android:layout_height="36dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:layout_marginRight="8dp"
|
||||||
|
tools:background="@drawable/bg_rounded_8dp"
|
||||||
|
tools:backgroundTint="#f44336"
|
||||||
|
tools:gravity="center"
|
||||||
|
tools:text="nb"
|
||||||
|
tools:textSize="22sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/attendanceType"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="center"
|
||||||
|
android:maxLines="2"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:textSize="16sp"
|
||||||
|
tools:text="nieobecność usprawiedliweniowsza1234324" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/attendanceIcon"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_marginHorizontal="8dp"
|
||||||
|
tools:srcCompat="@sample/check" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/attendanceDetails"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/dialog_lesson_attendance_details" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="1dp"
|
android:layout_height="1dp"
|
||||||
|
@ -1,15 +1,17 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?><!--
|
||||||
<!--
|
|
||||||
~ Copyright (c) Kuba Szczodrzyński 2020-4-3.
|
~ Copyright (c) Kuba Szczodrzyński 2020-4-3.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
|
<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"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
tools:ignore="HardcodedText">
|
tools:ignore="HardcodedText">
|
||||||
|
|
||||||
<data>
|
<data>
|
||||||
<variable name="app" type="pl.szczodrzynski.edziennik.App"/>
|
|
||||||
|
<variable
|
||||||
|
name="app"
|
||||||
|
type="pl.szczodrzynski.edziennik.App" />
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
<ScrollView
|
<ScrollView
|
||||||
@ -39,7 +41,7 @@
|
|||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" />-->
|
app:layout_behavior="@string/appbar_scrolling_view_behavior" />-->
|
||||||
|
|
||||||
<Switch
|
<com.google.android.material.checkbox.MaterialCheckBox
|
||||||
android:id="@+id/chucker"
|
android:id="@+id/chucker"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
@ -87,7 +89,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:fontFamily="monospace"
|
android:fontFamily="monospace"
|
||||||
tools:text="Cookies:\n\nsynergia.librus.pl\n DZIENNIKSID=L01~1234567890abcdef"/>
|
tools:text="Cookies:\n\nsynergia.librus.pl\n DZIENNIKSID=L01~1234567890abcdef" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/unarchive"
|
android:id="@+id/unarchive"
|
||||||
@ -99,9 +101,9 @@
|
|||||||
|
|
||||||
<pl.szczodrzynski.edziennik.utils.TextInputDropDown
|
<pl.szczodrzynski.edziennik.utils.TextInputDropDown
|
||||||
android:id="@+id/profile"
|
android:id="@+id/profile"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content" />
|
||||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox" />
|
|
||||||
|
|
||||||
<com.google.android.material.checkbox.MaterialCheckBox
|
<com.google.android.material.checkbox.MaterialCheckBox
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@ -109,13 +111,36 @@
|
|||||||
android:checked="@={app.config.archiverEnabled}"
|
android:checked="@={app.config.archiverEnabled}"
|
||||||
android:text="Archiver enabled" />
|
android:text="Archiver enabled" />
|
||||||
|
|
||||||
|
<com.google.android.material.checkbox.MaterialCheckBox
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:checked="@={app.config.apiAvailabilityCheck}"
|
||||||
|
android:text="Availability check enabled" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/resetCert"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Reset API signature"
|
||||||
|
android:textAllCaps="false" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/disableDebug"
|
android:id="@+id/disableDebug"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
android:text="Disable Dev Mode"
|
android:text="Disable Dev Mode"
|
||||||
android:textAllCaps="false"
|
android:textAllCaps="false"
|
||||||
app:backgroundTint="@color/windowBackgroundRed" />
|
app:backgroundTint="@color/windowBackgroundRed" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/rebuildConfig"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:text="Rebuild App.config"
|
||||||
|
android:textAllCaps="false" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</layout>
|
</layout>
|
||||||
|
@ -48,16 +48,16 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="top"
|
android:layout_gravity="top"
|
||||||
android:paddingHorizontal="8dp"
|
android:baselineAligned="false"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:baselineAligned="false">
|
android:paddingHorizontal="8dp"
|
||||||
|
android:paddingVertical="4dp">
|
||||||
<!--tools:background="@drawable/timetable_subject_color_rounded"-->
|
<!--tools:background="@drawable/timetable_subject_color_rounded"-->
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/subjectName"
|
android:id="@+id/subjectName"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginVertical="4dp"
|
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:fontFamily="sans-serif-light"
|
android:fontFamily="sans-serif-light"
|
||||||
@ -75,8 +75,8 @@
|
|||||||
android:layout_height="12dp"
|
android:layout_height="12dp"
|
||||||
android:layout_gravity="center_vertical"
|
android:layout_gravity="center_vertical"
|
||||||
android:layout_marginHorizontal="8dp"
|
android:layout_marginHorizontal="8dp"
|
||||||
android:visibility="@{unread ? View.VISIBLE : View.GONE}"
|
android:background="@drawable/unread_red_circle"
|
||||||
android:background="@drawable/unread_red_circle" />
|
android:visibility="@{unread ? View.VISIBLE : View.GONE}" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/attendanceIcon"
|
android:id="@+id/attendanceIcon"
|
||||||
@ -87,29 +87,18 @@
|
|||||||
tools:srcCompat="@sample/check"
|
tools:srcCompat="@sample/check"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/imageView4"
|
|
||||||
android:layout_width="24dp"
|
|
||||||
android:layout_height="24dp"
|
|
||||||
android:layout_weight="0"
|
|
||||||
app:srcCompat="@drawable/bg_circle"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/textView6"
|
android:id="@+id/lessonNumberText"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_vertical"
|
android:layout_gravity="center_vertical"
|
||||||
android:fontFamily="sans-serif-condensed-light"
|
android:fontFamily="sans-serif-condensed-light"
|
||||||
android:includeFontPadding="false"
|
android:includeFontPadding="false"
|
||||||
android:layout_marginBottom="-4dp"
|
|
||||||
android:paddingHorizontal="4dp"
|
android:paddingHorizontal="4dp"
|
||||||
android:text="@{Integer.toString(lessonNumber)}"
|
android:text="@{Integer.toString(lessonNumber)}"
|
||||||
android:textSize="28sp"
|
android:textSize="28sp"
|
||||||
android:visibility="@{lessonNumber != null ? View.VISIBLE : View.GONE}"
|
android:visibility="@{lessonNumber != null ? View.VISIBLE : View.GONE}"
|
||||||
tools:text="3"/>
|
tools:text="3" />
|
||||||
<!--android:layout_marginTop="@{annotationVisible ? `-4dp` : `4dp`}"
|
|
||||||
android:layout_marginBottom="@{annotationVisible ? `-4dp` : `0dp`}"-->
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
@ -149,7 +138,8 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:gravity="end|bottom"
|
android:gravity="end|bottom"
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal"
|
||||||
|
android:paddingBottom="2dp">
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:id="@+id/event3"
|
android:id="@+id/event3"
|
||||||
|
@ -856,7 +856,7 @@
|
|||||||
<string name="settings_about_licenses_text">Open-Source-Lizenzen</string>
|
<string name="settings_about_licenses_text">Open-Source-Lizenzen</string>
|
||||||
<string name="settings_about_privacy_policy_text">Datenschutzrichtlinie</string>
|
<string name="settings_about_privacy_policy_text">Datenschutzrichtlinie</string>
|
||||||
<string name="settings_card_register_title">E-Klassenbuch</string>
|
<string name="settings_card_register_title">E-Klassenbuch</string>
|
||||||
<string name="settings_about_title_subtext">© Kuba Szczodrzyński && Kacper Ziubryniewicz\nSeptember 2018 - Juni 2021</string>
|
<string name="settings_about_title_subtext">© Kuba Szczodrzyński && Kacper Ziubryniewicz\nSeptember 2018 - 2021</string>
|
||||||
<string name="settings_about_update_subtext">Klicken Sie hier, um nach Aktualisierungen zu suchen</string>
|
<string name="settings_about_update_subtext">Klicken Sie hier, um nach Aktualisierungen zu suchen</string>
|
||||||
<string name="settings_about_update_text">Aktualisierung</string>
|
<string name="settings_about_update_text">Aktualisierung</string>
|
||||||
<string name="settings_about_version_text">Version</string>
|
<string name="settings_about_version_text">Version</string>
|
||||||
|
@ -858,7 +858,7 @@
|
|||||||
<string name="settings_about_licenses_text">Open-source licenses</string>
|
<string name="settings_about_licenses_text">Open-source licenses</string>
|
||||||
<string name="settings_about_privacy_policy_text">Privacy policy</string>
|
<string name="settings_about_privacy_policy_text">Privacy policy</string>
|
||||||
<string name="settings_card_register_title">E-register</string>
|
<string name="settings_card_register_title">E-register</string>
|
||||||
<string name="settings_about_title_subtext">© Kuba Szczodrzyński && Kacper Ziubryniewicz\nSeptember 2018 - June 2021</string>
|
<string name="settings_about_title_subtext">© Kuba Szczodrzyński && Kacper Ziubryniewicz\nSeptember 2018 - 2021</string>
|
||||||
<string name="settings_about_update_subtext">Click to check for updates</string>
|
<string name="settings_about_update_subtext">Click to check for updates</string>
|
||||||
<string name="settings_about_update_text">Update</string>
|
<string name="settings_about_update_text">Update</string>
|
||||||
<string name="settings_about_version_text">Version</string>
|
<string name="settings_about_version_text">Version</string>
|
||||||
|
@ -921,7 +921,7 @@
|
|||||||
<string name="settings_about_licenses_text">Licencje open-source</string>
|
<string name="settings_about_licenses_text">Licencje open-source</string>
|
||||||
<string name="settings_about_privacy_policy_text">Polityka prywatności</string>
|
<string name="settings_about_privacy_policy_text">Polityka prywatności</string>
|
||||||
<string name="settings_card_register_title">E-dziennik</string>
|
<string name="settings_card_register_title">E-dziennik</string>
|
||||||
<string name="settings_about_title_subtext">© Kuba Szczodrzyński && Kacper Ziubryniewicz\nwrzesień 2018 - czerwiec 2021</string>
|
<string name="settings_about_title_subtext">© Kuba Szczodrzyński && Kacper Ziubryniewicz\nwrzesień 2018 - 2021</string>
|
||||||
<string name="settings_about_update_subtext">Kliknij, aby sprawdzić aktualizacje</string>
|
<string name="settings_about_update_subtext">Kliknij, aby sprawdzić aktualizacje</string>
|
||||||
<string name="settings_about_update_text">Aktualizacja</string>
|
<string name="settings_about_update_text">Aktualizacja</string>
|
||||||
<string name="settings_about_version_text">Wersja</string>
|
<string name="settings_about_version_text">Wersja</string>
|
||||||
@ -1463,4 +1463,5 @@
|
|||||||
<string name="notification_attendance_long_format">Rodzaj: %s\nTermin: %s, %s\nNr lekcji: %s\nPrzedmiot: %s\nNauczyciel: %s\nTemat lekcji: %s</string>
|
<string name="notification_attendance_long_format">Rodzaj: %s\nTermin: %s, %s\nNr lekcji: %s\nPrzedmiot: %s\nNauczyciel: %s\nTemat lekcji: %s</string>
|
||||||
<string name="contributors_subtext_format" translatable="false">\@%s - %s</string>
|
<string name="contributors_subtext_format" translatable="false">\@%s - %s</string>
|
||||||
<string name="contributors_headline">Najłatwiejszy sposób na korzystanie z e-dziennika.</string>
|
<string name="contributors_headline">Najłatwiejszy sposób na korzystanie z e-dziennika.</string>
|
||||||
|
<string name="dialog_lesson_attendance_details">Szczegóły</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -5,8 +5,8 @@ buildscript {
|
|||||||
kotlin_version = '1.5.20'
|
kotlin_version = '1.5.20'
|
||||||
|
|
||||||
release = [
|
release = [
|
||||||
versionName: "4.9",
|
versionName: "4.10",
|
||||||
versionCode: 4090099
|
versionCode: 4100099
|
||||||
]
|
]
|
||||||
|
|
||||||
setup = [
|
setup = [
|
||||||
|
Loading…
x
Reference in New Issue
Block a user