mirror of
https://github.com/wulkanowy/wulkanowy.git
synced 2025-02-23 15:04:47 +01:00
Merge branch 'release/2.0.0'
This commit is contained in:
commit
18dbbba328
1
.gitignore
vendored
1
.gitignore
vendored
@ -119,3 +119,4 @@ Thumbs.db
|
|||||||
app/src/release/agconnect-services.json
|
app/src/release/agconnect-services.json
|
||||||
app/src/release/agconnect-credentials.json
|
app/src/release/agconnect-credentials.json
|
||||||
.idea/deploymentTargetDropDown.xml
|
.idea/deploymentTargetDropDown.xml
|
||||||
|
.idea/kotlinc.xml
|
||||||
|
@ -23,8 +23,8 @@ android {
|
|||||||
testApplicationId "io.github.tests.wulkanowy"
|
testApplicationId "io.github.tests.wulkanowy"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 33
|
targetSdkVersion 33
|
||||||
versionCode 121
|
versionCode 122
|
||||||
versionName "1.9.2"
|
versionName "2.0.0"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
|
||||||
resValue "string", "app_name", "Wulkanowy"
|
resValue "string", "app_name", "Wulkanowy"
|
||||||
@ -177,36 +177,36 @@ huaweiPublish {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
work_manager = "2.7.1"
|
work_manager = "2.8.1"
|
||||||
android_hilt = "1.0.0"
|
android_hilt = "1.0.0"
|
||||||
room = "2.4.3"
|
room = "2.5.1"
|
||||||
chucker = "3.5.2"
|
chucker = "3.5.2"
|
||||||
mockk = "1.13.3"
|
mockk = "1.13.5"
|
||||||
coroutines = "1.6.4"
|
coroutines = "1.6.4"
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation "io.github.wulkanowy:sdk:1.9.2"
|
implementation "io.github.wulkanowy:sdk:2.0.0"
|
||||||
|
|
||||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.8'
|
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.3'
|
||||||
|
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1"
|
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0"
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines"
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines"
|
||||||
|
|
||||||
implementation "androidx.core:core-ktx:1.9.0"
|
implementation "androidx.core:core-ktx:1.10.0"
|
||||||
implementation 'androidx.core:core-splashscreen:1.0.0'
|
implementation 'androidx.core:core-splashscreen:1.0.1'
|
||||||
implementation "androidx.activity:activity-ktx:1.6.1"
|
implementation "androidx.activity:activity-ktx:1.7.1"
|
||||||
implementation "androidx.appcompat:appcompat:1.5.1"
|
implementation "androidx.appcompat:appcompat:1.6.1"
|
||||||
implementation "androidx.fragment:fragment-ktx:1.5.5"
|
implementation "androidx.fragment:fragment-ktx:1.5.7"
|
||||||
implementation "androidx.annotation:annotation:1.5.0"
|
implementation "androidx.annotation:annotation:1.6.0"
|
||||||
|
|
||||||
implementation "androidx.preference:preference-ktx:1.2.0"
|
implementation "androidx.preference:preference-ktx:1.2.0"
|
||||||
implementation "androidx.recyclerview:recyclerview:1.2.1"
|
implementation "androidx.recyclerview:recyclerview:1.3.0"
|
||||||
implementation "androidx.viewpager2:viewpager2:1.1.0-beta01"
|
implementation "androidx.viewpager2:viewpager2:1.1.0-beta01"
|
||||||
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
|
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
|
||||||
implementation "androidx.constraintlayout:constraintlayout:2.1.4"
|
implementation "androidx.constraintlayout:constraintlayout:2.1.4"
|
||||||
implementation "androidx.coordinatorlayout:coordinatorlayout:1.2.0"
|
implementation "androidx.coordinatorlayout:coordinatorlayout:1.2.0"
|
||||||
implementation "com.google.android.material:material:1.7.0"
|
implementation "com.google.android.material:material:1.8.0"
|
||||||
implementation "com.github.wulkanowy:material-chips-input:2.3.1"
|
implementation "com.github.wulkanowy:material-chips-input:2.3.1"
|
||||||
implementation "com.github.PhilJay:MPAndroidChart:v3.1.0"
|
implementation "com.github.PhilJay:MPAndroidChart:v3.1.0"
|
||||||
implementation 'com.github.lopspower:CircularImageView:4.3.0'
|
implementation 'com.github.lopspower:CircularImageView:4.3.0'
|
||||||
@ -214,7 +214,7 @@ dependencies {
|
|||||||
implementation "androidx.work:work-runtime-ktx:$work_manager"
|
implementation "androidx.work:work-runtime-ktx:$work_manager"
|
||||||
playImplementation "androidx.work:work-gcm:$work_manager"
|
playImplementation "androidx.work:work-gcm:$work_manager"
|
||||||
|
|
||||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.5.1"
|
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.6.1"
|
||||||
|
|
||||||
implementation "androidx.room:room-runtime:$room"
|
implementation "androidx.room:room-runtime:$room"
|
||||||
implementation "androidx.room:room-ktx:$room"
|
implementation "androidx.room:room-ktx:$room"
|
||||||
@ -229,30 +229,30 @@ dependencies {
|
|||||||
implementation "com.github.YarikSOffice:lingver:1.3.0"
|
implementation "com.github.YarikSOffice:lingver:1.3.0"
|
||||||
|
|
||||||
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
|
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
|
||||||
implementation "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:0.8.0"
|
implementation "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0"
|
||||||
implementation "com.squareup.okhttp3:logging-interceptor:4.10.0"
|
implementation "com.squareup.okhttp3:logging-interceptor:4.11.0"
|
||||||
|
|
||||||
implementation "com.jakewharton.timber:timber:5.0.1"
|
implementation "com.jakewharton.timber:timber:5.0.1"
|
||||||
implementation "at.favre.lib:slf4j-timber:1.0.1"
|
implementation "at.favre.lib:slf4j-timber:1.0.1"
|
||||||
implementation 'com.github.bastienpaulfr:Treessence:1.0.5'
|
implementation 'com.github.bastienpaulfr:Treessence:1.0.5'
|
||||||
implementation "com.mikepenz:aboutlibraries-core:$about_libraries"
|
implementation "com.mikepenz:aboutlibraries-core:$about_libraries"
|
||||||
implementation "io.coil-kt:coil:2.2.2"
|
implementation "io.coil-kt:coil:2.3.0"
|
||||||
implementation "io.github.wulkanowy:AppKillerManager:3.0.1"
|
implementation "io.github.wulkanowy:AppKillerManager:3.0.1"
|
||||||
implementation 'me.xdrop:fuzzywuzzy:1.4.0'
|
implementation 'me.xdrop:fuzzywuzzy:1.4.0'
|
||||||
implementation 'com.fredporciuncula:flow-preferences:1.8.0'
|
implementation 'com.fredporciuncula:flow-preferences:1.9.1'
|
||||||
implementation 'org.apache.commons:commons-text:1.10.0'
|
implementation 'org.apache.commons:commons-text:1.10.0'
|
||||||
|
|
||||||
playImplementation platform('com.google.firebase:firebase-bom:31.1.1')
|
playImplementation platform('com.google.firebase:firebase-bom:31.5.0')
|
||||||
playImplementation 'com.google.firebase:firebase-analytics-ktx'
|
playImplementation 'com.google.firebase:firebase-analytics-ktx'
|
||||||
playImplementation 'com.google.firebase:firebase-messaging:'
|
playImplementation 'com.google.firebase:firebase-messaging:'
|
||||||
playImplementation 'com.google.firebase:firebase-crashlytics:'
|
playImplementation 'com.google.firebase:firebase-crashlytics:'
|
||||||
playImplementation 'com.google.firebase:firebase-config-ktx'
|
playImplementation 'com.google.firebase:firebase-config-ktx'
|
||||||
playImplementation 'com.google.android.play:core:1.10.3'
|
playImplementation 'com.google.android.play:core:1.10.3'
|
||||||
playImplementation 'com.google.android.play:core-ktx:1.8.1'
|
playImplementation 'com.google.android.play:core-ktx:1.8.1'
|
||||||
playImplementation 'com.google.android.gms:play-services-ads:21.4.0'
|
playImplementation 'com.google.android.gms:play-services-ads:22.0.0'
|
||||||
|
|
||||||
hmsImplementation 'com.huawei.hms:hianalytics:6.9.0.301'
|
hmsImplementation 'com.huawei.hms:hianalytics:6.9.1.200'
|
||||||
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.7.3.302'
|
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.9.0.300'
|
||||||
|
|
||||||
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker"
|
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker"
|
||||||
|
|
||||||
@ -265,17 +265,17 @@ dependencies {
|
|||||||
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines"
|
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines"
|
||||||
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
||||||
|
|
||||||
testImplementation 'org.robolectric:robolectric:4.9.2'
|
testImplementation 'org.robolectric:robolectric:4.10'
|
||||||
testImplementation "androidx.test:runner:1.5.1"
|
testImplementation "androidx.test:runner:1.5.2"
|
||||||
testImplementation "androidx.test.ext:junit:1.1.4"
|
testImplementation "androidx.test.ext:junit:1.1.5"
|
||||||
testImplementation "androidx.test:core:1.5.0"
|
testImplementation "androidx.test:core:1.5.0"
|
||||||
testImplementation "androidx.room:room-testing:$room"
|
testImplementation "androidx.room:room-testing:$room"
|
||||||
testImplementation "com.google.dagger:hilt-android-testing:$hilt_version"
|
testImplementation "com.google.dagger:hilt-android-testing:$hilt_version"
|
||||||
kaptTest "com.google.dagger:hilt-android-compiler:$hilt_version"
|
kaptTest "com.google.dagger:hilt-android-compiler:$hilt_version"
|
||||||
|
|
||||||
androidTestImplementation "androidx.test:core:1.5.0"
|
androidTestImplementation "androidx.test:core:1.5.0"
|
||||||
androidTestImplementation "androidx.test:runner:1.5.1"
|
androidTestImplementation "androidx.test:runner:1.5.2"
|
||||||
androidTestImplementation "androidx.test.ext:junit:1.1.4"
|
androidTestImplementation "androidx.test.ext:junit:1.1.5"
|
||||||
androidTestImplementation "io.mockk:mockk-android:$mockk"
|
androidTestImplementation "io.mockk:mockk-android:$mockk"
|
||||||
androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<background android:drawable="@color/colorPrimary" />
|
<background android:drawable="@color/colorIcon" />
|
||||||
<foreground android:drawable="@drawable/ic_launcher_foreground_dev" />
|
<foreground android:drawable="@drawable/ic_launcher_foreground_dev" />
|
||||||
<monochrome android:drawable="@drawable/ic_launcher_foreground_dev_mono" />
|
<monochrome android:drawable="@drawable/ic_launcher_foreground_dev_mono" />
|
||||||
</adaptive-icon>
|
</adaptive-icon>
|
||||||
|
@ -72,7 +72,7 @@
|
|||||||
android:name=".ui.modules.message.send.SendMessageActivity"
|
android:name=".ui.modules.message.send.SendMessageActivity"
|
||||||
android:configChanges="orientation|screenSize"
|
android:configChanges="orientation|screenSize"
|
||||||
android:label="@string/send_message_title"
|
android:label="@string/send_message_title"
|
||||||
android:theme="@style/WulkanowyTheme.MessageSend"
|
android:theme="@style/WulkanowyTheme.NoActionBar"
|
||||||
android:windowSoftInputMode="adjustResize" />
|
android:windowSoftInputMode="adjustResize" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.modules.timetablewidget.TimetableWidgetConfigureActivity"
|
android:name=".ui.modules.timetablewidget.TimetableWidgetConfigureActivity"
|
||||||
|
@ -20,7 +20,6 @@ import io.github.wulkanowy.data.repositories.PreferencesRepository
|
|||||||
import io.github.wulkanowy.sdk.Sdk
|
import io.github.wulkanowy.sdk.Sdk
|
||||||
import io.github.wulkanowy.utils.AppInfo
|
import io.github.wulkanowy.utils.AppInfo
|
||||||
import io.github.wulkanowy.utils.RemoteConfigHelper
|
import io.github.wulkanowy.utils.RemoteConfigHelper
|
||||||
import kotlinx.serialization.ExperimentalSerializationApi
|
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import okhttp3.MediaType.Companion.toMediaType
|
import okhttp3.MediaType.Companion.toMediaType
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
@ -81,7 +80,6 @@ internal class DataModule {
|
|||||||
.readTimeout(30, TimeUnit.SECONDS)
|
.readTimeout(30, TimeUnit.SECONDS)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
@OptIn(ExperimentalSerializationApi::class)
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
fun provideRetrofit(
|
fun provideRetrofit(
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package io.github.wulkanowy.data.db.dao
|
package io.github.wulkanowy.data.db.dao
|
||||||
|
|
||||||
import androidx.room.*
|
import androidx.room.*
|
||||||
import androidx.room.OnConflictStrategy.ABORT
|
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.github.wulkanowy.data.db.entities.StudentNickAndAvatar
|
import io.github.wulkanowy.data.db.entities.StudentNickAndAvatar
|
||||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||||
@ -11,7 +10,7 @@ import javax.inject.Singleton
|
|||||||
@Dao
|
@Dao
|
||||||
abstract class StudentDao {
|
abstract class StudentDao {
|
||||||
|
|
||||||
@Insert(onConflict = ABORT)
|
@Insert(onConflict = OnConflictStrategy.ABORT)
|
||||||
abstract suspend fun insertAll(student: List<Student>): List<Long>
|
abstract suspend fun insertAll(student: List<Student>): List<Long>
|
||||||
|
|
||||||
@Delete
|
@Delete
|
||||||
|
@ -22,6 +22,7 @@ data class Exam(
|
|||||||
|
|
||||||
val subject: String,
|
val subject: String,
|
||||||
|
|
||||||
|
@Deprecated("not available anymore")
|
||||||
val group: String,
|
val group: String,
|
||||||
|
|
||||||
val type: String,
|
val type: String,
|
||||||
|
@ -10,9 +10,9 @@ fun List<SdkConference>.mapToEntities(semester: Semester) = map {
|
|||||||
diaryId = semester.diaryId,
|
diaryId = semester.diaryId,
|
||||||
agenda = it.agenda,
|
agenda = it.agenda,
|
||||||
conferenceId = it.id,
|
conferenceId = it.id,
|
||||||
date = it.dateZoned.toInstant(),
|
date = it.date.toInstant(),
|
||||||
presentOnConference = it.presentOnConference,
|
presentOnConference = it.presentOnConference,
|
||||||
subject = it.subject,
|
subject = it.topic,
|
||||||
title = it.title
|
title = it.place,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ fun List<SdkExam>.mapToEntities(semester: Semester) = map {
|
|||||||
date = it.date,
|
date = it.date,
|
||||||
entryDate = it.entryDate,
|
entryDate = it.entryDate,
|
||||||
subject = it.subject,
|
subject = it.subject,
|
||||||
group = it.group,
|
group = "",
|
||||||
type = it.type,
|
type = it.type,
|
||||||
description = it.description,
|
description = it.description,
|
||||||
teacher = it.teacher,
|
teacher = it.teacher,
|
||||||
|
@ -26,7 +26,7 @@ fun List<SdkMessage>.mapToEntities(
|
|||||||
messageId = it.id,
|
messageId = it.id,
|
||||||
correspondents = it.correspondents,
|
correspondents = it.correspondents,
|
||||||
subject = it.subject.trim(),
|
subject = it.subject.trim(),
|
||||||
date = it.dateZoned.toInstant(),
|
date = it.date.toInstant(),
|
||||||
folderId = it.folderId,
|
folderId = it.folderId,
|
||||||
unread = it.unread,
|
unread = it.unread,
|
||||||
unreadBy = it.unreadBy,
|
unreadBy = it.unreadBy,
|
||||||
|
@ -9,7 +9,7 @@ import io.github.wulkanowy.sdk.pojo.Token as SdkToken
|
|||||||
fun List<SdkDevice>.mapToEntities(student: Student) = map {
|
fun List<SdkDevice>.mapToEntities(student: Student) = map {
|
||||||
MobileDevice(
|
MobileDevice(
|
||||||
userLoginId = student.userLoginId,
|
userLoginId = student.userLoginId,
|
||||||
date = it.createDateZoned.toInstant(),
|
date = it.createDate.toInstant(),
|
||||||
deviceId = it.id,
|
deviceId = it.id,
|
||||||
name = it.name
|
name = it.name
|
||||||
)
|
)
|
||||||
|
@ -3,22 +3,24 @@ package io.github.wulkanowy.data.mappers
|
|||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||||
import io.github.wulkanowy.data.pojos.*
|
import io.github.wulkanowy.data.pojos.*
|
||||||
import io.github.wulkanowy.sdk.Sdk
|
|
||||||
import io.github.wulkanowy.sdk.mapper.mapSemesters
|
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import io.github.wulkanowy.sdk.scrapper.register.RegisterStudent as SdkRegisterStudent
|
import io.github.wulkanowy.sdk.pojo.RegisterStudent as SdkRegisterStudent
|
||||||
import io.github.wulkanowy.sdk.scrapper.register.RegisterUser as SdkRegisterUser
|
import io.github.wulkanowy.sdk.pojo.RegisterUser as SdkRegisterUser
|
||||||
|
|
||||||
fun SdkRegisterUser.mapToPojo(password: String) = RegisterUser(
|
fun SdkRegisterUser.mapToPojo(password: String?) = RegisterUser(
|
||||||
email = email,
|
email = email,
|
||||||
login = login,
|
login = login,
|
||||||
password = password,
|
password = password,
|
||||||
baseUrl = baseUrl,
|
scrapperBaseUrl = scrapperBaseUrl,
|
||||||
|
loginMode = loginMode,
|
||||||
loginType = loginType,
|
loginType = loginType,
|
||||||
symbols = symbols.map { registerSymbol ->
|
symbols = symbols.map { registerSymbol ->
|
||||||
RegisterSymbol(
|
RegisterSymbol(
|
||||||
symbol = registerSymbol.symbol,
|
symbol = registerSymbol.symbol,
|
||||||
error = registerSymbol.error,
|
error = registerSymbol.error,
|
||||||
|
hebeBaseUrl = registerSymbol.hebeBaseUrl,
|
||||||
|
keyId = registerSymbol.keyId,
|
||||||
|
privatePem = registerSymbol.privatePem,
|
||||||
userName = registerSymbol.userName,
|
userName = registerSymbol.userName,
|
||||||
schools = registerSymbol.schools.map {
|
schools = registerSymbol.schools.map {
|
||||||
RegisterUnit(
|
RegisterUnit(
|
||||||
@ -42,14 +44,13 @@ fun SdkRegisterUser.mapToPojo(password: String) = RegisterUser(
|
|||||||
classId = registerSubject.classId,
|
classId = registerSubject.classId,
|
||||||
isParent = registerSubject.isParent,
|
isParent = registerSubject.isParent,
|
||||||
semesters = registerSubject.semesters
|
semesters = registerSubject.semesters
|
||||||
.mapSemesters()
|
|
||||||
.mapToEntities(registerSubject.studentId),
|
.mapToEntities(registerSubject.studentId),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
fun RegisterStudent.mapToStudentWithSemesters(
|
fun RegisterStudent.mapToStudentWithSemesters(
|
||||||
@ -68,17 +69,17 @@ fun RegisterStudent.mapToStudentWithSemesters(
|
|||||||
classId = classId,
|
classId = classId,
|
||||||
studentId = studentId,
|
studentId = studentId,
|
||||||
symbol = symbol.symbol,
|
symbol = symbol.symbol,
|
||||||
loginType = user.loginType.name,
|
loginType = user.loginType?.name.orEmpty(),
|
||||||
schoolName = unit.schoolName,
|
schoolName = unit.schoolName,
|
||||||
schoolShortName = unit.schoolShortName,
|
schoolShortName = unit.schoolShortName,
|
||||||
schoolSymbol = unit.schoolId,
|
schoolSymbol = unit.schoolId,
|
||||||
studentName = "$studentName $studentSurname",
|
studentName = "$studentName $studentSurname",
|
||||||
loginMode = Sdk.Mode.SCRAPPER.name,
|
loginMode = user.loginMode.name,
|
||||||
scrapperBaseUrl = user.baseUrl,
|
scrapperBaseUrl = user.scrapperBaseUrl.orEmpty(),
|
||||||
mobileBaseUrl = "",
|
mobileBaseUrl = symbol.hebeBaseUrl.orEmpty(),
|
||||||
certificateKey = "",
|
certificateKey = symbol.keyId.orEmpty(),
|
||||||
privateKey = "",
|
privateKey = symbol.privatePem.orEmpty(),
|
||||||
password = user.password,
|
password = user.password.orEmpty(),
|
||||||
isCurrent = false,
|
isCurrent = false,
|
||||||
registrationDate = Instant.now(),
|
registrationDate = Instant.now(),
|
||||||
).apply {
|
).apply {
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
package io.github.wulkanowy.data.mappers
|
|
||||||
|
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
|
||||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
|
||||||
import java.time.Instant
|
|
||||||
import io.github.wulkanowy.sdk.pojo.Student as SdkStudent
|
|
||||||
|
|
||||||
fun List<SdkStudent>.mapToEntities(password: String = "", colors: List<Long>) = map {
|
|
||||||
StudentWithSemesters(
|
|
||||||
student = Student(
|
|
||||||
email = it.email,
|
|
||||||
password = password,
|
|
||||||
isParent = it.isParent,
|
|
||||||
symbol = it.symbol,
|
|
||||||
studentId = it.studentId,
|
|
||||||
userLoginId = it.userLoginId,
|
|
||||||
userName = it.userName,
|
|
||||||
studentName = it.studentName + " " + it.studentSurname,
|
|
||||||
schoolSymbol = it.schoolSymbol,
|
|
||||||
schoolShortName = it.schoolShortName,
|
|
||||||
schoolName = it.schoolName,
|
|
||||||
className = it.className,
|
|
||||||
classId = it.classId,
|
|
||||||
scrapperBaseUrl = it.scrapperBaseUrl,
|
|
||||||
loginType = it.loginType.name,
|
|
||||||
isCurrent = false,
|
|
||||||
registrationDate = Instant.now(),
|
|
||||||
mobileBaseUrl = it.mobileBaseUrl,
|
|
||||||
privateKey = it.privateKey,
|
|
||||||
certificateKey = it.certificateKey,
|
|
||||||
loginMode = it.loginMode.name,
|
|
||||||
).apply {
|
|
||||||
avatarColor = colors.random()
|
|
||||||
},
|
|
||||||
semesters = it.semesters.mapToEntities(it.studentId)
|
|
||||||
)
|
|
||||||
}
|
|
@ -5,10 +5,10 @@ import io.github.wulkanowy.data.db.entities.Timetable
|
|||||||
import io.github.wulkanowy.data.db.entities.TimetableAdditional
|
import io.github.wulkanowy.data.db.entities.TimetableAdditional
|
||||||
import io.github.wulkanowy.data.db.entities.TimetableHeader
|
import io.github.wulkanowy.data.db.entities.TimetableHeader
|
||||||
import io.github.wulkanowy.data.pojos.TimetableFull
|
import io.github.wulkanowy.data.pojos.TimetableFull
|
||||||
import io.github.wulkanowy.sdk.pojo.TimetableFull as SdkTimetableFull
|
import io.github.wulkanowy.sdk.pojo.Timetable as SdkTimetableFull
|
||||||
import io.github.wulkanowy.sdk.pojo.TimetableDayHeader as SdkTimetableHeader
|
import io.github.wulkanowy.sdk.pojo.TimetableDayHeader as SdkTimetableHeader
|
||||||
import io.github.wulkanowy.sdk.pojo.Timetable as SdkTimetable
|
import io.github.wulkanowy.sdk.pojo.Lesson as SdkLesson
|
||||||
import io.github.wulkanowy.sdk.pojo.TimetableAdditional as SdkTimetableAdditional
|
import io.github.wulkanowy.sdk.pojo.LessonAdditional as SdkTimetableAdditional
|
||||||
|
|
||||||
fun SdkTimetableFull.mapToEntities(semester: Semester) = TimetableFull(
|
fun SdkTimetableFull.mapToEntities(semester: Semester) = TimetableFull(
|
||||||
lessons = lessons.mapToEntities(semester),
|
lessons = lessons.mapToEntities(semester),
|
||||||
@ -16,13 +16,13 @@ fun SdkTimetableFull.mapToEntities(semester: Semester) = TimetableFull(
|
|||||||
headers = headers.mapToEntities(semester)
|
headers = headers.mapToEntities(semester)
|
||||||
)
|
)
|
||||||
|
|
||||||
fun List<SdkTimetable>.mapToEntities(semester: Semester) = map {
|
fun List<SdkLesson>.mapToEntities(semester: Semester) = map {
|
||||||
Timetable(
|
Timetable(
|
||||||
studentId = semester.studentId,
|
studentId = semester.studentId,
|
||||||
diaryId = semester.diaryId,
|
diaryId = semester.diaryId,
|
||||||
number = it.number,
|
number = it.number,
|
||||||
start = it.startZoned.toInstant(),
|
start = it.start.toInstant(),
|
||||||
end = it.endZoned.toInstant(),
|
end = it.end.toInstant(),
|
||||||
date = it.date,
|
date = it.date,
|
||||||
subject = it.subject,
|
subject = it.subject,
|
||||||
subjectOld = it.subjectOld,
|
subjectOld = it.subjectOld,
|
||||||
@ -45,8 +45,8 @@ fun List<SdkTimetableAdditional>.mapToEntities(semester: Semester) = map {
|
|||||||
diaryId = semester.diaryId,
|
diaryId = semester.diaryId,
|
||||||
subject = it.subject,
|
subject = it.subject,
|
||||||
date = it.date,
|
date = it.date,
|
||||||
start = it.startZoned.toInstant(),
|
start = it.start.toInstant(),
|
||||||
end = it.endZoned.toInstant(),
|
end = it.end.toInstant(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,20 +1,25 @@
|
|||||||
package io.github.wulkanowy.data.pojos
|
package io.github.wulkanowy.data.pojos
|
||||||
|
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
|
import io.github.wulkanowy.sdk.Sdk
|
||||||
import io.github.wulkanowy.sdk.scrapper.Scrapper
|
import io.github.wulkanowy.sdk.scrapper.Scrapper
|
||||||
|
|
||||||
data class RegisterUser(
|
data class RegisterUser(
|
||||||
val email: String,
|
val email: String,
|
||||||
val password: String,
|
val password: String?,
|
||||||
val login: String, // may be the same as email
|
val login: String, // may be the same as email
|
||||||
val baseUrl: String,
|
val scrapperBaseUrl: String?,
|
||||||
val loginType: Scrapper.LoginType,
|
val loginType: Scrapper.LoginType?,
|
||||||
|
val loginMode: Sdk.Mode,
|
||||||
val symbols: List<RegisterSymbol>,
|
val symbols: List<RegisterSymbol>,
|
||||||
) : java.io.Serializable
|
) : java.io.Serializable
|
||||||
|
|
||||||
data class RegisterSymbol(
|
data class RegisterSymbol(
|
||||||
val symbol: String,
|
val symbol: String,
|
||||||
val error: Throwable?,
|
val error: Throwable?,
|
||||||
|
val hebeBaseUrl: String?,
|
||||||
|
val keyId: String?,
|
||||||
|
val privatePem: String?,
|
||||||
val userName: String,
|
val userName: String,
|
||||||
val schools: List<RegisterUnit>,
|
val schools: List<RegisterUnit>,
|
||||||
) : java.io.Serializable
|
) : java.io.Serializable
|
||||||
|
@ -19,7 +19,6 @@ class AppCreatorRepository @Inject constructor(
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
@OptIn(ExperimentalSerializationApi::class)
|
@OptIn(ExperimentalSerializationApi::class)
|
||||||
@Suppress("BlockingMethodInNonBlockingContext")
|
|
||||||
suspend fun getAppCreators() = withContext(dispatchers.io) {
|
suspend fun getAppCreators() = withContext(dispatchers.io) {
|
||||||
val inputStream = context.assets.open("contributors.json").buffered()
|
val inputStream = context.assets.open("contributors.json").buffered()
|
||||||
json.decodeFromStream<List<Contributor>>(inputStream)
|
json.decodeFromStream<List<Contributor>>(inputStream)
|
||||||
|
@ -59,7 +59,7 @@ class AttendanceRepository @Inject constructor(
|
|||||||
}
|
}
|
||||||
sdk.init(student)
|
sdk.init(student)
|
||||||
.switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
|
.switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
|
||||||
.getAttendance(start.monday, end.sunday, semester.semesterId)
|
.getAttendance(start.monday, end.sunday)
|
||||||
.mapToEntities(semester, lessons)
|
.mapToEntities(semester, lessons)
|
||||||
},
|
},
|
||||||
saveFetchResult = { old, new ->
|
saveFetchResult = { old, new ->
|
||||||
|
@ -52,7 +52,7 @@ class ExamRepository @Inject constructor(
|
|||||||
fetch = {
|
fetch = {
|
||||||
sdk.init(student)
|
sdk.init(student)
|
||||||
.switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
|
.switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
|
||||||
.getExams(start.startExamsDay, start.endExamsDay, semester.semesterId)
|
.getExams(start.startExamsDay, start.endExamsDay)
|
||||||
.mapToEntities(semester)
|
.mapToEntities(semester)
|
||||||
},
|
},
|
||||||
saveFetchResult = { old, new ->
|
saveFetchResult = { old, new ->
|
||||||
|
@ -42,7 +42,7 @@ class NoteRepository @Inject constructor(
|
|||||||
fetch = {
|
fetch = {
|
||||||
sdk.init(student)
|
sdk.init(student)
|
||||||
.switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
|
.switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
|
||||||
.getNotes(semester.semesterId)
|
.getNotes()
|
||||||
.mapToEntities(semester)
|
.mapToEntities(semester)
|
||||||
},
|
},
|
||||||
saveFetchResult = { old, new ->
|
saveFetchResult = { old, new ->
|
||||||
|
@ -2,14 +2,17 @@ package io.github.wulkanowy.data.repositories
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
|
import androidx.annotation.StringRes
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
import com.fredporciuncula.flow.preferences.FlowSharedPreferences
|
import com.fredporciuncula.flow.preferences.FlowSharedPreferences
|
||||||
import com.fredporciuncula.flow.preferences.Preference
|
import com.fredporciuncula.flow.preferences.Preference
|
||||||
|
import com.fredporciuncula.flow.preferences.Serializer
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.enums.*
|
import io.github.wulkanowy.data.enums.*
|
||||||
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
|
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
|
||||||
import io.github.wulkanowy.ui.modules.grade.GradeAverageMode
|
import io.github.wulkanowy.ui.modules.grade.GradeAverageMode
|
||||||
|
import io.github.wulkanowy.ui.modules.settings.appearance.menuorder.AppMenuItem
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.serialization.decodeFromString
|
import kotlinx.serialization.decodeFromString
|
||||||
@ -28,29 +31,35 @@ class PreferencesRepository @Inject constructor(
|
|||||||
private val json: Json,
|
private val json: Json,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val startMenuIndex: Int
|
|
||||||
get() = getString(R.string.pref_key_start_menu, R.string.pref_default_startup).toInt()
|
|
||||||
|
|
||||||
val isShowPresent: Boolean
|
val isShowPresent: Boolean
|
||||||
get() = getBoolean(
|
get() = getBoolean(
|
||||||
R.string.pref_key_attendance_present,
|
R.string.pref_key_attendance_present,
|
||||||
R.bool.pref_default_attendance_present
|
R.bool.pref_default_attendance_present
|
||||||
)
|
)
|
||||||
|
|
||||||
val gradeAverageMode: GradeAverageMode
|
private val gradeAverageModePref: Preference<GradeAverageMode>
|
||||||
get() = GradeAverageMode.getByValue(
|
get() = getObjectFlow(
|
||||||
getString(
|
|
||||||
R.string.pref_key_grade_average_mode,
|
R.string.pref_key_grade_average_mode,
|
||||||
R.string.pref_default_grade_average_mode
|
R.string.pref_default_grade_average_mode,
|
||||||
)
|
object : Serializer<GradeAverageMode> {
|
||||||
|
override fun serialize(value: GradeAverageMode) = value.value
|
||||||
|
override fun deserialize(serialized: String) =
|
||||||
|
GradeAverageMode.getByValue(serialized)
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
val gradeAverageForceCalc: Boolean
|
val gradeAverageModeFlow: Flow<GradeAverageMode>
|
||||||
get() = getBoolean(
|
get() = gradeAverageModePref.asFlow()
|
||||||
R.string.pref_key_grade_average_force_calc,
|
|
||||||
R.bool.pref_default_grade_average_force_calc
|
private val gradeAverageForceCalcPref: Preference<Boolean>
|
||||||
|
get() = flowSharedPref.getBoolean(
|
||||||
|
context.getString(R.string.pref_key_grade_average_force_calc),
|
||||||
|
context.resources.getBoolean(R.bool.pref_default_grade_average_force_calc)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val gradeAverageForceCalcFlow: Flow<Boolean>
|
||||||
|
get() = gradeAverageForceCalcPref.asFlow()
|
||||||
|
|
||||||
val gradeExpandMode: GradeExpandMode
|
val gradeExpandMode: GradeExpandMode
|
||||||
get() = GradeExpandMode.getByValue(
|
get() = GradeExpandMode.getByValue(
|
||||||
getString(
|
getString(
|
||||||
@ -140,12 +149,24 @@ class PreferencesRepository @Inject constructor(
|
|||||||
R.string.pref_default_grade_modifier_plus
|
R.string.pref_default_grade_modifier_plus
|
||||||
).toDouble()
|
).toDouble()
|
||||||
|
|
||||||
|
val gradePlusModifierFlow: Flow<Double>
|
||||||
|
get() = getStringFlow(
|
||||||
|
R.string.pref_key_grade_modifier_plus,
|
||||||
|
R.string.pref_default_grade_modifier_plus
|
||||||
|
).asFlow().map { it.toDouble() }
|
||||||
|
|
||||||
val gradeMinusModifier: Double
|
val gradeMinusModifier: Double
|
||||||
get() = getString(
|
get() = getString(
|
||||||
R.string.pref_key_grade_modifier_minus,
|
R.string.pref_key_grade_modifier_minus,
|
||||||
R.string.pref_default_grade_modifier_minus
|
R.string.pref_default_grade_modifier_minus
|
||||||
).toDouble()
|
).toDouble()
|
||||||
|
|
||||||
|
val gradeMinusModifierFlow: Flow<Double>
|
||||||
|
get() = getStringFlow(
|
||||||
|
R.string.pref_key_grade_modifier_minus,
|
||||||
|
R.string.pref_default_grade_modifier_minus
|
||||||
|
).asFlow().map { it.toDouble() }
|
||||||
|
|
||||||
val fillMessageContent: Boolean
|
val fillMessageContent: Boolean
|
||||||
get() = getBoolean(
|
get() = getBoolean(
|
||||||
R.string.pref_key_fill_message_content,
|
R.string.pref_key_fill_message_content,
|
||||||
@ -180,24 +201,17 @@ class PreferencesRepository @Inject constructor(
|
|||||||
R.bool.pref_default_timetable_show_timers
|
R.bool.pref_default_timetable_show_timers
|
||||||
)
|
)
|
||||||
|
|
||||||
var isHomeworkFullscreen: Boolean
|
|
||||||
get() = getBoolean(
|
|
||||||
R.string.pref_key_homework_fullscreen,
|
|
||||||
R.bool.pref_default_homework_fullscreen
|
|
||||||
)
|
|
||||||
set(value) = sharedPref.edit().putBoolean("homework_fullscreen", value).apply()
|
|
||||||
|
|
||||||
val showSubjectsWithoutGrades: Boolean
|
val showSubjectsWithoutGrades: Boolean
|
||||||
get() = getBoolean(
|
get() = getBoolean(
|
||||||
R.string.pref_key_subjects_without_grades,
|
R.string.pref_key_subjects_without_grades,
|
||||||
R.bool.pref_default_subjects_without_grades
|
R.bool.pref_default_subjects_without_grades
|
||||||
)
|
)
|
||||||
|
|
||||||
val isOptionalArithmeticAverage: Boolean
|
val isOptionalArithmeticAverageFlow: Flow<Boolean>
|
||||||
get() = getBoolean(
|
get() = flowSharedPref.getBoolean(
|
||||||
R.string.pref_key_optional_arithmetic_average,
|
context.getString(R.string.pref_key_optional_arithmetic_average),
|
||||||
R.bool.pref_default_optional_arithmetic_average
|
context.resources.getBoolean(R.bool.pref_default_optional_arithmetic_average)
|
||||||
)
|
).asFlow()
|
||||||
|
|
||||||
var lasSyncDate: Instant?
|
var lasSyncDate: Instant?
|
||||||
get() = getLong(R.string.pref_key_last_sync_date, R.string.pref_default_last_sync_date)
|
get() = getLong(R.string.pref_key_last_sync_date, R.string.pref_default_last_sync_date)
|
||||||
@ -315,6 +329,20 @@ class PreferencesRepository @Inject constructor(
|
|||||||
putBoolean(context.getString(R.string.pref_key_ads_enabled), value)
|
putBoolean(context.getString(R.string.pref_key_ads_enabled), value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var appMenuItemOrder: List<AppMenuItem>
|
||||||
|
get() {
|
||||||
|
val value = sharedPref.getString(PREF_KEY_APP_MENU_ITEM_ORDER, null)
|
||||||
|
?: return AppMenuItem.defaultAppMenuItemList
|
||||||
|
|
||||||
|
return json.decodeFromString(value)
|
||||||
|
}
|
||||||
|
set(value) = sharedPref.edit {
|
||||||
|
putString(
|
||||||
|
PREF_KEY_APP_MENU_ITEM_ORDER,
|
||||||
|
json.encodeToString(value)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
var installationId: String
|
var installationId: String
|
||||||
get() = sharedPref.getString(PREF_KEY_INSTALLATION_ID, null).orEmpty()
|
get() = sharedPref.getString(PREF_KEY_INSTALLATION_ID, null).orEmpty()
|
||||||
private set(value) = sharedPref.edit { putString(PREF_KEY_INSTALLATION_ID, value) }
|
private set(value) = sharedPref.edit { putString(PREF_KEY_INSTALLATION_ID, value) }
|
||||||
@ -330,6 +358,21 @@ class PreferencesRepository @Inject constructor(
|
|||||||
private fun getLong(id: String, default: Int) =
|
private fun getLong(id: String, default: Int) =
|
||||||
sharedPref.getLong(id, context.resources.getString(default).toLong())
|
sharedPref.getLong(id, context.resources.getString(default).toLong())
|
||||||
|
|
||||||
|
private fun getStringFlow(id: Int, default: Int) =
|
||||||
|
flowSharedPref.getString(context.getString(id), context.getString(default))
|
||||||
|
|
||||||
|
private fun <T : Any> getObjectFlow(
|
||||||
|
@StringRes id: Int,
|
||||||
|
@StringRes default: Int,
|
||||||
|
serializer: Serializer<T>
|
||||||
|
): Preference<T> = flowSharedPref.getObject(
|
||||||
|
key = context.getString(id),
|
||||||
|
serializer = serializer,
|
||||||
|
defaultValue = serializer.deserialize(
|
||||||
|
flowSharedPref.getString(context.getString(default)).get()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
private fun getString(id: Int, default: Int) = getString(context.getString(id), default)
|
private fun getString(id: Int, default: Int) = getString(context.getString(id), default)
|
||||||
|
|
||||||
private fun getString(id: String, default: Int) =
|
private fun getString(id: String, default: Int) =
|
||||||
@ -341,6 +384,7 @@ class PreferencesRepository @Inject constructor(
|
|||||||
sharedPref.getBoolean(id, context.resources.getBoolean(default))
|
sharedPref.getBoolean(id, context.resources.getBoolean(default))
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
|
private const val PREF_KEY_APP_MENU_ITEM_ORDER = "app_menu_item_order"
|
||||||
private const val PREF_KEY_INSTALLATION_ID = "installation_id"
|
private const val PREF_KEY_INSTALLATION_ID = "installation_id"
|
||||||
private const val PREF_KEY_DASHBOARD_ITEMS_POSITION = "dashboard_items_position"
|
private const val PREF_KEY_DASHBOARD_ITEMS_POSITION = "dashboard_items_position"
|
||||||
private const val PREF_KEY_IN_APP_REVIEW_COUNT = "in_app_review_count"
|
private const val PREF_KEY_IN_APP_REVIEW_COUNT = "in_app_review_count"
|
||||||
|
@ -40,7 +40,7 @@ class SemesterRepository @Inject constructor(
|
|||||||
val isNoSemesters = semesters.isEmpty()
|
val isNoSemesters = semesters.isEmpty()
|
||||||
|
|
||||||
val isRefreshOnModeChangeRequired = when {
|
val isRefreshOnModeChangeRequired = when {
|
||||||
Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.API -> {
|
Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.HEBE -> {
|
||||||
semesters.firstOrNull { it.isCurrent }?.let {
|
semesters.firstOrNull { it.isCurrent }?.let {
|
||||||
0 == it.diaryId && 0 == it.kindergartenDiaryId
|
0 == it.diaryId && 0 == it.kindergartenDiaryId
|
||||||
} == true
|
} == true
|
||||||
|
@ -10,11 +10,9 @@ import io.github.wulkanowy.data.db.entities.Student
|
|||||||
import io.github.wulkanowy.data.db.entities.StudentNickAndAvatar
|
import io.github.wulkanowy.data.db.entities.StudentNickAndAvatar
|
||||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||||
import io.github.wulkanowy.data.exceptions.NoCurrentStudentException
|
import io.github.wulkanowy.data.exceptions.NoCurrentStudentException
|
||||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
|
||||||
import io.github.wulkanowy.data.mappers.mapToPojo
|
import io.github.wulkanowy.data.mappers.mapToPojo
|
||||||
import io.github.wulkanowy.data.pojos.RegisterUser
|
import io.github.wulkanowy.data.pojos.RegisterUser
|
||||||
import io.github.wulkanowy.sdk.Sdk
|
import io.github.wulkanowy.sdk.Sdk
|
||||||
import io.github.wulkanowy.utils.AppInfo
|
|
||||||
import io.github.wulkanowy.utils.DispatchersProvider
|
import io.github.wulkanowy.utils.DispatchersProvider
|
||||||
import io.github.wulkanowy.utils.security.decrypt
|
import io.github.wulkanowy.utils.security.decrypt
|
||||||
import io.github.wulkanowy.utils.security.encrypt
|
import io.github.wulkanowy.utils.security.encrypt
|
||||||
@ -29,37 +27,35 @@ class StudentRepository @Inject constructor(
|
|||||||
private val studentDb: StudentDao,
|
private val studentDb: StudentDao,
|
||||||
private val semesterDb: SemesterDao,
|
private val semesterDb: SemesterDao,
|
||||||
private val sdk: Sdk,
|
private val sdk: Sdk,
|
||||||
private val appInfo: AppInfo,
|
|
||||||
private val appDatabase: AppDatabase
|
private val appDatabase: AppDatabase
|
||||||
) {
|
) {
|
||||||
|
|
||||||
suspend fun isStudentSaved() = getSavedStudents(false).isNotEmpty()
|
|
||||||
|
|
||||||
suspend fun isCurrentStudentSet() = studentDb.loadCurrent()?.isCurrent ?: false
|
suspend fun isCurrentStudentSet() = studentDb.loadCurrent()?.isCurrent ?: false
|
||||||
|
|
||||||
suspend fun getStudentsApi(
|
suspend fun getStudentsApi(
|
||||||
pin: String,
|
pin: String,
|
||||||
symbol: String,
|
symbol: String,
|
||||||
token: String
|
token: String
|
||||||
): List<StudentWithSemesters> =
|
): RegisterUser = sdk
|
||||||
sdk.getStudentsFromMobileApi(token, pin, symbol, "")
|
.getStudentsFromHebe(token, pin, symbol, "")
|
||||||
.mapToEntities(colors = appInfo.defaultColorsForAvatar)
|
.mapToPojo(null)
|
||||||
|
|
||||||
suspend fun getStudentsScrapper(
|
suspend fun getStudentsScrapper(
|
||||||
email: String,
|
email: String,
|
||||||
password: String,
|
password: String,
|
||||||
scrapperBaseUrl: String,
|
scrapperBaseUrl: String,
|
||||||
symbol: String
|
symbol: String
|
||||||
): List<StudentWithSemesters> =
|
): RegisterUser = sdk
|
||||||
sdk.getStudentsFromScrapper(email, password, scrapperBaseUrl, symbol)
|
.getUserSubjectsFromScrapper(email, password, scrapperBaseUrl, symbol)
|
||||||
.mapToEntities(password, appInfo.defaultColorsForAvatar)
|
.mapToPojo(password)
|
||||||
|
|
||||||
suspend fun getUserSubjectsFromScrapper(
|
suspend fun getUserSubjectsFromScrapper(
|
||||||
email: String,
|
email: String,
|
||||||
password: String,
|
password: String,
|
||||||
scrapperBaseUrl: String,
|
scrapperBaseUrl: String,
|
||||||
symbol: String
|
symbol: String
|
||||||
): RegisterUser = sdk.getUserSubjectsFromScrapper(email, password, scrapperBaseUrl, symbol)
|
): RegisterUser = sdk
|
||||||
|
.getUserSubjectsFromScrapper(email, password, scrapperBaseUrl, symbol)
|
||||||
.mapToPojo(password)
|
.mapToPojo(password)
|
||||||
|
|
||||||
suspend fun getStudentsHybrid(
|
suspend fun getStudentsHybrid(
|
||||||
@ -67,15 +63,15 @@ class StudentRepository @Inject constructor(
|
|||||||
password: String,
|
password: String,
|
||||||
scrapperBaseUrl: String,
|
scrapperBaseUrl: String,
|
||||||
symbol: String
|
symbol: String
|
||||||
): List<StudentWithSemesters> =
|
): RegisterUser = sdk
|
||||||
sdk.getStudentsHybrid(email, password, scrapperBaseUrl, "", symbol)
|
.getStudentsHybrid(email, password, scrapperBaseUrl, "", symbol)
|
||||||
.mapToEntities(password, appInfo.defaultColorsForAvatar)
|
.mapToPojo(password)
|
||||||
|
|
||||||
suspend fun getSavedStudents(decryptPass: Boolean = true) =
|
suspend fun getSavedStudents(decryptPass: Boolean = true) =
|
||||||
studentDb.loadStudentsWithSemesters()
|
studentDb.loadStudentsWithSemesters()
|
||||||
.map {
|
.map {
|
||||||
it.apply {
|
it.apply {
|
||||||
if (decryptPass && Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.API) {
|
if (decryptPass && Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.HEBE) {
|
||||||
student.password = withContext(dispatchers.io) {
|
student.password = withContext(dispatchers.io) {
|
||||||
decrypt(student.password)
|
decrypt(student.password)
|
||||||
}
|
}
|
||||||
@ -85,7 +81,7 @@ class StudentRepository @Inject constructor(
|
|||||||
|
|
||||||
suspend fun getSavedStudentById(id: Long, decryptPass: Boolean = true) =
|
suspend fun getSavedStudentById(id: Long, decryptPass: Boolean = true) =
|
||||||
studentDb.loadStudentWithSemestersById(id)?.apply {
|
studentDb.loadStudentWithSemestersById(id)?.apply {
|
||||||
if (decryptPass && Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.API) {
|
if (decryptPass && Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.HEBE) {
|
||||||
student.password = withContext(dispatchers.io) {
|
student.password = withContext(dispatchers.io) {
|
||||||
decrypt(student.password)
|
decrypt(student.password)
|
||||||
}
|
}
|
||||||
@ -95,7 +91,7 @@ class StudentRepository @Inject constructor(
|
|||||||
suspend fun getStudentById(id: Long, decryptPass: Boolean = true): Student {
|
suspend fun getStudentById(id: Long, decryptPass: Boolean = true): Student {
|
||||||
val student = studentDb.loadById(id) ?: throw NoCurrentStudentException()
|
val student = studentDb.loadById(id) ?: throw NoCurrentStudentException()
|
||||||
|
|
||||||
if (decryptPass && Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.API) {
|
if (decryptPass && Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.HEBE) {
|
||||||
student.password = withContext(dispatchers.io) {
|
student.password = withContext(dispatchers.io) {
|
||||||
decrypt(student.password)
|
decrypt(student.password)
|
||||||
}
|
}
|
||||||
@ -106,7 +102,7 @@ class StudentRepository @Inject constructor(
|
|||||||
suspend fun getCurrentStudent(decryptPass: Boolean = true): Student {
|
suspend fun getCurrentStudent(decryptPass: Boolean = true): Student {
|
||||||
val student = studentDb.loadCurrent() ?: throw NoCurrentStudentException()
|
val student = studentDb.loadCurrent() ?: throw NoCurrentStudentException()
|
||||||
|
|
||||||
if (decryptPass && Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.API) {
|
if (decryptPass && Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.HEBE) {
|
||||||
student.password = withContext(dispatchers.io) {
|
student.password = withContext(dispatchers.io) {
|
||||||
decrypt(student.password)
|
decrypt(student.password)
|
||||||
}
|
}
|
||||||
@ -119,7 +115,7 @@ class StudentRepository @Inject constructor(
|
|||||||
val students = studentsWithSemesters.map { it.student }
|
val students = studentsWithSemesters.map { it.student }
|
||||||
.map {
|
.map {
|
||||||
it.apply {
|
it.apply {
|
||||||
if (Sdk.Mode.valueOf(it.loginMode) != Sdk.Mode.API) {
|
if (Sdk.Mode.valueOf(it.loginMode) != Sdk.Mode.HEBE) {
|
||||||
password = withContext(dispatchers.io) {
|
password = withContext(dispatchers.io) {
|
||||||
encrypt(password, context)
|
encrypt(password, context)
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ class TeacherRepository @Inject constructor(
|
|||||||
fetch = {
|
fetch = {
|
||||||
sdk.init(student)
|
sdk.init(student)
|
||||||
.switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
|
.switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
|
||||||
.getTeachers(semester.semesterId)
|
.getTeachers()
|
||||||
.mapToEntities(semester)
|
.mapToEntities(semester)
|
||||||
},
|
},
|
||||||
saveFetchResult = { old, new ->
|
saveFetchResult = { old, new ->
|
||||||
|
@ -13,6 +13,7 @@ import io.github.wulkanowy.utils.*
|
|||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
import java.time.Instant
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
@ -65,7 +66,7 @@ class TimetableRepository @Inject constructor(
|
|||||||
fetch = {
|
fetch = {
|
||||||
val timetableFull = sdk.init(student)
|
val timetableFull = sdk.init(student)
|
||||||
.switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
|
.switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
|
||||||
.getTimetableFull(start.monday, end.sunday)
|
.getTimetable(start.monday, end.sunday)
|
||||||
|
|
||||||
timetableFull.mapToEntities(semester)
|
timetableFull.mapToEntities(semester)
|
||||||
},
|
},
|
||||||
@ -164,6 +165,11 @@ class TimetableRepository @Inject constructor(
|
|||||||
timetableHeaderDb.insertAll(new uniqueSubtract old)
|
timetableHeaderDb.insertAll(new uniqueSubtract old)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getLastRefreshTimestamp(semester: Semester, start: LocalDate, end: LocalDate): Instant {
|
||||||
|
val refreshKey = getRefreshKey(cacheKey, semester, start, end)
|
||||||
|
return refreshHelper.getLastRefreshTimestamp(refreshKey)
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun saveAdditionalList(additionalList: List<TimetableAdditional>) =
|
suspend fun saveAdditionalList(additionalList: List<TimetableAdditional>) =
|
||||||
timetableAdditionalDb.insertAll(additionalList)
|
timetableAdditionalDb.insertAll(additionalList)
|
||||||
|
|
||||||
|
@ -4,18 +4,12 @@ import android.os.Build.VERSION.SDK_INT
|
|||||||
import android.os.Build.VERSION_CODES.O
|
import android.os.Build.VERSION_CODES.O
|
||||||
import androidx.core.app.NotificationManagerCompat
|
import androidx.core.app.NotificationManagerCompat
|
||||||
import androidx.lifecycle.asFlow
|
import androidx.lifecycle.asFlow
|
||||||
|
import androidx.work.*
|
||||||
import androidx.work.BackoffPolicy.EXPONENTIAL
|
import androidx.work.BackoffPolicy.EXPONENTIAL
|
||||||
import androidx.work.Constraints
|
|
||||||
import androidx.work.Data
|
|
||||||
import androidx.work.ExistingPeriodicWorkPolicy.KEEP
|
import androidx.work.ExistingPeriodicWorkPolicy.KEEP
|
||||||
import androidx.work.ExistingPeriodicWorkPolicy.REPLACE
|
import androidx.work.ExistingPeriodicWorkPolicy.UPDATE
|
||||||
import androidx.work.ExistingWorkPolicy
|
|
||||||
import androidx.work.NetworkType.CONNECTED
|
import androidx.work.NetworkType.CONNECTED
|
||||||
import androidx.work.NetworkType.UNMETERED
|
import androidx.work.NetworkType.UNMETERED
|
||||||
import androidx.work.OneTimeWorkRequestBuilder
|
|
||||||
import androidx.work.PeriodicWorkRequestBuilder
|
|
||||||
import androidx.work.WorkInfo
|
|
||||||
import androidx.work.WorkManager
|
|
||||||
import io.github.wulkanowy.data.db.SharedPrefProvider
|
import io.github.wulkanowy.data.db.SharedPrefProvider
|
||||||
import io.github.wulkanowy.data.db.SharedPrefProvider.Companion.APP_VERSION_CODE_KEY
|
import io.github.wulkanowy.data.db.SharedPrefProvider.Companion.APP_VERSION_CODE_KEY
|
||||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
@ -60,7 +54,7 @@ class SyncManager @Inject constructor(
|
|||||||
val serviceInterval = preferencesRepository.servicesInterval
|
val serviceInterval = preferencesRepository.servicesInterval
|
||||||
|
|
||||||
workManager.enqueueUniquePeriodicWork(
|
workManager.enqueueUniquePeriodicWork(
|
||||||
SyncWorker::class.java.simpleName, if (restart) REPLACE else KEEP,
|
SyncWorker::class.java.simpleName, if (restart) UPDATE else KEEP,
|
||||||
PeriodicWorkRequestBuilder<SyncWorker>(serviceInterval, MINUTES)
|
PeriodicWorkRequestBuilder<SyncWorker>(serviceInterval, MINUTES)
|
||||||
.setInitialDelay(10, MINUTES)
|
.setInitialDelay(10, MINUTES)
|
||||||
.setBackoffCriteria(EXPONENTIAL, 30, MINUTES)
|
.setBackoffCriteria(EXPONENTIAL, 30, MINUTES)
|
||||||
|
@ -4,7 +4,6 @@ import android.content.Intent
|
|||||||
import android.widget.RemoteViewsService
|
import android.widget.RemoteViewsService
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.data.db.SharedPrefProvider
|
import io.github.wulkanowy.data.db.SharedPrefProvider
|
||||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
|
||||||
import io.github.wulkanowy.data.repositories.SemesterRepository
|
import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||||
import io.github.wulkanowy.data.repositories.TimetableRepository
|
import io.github.wulkanowy.data.repositories.TimetableRepository
|
||||||
@ -24,14 +23,13 @@ class TimetableWidgetService : RemoteViewsService() {
|
|||||||
@Inject
|
@Inject
|
||||||
lateinit var semesterRepo: SemesterRepository
|
lateinit var semesterRepo: SemesterRepository
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var prefRepository: PreferencesRepository
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var sharedPref: SharedPrefProvider
|
lateinit var sharedPref: SharedPrefProvider
|
||||||
|
|
||||||
override fun onGetViewFactory(intent: Intent?): RemoteViewsFactory {
|
override fun onGetViewFactory(intent: Intent?): RemoteViewsFactory {
|
||||||
Timber.d("TimetableWidgetFactory created")
|
Timber.d("TimetableWidgetFactory created")
|
||||||
return TimetableWidgetFactory(timetableRepo, studentRepo, semesterRepo, prefRepository, sharedPref, applicationContext, intent)
|
return TimetableWidgetFactory(
|
||||||
|
timetableRepo, studentRepo, semesterRepo, sharedPref, applicationContext, intent
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,9 @@ import android.app.ActivityManager
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AlertDialog
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.viewbinding.ViewBinding
|
import androidx.viewbinding.ViewBinding
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import com.google.android.material.snackbar.Snackbar.LENGTH_LONG
|
import com.google.android.material.snackbar.Snackbar.LENGTH_LONG
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
@ -30,6 +30,8 @@ abstract class BaseActivity<T : BasePresenter<out BaseView>, VB : ViewBinding> :
|
|||||||
|
|
||||||
protected var messageContainer: View? = null
|
protected var messageContainer: View? = null
|
||||||
|
|
||||||
|
protected var messageAnchor: View? = null
|
||||||
|
|
||||||
abstract var presenter: T
|
abstract var presenter: T
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
@ -48,6 +50,7 @@ abstract class BaseActivity<T : BasePresenter<out BaseView>, VB : ViewBinding> :
|
|||||||
if (messageContainer != null) {
|
if (messageContainer != null) {
|
||||||
Snackbar.make(messageContainer!!, text, LENGTH_LONG)
|
Snackbar.make(messageContainer!!, text, LENGTH_LONG)
|
||||||
.setAction(R.string.all_details) { showErrorDetailsDialog(error) }
|
.setAction(R.string.all_details) { showErrorDetailsDialog(error) }
|
||||||
|
.apply { messageAnchor?.let { anchorView = it } }
|
||||||
.show()
|
.show()
|
||||||
} else showMessage(text)
|
} else showMessage(text)
|
||||||
}
|
}
|
||||||
@ -57,12 +60,15 @@ abstract class BaseActivity<T : BasePresenter<out BaseView>, VB : ViewBinding> :
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun showMessage(text: String) {
|
override fun showMessage(text: String) {
|
||||||
if (messageContainer != null) Snackbar.make(messageContainer!!, text, LENGTH_LONG).show()
|
if (messageContainer != null) {
|
||||||
else Toast.makeText(this, text, Toast.LENGTH_LONG).show()
|
Snackbar.make(messageContainer!!, text, LENGTH_LONG)
|
||||||
|
.apply { messageAnchor?.let { anchorView = it } }
|
||||||
|
.show()
|
||||||
|
} else Toast.makeText(this, text, Toast.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showExpiredDialog() {
|
override fun showExpiredDialog() {
|
||||||
AlertDialog.Builder(this)
|
MaterialAlertDialogBuilder(this)
|
||||||
.setTitle(R.string.main_session_expired)
|
.setTitle(R.string.main_session_expired)
|
||||||
.setMessage(R.string.main_session_relogin)
|
.setMessage(R.string.main_session_relogin)
|
||||||
.setPositiveButton(R.string.main_log_in) { _, _ -> presenter.onExpiredLoginSelected() }
|
.setPositiveButton(R.string.main_log_in) { _, _ -> presenter.onExpiredLoginSelected() }
|
||||||
@ -74,6 +80,7 @@ abstract class BaseActivity<T : BasePresenter<out BaseView>, VB : ViewBinding> :
|
|||||||
messageContainer?.let {
|
messageContainer?.let {
|
||||||
Snackbar.make(it, R.string.error_password_change_required, LENGTH_LONG)
|
Snackbar.make(it, R.string.error_password_change_required, LENGTH_LONG)
|
||||||
.setAction(R.string.all_change) { openInternetBrowser(redirectUrl) }
|
.setAction(R.string.all_change) { openInternetBrowser(redirectUrl) }
|
||||||
|
.apply { messageAnchor?.let { anchorView = it } }
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,14 @@
|
|||||||
package io.github.wulkanowy.ui.base
|
package io.github.wulkanowy.ui.base
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.annotation.CallSuper
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import androidx.viewbinding.ViewBinding
|
import androidx.viewbinding.ViewBinding
|
||||||
|
import com.google.android.material.elevation.SurfaceColors
|
||||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||||
import io.github.wulkanowy.utils.lifecycleAwareVariable
|
import io.github.wulkanowy.utils.lifecycleAwareVariable
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -38,6 +44,19 @@ abstract class BaseDialogFragment<VB : ViewBinding> : DialogFragment(), BaseView
|
|||||||
ErrorDialog.newInstance(error).show(childFragmentManager, error.toString())
|
ErrorDialog.newInstance(error).show(childFragmentManager, error.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@CallSuper
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
view.setBackgroundColor(SurfaceColors.SURFACE_3.getColor(requireContext()))
|
||||||
|
}
|
||||||
|
|
||||||
|
@CallSuper
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
) = binding.root
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
analyticsHelper.setCurrentScreen(requireActivity(), this::class.simpleName)
|
analyticsHelper.setCurrentScreen(requireActivity(), this::class.simpleName)
|
||||||
|
@ -4,13 +4,13 @@ import android.app.Dialog
|
|||||||
import android.content.ClipData
|
import android.content.ClipData
|
||||||
import android.content.ClipboardManager
|
import android.content.ClipboardManager
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import android.widget.Toast.LENGTH_LONG
|
import android.widget.Toast.LENGTH_LONG
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
import androidx.core.view.isGone
|
import androidx.core.view.isGone
|
||||||
import androidx.fragment.app.DialogFragment
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
@ -20,7 +20,7 @@ import io.github.wulkanowy.utils.*
|
|||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class ErrorDialog : DialogFragment() {
|
class ErrorDialog : BaseDialogFragment<DialogErrorBinding>() {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var appInfo: AppInfo
|
lateinit var appInfo: AppInfo
|
||||||
@ -28,6 +28,8 @@ class ErrorDialog : DialogFragment() {
|
|||||||
@Inject
|
@Inject
|
||||||
lateinit var preferencesRepository: PreferencesRepository
|
lateinit var preferencesRepository: PreferencesRepository
|
||||||
|
|
||||||
|
private lateinit var error: Throwable
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val ARGUMENT_KEY = "error"
|
private const val ARGUMENT_KEY = "error"
|
||||||
|
|
||||||
@ -36,32 +38,31 @@ class ErrorDialog : DialogFragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
error = requireArguments().serializable(ARGUMENT_KEY)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
val error = requireArguments().serializable<Throwable>(ARGUMENT_KEY)
|
|
||||||
|
|
||||||
val binding = DialogErrorBinding.inflate(layoutInflater)
|
|
||||||
binding.bindErrorDetails(error)
|
|
||||||
|
|
||||||
return getAlertDialog(binding, error).apply {
|
|
||||||
enableReportButtonIfErrorIsReportable(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getAlertDialog(binding: DialogErrorBinding, error: Throwable): AlertDialog {
|
|
||||||
return MaterialAlertDialogBuilder(requireContext()).apply {
|
return MaterialAlertDialogBuilder(requireContext()).apply {
|
||||||
val errorStacktrace = error.stackTraceToString()
|
val errorStacktrace = error.stackTraceToString()
|
||||||
setTitle(R.string.all_details)
|
setTitle(R.string.all_details)
|
||||||
setView(binding.root)
|
setView(DialogErrorBinding.inflate(layoutInflater).apply { binding = this }.root)
|
||||||
setNeutralButton(R.string.about_feedback) { _, _ ->
|
setNeutralButton(R.string.about_feedback) { _, _ ->
|
||||||
openConfirmDialog { openEmailClient(errorStacktrace) }
|
openConfirmDialog { openEmailClient(errorStacktrace) }
|
||||||
}
|
}
|
||||||
setNegativeButton(android.R.string.cancel) { _, _ -> }
|
setNegativeButton(android.R.string.cancel) { _, _ -> }
|
||||||
setPositiveButton(android.R.string.copy) { _, _ -> copyErrorToClipboard(errorStacktrace) }
|
setPositiveButton(android.R.string.copy) { _, _ -> copyErrorToClipboard(errorStacktrace) }
|
||||||
}.create()
|
}.create().apply {
|
||||||
|
setOnShowListener {
|
||||||
|
getButton(AlertDialog.BUTTON_NEUTRAL).isEnabled = error.isShouldBeReported()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun DialogErrorBinding.bindErrorDetails(error: Throwable) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
return with(this) {
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
with(binding) {
|
||||||
errorDialogHumanizedMessage.text = resources.getErrorString(error)
|
errorDialogHumanizedMessage.text = resources.getErrorString(error)
|
||||||
errorDialogErrorMessage.text = error.localizedMessage
|
errorDialogErrorMessage.text = error.localizedMessage
|
||||||
errorDialogErrorMessage.isGone = error.localizedMessage.isNullOrBlank()
|
errorDialogErrorMessage.isGone = error.localizedMessage.isNullOrBlank()
|
||||||
@ -70,12 +71,6 @@ class ErrorDialog : DialogFragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun AlertDialog.enableReportButtonIfErrorIsReportable(error: Throwable) {
|
|
||||||
setOnShowListener {
|
|
||||||
getButton(AlertDialog.BUTTON_NEUTRAL).isEnabled = error.isShouldBeReported()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun copyErrorToClipboard(errorStacktrace: String) {
|
private fun copyErrorToClipboard(errorStacktrace: String) {
|
||||||
val clip = ClipData.newPlainText("Error details", errorStacktrace)
|
val clip = ClipData.newPlainText("Error details", errorStacktrace)
|
||||||
requireActivity().getSystemService<ClipboardManager>()?.setPrimaryClip(clip)
|
requireActivity().getSystemService<ClipboardManager>()?.setPrimaryClip(clip)
|
||||||
@ -83,7 +78,7 @@ class ErrorDialog : DialogFragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun openConfirmDialog(callback: () -> Unit) {
|
private fun openConfirmDialog(callback: () -> Unit) {
|
||||||
AlertDialog.Builder(requireContext())
|
MaterialAlertDialogBuilder(requireContext())
|
||||||
.setTitle(R.string.dialog_error_check_update)
|
.setTitle(R.string.dialog_error_check_update)
|
||||||
.setMessage(R.string.dialog_error_check_update_message)
|
.setMessage(R.string.dialog_error_check_update_message)
|
||||||
.setNeutralButton(R.string.about_feedback) { _, _ -> callback() }
|
.setNeutralButton(R.string.about_feedback) { _, _ -> callback() }
|
||||||
@ -113,8 +108,4 @@ class ErrorDialog : DialogFragment() {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showMessage(text: String) {
|
|
||||||
Toast.makeText(requireContext(), text, LENGTH_LONG).show()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -6,15 +6,14 @@ import android.content.pm.PackageManager.GET_ACTIVITIES
|
|||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.app.AppCompatDelegate
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
|
import com.google.android.material.color.DynamicColors
|
||||||
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_NO
|
|
||||||
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_YES
|
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.enums.AppTheme
|
import io.github.wulkanowy.data.enums.AppTheme
|
||||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
import io.github.wulkanowy.ui.modules.login.LoginActivity
|
import io.github.wulkanowy.ui.modules.login.LoginActivity
|
||||||
|
import io.github.wulkanowy.ui.modules.luckynumberwidget.LuckyNumberWidgetConfigureActivity
|
||||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||||
import io.github.wulkanowy.ui.modules.message.send.SendMessageActivity
|
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetConfigureActivity
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@ -28,18 +27,19 @@ class ThemeManager @Inject constructor(private val preferencesRepository: Prefer
|
|||||||
when (activity) {
|
when (activity) {
|
||||||
is MainActivity -> activity.setTheme(R.style.WulkanowyTheme_Black)
|
is MainActivity -> activity.setTheme(R.style.WulkanowyTheme_Black)
|
||||||
is LoginActivity -> activity.setTheme(R.style.WulkanowyTheme_Login_Black)
|
is LoginActivity -> activity.setTheme(R.style.WulkanowyTheme_Login_Black)
|
||||||
is SendMessageActivity -> activity.setTheme(R.style.WulkanowyTheme_MessageSend_Black)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (activity is TimetableWidgetConfigureActivity || activity is LuckyNumberWidgetConfigureActivity) {
|
||||||
|
DynamicColors.applyToActivityIfAvailable(activity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun applyDefaultTheme() {
|
fun applyDefaultTheme() {
|
||||||
AppCompatDelegate.setDefaultNightMode(
|
AppCompatDelegate.setDefaultNightMode(
|
||||||
when (preferencesRepository.appTheme) {
|
when (preferencesRepository.appTheme) {
|
||||||
AppTheme.LIGHT -> MODE_NIGHT_NO
|
AppTheme.LIGHT -> AppCompatDelegate.MODE_NIGHT_NO
|
||||||
AppTheme.DARK, AppTheme.BLACK -> MODE_NIGHT_YES
|
AppTheme.DARK, AppTheme.BLACK -> AppCompatDelegate.MODE_NIGHT_YES
|
||||||
AppTheme.SYSTEM -> MODE_NIGHT_FOLLOW_SYSTEM
|
AppTheme.SYSTEM -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -52,7 +52,6 @@ class ThemeManager @Inject constructor(private val preferencesRepository: Prefer
|
|||||||
.let {
|
.let {
|
||||||
it == R.style.WulkanowyTheme_Black || it == R.style.WulkanowyTheme_NoActionBar
|
it == R.style.WulkanowyTheme_Black || it == R.style.WulkanowyTheme_NoActionBar
|
||||||
|| it == R.style.WulkanowyTheme_Login || it == R.style.WulkanowyTheme_Login_Black
|
|| it == R.style.WulkanowyTheme_Login || it == R.style.WulkanowyTheme_Login_Black
|
||||||
|| it == R.style.WulkanowyTheme_MessageSend || it == R.style.WulkanowyTheme_MessageSend_Black
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
|
@ -9,11 +9,14 @@ import io.github.wulkanowy.ui.modules.exam.ExamFragment
|
|||||||
import io.github.wulkanowy.ui.modules.grade.GradeFragment
|
import io.github.wulkanowy.ui.modules.grade.GradeFragment
|
||||||
import io.github.wulkanowy.ui.modules.homework.HomeworkFragment
|
import io.github.wulkanowy.ui.modules.homework.HomeworkFragment
|
||||||
import io.github.wulkanowy.ui.modules.luckynumber.LuckyNumberFragment
|
import io.github.wulkanowy.ui.modules.luckynumber.LuckyNumberFragment
|
||||||
|
import io.github.wulkanowy.ui.modules.luckynumber.history.LuckyNumberHistoryFragment
|
||||||
import io.github.wulkanowy.ui.modules.message.MessageFragment
|
import io.github.wulkanowy.ui.modules.message.MessageFragment
|
||||||
|
import io.github.wulkanowy.ui.modules.mobiledevice.MobileDeviceFragment
|
||||||
import io.github.wulkanowy.ui.modules.more.MoreFragment
|
import io.github.wulkanowy.ui.modules.more.MoreFragment
|
||||||
import io.github.wulkanowy.ui.modules.note.NoteFragment
|
import io.github.wulkanowy.ui.modules.note.NoteFragment
|
||||||
import io.github.wulkanowy.ui.modules.schoolandteachers.school.SchoolFragment
|
import io.github.wulkanowy.ui.modules.schoolandteachers.SchoolAndTeachersFragment
|
||||||
import io.github.wulkanowy.ui.modules.schoolannouncement.SchoolAnnouncementFragment
|
import io.github.wulkanowy.ui.modules.schoolannouncement.SchoolAnnouncementFragment
|
||||||
|
import io.github.wulkanowy.ui.modules.settings.SettingsFragment
|
||||||
import io.github.wulkanowy.ui.modules.timetable.TimetableFragment
|
import io.github.wulkanowy.ui.modules.timetable.TimetableFragment
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
@ -39,10 +42,13 @@ sealed class Destination {
|
|||||||
NOTE(Note),
|
NOTE(Note),
|
||||||
CONFERENCE(Conference),
|
CONFERENCE(Conference),
|
||||||
SCHOOL_ANNOUNCEMENT(SchoolAnnouncement),
|
SCHOOL_ANNOUNCEMENT(SchoolAnnouncement),
|
||||||
SCHOOL(School),
|
SCHOOL_AND_TEACHERS(SchoolAndTeachers),
|
||||||
LUCKY_NUMBER(More),
|
LUCKY_NUMBER(LuckyNumber),
|
||||||
|
LUCKY_NUMBER_HISTORY(LuckyNumberHistory),
|
||||||
MORE(More),
|
MORE(More),
|
||||||
MESSAGE(Message);
|
MESSAGE(Message),
|
||||||
|
MOBILE_DEVICE(MobileDevice),
|
||||||
|
SETTINGS(Settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@ -103,9 +109,9 @@ sealed class Destination {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
object School : Destination() {
|
object SchoolAndTeachers : Destination() {
|
||||||
override val destinationType get() = Type.SCHOOL
|
override val destinationType get() = Type.SCHOOL_AND_TEACHERS
|
||||||
override val destinationFragment get() = SchoolFragment.newInstance()
|
override val destinationFragment get() = SchoolAndTeachersFragment.newInstance()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@ -114,6 +120,12 @@ sealed class Destination {
|
|||||||
override val destinationFragment get() = LuckyNumberFragment.newInstance()
|
override val destinationFragment get() = LuckyNumberFragment.newInstance()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
object LuckyNumberHistory : Destination() {
|
||||||
|
override val destinationType get() = Type.LUCKY_NUMBER_HISTORY
|
||||||
|
override val destinationFragment get() = LuckyNumberHistoryFragment.newInstance()
|
||||||
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
object More : Destination() {
|
object More : Destination() {
|
||||||
override val destinationType get() = Type.MORE
|
override val destinationType get() = Type.MORE
|
||||||
@ -125,4 +137,16 @@ sealed class Destination {
|
|||||||
override val destinationType get() = Type.MESSAGE
|
override val destinationType get() = Type.MESSAGE
|
||||||
override val destinationFragment get() = MessageFragment.newInstance()
|
override val destinationFragment get() = MessageFragment.newInstance()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
object MobileDevice : Destination() {
|
||||||
|
override val destinationType get() = Type.MOBILE_DEVICE
|
||||||
|
override val destinationFragment get() = MobileDeviceFragment.newInstance()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
object Settings : Destination() {
|
||||||
|
override val destinationType get() = Type.SETTINGS
|
||||||
|
override val destinationFragment get() = SettingsFragment.newInstance()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import androidx.appcompat.app.AlertDialog
|
|||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
import androidx.core.view.get
|
import androidx.core.view.get
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
@ -114,7 +115,7 @@ class AccountDetailsFragment :
|
|||||||
|
|
||||||
override fun showLogoutConfirmDialog() {
|
override fun showLogoutConfirmDialog() {
|
||||||
context?.let {
|
context?.let {
|
||||||
AlertDialog.Builder(it)
|
MaterialAlertDialogBuilder(it)
|
||||||
.setTitle(R.string.account_logout_student)
|
.setTitle(R.string.account_logout_student)
|
||||||
.setMessage(R.string.account_confirm)
|
.setMessage(R.string.account_confirm)
|
||||||
.setPositiveButton(R.string.account_logout) { _, _ -> presenter.onLogoutConfirm() }
|
.setPositiveButton(R.string.account_logout) { _, _ -> presenter.onLogoutConfirm() }
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
package io.github.wulkanowy.ui.modules.account.accountedit
|
package io.github.wulkanowy.ui.modules.account.accountedit
|
||||||
|
|
||||||
|
import android.app.Dialog
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.github.wulkanowy.databinding.DialogAccountEditBinding
|
import io.github.wulkanowy.databinding.DialogAccountEditBinding
|
||||||
@ -31,16 +31,12 @@ class AccountEditDialog : BaseDialogFragment<DialogAccountEditBinding>(), Accoun
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
setStyle(STYLE_NO_TITLE, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
inflater: LayoutInflater,
|
return MaterialAlertDialogBuilder(requireContext(), theme)
|
||||||
container: ViewGroup?,
|
.setView(DialogAccountEditBinding.inflate(layoutInflater).apply { binding = this }.root)
|
||||||
savedInstanceState: Bundle?
|
.create()
|
||||||
): View = DialogAccountEditBinding.inflate(inflater).apply { binding = this }.root
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
package io.github.wulkanowy.ui.modules.account.accountquick
|
package io.github.wulkanowy.ui.modules.account.accountquick
|
||||||
|
|
||||||
|
import android.app.Dialog
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||||
import io.github.wulkanowy.databinding.DialogAccountQuickBinding
|
import io.github.wulkanowy.databinding.DialogAccountQuickBinding
|
||||||
@ -36,19 +36,17 @@ class AccountQuickDialog : BaseDialogFragment<DialogAccountQuickBinding>(), Acco
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
super.onCreate(savedInstanceState)
|
return MaterialAlertDialogBuilder(requireContext(), theme)
|
||||||
setStyle(STYLE_NO_TITLE, 0)
|
.setView(
|
||||||
|
DialogAccountQuickBinding.inflate(layoutInflater)
|
||||||
|
.apply { binding = this }.root
|
||||||
|
)
|
||||||
|
.create()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(
|
|
||||||
inflater: LayoutInflater,
|
|
||||||
container: ViewGroup?,
|
|
||||||
savedInstanceState: Bundle?
|
|
||||||
) = DialogAccountQuickBinding.inflate(inflater).apply { binding = this }.root
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
val studentsWithSemesters = requireArguments()
|
val studentsWithSemesters = requireArguments()
|
||||||
.serializable<Array<StudentWithSemesters>>(STUDENTS_ARGUMENT_KEY).toList()
|
.serializable<Array<StudentWithSemesters>>(STUDENTS_ARGUMENT_KEY).toList()
|
||||||
|
|
||||||
|
@ -1,21 +1,20 @@
|
|||||||
package io.github.wulkanowy.ui.modules.attendance
|
package io.github.wulkanowy.ui.modules.attendance
|
||||||
|
|
||||||
|
import android.app.Dialog
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
import androidx.fragment.app.DialogFragment
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.data.db.entities.Attendance
|
import io.github.wulkanowy.data.db.entities.Attendance
|
||||||
import io.github.wulkanowy.databinding.DialogAttendanceBinding
|
import io.github.wulkanowy.databinding.DialogAttendanceBinding
|
||||||
|
import io.github.wulkanowy.ui.base.BaseDialogFragment
|
||||||
import io.github.wulkanowy.utils.descriptionRes
|
import io.github.wulkanowy.utils.descriptionRes
|
||||||
import io.github.wulkanowy.utils.lifecycleAwareVariable
|
|
||||||
import io.github.wulkanowy.utils.serializable
|
import io.github.wulkanowy.utils.serializable
|
||||||
import io.github.wulkanowy.utils.toFormattedString
|
import io.github.wulkanowy.utils.toFormattedString
|
||||||
|
|
||||||
class AttendanceDialog : DialogFragment() {
|
@AndroidEntryPoint
|
||||||
|
class AttendanceDialog : BaseDialogFragment<DialogAttendanceBinding>() {
|
||||||
private var binding: DialogAttendanceBinding by lifecycleAwareVariable()
|
|
||||||
|
|
||||||
private lateinit var attendance: Attendance
|
private lateinit var attendance: Attendance
|
||||||
|
|
||||||
@ -30,15 +29,14 @@ class AttendanceDialog : DialogFragment() {
|
|||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setStyle(STYLE_NO_TITLE, 0)
|
|
||||||
attendance = requireArguments().serializable(ARGUMENT_KEY)
|
attendance = requireArguments().serializable(ARGUMENT_KEY)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
inflater: LayoutInflater,
|
return MaterialAlertDialogBuilder(requireContext(), theme)
|
||||||
container: ViewGroup?,
|
.setView(DialogAttendanceBinding.inflate(layoutInflater).apply { binding = this }.root)
|
||||||
savedInstanceState: Bundle?
|
.create()
|
||||||
) = DialogAttendanceBinding.inflate(inflater).apply { binding = this }.root
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
@ -4,10 +4,10 @@ import android.content.DialogInterface.BUTTON_POSITIVE
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.*
|
import android.view.*
|
||||||
import android.view.View.*
|
import android.view.View.*
|
||||||
import androidx.appcompat.app.AlertDialog
|
|
||||||
import androidx.appcompat.view.ActionMode
|
import androidx.appcompat.view.ActionMode
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.db.entities.Attendance
|
import io.github.wulkanowy.data.db.entities.Attendance
|
||||||
@ -124,7 +124,7 @@ class AttendanceFragment : BaseFragment<FragmentAttendanceBinding>(R.layout.frag
|
|||||||
|
|
||||||
attendanceExcuseButton.setOnClickListener { presenter.onExcuseButtonClick() }
|
attendanceExcuseButton.setOnClickListener { presenter.onExcuseButtonClick() }
|
||||||
|
|
||||||
attendanceNavContainer.elevation = requireContext().dpToPx(8f)
|
attendanceNavContainer.elevation = requireContext().dpToPx(3f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,7 +228,7 @@ class AttendanceFragment : BaseFragment<FragmentAttendanceBinding>(R.layout.frag
|
|||||||
|
|
||||||
override fun showExcuseDialog() {
|
override fun showExcuseDialog() {
|
||||||
val dialogBinding = DialogExcuseBinding.inflate(LayoutInflater.from(context))
|
val dialogBinding = DialogExcuseBinding.inflate(LayoutInflater.from(context))
|
||||||
AlertDialog.Builder(requireContext())
|
MaterialAlertDialogBuilder(requireContext())
|
||||||
.setTitle(R.string.attendance_excuse_title)
|
.setTitle(R.string.attendance_excuse_title)
|
||||||
.setView(dialogBinding.root)
|
.setView(dialogBinding.root)
|
||||||
.setNegativeButton(android.R.string.cancel) { _, _ -> }
|
.setNegativeButton(android.R.string.cancel) { _, _ -> }
|
||||||
|
@ -1,21 +1,20 @@
|
|||||||
package io.github.wulkanowy.ui.modules.conference
|
package io.github.wulkanowy.ui.modules.conference
|
||||||
|
|
||||||
|
import android.app.Dialog
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.fragment.app.DialogFragment
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.data.db.entities.Conference
|
import io.github.wulkanowy.data.db.entities.Conference
|
||||||
import io.github.wulkanowy.databinding.DialogConferenceBinding
|
import io.github.wulkanowy.databinding.DialogConferenceBinding
|
||||||
import io.github.wulkanowy.utils.lifecycleAwareVariable
|
import io.github.wulkanowy.ui.base.BaseDialogFragment
|
||||||
import io.github.wulkanowy.utils.serializable
|
import io.github.wulkanowy.utils.serializable
|
||||||
import io.github.wulkanowy.utils.toFormattedString
|
import io.github.wulkanowy.utils.toFormattedString
|
||||||
|
|
||||||
class ConferenceDialog : DialogFragment() {
|
@AndroidEntryPoint
|
||||||
|
class ConferenceDialog : BaseDialogFragment<DialogConferenceBinding>() {
|
||||||
private var binding: DialogConferenceBinding by lifecycleAwareVariable()
|
|
||||||
|
|
||||||
private lateinit var conference: Conference
|
private lateinit var conference: Conference
|
||||||
|
|
||||||
@ -30,15 +29,14 @@ class ConferenceDialog : DialogFragment() {
|
|||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setStyle(STYLE_NO_TITLE, 0)
|
|
||||||
conference = requireArguments().serializable(ARGUMENT_KEY)
|
conference = requireArguments().serializable(ARGUMENT_KEY)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
inflater: LayoutInflater,
|
return MaterialAlertDialogBuilder(requireContext(), theme)
|
||||||
container: ViewGroup?,
|
.setView(DialogConferenceBinding.inflate(layoutInflater).apply { binding = this }.root)
|
||||||
savedInstanceState: Bundle?
|
.create()
|
||||||
) = DialogConferenceBinding.inflate(inflater).also { binding = it }.root
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
@ -16,7 +16,7 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class ConferenceFragment : BaseFragment<FragmentConferenceBinding>(R.layout.fragment_conference),
|
class ConferenceFragment : BaseFragment<FragmentConferenceBinding>(R.layout.fragment_conference),
|
||||||
ConferenceView, MainView.TitledView {
|
ConferenceView, MainView.TitledView, MainView.MainChildView {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var presenter: ConferencePresenter
|
lateinit var presenter: ConferencePresenter
|
||||||
@ -109,6 +109,14 @@ class ConferenceFragment : BaseFragment<FragmentConferenceBinding>(R.layout.frag
|
|||||||
(activity as? MainActivity)?.showDialogFragment(ConferenceDialog.newInstance(conference))
|
(activity as? MainActivity)?.showDialogFragment(ConferenceDialog.newInstance(conference))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onFragmentReselected() {
|
||||||
|
if (::presenter.isInitialized) presenter.onFragmentReselected()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun resetView() {
|
||||||
|
binding.conferenceRecycler.smoothScrollToPosition(0)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
presenter.onDetachView()
|
presenter.onDetachView()
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
|
@ -96,4 +96,11 @@ class ConferencePresenter @Inject constructor(
|
|||||||
.onResourceError(errorHandler::dispatch)
|
.onResourceError(errorHandler::dispatch)
|
||||||
.launch()
|
.launch()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onFragmentReselected() {
|
||||||
|
Timber.i("Conference is reselected")
|
||||||
|
if (view?.isViewEmpty == false) {
|
||||||
|
view?.resetView()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,4 +28,6 @@ interface ConferenceView : BaseView {
|
|||||||
fun showContent(show: Boolean)
|
fun showContent(show: Boolean)
|
||||||
|
|
||||||
fun openConferenceDialog(conference: Conference)
|
fun openConferenceDialog(conference: Conference)
|
||||||
|
|
||||||
|
fun resetView()
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import androidx.recyclerview.widget.DefaultItemAnimator
|
|||||||
import androidx.recyclerview.widget.ItemTouchHelper
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.databinding.FragmentDashboardBinding
|
import io.github.wulkanowy.databinding.FragmentDashboardBinding
|
||||||
@ -148,7 +149,7 @@ class DashboardFragment : BaseFragment<FragmentDashboardBinding>(R.layout.fragme
|
|||||||
val values = requireContext().resources.getStringArray(R.array.dashboard_tile_values)
|
val values = requireContext().resources.getStringArray(R.array.dashboard_tile_values)
|
||||||
val selectedItemsState = values.map { value -> selectedItems.any { it.name == value } }
|
val selectedItemsState = values.map { value -> selectedItems.any { it.name == value } }
|
||||||
|
|
||||||
AlertDialog.Builder(requireContext())
|
MaterialAlertDialogBuilder(requireContext())
|
||||||
.setTitle(R.string.pref_dashboard_appearance_tiles_title)
|
.setTitle(R.string.pref_dashboard_appearance_tiles_title)
|
||||||
.setMultiChoiceItems(entries, selectedItemsState.toBooleanArray()) { _, _, _ -> }
|
.setMultiChoiceItems(entries, selectedItemsState.toBooleanArray()) { _, _, _ -> }
|
||||||
.setPositiveButton(android.R.string.ok) { dialog, _ ->
|
.setPositiveButton(android.R.string.ok) { dialog, _ ->
|
||||||
|
@ -606,7 +606,7 @@ class DashboardPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
is Resource.Error -> {
|
is Resource.Error -> {
|
||||||
Timber.i("Loading dashboard admin message result: An exception occurred")
|
Timber.i("Loading dashboard admin message result: An exception occurred")
|
||||||
errorHandler.dispatch(it.error)
|
Timber.e(it.error)
|
||||||
updateData(
|
updateData(
|
||||||
dashboardItem = DashboardItem.AdminMessages(
|
dashboardItem = DashboardItem.AdminMessages(
|
||||||
adminMessage = null,
|
adminMessage = null,
|
||||||
@ -748,7 +748,7 @@ class DashboardPresenter @Inject constructor(
|
|||||||
itemsLoadedList.find { it.type == DashboardItem.Type.ACCOUNT }?.error != null
|
itemsLoadedList.find { it.type == DashboardItem.Type.ACCOUNT }?.error != null
|
||||||
val isGeneralError =
|
val isGeneralError =
|
||||||
filteredItems.none { it.error == null } && filteredItems.isNotEmpty() || isAccountItemError
|
filteredItems.none { it.error == null } && filteredItems.isNotEmpty() || isAccountItemError
|
||||||
val firstError = itemsLoadedList.mapNotNull { it.error }.firstOrNull()
|
val firstError = itemsLoadedList.firstNotNullOfOrNull { it.error }
|
||||||
|
|
||||||
val filteredOriginalLoadedList =
|
val filteredOriginalLoadedList =
|
||||||
dashboardItemLoadedList.filterNot { it.type == DashboardItem.Type.ACCOUNT }
|
dashboardItemLoadedList.filterNot { it.type == DashboardItem.Type.ACCOUNT }
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package io.github.wulkanowy.ui.modules.dashboard.adapters
|
package io.github.wulkanowy.ui.modules.dashboard.adapters
|
||||||
|
|
||||||
|
import android.content.res.ColorStateList
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
@ -8,6 +9,7 @@ import io.github.wulkanowy.data.enums.GradeColorTheme
|
|||||||
import io.github.wulkanowy.databinding.SubitemDashboardGradesBinding
|
import io.github.wulkanowy.databinding.SubitemDashboardGradesBinding
|
||||||
import io.github.wulkanowy.databinding.SubitemDashboardSmallGradeBinding
|
import io.github.wulkanowy.databinding.SubitemDashboardSmallGradeBinding
|
||||||
import io.github.wulkanowy.utils.getBackgroundColor
|
import io.github.wulkanowy.utils.getBackgroundColor
|
||||||
|
import io.github.wulkanowy.utils.getCompatColor
|
||||||
|
|
||||||
class DashboardGradesAdapter : RecyclerView.Adapter<DashboardGradesAdapter.ViewHolder>() {
|
class DashboardGradesAdapter : RecyclerView.Adapter<DashboardGradesAdapter.ViewHolder>() {
|
||||||
|
|
||||||
@ -37,7 +39,9 @@ class DashboardGradesAdapter : RecyclerView.Adapter<DashboardGradesAdapter.ViewH
|
|||||||
|
|
||||||
with(subitemBinding.dashboardSmallGradeSubitemValue) {
|
with(subitemBinding.dashboardSmallGradeSubitemValue) {
|
||||||
text = it.entry
|
text = it.entry
|
||||||
setBackgroundResource(it.getBackgroundColor(gradeColorTheme))
|
backgroundTintList = ColorStateList.valueOf(
|
||||||
|
context.getCompatColor(it.getBackgroundColor(gradeColorTheme))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
dashboardGradesSubitemGradeContainer.addView(subitemBinding.root)
|
dashboardGradesSubitemGradeContainer.addView(subitemBinding.root)
|
||||||
|
@ -1,23 +1,22 @@
|
|||||||
package io.github.wulkanowy.ui.modules.exam
|
package io.github.wulkanowy.ui.modules.exam
|
||||||
|
|
||||||
|
import android.app.Dialog
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
import androidx.fragment.app.DialogFragment
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.db.entities.Exam
|
import io.github.wulkanowy.data.db.entities.Exam
|
||||||
import io.github.wulkanowy.databinding.DialogExamBinding
|
import io.github.wulkanowy.databinding.DialogExamBinding
|
||||||
import io.github.wulkanowy.utils.lifecycleAwareVariable
|
import io.github.wulkanowy.ui.base.BaseDialogFragment
|
||||||
import io.github.wulkanowy.utils.openCalendarEventAdd
|
import io.github.wulkanowy.utils.openCalendarEventAdd
|
||||||
import io.github.wulkanowy.utils.serializable
|
import io.github.wulkanowy.utils.serializable
|
||||||
import io.github.wulkanowy.utils.toFormattedString
|
import io.github.wulkanowy.utils.toFormattedString
|
||||||
import java.time.LocalTime
|
import java.time.LocalTime
|
||||||
|
|
||||||
class ExamDialog : DialogFragment() {
|
@AndroidEntryPoint
|
||||||
|
class ExamDialog : BaseDialogFragment<DialogExamBinding>() {
|
||||||
private var binding: DialogExamBinding by lifecycleAwareVariable()
|
|
||||||
|
|
||||||
private lateinit var exam: Exam
|
private lateinit var exam: Exam
|
||||||
|
|
||||||
@ -32,15 +31,14 @@ class ExamDialog : DialogFragment() {
|
|||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setStyle(STYLE_NO_TITLE, 0)
|
|
||||||
exam = requireArguments().serializable(ARGUMENT_KEY)
|
exam = requireArguments().serializable(ARGUMENT_KEY)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
inflater: LayoutInflater,
|
return MaterialAlertDialogBuilder(requireContext(), theme)
|
||||||
container: ViewGroup?,
|
.setView(DialogExamBinding.inflate(layoutInflater).apply { binding = this }.root)
|
||||||
savedInstanceState: Bundle?
|
.create()
|
||||||
) = DialogExamBinding.inflate(inflater).apply { binding = this }.root
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
@ -2,9 +2,7 @@ package io.github.wulkanowy.ui.modules.exam
|
|||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.View.GONE
|
import android.view.View.*
|
||||||
import android.view.View.INVISIBLE
|
|
||||||
import android.view.View.VISIBLE
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
@ -20,7 +18,7 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class ExamFragment : BaseFragment<FragmentExamBinding>(R.layout.fragment_exam), ExamView,
|
class ExamFragment : BaseFragment<FragmentExamBinding>(R.layout.fragment_exam), ExamView,
|
||||||
MainView.TitledView {
|
MainView.TitledView, MainView.MainChildView {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var presenter: ExamPresenter
|
lateinit var presenter: ExamPresenter
|
||||||
@ -64,7 +62,7 @@ class ExamFragment : BaseFragment<FragmentExamBinding>(R.layout.fragment_exam),
|
|||||||
examPreviousButton.setOnClickListener { presenter.onPreviousWeek() }
|
examPreviousButton.setOnClickListener { presenter.onPreviousWeek() }
|
||||||
examNextButton.setOnClickListener { presenter.onNextWeek() }
|
examNextButton.setOnClickListener { presenter.onNextWeek() }
|
||||||
|
|
||||||
examNavContainer.elevation = requireContext().dpToPx(8f)
|
examNavContainer.elevation = requireContext().dpToPx(3f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,6 +124,14 @@ class ExamFragment : BaseFragment<FragmentExamBinding>(R.layout.fragment_exam),
|
|||||||
(activity as? MainActivity)?.showDialogFragment(ExamDialog.newInstance(exam))
|
(activity as? MainActivity)?.showDialogFragment(ExamDialog.newInstance(exam))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onFragmentReselected() {
|
||||||
|
if (::presenter.isInitialized) presenter.onViewReselected()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun resetView() {
|
||||||
|
binding.examRecycler.smoothScrollToPosition(0)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onSaveInstanceState(outState: Bundle) {
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
super.onSaveInstanceState(outState)
|
super.onSaveInstanceState(outState)
|
||||||
outState.putLong(SAVED_DATE_KEY, presenter.currentDate.toEpochDay())
|
outState.putLong(SAVED_DATE_KEY, presenter.currentDate.toEpochDay())
|
||||||
|
@ -175,4 +175,17 @@ class ExamPresenter @Inject constructor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onViewReselected() {
|
||||||
|
Timber.i("Exam view is reselected")
|
||||||
|
|
||||||
|
baseDate = now().nextOrSameSchoolDay
|
||||||
|
|
||||||
|
if (currentDate != baseDate) {
|
||||||
|
reloadView(baseDate)
|
||||||
|
loadData()
|
||||||
|
} else if (view?.isViewEmpty == false) {
|
||||||
|
view?.resetView()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,4 +34,6 @@ interface ExamView : BaseView {
|
|||||||
fun showPreButton(show: Boolean)
|
fun showPreButton(show: Boolean)
|
||||||
|
|
||||||
fun showExamDialog(exam: Exam)
|
fun showExamDialog(exam: Exam)
|
||||||
|
|
||||||
|
fun resetView()
|
||||||
}
|
}
|
||||||
|
@ -12,50 +12,72 @@ import io.github.wulkanowy.sdk.Sdk
|
|||||||
import io.github.wulkanowy.ui.modules.grade.GradeAverageMode.*
|
import io.github.wulkanowy.ui.modules.grade.GradeAverageMode.*
|
||||||
import io.github.wulkanowy.utils.calcAverage
|
import io.github.wulkanowy.utils.calcAverage
|
||||||
import io.github.wulkanowy.utils.changeModifier
|
import io.github.wulkanowy.utils.changeModifier
|
||||||
import kotlinx.coroutines.FlowPreview
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
|
import kotlinx.coroutines.flow.flatMapLatest
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@OptIn(FlowPreview::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
class GradeAverageProvider @Inject constructor(
|
class GradeAverageProvider @Inject constructor(
|
||||||
private val semesterRepository: SemesterRepository,
|
private val semesterRepository: SemesterRepository,
|
||||||
private val gradeRepository: GradeRepository,
|
private val gradeRepository: GradeRepository,
|
||||||
private val preferencesRepository: PreferencesRepository
|
private val preferencesRepository: PreferencesRepository
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val plusModifier get() = preferencesRepository.gradePlusModifier
|
private data class AverageCalcParams(
|
||||||
|
val gradeAverageMode: GradeAverageMode,
|
||||||
|
val forceAverageCalc: Boolean,
|
||||||
|
val isOptionalArithmeticAverage: Boolean,
|
||||||
|
val plusModifier: Double,
|
||||||
|
val minusModifier: Double,
|
||||||
|
)
|
||||||
|
|
||||||
private val minusModifier get() = preferencesRepository.gradeMinusModifier
|
fun getGradesDetailsWithAverage(
|
||||||
|
student: Student,
|
||||||
private val isOptionalArithmeticAverage get() = preferencesRepository.isOptionalArithmeticAverage
|
semesterId: Int,
|
||||||
|
forceRefresh: Boolean
|
||||||
fun getGradesDetailsWithAverage(student: Student, semesterId: Int, forceRefresh: Boolean) =
|
): Flow<Resource<List<GradeSubject>>> = combine(
|
||||||
|
flow = preferencesRepository.gradeAverageModeFlow,
|
||||||
|
flow2 = preferencesRepository.gradeAverageForceCalcFlow,
|
||||||
|
flow3 = preferencesRepository.isOptionalArithmeticAverageFlow,
|
||||||
|
flow4 = preferencesRepository.gradePlusModifierFlow,
|
||||||
|
flow5 = preferencesRepository.gradeMinusModifierFlow,
|
||||||
|
) { gradeAverageMode, forceAverageCalc, isOptionalArithmeticAverage, plusModifier, minusModifier ->
|
||||||
|
AverageCalcParams(
|
||||||
|
gradeAverageMode = gradeAverageMode,
|
||||||
|
forceAverageCalc = forceAverageCalc,
|
||||||
|
isOptionalArithmeticAverage = isOptionalArithmeticAverage,
|
||||||
|
plusModifier = plusModifier,
|
||||||
|
minusModifier = minusModifier,
|
||||||
|
)
|
||||||
|
}.flatMapLatest { params ->
|
||||||
flatResourceFlow {
|
flatResourceFlow {
|
||||||
val semesters = semesterRepository.getSemesters(student)
|
val semesters = semesterRepository.getSemesters(student)
|
||||||
|
when (params.gradeAverageMode) {
|
||||||
when (preferencesRepository.gradeAverageMode) {
|
|
||||||
ONE_SEMESTER -> getGradeSubjects(
|
ONE_SEMESTER -> getGradeSubjects(
|
||||||
student = student,
|
student = student,
|
||||||
semester = semesters.single { it.semesterId == semesterId },
|
semester = semesters.single { it.semesterId == semesterId },
|
||||||
forceRefresh = forceRefresh
|
forceRefresh = forceRefresh,
|
||||||
|
params = params,
|
||||||
)
|
)
|
||||||
BOTH_SEMESTERS -> calculateCombinedAverage(
|
BOTH_SEMESTERS -> calculateCombinedAverage(
|
||||||
student = student,
|
student = student,
|
||||||
semesters = semesters,
|
semesters = semesters,
|
||||||
semesterId = semesterId,
|
semesterId = semesterId,
|
||||||
forceRefresh = forceRefresh,
|
forceRefresh = forceRefresh,
|
||||||
averageMode = BOTH_SEMESTERS
|
config = params,
|
||||||
)
|
)
|
||||||
ALL_YEAR -> calculateCombinedAverage(
|
ALL_YEAR -> calculateCombinedAverage(
|
||||||
student = student,
|
student = student,
|
||||||
semesters = semesters,
|
semesters = semesters,
|
||||||
semesterId = semesterId,
|
semesterId = semesterId,
|
||||||
forceRefresh = forceRefresh,
|
forceRefresh = forceRefresh,
|
||||||
averageMode = ALL_YEAR
|
config = params,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}.distinctUntilChanged()
|
}.distinctUntilChanged()
|
||||||
|
|
||||||
private fun calculateCombinedAverage(
|
private fun calculateCombinedAverage(
|
||||||
@ -63,19 +85,19 @@ class GradeAverageProvider @Inject constructor(
|
|||||||
semesters: List<Semester>,
|
semesters: List<Semester>,
|
||||||
semesterId: Int,
|
semesterId: Int,
|
||||||
forceRefresh: Boolean,
|
forceRefresh: Boolean,
|
||||||
averageMode: GradeAverageMode
|
config: AverageCalcParams,
|
||||||
): Flow<Resource<List<GradeSubject>>> {
|
): Flow<Resource<List<GradeSubject>>> {
|
||||||
val isGradeAverageForceCalc = preferencesRepository.gradeAverageForceCalc
|
|
||||||
val selectedSemester = semesters.single { it.semesterId == semesterId }
|
val selectedSemester = semesters.single { it.semesterId == semesterId }
|
||||||
val firstSemester =
|
val firstSemester =
|
||||||
semesters.single { it.diaryId == selectedSemester.diaryId && it.semesterName == 1 }
|
semesters.single { it.diaryId == selectedSemester.diaryId && it.semesterName == 1 }
|
||||||
|
|
||||||
val selectedSemesterGradeSubjects =
|
val selectedSemesterGradeSubjects =
|
||||||
getGradeSubjects(student, selectedSemester, forceRefresh)
|
getGradeSubjects(student, selectedSemester, forceRefresh, config)
|
||||||
|
|
||||||
if (selectedSemester == firstSemester) return selectedSemesterGradeSubjects
|
if (selectedSemester == firstSemester) return selectedSemesterGradeSubjects
|
||||||
|
|
||||||
val firstSemesterGradeSubjects = getGradeSubjects(student, firstSemester, forceRefresh)
|
val firstSemesterGradeSubjects =
|
||||||
|
getGradeSubjects(student, firstSemester, forceRefresh, config)
|
||||||
|
|
||||||
return selectedSemesterGradeSubjects.combine(firstSemesterGradeSubjects) { secondSemesterGradeSubject, firstSemesterGradeSubject ->
|
return selectedSemesterGradeSubjects.combine(firstSemesterGradeSubjects) { secondSemesterGradeSubject, firstSemesterGradeSubject ->
|
||||||
if (firstSemesterGradeSubject.errorOrNull != null) {
|
if (firstSemesterGradeSubject.errorOrNull != null) {
|
||||||
@ -91,21 +113,21 @@ class GradeAverageProvider @Inject constructor(
|
|||||||
val firstSemesterSubject = firstSemesterGradeSubject.dataOrNull.orEmpty()
|
val firstSemesterSubject = firstSemesterGradeSubject.dataOrNull.orEmpty()
|
||||||
.singleOrNull { it.subject == secondSemesterSubject.subject }
|
.singleOrNull { it.subject == secondSemesterSubject.subject }
|
||||||
|
|
||||||
val updatedAverage = if (averageMode == ALL_YEAR) {
|
val updatedAverage = if (config.gradeAverageMode == ALL_YEAR) {
|
||||||
calculateAllYearAverage(
|
calculateAllYearAverage(
|
||||||
student = student,
|
student = student,
|
||||||
isAnyVulcanAverage = isAnyVulcanAverageInFirstSemester || isAnyVulcanAverageInSecondSemester,
|
isAnyVulcanAverage = isAnyVulcanAverageInFirstSemester || isAnyVulcanAverageInSecondSemester,
|
||||||
isGradeAverageForceCalc = isGradeAverageForceCalc,
|
|
||||||
secondSemesterSubject = secondSemesterSubject,
|
secondSemesterSubject = secondSemesterSubject,
|
||||||
firstSemesterSubject = firstSemesterSubject
|
firstSemesterSubject = firstSemesterSubject,
|
||||||
|
config = config,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
calculateBothSemestersAverage(
|
calculateBothSemestersAverage(
|
||||||
student = student,
|
student = student,
|
||||||
isAnyVulcanAverage = isAnyVulcanAverageInFirstSemester || isAnyVulcanAverageInSecondSemester,
|
isAnyVulcanAverage = isAnyVulcanAverageInFirstSemester || isAnyVulcanAverageInSecondSemester,
|
||||||
isGradeAverageForceCalc = isGradeAverageForceCalc,
|
|
||||||
secondSemesterSubject = secondSemesterSubject,
|
secondSemesterSubject = secondSemesterSubject,
|
||||||
firstSemesterSubject = firstSemesterSubject
|
firstSemesterSubject = firstSemesterSubject,
|
||||||
|
config = config
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
secondSemesterSubject.copy(average = updatedAverage)
|
secondSemesterSubject.copy(average = updatedAverage)
|
||||||
@ -117,17 +139,17 @@ class GradeAverageProvider @Inject constructor(
|
|||||||
private fun calculateAllYearAverage(
|
private fun calculateAllYearAverage(
|
||||||
student: Student,
|
student: Student,
|
||||||
isAnyVulcanAverage: Boolean,
|
isAnyVulcanAverage: Boolean,
|
||||||
isGradeAverageForceCalc: Boolean,
|
|
||||||
secondSemesterSubject: GradeSubject,
|
secondSemesterSubject: GradeSubject,
|
||||||
firstSemesterSubject: GradeSubject?
|
firstSemesterSubject: GradeSubject?,
|
||||||
) = if (!isAnyVulcanAverage || isGradeAverageForceCalc) {
|
config: AverageCalcParams,
|
||||||
val updatedSecondSemesterGrades =
|
) = if (!isAnyVulcanAverage || config.forceAverageCalc) {
|
||||||
secondSemesterSubject.grades.updateModifiers(student)
|
val updatedSecondSemesterGrades = secondSemesterSubject.grades
|
||||||
val updatedFirstSemesterGrades =
|
.updateModifiers(student, config)
|
||||||
firstSemesterSubject?.grades?.updateModifiers(student).orEmpty()
|
val updatedFirstSemesterGrades = firstSemesterSubject?.grades
|
||||||
|
?.updateModifiers(student, config).orEmpty()
|
||||||
|
|
||||||
(updatedSecondSemesterGrades + updatedFirstSemesterGrades).calcAverage(
|
(updatedSecondSemesterGrades + updatedFirstSemesterGrades).calcAverage(
|
||||||
isOptionalArithmeticAverage
|
config.isOptionalArithmeticAverage
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
secondSemesterSubject.average
|
secondSemesterSubject.average
|
||||||
@ -136,32 +158,35 @@ class GradeAverageProvider @Inject constructor(
|
|||||||
private fun calculateBothSemestersAverage(
|
private fun calculateBothSemestersAverage(
|
||||||
student: Student,
|
student: Student,
|
||||||
isAnyVulcanAverage: Boolean,
|
isAnyVulcanAverage: Boolean,
|
||||||
isGradeAverageForceCalc: Boolean,
|
|
||||||
secondSemesterSubject: GradeSubject,
|
secondSemesterSubject: GradeSubject,
|
||||||
firstSemesterSubject: GradeSubject?
|
firstSemesterSubject: GradeSubject?,
|
||||||
): Double = if (!isAnyVulcanAverage || isGradeAverageForceCalc) {
|
config: AverageCalcParams,
|
||||||
|
): Double {
|
||||||
|
return if (!isAnyVulcanAverage || config.forceAverageCalc) {
|
||||||
val divider = if (secondSemesterSubject.grades.any { it.weightValue > .0 }) 2 else 1
|
val divider = if (secondSemesterSubject.grades.any { it.weightValue > .0 }) 2 else 1
|
||||||
|
val secondSemesterAverage = secondSemesterSubject.grades
|
||||||
val secondSemesterAverage = secondSemesterSubject.grades.updateModifiers(student)
|
.updateModifiers(student, config)
|
||||||
.calcAverage(isOptionalArithmeticAverage)
|
.calcAverage(config.isOptionalArithmeticAverage)
|
||||||
val firstSemesterAverage = firstSemesterSubject?.grades?.updateModifiers(student)
|
val firstSemesterAverage = firstSemesterSubject?.grades
|
||||||
?.calcAverage(isOptionalArithmeticAverage) ?: secondSemesterAverage
|
?.updateModifiers(student, config)
|
||||||
|
?.calcAverage(config.isOptionalArithmeticAverage) ?: secondSemesterAverage
|
||||||
|
|
||||||
(secondSemesterAverage + firstSemesterAverage) / divider
|
(secondSemesterAverage + firstSemesterAverage) / divider
|
||||||
} else {
|
} else {
|
||||||
val divider = if (secondSemesterSubject.average > 0) 2 else 1
|
val divider = if (secondSemesterSubject.average > 0) 2 else 1
|
||||||
|
|
||||||
(secondSemesterSubject.average + (firstSemesterSubject?.average
|
secondSemesterSubject.average.plus(
|
||||||
?: secondSemesterSubject.average)) / divider
|
(firstSemesterSubject?.average ?: secondSemesterSubject.average)
|
||||||
|
) / divider
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getGradeSubjects(
|
private fun getGradeSubjects(
|
||||||
student: Student,
|
student: Student,
|
||||||
semester: Semester,
|
semester: Semester,
|
||||||
forceRefresh: Boolean
|
forceRefresh: Boolean,
|
||||||
|
params: AverageCalcParams,
|
||||||
): Flow<Resource<List<GradeSubject>>> {
|
): Flow<Resource<List<GradeSubject>>> {
|
||||||
val isGradeAverageForceCalc = preferencesRepository.gradeAverageForceCalc
|
|
||||||
|
|
||||||
return gradeRepository.getGrades(student, semester, forceRefresh = forceRefresh)
|
return gradeRepository.getGrades(student, semester, forceRefresh = forceRefresh)
|
||||||
.mapResourceData { res ->
|
.mapResourceData { res ->
|
||||||
val (details, summaries) = res
|
val (details, summaries) = res
|
||||||
@ -172,13 +197,15 @@ class GradeAverageProvider @Inject constructor(
|
|||||||
student = student,
|
student = student,
|
||||||
semester = semester,
|
semester = semester,
|
||||||
grades = allGrades.toList(),
|
grades = allGrades.toList(),
|
||||||
calcAverage = isAnyAverage
|
calcAverage = isAnyAverage,
|
||||||
|
params = params,
|
||||||
).map { summary ->
|
).map { summary ->
|
||||||
val grades = allGrades[summary.subject].orEmpty()
|
val grades = allGrades[summary.subject].orEmpty()
|
||||||
GradeSubject(
|
GradeSubject(
|
||||||
subject = summary.subject,
|
subject = summary.subject,
|
||||||
average = if (!isAnyAverage || isGradeAverageForceCalc) {
|
average = if (!isAnyAverage || params.forceAverageCalc) {
|
||||||
grades.updateModifiers(student).calcAverage(isOptionalArithmeticAverage)
|
grades.updateModifiers(student, params)
|
||||||
|
.calcAverage(params.isOptionalArithmeticAverage)
|
||||||
} else summary.average,
|
} else summary.average,
|
||||||
points = summary.pointsSum,
|
points = summary.pointsSum,
|
||||||
summary = summary,
|
summary = summary,
|
||||||
@ -195,7 +222,8 @@ class GradeAverageProvider @Inject constructor(
|
|||||||
student: Student,
|
student: Student,
|
||||||
semester: Semester,
|
semester: Semester,
|
||||||
grades: List<Pair<String, List<Grade>>>,
|
grades: List<Pair<String, List<Grade>>>,
|
||||||
calcAverage: Boolean
|
calcAverage: Boolean,
|
||||||
|
params: AverageCalcParams,
|
||||||
): List<GradeSummary> {
|
): List<GradeSummary> {
|
||||||
if (isNotEmpty() && size > grades.size) return this
|
if (isNotEmpty() && size > grades.size) return this
|
||||||
|
|
||||||
@ -211,15 +239,16 @@ class GradeAverageProvider @Inject constructor(
|
|||||||
proposedPoints = "",
|
proposedPoints = "",
|
||||||
finalPoints = "",
|
finalPoints = "",
|
||||||
pointsSum = "",
|
pointsSum = "",
|
||||||
average = if (calcAverage) details.updateModifiers(student)
|
average = if (calcAverage) details.updateModifiers(student, params)
|
||||||
.calcAverage(isOptionalArithmeticAverage) else .0
|
.calcAverage(params.isOptionalArithmeticAverage) else .0
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun List<Grade>.updateModifiers(student: Student): List<Grade> {
|
private fun List<Grade>.updateModifiers(
|
||||||
return if (student.loginMode == Sdk.Mode.SCRAPPER.name) {
|
student: Student,
|
||||||
map { it.changeModifier(plusModifier, minusModifier) }
|
params: AverageCalcParams,
|
||||||
|
): List<Grade> = if (student.loginMode == Sdk.Mode.SCRAPPER.name) {
|
||||||
|
map { it.changeModifier(params.plusModifier, params.minusModifier) }
|
||||||
} else this
|
} else this
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@ -8,6 +8,7 @@ import android.view.View
|
|||||||
import android.view.View.INVISIBLE
|
import android.view.View.INVISIBLE
|
||||||
import android.view.View.VISIBLE
|
import android.view.View.VISIBLE
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.google.android.material.tabs.TabLayoutMediator
|
import com.google.android.material.tabs.TabLayoutMediator
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
@ -141,7 +142,7 @@ class GradeFragment : BaseFragment<FragmentGradeBinding>(R.layout.fragment_grade
|
|||||||
val choices = semesters.map { getString(R.string.grade_semester, it.semesterName) }
|
val choices = semesters.map { getString(R.string.grade_semester, it.semesterName) }
|
||||||
.toTypedArray()
|
.toTypedArray()
|
||||||
|
|
||||||
AlertDialog.Builder(requireContext())
|
MaterialAlertDialogBuilder(requireContext())
|
||||||
.setSingleChoiceItems(choices, selectedIndex) { dialog, which ->
|
.setSingleChoiceItems(choices, selectedIndex) { dialog, which ->
|
||||||
presenter.onSemesterSelected(which)
|
presenter.onSemesterSelected(which)
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package io.github.wulkanowy.ui.modules.grade.details
|
package io.github.wulkanowy.ui.modules.grade.details
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.res.ColorStateList
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@ -17,9 +18,10 @@ import io.github.wulkanowy.databinding.HeaderGradeDetailsBinding
|
|||||||
import io.github.wulkanowy.databinding.ItemGradeDetailsBinding
|
import io.github.wulkanowy.databinding.ItemGradeDetailsBinding
|
||||||
import io.github.wulkanowy.ui.base.BaseExpandableAdapter
|
import io.github.wulkanowy.ui.base.BaseExpandableAdapter
|
||||||
import io.github.wulkanowy.utils.getBackgroundColor
|
import io.github.wulkanowy.utils.getBackgroundColor
|
||||||
|
import io.github.wulkanowy.utils.getCompatColor
|
||||||
import io.github.wulkanowy.utils.toFormattedString
|
import io.github.wulkanowy.utils.toFormattedString
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.util.BitSet
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class GradeDetailsAdapter @Inject constructor() : BaseExpandableAdapter<RecyclerView.ViewHolder>() {
|
class GradeDetailsAdapter @Inject constructor() : BaseExpandableAdapter<RecyclerView.ViewHolder>() {
|
||||||
@ -203,7 +205,9 @@ class GradeDetailsAdapter @Inject constructor() : BaseExpandableAdapter<Recycler
|
|||||||
with(holder.binding) {
|
with(holder.binding) {
|
||||||
gradeItemValue.run {
|
gradeItemValue.run {
|
||||||
text = grade.entry
|
text = grade.entry
|
||||||
setBackgroundResource(grade.getBackgroundColor(gradeColorTheme))
|
backgroundTintList = ColorStateList.valueOf(
|
||||||
|
context.getCompatColor(grade.getBackgroundColor(gradeColorTheme))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
gradeItemDescription.text = when {
|
gradeItemDescription.text = when {
|
||||||
grade.description.isNotBlank() -> grade.description
|
grade.description.isNotBlank() -> grade.description
|
||||||
|
@ -1,22 +1,23 @@
|
|||||||
package io.github.wulkanowy.ui.modules.grade.details
|
package io.github.wulkanowy.ui.modules.grade.details
|
||||||
|
|
||||||
|
import android.app.Dialog
|
||||||
|
import android.content.res.ColorStateList
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.View.GONE
|
import android.view.View.GONE
|
||||||
import android.view.ViewGroup
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
import androidx.fragment.app.DialogFragment
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.db.entities.Grade
|
import io.github.wulkanowy.data.db.entities.Grade
|
||||||
import io.github.wulkanowy.data.enums.GradeColorTheme
|
import io.github.wulkanowy.data.enums.GradeColorTheme
|
||||||
import io.github.wulkanowy.databinding.DialogGradeBinding
|
import io.github.wulkanowy.databinding.DialogGradeBinding
|
||||||
|
import io.github.wulkanowy.ui.base.BaseDialogFragment
|
||||||
import io.github.wulkanowy.utils.*
|
import io.github.wulkanowy.utils.*
|
||||||
|
|
||||||
|
@AndroidEntryPoint
|
||||||
class GradeDetailsDialog : DialogFragment() {
|
class GradeDetailsDialog : BaseDialogFragment<DialogGradeBinding>() {
|
||||||
|
|
||||||
private var binding: DialogGradeBinding by lifecycleAwareVariable()
|
|
||||||
|
|
||||||
private lateinit var grade: Grade
|
private lateinit var grade: Grade
|
||||||
|
|
||||||
@ -38,16 +39,15 @@ class GradeDetailsDialog : DialogFragment() {
|
|||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setStyle(STYLE_NO_TITLE, 0)
|
|
||||||
grade = requireArguments().serializable(ARGUMENT_KEY)
|
grade = requireArguments().serializable(ARGUMENT_KEY)
|
||||||
gradeColorTheme = requireArguments().serializable(COLOR_THEME_KEY)
|
gradeColorTheme = requireArguments().serializable(COLOR_THEME_KEY)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
inflater: LayoutInflater,
|
return MaterialAlertDialogBuilder(requireContext(), theme)
|
||||||
container: ViewGroup?,
|
.setView(DialogGradeBinding.inflate(layoutInflater).apply { binding = this }.root)
|
||||||
savedInstanceState: Bundle?
|
.create()
|
||||||
) = DialogGradeBinding.inflate(inflater).apply { binding = this }.root
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
@ -55,10 +55,9 @@ class GradeDetailsDialog : DialogFragment() {
|
|||||||
with(binding) {
|
with(binding) {
|
||||||
gradeDialogSubject.text = grade.subject
|
gradeDialogSubject.text = grade.subject
|
||||||
|
|
||||||
gradeDialogColorAndWeightValue.run {
|
gradeDialogWeightValue.text = grade.weight
|
||||||
text = context.getString(R.string.grade_weight_value, grade.weight)
|
gradeDialogWeightLayout.backgroundTintList =
|
||||||
setBackgroundResource(grade.getGradeColor())
|
ColorStateList.valueOf(requireContext().getCompatColor(grade.getGradeColor()))
|
||||||
}
|
|
||||||
|
|
||||||
gradeDialogDateValue.text = grade.date.toFormattedString()
|
gradeDialogDateValue.text = grade.date.toFormattedString()
|
||||||
gradeDialogColorValue.text = getString(grade.colorStringId)
|
gradeDialogColorValue.text = getString(grade.colorStringId)
|
||||||
@ -72,7 +71,12 @@ class GradeDetailsDialog : DialogFragment() {
|
|||||||
|
|
||||||
gradeDialogValue.run {
|
gradeDialogValue.run {
|
||||||
text = grade.entry
|
text = grade.entry
|
||||||
setBackgroundResource(grade.getBackgroundColor(gradeColorTheme))
|
backgroundTintList = ColorStateList.valueOf(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
requireContext(),
|
||||||
|
grade.getBackgroundColor(gradeColorTheme)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
gradeDialogTeacherValue.text = grade.teacher.ifBlank { getString(R.string.all_no_data) }
|
gradeDialogTeacherValue.text = grade.teacher.ifBlank { getString(R.string.all_no_data) }
|
||||||
|
@ -116,7 +116,9 @@ class GradeStatisticsAdapter @Inject constructor() :
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
binding.gradeStatisticsTypeSwitch.setOnCheckedChangeListener { _, checkedId ->
|
binding.gradeStatisticsTypeSwitch.addOnButtonCheckedListener { _, checkedId, isChecked ->
|
||||||
|
if (!isChecked) return@addOnButtonCheckedListener
|
||||||
|
|
||||||
currentDataType = when (checkedId) {
|
currentDataType = when (checkedId) {
|
||||||
R.id.gradeStatisticsTypePartial -> GradeStatisticsItem.DataType.PARTIAL
|
R.id.gradeStatisticsTypePartial -> GradeStatisticsItem.DataType.PARTIAL
|
||||||
R.id.gradeStatisticsTypeSemester -> GradeStatisticsItem.DataType.SEMESTER
|
R.id.gradeStatisticsTypeSemester -> GradeStatisticsItem.DataType.SEMESTER
|
||||||
|
@ -7,6 +7,7 @@ import android.view.View.INVISIBLE
|
|||||||
import android.view.View.VISIBLE
|
import android.view.View.VISIBLE
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.db.entities.GradeSummary
|
import io.github.wulkanowy.data.db.entities.GradeSummary
|
||||||
@ -118,7 +119,7 @@ class GradeSummaryFragment :
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun showCalculatedAverageHelpDialog() {
|
override fun showCalculatedAverageHelpDialog() {
|
||||||
AlertDialog.Builder(requireContext())
|
MaterialAlertDialogBuilder(requireContext())
|
||||||
.setTitle(R.string.grade_summary_calculated_average_help_dialog_title)
|
.setTitle(R.string.grade_summary_calculated_average_help_dialog_title)
|
||||||
.setMessage(R.string.grade_summary_calculated_average_help_dialog_message)
|
.setMessage(R.string.grade_summary_calculated_average_help_dialog_message)
|
||||||
.setPositiveButton(R.string.all_close) { _, _ -> }
|
.setPositiveButton(R.string.all_close) { _, _ -> }
|
||||||
@ -126,7 +127,7 @@ class GradeSummaryFragment :
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun showFinalAverageHelpDialog() {
|
override fun showFinalAverageHelpDialog() {
|
||||||
AlertDialog.Builder(requireContext())
|
MaterialAlertDialogBuilder(requireContext())
|
||||||
.setTitle(R.string.grade_summary_final_average_help_dialog_title)
|
.setTitle(R.string.grade_summary_final_average_help_dialog_title)
|
||||||
.setMessage(R.string.grade_summary_final_average_help_dialog_message)
|
.setMessage(R.string.grade_summary_final_average_help_dialog_message)
|
||||||
.setPositiveButton(R.string.all_close) { _, _ -> }
|
.setPositiveButton(R.string.all_close) { _, _ -> }
|
||||||
|
@ -21,7 +21,7 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class HomeworkFragment : BaseFragment<FragmentHomeworkBinding>(R.layout.fragment_homework),
|
class HomeworkFragment : BaseFragment<FragmentHomeworkBinding>(R.layout.fragment_homework),
|
||||||
HomeworkView, MainView.TitledView {
|
HomeworkView, MainView.TitledView, MainView.MainChildView {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var presenter: HomeworkPresenter
|
lateinit var presenter: HomeworkPresenter
|
||||||
@ -67,7 +67,7 @@ class HomeworkFragment : BaseFragment<FragmentHomeworkBinding>(R.layout.fragment
|
|||||||
|
|
||||||
openAddHomeworkButton.setOnClickListener { presenter.onHomeworkAddButtonClicked() }
|
openAddHomeworkButton.setOnClickListener { presenter.onHomeworkAddButtonClicked() }
|
||||||
|
|
||||||
homeworkNavContainer.elevation = requireContext().dpToPx(8f)
|
homeworkNavContainer.elevation = requireContext().dpToPx(3f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,6 +133,14 @@ class HomeworkFragment : BaseFragment<FragmentHomeworkBinding>(R.layout.fragment
|
|||||||
(activity as? MainActivity)?.showDialogFragment(HomeworkAddDialog())
|
(activity as? MainActivity)?.showDialogFragment(HomeworkAddDialog())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onFragmentReselected() {
|
||||||
|
if (::presenter.isInitialized) presenter.onViewReselected()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun resetView() {
|
||||||
|
binding.homeworkRecycler.smoothScrollToPosition(0)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onSaveInstanceState(outState: Bundle) {
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
super.onSaveInstanceState(outState)
|
super.onSaveInstanceState(outState)
|
||||||
outState.putLong(SAVED_DATE_KEY, presenter.currentDate.toEpochDay())
|
outState.putLong(SAVED_DATE_KEY, presenter.currentDate.toEpochDay())
|
||||||
|
@ -181,4 +181,17 @@ class HomeworkPresenter @Inject constructor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onViewReselected() {
|
||||||
|
Timber.i("Homework view is reselected")
|
||||||
|
|
||||||
|
baseDate = LocalDate.now().nextOrSameSchoolDay
|
||||||
|
|
||||||
|
if (currentDate != baseDate) {
|
||||||
|
reloadView(baseDate)
|
||||||
|
loadData()
|
||||||
|
} else if (view?.isViewEmpty == false) {
|
||||||
|
view?.resetView()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,4 +36,6 @@ interface HomeworkView : BaseView {
|
|||||||
fun showHomeworkDialog(homework: Homework)
|
fun showHomeworkDialog(homework: Homework)
|
||||||
|
|
||||||
fun showAddHomeworkDialog()
|
fun showAddHomeworkDialog()
|
||||||
|
|
||||||
|
fun resetView()
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package io.github.wulkanowy.ui.modules.homework.add
|
package io.github.wulkanowy.ui.modules.homework.add
|
||||||
|
|
||||||
|
import android.app.Dialog
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.core.widget.doOnTextChanged
|
import androidx.core.widget.doOnTextChanged
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.databinding.DialogHomeworkAddBinding
|
import io.github.wulkanowy.databinding.DialogHomeworkAddBinding
|
||||||
@ -24,17 +24,12 @@ class HomeworkAddDialog : BaseDialogFragment<DialogHomeworkAddBinding>(), Homewo
|
|||||||
//todo: move it to presenter
|
//todo: move it to presenter
|
||||||
private var date: LocalDate? = null
|
private var date: LocalDate? = null
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
super.onCreate(savedInstanceState)
|
return MaterialAlertDialogBuilder(requireContext(), theme)
|
||||||
setStyle(STYLE_NO_TITLE, 0)
|
.setView(DialogHomeworkAddBinding.inflate(layoutInflater).apply { binding = this }.root)
|
||||||
|
.create()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(
|
|
||||||
inflater: LayoutInflater,
|
|
||||||
container: ViewGroup?,
|
|
||||||
savedInstanceState: Bundle?
|
|
||||||
) = DialogHomeworkAddBinding.inflate(inflater).apply { binding = this }.root
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
presenter.onAttachView(this)
|
presenter.onAttachView(this)
|
||||||
|
@ -31,14 +31,8 @@ class HomeworkDetailsAdapter @Inject constructor() :
|
|||||||
attachments = value?.attachments.orEmpty()
|
attachments = value?.attachments.orEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
var isHomeworkFullscreen = false
|
|
||||||
|
|
||||||
var onAttachmentClickListener: (url: String) -> Unit = {}
|
var onAttachmentClickListener: (url: String) -> Unit = {}
|
||||||
|
|
||||||
var onFullScreenClickListener = {}
|
|
||||||
|
|
||||||
var onFullScreenExitClickListener = {}
|
|
||||||
|
|
||||||
var onDeleteClickListener: (homework: Homework) -> Unit = {}
|
var onDeleteClickListener: (homework: Homework) -> Unit = {}
|
||||||
|
|
||||||
override fun getItemCount() = 1 + if (attachments.isNotEmpty()) attachments.size + 1 else 0
|
override fun getItemCount() = 1 + if (attachments.isNotEmpty()) attachments.size + 1 else 0
|
||||||
@ -82,18 +76,6 @@ class HomeworkDetailsAdapter @Inject constructor() :
|
|||||||
homeworkDialogTeacher.text = homework?.teacher.ifNullOrBlank { noDataString }
|
homeworkDialogTeacher.text = homework?.teacher.ifNullOrBlank { noDataString }
|
||||||
homeworkDialogContent.text = homework?.content.ifNullOrBlank { noDataString }
|
homeworkDialogContent.text = homework?.content.ifNullOrBlank { noDataString }
|
||||||
homeworkDialogDelete.visibility = if (homework?.isAddedByUser == true) VISIBLE else GONE
|
homeworkDialogDelete.visibility = if (homework?.isAddedByUser == true) VISIBLE else GONE
|
||||||
homeworkDialogFullScreen.visibility = if (isHomeworkFullscreen) GONE else VISIBLE
|
|
||||||
homeworkDialogFullScreenExit.visibility = if (isHomeworkFullscreen) VISIBLE else GONE
|
|
||||||
homeworkDialogFullScreen.setOnClickListener {
|
|
||||||
homeworkDialogFullScreen.visibility = GONE
|
|
||||||
homeworkDialogFullScreenExit.visibility = VISIBLE
|
|
||||||
onFullScreenClickListener()
|
|
||||||
}
|
|
||||||
homeworkDialogFullScreenExit.setOnClickListener {
|
|
||||||
homeworkDialogFullScreen.visibility = VISIBLE
|
|
||||||
homeworkDialogFullScreenExit.visibility = GONE
|
|
||||||
onFullScreenExitClickListener()
|
|
||||||
}
|
|
||||||
homeworkDialogDelete.setOnClickListener {
|
homeworkDialogDelete.setOnClickListener {
|
||||||
onDeleteClickListener(homework!!)
|
onDeleteClickListener(homework!!)
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
package io.github.wulkanowy.ui.modules.homework.details
|
package io.github.wulkanowy.ui.modules.homework.details
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.Dialog
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
|
|
||||||
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
|
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.db.entities.Homework
|
import io.github.wulkanowy.data.db.entities.Homework
|
||||||
@ -43,15 +41,14 @@ class HomeworkDetailsDialog : BaseDialogFragment<DialogHomeworkBinding>(), Homew
|
|||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setStyle(STYLE_NO_TITLE, 0)
|
|
||||||
homework = requireArguments().serializable(ARGUMENT_KEY)
|
homework = requireArguments().serializable(ARGUMENT_KEY)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
inflater: LayoutInflater,
|
return MaterialAlertDialogBuilder(requireContext(), theme)
|
||||||
container: ViewGroup?,
|
.setView(DialogHomeworkBinding.inflate(layoutInflater).apply { binding = this }.root)
|
||||||
savedInstanceState: Bundle?
|
.create()
|
||||||
) = DialogHomeworkBinding.inflate(inflater).apply { binding = this }.root
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
@ -67,26 +64,11 @@ class HomeworkDetailsDialog : BaseDialogFragment<DialogHomeworkBinding>(), Homew
|
|||||||
homeworkDialogClose.setOnClickListener { dismiss() }
|
homeworkDialogClose.setOnClickListener { dismiss() }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (presenter.isHomeworkFullscreen) {
|
|
||||||
dialog?.window?.setLayout(MATCH_PARENT, MATCH_PARENT)
|
|
||||||
} else {
|
|
||||||
dialog?.window?.setLayout(WRAP_CONTENT, WRAP_CONTENT)
|
|
||||||
}
|
|
||||||
|
|
||||||
with(binding.homeworkDialogRecycler) {
|
with(binding.homeworkDialogRecycler) {
|
||||||
layoutManager = LinearLayoutManager(context)
|
layoutManager = LinearLayoutManager(context)
|
||||||
adapter = detailsAdapter.apply {
|
adapter = detailsAdapter.apply {
|
||||||
onAttachmentClickListener = { context.openInternetBrowser(it, ::showMessage) }
|
onAttachmentClickListener = { context.openInternetBrowser(it, ::showMessage) }
|
||||||
onFullScreenClickListener = {
|
|
||||||
dialog?.window?.setLayout(MATCH_PARENT, MATCH_PARENT)
|
|
||||||
presenter.isHomeworkFullscreen = true
|
|
||||||
}
|
|
||||||
onFullScreenExitClickListener = {
|
|
||||||
dialog?.window?.setLayout(WRAP_CONTENT, WRAP_CONTENT)
|
|
||||||
presenter.isHomeworkFullscreen = false
|
|
||||||
}
|
|
||||||
onDeleteClickListener = { homework -> presenter.deleteHomework(homework) }
|
onDeleteClickListener = { homework -> presenter.deleteHomework(homework) }
|
||||||
isHomeworkFullscreen = presenter.isHomeworkFullscreen
|
|
||||||
homework = this@HomeworkDetailsDialog.homework
|
homework = this@HomeworkDetailsDialog.homework
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ import io.github.wulkanowy.data.logResourceStatus
|
|||||||
import io.github.wulkanowy.data.onResourceError
|
import io.github.wulkanowy.data.onResourceError
|
||||||
import io.github.wulkanowy.data.onResourceSuccess
|
import io.github.wulkanowy.data.onResourceSuccess
|
||||||
import io.github.wulkanowy.data.repositories.HomeworkRepository
|
import io.github.wulkanowy.data.repositories.HomeworkRepository
|
||||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
|
||||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||||
import io.github.wulkanowy.data.resourceFlow
|
import io.github.wulkanowy.data.resourceFlow
|
||||||
import io.github.wulkanowy.ui.base.BasePresenter
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
@ -19,15 +18,8 @@ class HomeworkDetailsPresenter @Inject constructor(
|
|||||||
studentRepository: StudentRepository,
|
studentRepository: StudentRepository,
|
||||||
private val homeworkRepository: HomeworkRepository,
|
private val homeworkRepository: HomeworkRepository,
|
||||||
private val analytics: AnalyticsHelper,
|
private val analytics: AnalyticsHelper,
|
||||||
private val preferencesRepository: PreferencesRepository
|
|
||||||
) : BasePresenter<HomeworkDetailsView>(errorHandler, studentRepository) {
|
) : BasePresenter<HomeworkDetailsView>(errorHandler, studentRepository) {
|
||||||
|
|
||||||
var isHomeworkFullscreen
|
|
||||||
get() = preferencesRepository.isHomeworkFullscreen
|
|
||||||
set(value) {
|
|
||||||
preferencesRepository.isHomeworkFullscreen = value
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onAttachView(view: HomeworkDetailsView) {
|
override fun onAttachView(view: HomeworkDetailsView) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
view.initView()
|
view.initView()
|
||||||
|
@ -4,13 +4,15 @@ import android.content.Context
|
|||||||
import android.database.sqlite.SQLiteConstraintException
|
import android.database.sqlite.SQLiteConstraintException
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.sdk.mobile.exception.InvalidPinException
|
import io.github.wulkanowy.sdk.hebe.exception.InvalidPinException
|
||||||
import io.github.wulkanowy.sdk.mobile.exception.InvalidSymbolException
|
import io.github.wulkanowy.sdk.hebe.exception.InvalidTokenException
|
||||||
import io.github.wulkanowy.sdk.mobile.exception.InvalidTokenException
|
import io.github.wulkanowy.sdk.hebe.exception.TokenDeadException
|
||||||
import io.github.wulkanowy.sdk.mobile.exception.TokenDeadException
|
import io.github.wulkanowy.sdk.hebe.exception.UnknownTokenException
|
||||||
import io.github.wulkanowy.sdk.scrapper.login.BadCredentialsException
|
import io.github.wulkanowy.sdk.scrapper.login.BadCredentialsException
|
||||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
import io.github.wulkanowy.sdk.hebe.exception.InvalidSymbolException as InvalidHebeSymbolException
|
||||||
|
import io.github.wulkanowy.sdk.scrapper.login.InvalidSymbolException as InvalidScrapperSymbolException
|
||||||
|
|
||||||
class LoginErrorHandler @Inject constructor(
|
class LoginErrorHandler @Inject constructor(
|
||||||
@ApplicationContext context: Context,
|
@ApplicationContext context: Context,
|
||||||
@ -32,9 +34,11 @@ class LoginErrorHandler @Inject constructor(
|
|||||||
is BadCredentialsException -> onBadCredentials(error.message)
|
is BadCredentialsException -> onBadCredentials(error.message)
|
||||||
is SQLiteConstraintException -> onStudentDuplicate(resources.getString(R.string.login_duplicate_student))
|
is SQLiteConstraintException -> onStudentDuplicate(resources.getString(R.string.login_duplicate_student))
|
||||||
is TokenDeadException -> onInvalidToken(resources.getString(R.string.login_expired_token))
|
is TokenDeadException -> onInvalidToken(resources.getString(R.string.login_expired_token))
|
||||||
|
is UnknownTokenException,
|
||||||
is InvalidTokenException -> onInvalidToken(resources.getString(R.string.login_invalid_token))
|
is InvalidTokenException -> onInvalidToken(resources.getString(R.string.login_invalid_token))
|
||||||
is InvalidPinException -> onInvalidPin(resources.getString(R.string.login_invalid_pin))
|
is InvalidPinException -> onInvalidPin(resources.getString(R.string.login_invalid_pin))
|
||||||
is InvalidSymbolException -> onInvalidSymbol(resources.getString(R.string.login_invalid_symbol))
|
is InvalidScrapperSymbolException,
|
||||||
|
is InvalidHebeSymbolException -> onInvalidSymbol(resources.getString(R.string.login_invalid_symbol))
|
||||||
else -> super.proceed(error)
|
else -> super.proceed(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,9 +34,9 @@ class LoginAdvancedFragment :
|
|||||||
|
|
||||||
override val formLoginType: String
|
override val formLoginType: String
|
||||||
get() = when (binding.loginTypeSwitch.checkedRadioButtonId) {
|
get() = when (binding.loginTypeSwitch.checkedRadioButtonId) {
|
||||||
R.id.loginTypeApi -> "API"
|
R.id.loginTypeApi -> Sdk.Mode.HEBE.name
|
||||||
R.id.loginTypeScrapper -> "SCRAPPER"
|
R.id.loginTypeScrapper -> Sdk.Mode.SCRAPPER.name
|
||||||
else -> "HYBRID"
|
else -> Sdk.Mode.HYBRID.name
|
||||||
}
|
}
|
||||||
|
|
||||||
override val formUsernameValue: String
|
override val formUsernameValue: String
|
||||||
@ -99,7 +99,7 @@ class LoginAdvancedFragment :
|
|||||||
loginTypeSwitch.setOnCheckedChangeListener { _, checkedId ->
|
loginTypeSwitch.setOnCheckedChangeListener { _, checkedId ->
|
||||||
presenter.onLoginModeSelected(
|
presenter.onLoginModeSelected(
|
||||||
when (checkedId) {
|
when (checkedId) {
|
||||||
R.id.loginTypeApi -> Sdk.Mode.API
|
R.id.loginTypeApi -> Sdk.Mode.HEBE
|
||||||
R.id.loginTypeScrapper -> Sdk.Mode.SCRAPPER
|
R.id.loginTypeScrapper -> Sdk.Mode.SCRAPPER
|
||||||
else -> Sdk.Mode.HYBRID
|
else -> Sdk.Mode.HYBRID
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,12 @@
|
|||||||
package io.github.wulkanowy.ui.modules.login.advanced
|
package io.github.wulkanowy.ui.modules.login.advanced
|
||||||
|
|
||||||
import io.github.wulkanowy.data.Resource
|
import io.github.wulkanowy.data.Resource
|
||||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
|
||||||
import io.github.wulkanowy.data.logResourceStatus
|
import io.github.wulkanowy.data.logResourceStatus
|
||||||
import io.github.wulkanowy.data.onResourceNotLoading
|
import io.github.wulkanowy.data.onResourceNotLoading
|
||||||
import io.github.wulkanowy.data.pojos.RegisterStudent
|
|
||||||
import io.github.wulkanowy.data.pojos.RegisterSymbol
|
|
||||||
import io.github.wulkanowy.data.pojos.RegisterUnit
|
|
||||||
import io.github.wulkanowy.data.pojos.RegisterUser
|
import io.github.wulkanowy.data.pojos.RegisterUser
|
||||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||||
import io.github.wulkanowy.data.resourceFlow
|
import io.github.wulkanowy.data.resourceFlow
|
||||||
import io.github.wulkanowy.sdk.Sdk
|
import io.github.wulkanowy.sdk.Sdk
|
||||||
import io.github.wulkanowy.sdk.scrapper.Scrapper
|
|
||||||
import io.github.wulkanowy.sdk.scrapper.getNormalizedSymbol
|
import io.github.wulkanowy.sdk.scrapper.getNormalizedSymbol
|
||||||
import io.github.wulkanowy.ui.base.BasePresenter
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
import io.github.wulkanowy.ui.modules.login.LoginData
|
import io.github.wulkanowy.ui.modules.login.LoginData
|
||||||
@ -97,14 +92,16 @@ class LoginAdvancedPresenter @Inject constructor(
|
|||||||
fun onLoginModeSelected(type: Sdk.Mode) {
|
fun onLoginModeSelected(type: Sdk.Mode) {
|
||||||
view?.run {
|
view?.run {
|
||||||
when (type) {
|
when (type) {
|
||||||
Sdk.Mode.API -> {
|
Sdk.Mode.HEBE -> {
|
||||||
showOnlyMobileApiModeInputs()
|
showOnlyMobileApiModeInputs()
|
||||||
showMobileApiWarningMessage()
|
showMobileApiWarningMessage()
|
||||||
}
|
}
|
||||||
|
|
||||||
Sdk.Mode.SCRAPPER -> {
|
Sdk.Mode.SCRAPPER -> {
|
||||||
showOnlyScrapperModeInputs()
|
showOnlyScrapperModeInputs()
|
||||||
showScraperWarningMessage()
|
showScraperWarningMessage()
|
||||||
}
|
}
|
||||||
|
|
||||||
Sdk.Mode.HYBRID -> {
|
Sdk.Mode.HYBRID -> {
|
||||||
showOnlyHybridModeInputs()
|
showOnlyHybridModeInputs()
|
||||||
showHybridWarningMessage()
|
showHybridWarningMessage()
|
||||||
@ -145,11 +142,12 @@ class LoginAdvancedPresenter @Inject constructor(
|
|||||||
showProgress(true)
|
showProgress(true)
|
||||||
showContent(false)
|
showContent(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
is Resource.Success -> {
|
is Resource.Success -> {
|
||||||
analytics.logEvent(
|
analytics.logEvent(
|
||||||
"registration_form",
|
"registration_form",
|
||||||
"success" to true,
|
"success" to true,
|
||||||
"students" to it.data.size,
|
"scrapperBaseUrl" to view?.formHostValue.orEmpty(),
|
||||||
"error" to "No error"
|
"error" to "No error"
|
||||||
)
|
)
|
||||||
val loginData = LoginData(
|
val loginData = LoginData(
|
||||||
@ -158,14 +156,15 @@ class LoginAdvancedPresenter @Inject constructor(
|
|||||||
baseUrl = view?.formHostValue.orEmpty().trim(),
|
baseUrl = view?.formHostValue.orEmpty().trim(),
|
||||||
symbol = view?.formSymbolValue.orEmpty().trim().getNormalizedSymbol(),
|
symbol = view?.formSymbolValue.orEmpty().trim().getNormalizedSymbol(),
|
||||||
)
|
)
|
||||||
when (it.data.size) {
|
when (it.data.symbols.size) {
|
||||||
0 -> view?.navigateToSymbol(loginData)
|
0 -> view?.navigateToSymbol(loginData)
|
||||||
else -> view?.navigateToStudentSelect(
|
else -> view?.navigateToStudentSelect(
|
||||||
loginData = loginData,
|
loginData = loginData,
|
||||||
registerUser = it.data.toRegisterUser(loginData),
|
registerUser = it.data,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
is Resource.Error -> {
|
is Resource.Error -> {
|
||||||
analytics.logEvent(
|
analytics.logEvent(
|
||||||
"registration_form",
|
"registration_form",
|
||||||
@ -183,59 +182,7 @@ class LoginAdvancedPresenter @Inject constructor(
|
|||||||
}.launch("login")
|
}.launch("login")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun List<StudentWithSemesters>.toRegisterUser(loginData: LoginData) = RegisterUser(
|
private suspend fun getStudentsAppropriatesToLoginType(): RegisterUser {
|
||||||
email = loginData.login,
|
|
||||||
password = loginData.password,
|
|
||||||
login = loginData.login,
|
|
||||||
baseUrl = loginData.baseUrl,
|
|
||||||
loginType = firstOrNull()?.student?.loginType?.let(
|
|
||||||
Scrapper.LoginType::valueOf
|
|
||||||
) ?: Scrapper.LoginType.AUTO,
|
|
||||||
symbols = this
|
|
||||||
.groupBy { students -> students.student.symbol }
|
|
||||||
.map { (symbol, students) ->
|
|
||||||
RegisterSymbol(
|
|
||||||
symbol = symbol,
|
|
||||||
error = null,
|
|
||||||
userName = "",
|
|
||||||
schools = students
|
|
||||||
.groupBy { student ->
|
|
||||||
Triple(
|
|
||||||
first = student.student.schoolSymbol,
|
|
||||||
second = student.student.userLoginId,
|
|
||||||
third = student.student.schoolShortName
|
|
||||||
)
|
|
||||||
}
|
|
||||||
.map { (groupKey, students) ->
|
|
||||||
val (schoolId, loginId, schoolName) = groupKey
|
|
||||||
RegisterUnit(
|
|
||||||
students = students.map {
|
|
||||||
RegisterStudent(
|
|
||||||
studentId = it.student.studentId,
|
|
||||||
studentName = it.student.studentName,
|
|
||||||
studentSecondName = it.student.studentName,
|
|
||||||
studentSurname = it.student.studentName,
|
|
||||||
className = it.student.className,
|
|
||||||
classId = it.student.classId,
|
|
||||||
isParent = it.student.isParent,
|
|
||||||
semesters = it.semesters,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
userLoginId = loginId,
|
|
||||||
schoolId = schoolId,
|
|
||||||
schoolName = schoolName,
|
|
||||||
schoolShortName = schoolName,
|
|
||||||
parentIds = listOf(),
|
|
||||||
studentIds = listOf(),
|
|
||||||
employeeIds = listOf(),
|
|
||||||
error = null
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
private suspend fun getStudentsAppropriatesToLoginType(): List<StudentWithSemesters> {
|
|
||||||
val email = view?.formUsernameValue.orEmpty()
|
val email = view?.formUsernameValue.orEmpty()
|
||||||
val password = view?.formPassValue.orEmpty()
|
val password = view?.formPassValue.orEmpty()
|
||||||
val endpoint = view?.formHostValue.orEmpty()
|
val endpoint = view?.formHostValue.orEmpty()
|
||||||
@ -245,10 +192,11 @@ class LoginAdvancedPresenter @Inject constructor(
|
|||||||
val token = view?.formTokenValue.orEmpty()
|
val token = view?.formTokenValue.orEmpty()
|
||||||
|
|
||||||
return when (Sdk.Mode.valueOf(view?.formLoginType.orEmpty())) {
|
return when (Sdk.Mode.valueOf(view?.formLoginType.orEmpty())) {
|
||||||
Sdk.Mode.API -> studentRepository.getStudentsApi(pin, symbol, token)
|
Sdk.Mode.HEBE -> studentRepository.getStudentsApi(pin, symbol, token)
|
||||||
Sdk.Mode.SCRAPPER -> studentRepository.getStudentsScrapper(
|
Sdk.Mode.SCRAPPER -> studentRepository.getStudentsScrapper(
|
||||||
email, password, endpoint, symbol
|
email, password, endpoint, symbol
|
||||||
)
|
)
|
||||||
|
|
||||||
Sdk.Mode.HYBRID -> studentRepository.getStudentsHybrid(
|
Sdk.Mode.HYBRID -> studentRepository.getStudentsHybrid(
|
||||||
email, password, endpoint, symbol
|
email, password, endpoint, symbol
|
||||||
)
|
)
|
||||||
@ -267,8 +215,8 @@ class LoginAdvancedPresenter @Inject constructor(
|
|||||||
|
|
||||||
var isCorrect = true
|
var isCorrect = true
|
||||||
|
|
||||||
when (Sdk.Mode.valueOf(view?.formLoginType ?: "")) {
|
when (Sdk.Mode.valueOf(view?.formLoginType.orEmpty())) {
|
||||||
Sdk.Mode.API -> {
|
Sdk.Mode.HEBE -> {
|
||||||
if (pin.isEmpty()) {
|
if (pin.isEmpty()) {
|
||||||
view?.setErrorPinRequired()
|
view?.setErrorPinRequired()
|
||||||
isCorrect = false
|
isCorrect = false
|
||||||
@ -284,17 +232,17 @@ class LoginAdvancedPresenter @Inject constructor(
|
|||||||
isCorrect = false
|
isCorrect = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Sdk.Mode.HYBRID, Sdk.Mode.SCRAPPER -> {
|
Sdk.Mode.HYBRID, Sdk.Mode.SCRAPPER -> {
|
||||||
if (login.isEmpty()) {
|
if (login.isEmpty()) {
|
||||||
view?.setErrorUsernameRequired()
|
view?.setErrorUsernameRequired()
|
||||||
isCorrect = false
|
isCorrect = false
|
||||||
} else {
|
} else {
|
||||||
if ("@" in login && "standard" !in host) {
|
if ("@" in login && "login" in host) {
|
||||||
view?.setErrorLoginRequired()
|
view?.setErrorLoginRequired()
|
||||||
isCorrect = false
|
isCorrect = false
|
||||||
}
|
}
|
||||||
|
if ("@" !in login && "email" in host) {
|
||||||
if ("@" !in login && "standard" in host) {
|
|
||||||
view?.setErrorEmailRequired()
|
view?.setErrorEmailRequired()
|
||||||
isCorrect = false
|
isCorrect = false
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package io.github.wulkanowy.ui.modules.login.advanced
|
package io.github.wulkanowy.ui.modules.login.advanced
|
||||||
|
|
||||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
|
||||||
import io.github.wulkanowy.data.pojos.RegisterUser
|
import io.github.wulkanowy.data.pojos.RegisterUser
|
||||||
import io.github.wulkanowy.ui.base.BaseView
|
import io.github.wulkanowy.ui.base.BaseView
|
||||||
import io.github.wulkanowy.ui.modules.login.LoginData
|
import io.github.wulkanowy.ui.modules.login.LoginData
|
||||||
|
@ -15,12 +15,7 @@ import io.github.wulkanowy.databinding.FragmentLoginFormBinding
|
|||||||
import io.github.wulkanowy.ui.base.BaseFragment
|
import io.github.wulkanowy.ui.base.BaseFragment
|
||||||
import io.github.wulkanowy.ui.modules.login.LoginActivity
|
import io.github.wulkanowy.ui.modules.login.LoginActivity
|
||||||
import io.github.wulkanowy.ui.modules.login.LoginData
|
import io.github.wulkanowy.ui.modules.login.LoginData
|
||||||
import io.github.wulkanowy.utils.AppInfo
|
import io.github.wulkanowy.utils.*
|
||||||
import io.github.wulkanowy.utils.hideSoftInput
|
|
||||||
import io.github.wulkanowy.utils.openEmailClient
|
|
||||||
import io.github.wulkanowy.utils.openInternetBrowser
|
|
||||||
import io.github.wulkanowy.utils.setOnEditorDoneSignIn
|
|
||||||
import io.github.wulkanowy.utils.showSoftInput
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
@ -149,12 +144,14 @@ class LoginFormFragment : BaseFragment<FragmentLoginFormBinding>(R.layout.fragme
|
|||||||
override fun setErrorPassRequired(focus: Boolean) {
|
override fun setErrorPassRequired(focus: Boolean) {
|
||||||
with(binding.loginFormPassLayout) {
|
with(binding.loginFormPassLayout) {
|
||||||
error = getString(R.string.error_field_required)
|
error = getString(R.string.error_field_required)
|
||||||
|
setEndIconTintList(requireContext().getAttrColorStateList(R.attr.colorError))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setErrorPassInvalid(focus: Boolean) {
|
override fun setErrorPassInvalid(focus: Boolean) {
|
||||||
with(binding.loginFormPassLayout) {
|
with(binding.loginFormPassLayout) {
|
||||||
error = getString(R.string.login_invalid_password)
|
error = getString(R.string.login_invalid_password)
|
||||||
|
setEndIconTintList(requireContext().getAttrColorStateList(R.attr.colorError))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,6 +159,7 @@ class LoginFormFragment : BaseFragment<FragmentLoginFormBinding>(R.layout.fragme
|
|||||||
with(binding) {
|
with(binding) {
|
||||||
loginFormUsernameLayout.error = " "
|
loginFormUsernameLayout.error = " "
|
||||||
loginFormPassLayout.error = " "
|
loginFormPassLayout.error = " "
|
||||||
|
loginFormPassLayout.setEndIconTintList(requireContext().getAttrColorStateList(R.attr.colorError))
|
||||||
loginFormHostLayout.error = " "
|
loginFormHostLayout.error = " "
|
||||||
loginFormErrorBox.text = message ?: getString(R.string.login_incorrect_password_default)
|
loginFormErrorBox.text = message ?: getString(R.string.login_incorrect_password_default)
|
||||||
loginFormErrorBox.isVisible = true
|
loginFormErrorBox.isVisible = true
|
||||||
@ -181,6 +179,7 @@ class LoginFormFragment : BaseFragment<FragmentLoginFormBinding>(R.layout.fragme
|
|||||||
|
|
||||||
override fun clearPassError() {
|
override fun clearPassError() {
|
||||||
binding.loginFormPassLayout.error = null
|
binding.loginFormPassLayout.error = null
|
||||||
|
binding.loginFormPassLayout.setEndIconTintList(null)
|
||||||
binding.loginFormErrorBox.isVisible = false
|
binding.loginFormErrorBox.isVisible = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,6 +204,10 @@ class LoginFormFragment : BaseFragment<FragmentLoginFormBinding>(R.layout.fragme
|
|||||||
binding.loginFormContainer.visibility = if (show) VISIBLE else GONE
|
binding.loginFormContainer.visibility = if (show) VISIBLE else GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun showOtherOptionsButton(show: Boolean) {
|
||||||
|
binding.loginFormAdvancedButton.isVisible = show
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
override fun showVersion() {
|
override fun showVersion() {
|
||||||
binding.loginFormVersion.text = "v${appInfo.versionName}"
|
binding.loginFormVersion.text = "v${appInfo.versionName}"
|
||||||
|
@ -7,6 +7,7 @@ import io.github.wulkanowy.ui.base.BasePresenter
|
|||||||
import io.github.wulkanowy.ui.modules.login.LoginData
|
import io.github.wulkanowy.ui.modules.login.LoginData
|
||||||
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
|
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
|
||||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||||
|
import io.github.wulkanowy.utils.AppInfo
|
||||||
import io.github.wulkanowy.utils.ifNullOrBlank
|
import io.github.wulkanowy.utils.ifNullOrBlank
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
@ -15,6 +16,7 @@ import javax.inject.Inject
|
|||||||
class LoginFormPresenter @Inject constructor(
|
class LoginFormPresenter @Inject constructor(
|
||||||
studentRepository: StudentRepository,
|
studentRepository: StudentRepository,
|
||||||
private val loginErrorHandler: LoginErrorHandler,
|
private val loginErrorHandler: LoginErrorHandler,
|
||||||
|
private val appInfo: AppInfo,
|
||||||
private val analytics: AnalyticsHelper
|
private val analytics: AnalyticsHelper
|
||||||
) : BasePresenter<LoginFormView>(loginErrorHandler, studentRepository) {
|
) : BasePresenter<LoginFormView>(loginErrorHandler, studentRepository) {
|
||||||
|
|
||||||
@ -25,6 +27,7 @@ class LoginFormPresenter @Inject constructor(
|
|||||||
view.run {
|
view.run {
|
||||||
initView()
|
initView()
|
||||||
showContact(false)
|
showContact(false)
|
||||||
|
showOtherOptionsButton(appInfo.isDebug)
|
||||||
showVersion()
|
showVersion()
|
||||||
|
|
||||||
loginErrorHandler.onBadCredentials = {
|
loginErrorHandler.onBadCredentials = {
|
||||||
|
@ -56,6 +56,8 @@ interface LoginFormView : BaseView {
|
|||||||
|
|
||||||
fun showContent(show: Boolean)
|
fun showContent(show: Boolean)
|
||||||
|
|
||||||
|
fun showOtherOptionsButton(show: Boolean)
|
||||||
|
|
||||||
fun showVersion()
|
fun showVersion()
|
||||||
|
|
||||||
fun navigateToSymbol(loginData: LoginData)
|
fun navigateToSymbol(loginData: LoginData)
|
||||||
|
@ -55,7 +55,6 @@ class LoginStudentSelectFragment :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
binding = FragmentLoginStudentSelectBinding.bind(view)
|
binding = FragmentLoginStudentSelectBinding.bind(view)
|
||||||
|
@ -18,7 +18,7 @@ import javax.inject.Inject
|
|||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class LuckyNumberFragment :
|
class LuckyNumberFragment :
|
||||||
BaseFragment<FragmentLuckyNumberBinding>(R.layout.fragment_lucky_number), LuckyNumberView,
|
BaseFragment<FragmentLuckyNumberBinding>(R.layout.fragment_lucky_number), LuckyNumberView,
|
||||||
MainView.TitledView {
|
MainView.TitledView, MainView.MainChildView {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var presenter: LuckyNumberPresenter
|
lateinit var presenter: LuckyNumberPresenter
|
||||||
@ -86,6 +86,14 @@ class LuckyNumberFragment :
|
|||||||
(activity as? MainActivity)?.pushView(LuckyNumberHistoryFragment.newInstance())
|
(activity as? MainActivity)?.pushView(LuckyNumberHistoryFragment.newInstance())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onFragmentReselected() {
|
||||||
|
if (::presenter.isInitialized) presenter.onViewReselected()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun popView() {
|
||||||
|
(activity as? MainActivity)?.popView()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
presenter.onDetachView()
|
presenter.onDetachView()
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
|
@ -99,4 +99,9 @@ class LuckyNumberPresenter @Inject constructor(
|
|||||||
fun onDetailsClick() {
|
fun onDetailsClick() {
|
||||||
view?.showErrorDetailsDialog(lastError)
|
view?.showErrorDetailsDialog(lastError)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onViewReselected() {
|
||||||
|
Timber.i("Luckynumber view is reselected")
|
||||||
|
view?.popView()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,4 +26,6 @@ interface LuckyNumberView : BaseView {
|
|||||||
fun showContent(show: Boolean)
|
fun showContent(show: Boolean)
|
||||||
|
|
||||||
fun openLuckyNumberHistory()
|
fun openLuckyNumberHistory()
|
||||||
|
|
||||||
|
fun popView()
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ class LuckyNumberHistoryFragment :
|
|||||||
luckyNumberHistoryPreviousButton.setOnClickListener { presenter.onPreviousWeek() }
|
luckyNumberHistoryPreviousButton.setOnClickListener { presenter.onPreviousWeek() }
|
||||||
luckyNumberHistoryNextButton.setOnClickListener { presenter.onNextWeek() }
|
luckyNumberHistoryNextButton.setOnClickListener { presenter.onNextWeek() }
|
||||||
|
|
||||||
luckyNumberHistoryNavContainer.elevation = requireContext().dpToPx(8f)
|
luckyNumberHistoryNavContainer.elevation = requireContext().dpToPx(3f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,16 +1,12 @@
|
|||||||
package io.github.wulkanowy.ui.modules.luckynumberwidget
|
package io.github.wulkanowy.ui.modules.luckynumberwidget
|
||||||
|
|
||||||
import android.appwidget.AppWidgetManager.ACTION_APPWIDGET_UPDATE
|
import android.appwidget.AppWidgetManager.*
|
||||||
import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID
|
|
||||||
import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_IDS
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.R
|
|
||||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||||
import io.github.wulkanowy.databinding.ActivityWidgetConfigureBinding
|
import io.github.wulkanowy.databinding.ActivityWidgetConfigureBinding
|
||||||
import io.github.wulkanowy.ui.base.BaseActivity
|
import io.github.wulkanowy.ui.base.BaseActivity
|
||||||
@ -41,7 +37,6 @@ class LuckyNumberWidgetConfigureActivity :
|
|||||||
setContentView(
|
setContentView(
|
||||||
ActivityWidgetConfigureBinding.inflate(layoutInflater).apply { binding = this }.root
|
ActivityWidgetConfigureBinding.inflate(layoutInflater).apply { binding = this }.root
|
||||||
)
|
)
|
||||||
|
|
||||||
intent.extras.let {
|
intent.extras.let {
|
||||||
presenter.onAttachView(this, it?.getInt(EXTRA_APPWIDGET_ID))
|
presenter.onAttachView(this, it?.getInt(EXTRA_APPWIDGET_ID))
|
||||||
}
|
}
|
||||||
@ -56,22 +51,6 @@ class LuckyNumberWidgetConfigureActivity :
|
|||||||
configureAdapter.onClickListener = presenter::onItemSelect
|
configureAdapter.onClickListener = presenter::onItemSelect
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showThemeDialog() {
|
|
||||||
var items = arrayOf(
|
|
||||||
getString(R.string.widget_timetable_theme_light),
|
|
||||||
getString(R.string.widget_timetable_theme_dark)
|
|
||||||
)
|
|
||||||
if (appInfo.systemVersion >= Build.VERSION_CODES.Q) items += (getString(R.string.widget_timetable_theme_system))
|
|
||||||
|
|
||||||
dialog = AlertDialog.Builder(this, R.style.WulkanowyTheme_WidgetAccountSwitcher)
|
|
||||||
.setTitle(R.string.widget_timetable_theme_title)
|
|
||||||
.setOnDismissListener { presenter.onDismissThemeView() }
|
|
||||||
.setSingleChoiceItems(items, -1) { _, which ->
|
|
||||||
presenter.onThemeSelect(which)
|
|
||||||
}
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun updateData(data: List<StudentWithSemesters>, selectedStudentId: Long) {
|
override fun updateData(data: List<StudentWithSemesters>, selectedStudentId: Long) {
|
||||||
with(configureAdapter) {
|
with(configureAdapter) {
|
||||||
selectedId = selectedStudentId
|
selectedId = selectedStudentId
|
||||||
|
@ -8,7 +8,6 @@ import io.github.wulkanowy.data.resourceFlow
|
|||||||
import io.github.wulkanowy.ui.base.BasePresenter
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||||
import io.github.wulkanowy.ui.modules.luckynumberwidget.LuckyNumberWidgetProvider.Companion.getStudentWidgetKey
|
import io.github.wulkanowy.ui.modules.luckynumberwidget.LuckyNumberWidgetProvider.Companion.getStudentWidgetKey
|
||||||
import io.github.wulkanowy.ui.modules.luckynumberwidget.LuckyNumberWidgetProvider.Companion.getThemeWidgetKey
|
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -32,20 +31,9 @@ class LuckyNumberWidgetConfigurePresenter @Inject constructor(
|
|||||||
|
|
||||||
fun onItemSelect(student: Student) {
|
fun onItemSelect(student: Student) {
|
||||||
selectedStudent = student
|
selectedStudent = student
|
||||||
view?.showThemeDialog()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onThemeSelect(index: Int) {
|
|
||||||
appWidgetId?.let {
|
|
||||||
sharedPref.putLong(getThemeWidgetKey(it), index.toLong())
|
|
||||||
}
|
|
||||||
registerStudent(selectedStudent)
|
registerStudent(selectedStudent)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onDismissThemeView() {
|
|
||||||
view?.finishView()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun loadData() {
|
private fun loadData() {
|
||||||
resourceFlow { studentRepository.getSavedStudents(false) }.onEach {
|
resourceFlow { studentRepository.getSavedStudents(false) }.onEach {
|
||||||
when (it) {
|
when (it) {
|
||||||
@ -56,10 +44,7 @@ class LuckyNumberWidgetConfigurePresenter @Inject constructor(
|
|||||||
} ?: -1
|
} ?: -1
|
||||||
when {
|
when {
|
||||||
it.data.isEmpty() -> view?.openLoginView()
|
it.data.isEmpty() -> view?.openLoginView()
|
||||||
it.data.size == 1 -> {
|
it.data.size == 1 -> onItemSelect(it.data.single().student)
|
||||||
selectedStudent = it.data.single().student
|
|
||||||
view?.showThemeDialog()
|
|
||||||
}
|
|
||||||
else -> view?.updateData(it.data, selectedStudentId)
|
else -> view?.updateData(it.data, selectedStudentId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,6 @@ interface LuckyNumberWidgetConfigureView : BaseView {
|
|||||||
|
|
||||||
fun initView()
|
fun initView()
|
||||||
|
|
||||||
fun showThemeDialog()
|
|
||||||
|
|
||||||
fun updateData(data: List<StudentWithSemesters>, selectedStudentId: Long)
|
fun updateData(data: List<StudentWithSemesters>, selectedStudentId: Long)
|
||||||
|
|
||||||
fun updateLuckyNumberWidget(widgetId: Int)
|
fun updateLuckyNumberWidget(widgetId: Int)
|
||||||
|
@ -2,14 +2,12 @@ package io.github.wulkanowy.ui.modules.luckynumberwidget
|
|||||||
|
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
import android.appwidget.AppWidgetManager
|
import android.appwidget.AppWidgetManager
|
||||||
import android.appwidget.AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT
|
|
||||||
import android.appwidget.AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH
|
|
||||||
import android.appwidget.AppWidgetProvider
|
import android.appwidget.AppWidgetProvider
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View.GONE
|
import android.util.TypedValue.COMPLEX_UNIT_SP
|
||||||
import android.view.View.VISIBLE
|
import android.view.View
|
||||||
import android.widget.RemoteViews
|
import android.widget.RemoteViews
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
@ -17,7 +15,6 @@ import io.github.wulkanowy.data.Resource
|
|||||||
import io.github.wulkanowy.data.dataOrNull
|
import io.github.wulkanowy.data.dataOrNull
|
||||||
import io.github.wulkanowy.data.db.SharedPrefProvider
|
import io.github.wulkanowy.data.db.SharedPrefProvider
|
||||||
import io.github.wulkanowy.data.db.entities.LuckyNumber
|
import io.github.wulkanowy.data.db.entities.LuckyNumber
|
||||||
import io.github.wulkanowy.data.exceptions.NoCurrentStudentException
|
|
||||||
import io.github.wulkanowy.data.repositories.LuckyNumberRepository
|
import io.github.wulkanowy.data.repositories.LuckyNumberRepository
|
||||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||||
import io.github.wulkanowy.data.toFirstResult
|
import io.github.wulkanowy.data.toFirstResult
|
||||||
@ -41,16 +38,12 @@ class LuckyNumberWidgetProvider : AppWidgetProvider() {
|
|||||||
lateinit var sharedPref: SharedPrefProvider
|
lateinit var sharedPref: SharedPrefProvider
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
private const val LUCKY_NUMBER_WIDGET_MAX_SIZE = 196
|
||||||
|
|
||||||
const val LUCKY_NUMBER_PENDING_INTENT_ID = 200
|
private const val LUCKY_NUMBER_PENDING_INTENT_ID = 300
|
||||||
|
private const val LUCKY_NUMBER_HISTORY_PENDING_INTENT_ID = 301
|
||||||
|
|
||||||
fun getStudentWidgetKey(appWidgetId: Int) = "lucky_number_widget_student_$appWidgetId"
|
fun getStudentWidgetKey(appWidgetId: Int) = "lucky_number_widget_student_$appWidgetId"
|
||||||
|
|
||||||
fun getThemeWidgetKey(appWidgetId: Int) = "lucky_number_widget_theme_$appWidgetId"
|
|
||||||
|
|
||||||
fun getHeightWidgetKey(appWidgetId: Int) = "lucky_number_widget_height_$appWidgetId"
|
|
||||||
|
|
||||||
fun getWidthWidgetKey(appWidgetId: Int) = "lucky_number_widget_width_$appWidgetId"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onUpdate(
|
override fun onUpdate(
|
||||||
@ -59,9 +52,7 @@ class LuckyNumberWidgetProvider : AppWidgetProvider() {
|
|||||||
appWidgetIds: IntArray?
|
appWidgetIds: IntArray?
|
||||||
) {
|
) {
|
||||||
super.onUpdate(context, appWidgetManager, appWidgetIds)
|
super.onUpdate(context, appWidgetManager, appWidgetIds)
|
||||||
appWidgetIds?.forEach { appWidgetId ->
|
|
||||||
val luckyNumber =
|
|
||||||
getLuckyNumber(sharedPref.getLong(getStudentWidgetKey(appWidgetId), 0), appWidgetId)
|
|
||||||
val appIntent = PendingIntent.getActivity(
|
val appIntent = PendingIntent.getActivity(
|
||||||
context,
|
context,
|
||||||
LUCKY_NUMBER_PENDING_INTENT_ID,
|
LUCKY_NUMBER_PENDING_INTENT_ID,
|
||||||
@ -69,96 +60,77 @@ class LuckyNumberWidgetProvider : AppWidgetProvider() {
|
|||||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
|
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
|
||||||
)
|
)
|
||||||
|
|
||||||
if (luckyNumber is Resource.Error) {
|
val historyIntent = PendingIntent.getActivity(
|
||||||
Timber.e("Error loading lucky number for widget", luckyNumber.error)
|
context,
|
||||||
}
|
LUCKY_NUMBER_HISTORY_PENDING_INTENT_ID,
|
||||||
|
SplashActivity.getStartIntent(context, Destination.LuckyNumberHistory),
|
||||||
val remoteView =
|
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
|
||||||
RemoteViews(context.packageName, getCorrectLayoutId(appWidgetId, context))
|
|
||||||
.apply {
|
|
||||||
setTextViewText(
|
|
||||||
R.id.luckyNumberWidgetNumber,
|
|
||||||
luckyNumber.dataOrNull?.luckyNumber?.toString() ?: "#"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
appWidgetIds?.forEach { widgetId ->
|
||||||
|
val studentId = sharedPref.getLong(getStudentWidgetKey(widgetId), 0)
|
||||||
|
val luckyNumberResource = getLuckyNumber(studentId, widgetId)
|
||||||
|
val luckyNumber = luckyNumberResource.dataOrNull?.luckyNumber?.toString()
|
||||||
|
val remoteView = RemoteViews(context.packageName, R.layout.widget_luckynumber)
|
||||||
|
.apply {
|
||||||
|
setTextViewText(R.id.luckyNumberWidgetValue, luckyNumber ?: "-")
|
||||||
setOnClickPendingIntent(R.id.luckyNumberWidgetContainer, appIntent)
|
setOnClickPendingIntent(R.id.luckyNumberWidgetContainer, appIntent)
|
||||||
|
setOnClickPendingIntent(R.id.luckyNumberWidgetHistoryButton, historyIntent)
|
||||||
}
|
}
|
||||||
|
|
||||||
setStyles(remoteView, appWidgetId)
|
resizeWidget(context, appWidgetManager.getAppWidgetOptions(widgetId), remoteView)
|
||||||
appWidgetManager.updateAppWidget(appWidgetId, remoteView)
|
appWidgetManager.updateAppWidget(widgetId, remoteView)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAppWidgetOptionsChanged(
|
||||||
|
context: Context?,
|
||||||
|
appWidgetManager: AppWidgetManager?,
|
||||||
|
appWidgetId: Int,
|
||||||
|
newOptions: Bundle?
|
||||||
|
) {
|
||||||
|
super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions)
|
||||||
|
|
||||||
|
if (context == null || newOptions == null || appWidgetManager == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val remoteView = RemoteViews(context.packageName, R.layout.widget_luckynumber)
|
||||||
|
resizeWidget(context, newOptions, remoteView)
|
||||||
|
appWidgetManager.partiallyUpdateAppWidget(appWidgetId, remoteView)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun resizeWidget(context: Context, options: Bundle, remoteViews: RemoteViews) {
|
||||||
|
val (width, height) = options.getWidgetSize(context)
|
||||||
|
val size = minOf(width, height, LUCKY_NUMBER_WIDGET_MAX_SIZE).toFloat()
|
||||||
|
resizeWidgetContents(size, remoteViews)
|
||||||
|
Timber.v("LuckyNumberWidget resized: ${width}x${height} ($size)")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun resizeWidgetContents(size: Float, remoteViews: RemoteViews) {
|
||||||
|
var historyButtonVisibility = View.VISIBLE
|
||||||
|
var luckyNumberTextSize = 72f
|
||||||
|
|
||||||
|
if (size < 150) {
|
||||||
|
luckyNumberTextSize = 44f
|
||||||
|
historyButtonVisibility = View.GONE
|
||||||
|
}
|
||||||
|
if (size < 75) {
|
||||||
|
luckyNumberTextSize = 26f
|
||||||
|
}
|
||||||
|
|
||||||
|
remoteViews.apply {
|
||||||
|
setTextViewTextSize(R.id.luckyNumberWidgetValue, COMPLEX_UNIT_SP, luckyNumberTextSize)
|
||||||
|
setViewVisibility(R.id.luckyNumberWidgetHistoryButton, historyButtonVisibility)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDeleted(context: Context?, appWidgetIds: IntArray?) {
|
override fun onDeleted(context: Context?, appWidgetIds: IntArray?) {
|
||||||
super.onDeleted(context, appWidgetIds)
|
super.onDeleted(context, appWidgetIds)
|
||||||
appWidgetIds?.forEach { appWidgetId ->
|
appWidgetIds?.forEach { appWidgetId ->
|
||||||
with(sharedPref) {
|
sharedPref.delete(getStudentWidgetKey(appWidgetId))
|
||||||
delete(getHeightWidgetKey(appWidgetId))
|
|
||||||
delete(getStudentWidgetKey(appWidgetId))
|
|
||||||
delete(getThemeWidgetKey(appWidgetId))
|
|
||||||
delete(getWidthWidgetKey(appWidgetId))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun onAppWidgetOptionsChanged(
|
|
||||||
context: Context,
|
|
||||||
appWidgetManager: AppWidgetManager,
|
|
||||||
appWidgetId: Int,
|
|
||||||
newOptions: Bundle?
|
|
||||||
) {
|
|
||||||
super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions)
|
|
||||||
|
|
||||||
val remoteView = RemoteViews(context.packageName, getCorrectLayoutId(appWidgetId, context))
|
|
||||||
|
|
||||||
setStyles(remoteView, appWidgetId, newOptions)
|
|
||||||
appWidgetManager.updateAppWidget(appWidgetId, remoteView)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setStyles(views: RemoteViews, appWidgetId: Int, options: Bundle? = null) {
|
|
||||||
val width = options?.getInt(OPTION_APPWIDGET_MIN_WIDTH) ?: sharedPref.getLong(
|
|
||||||
getWidthWidgetKey(appWidgetId), 74
|
|
||||||
).toInt()
|
|
||||||
val height = options?.getInt(OPTION_APPWIDGET_MAX_HEIGHT) ?: sharedPref.getLong(
|
|
||||||
getHeightWidgetKey(appWidgetId), 74
|
|
||||||
).toInt()
|
|
||||||
|
|
||||||
with(sharedPref) {
|
|
||||||
putLong(getWidthWidgetKey(appWidgetId), width.toLong())
|
|
||||||
putLong(getHeightWidgetKey(appWidgetId), height.toLong())
|
|
||||||
}
|
|
||||||
|
|
||||||
val rows = getCellsForSize(height)
|
|
||||||
val cols = getCellsForSize(width)
|
|
||||||
|
|
||||||
Timber.d("New lucky number widget measurement: %dx%d", width, height)
|
|
||||||
Timber.d("Widget size: $cols x $rows")
|
|
||||||
|
|
||||||
when {
|
|
||||||
1 == cols && 1 == rows -> views.setVisibility(imageTop = false, imageLeft = false)
|
|
||||||
1 == cols && 1 < rows -> views.setVisibility(imageTop = true, imageLeft = false)
|
|
||||||
1 < cols && 1 == rows -> views.setVisibility(imageTop = false, imageLeft = true)
|
|
||||||
1 == cols && 1 == rows -> views.setVisibility(imageTop = true, imageLeft = false)
|
|
||||||
2 == cols && 1 == rows -> views.setVisibility(imageTop = false, imageLeft = true)
|
|
||||||
else -> views.setVisibility(imageTop = false, imageLeft = false, title = true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun RemoteViews.setVisibility(
|
|
||||||
imageTop: Boolean,
|
|
||||||
imageLeft: Boolean,
|
|
||||||
title: Boolean = false
|
|
||||||
) {
|
|
||||||
setViewVisibility(R.id.luckyNumberWidgetImageTop, if (imageTop) VISIBLE else GONE)
|
|
||||||
setViewVisibility(R.id.luckyNumberWidgetImageLeft, if (imageLeft) VISIBLE else GONE)
|
|
||||||
setViewVisibility(R.id.luckyNumberWidgetTitle, if (title) VISIBLE else GONE)
|
|
||||||
setViewVisibility(R.id.luckyNumberWidgetNumber, VISIBLE)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getCellsForSize(size: Int): Int {
|
|
||||||
var n = 2
|
|
||||||
while (74 * n - 30 < size) ++n
|
|
||||||
return n - 1
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getLuckyNumber(studentId: Long, appWidgetId: Int) = runBlocking {
|
private fun getLuckyNumber(studentId: Long, appWidgetId: Int) = runBlocking {
|
||||||
try {
|
try {
|
||||||
@ -181,22 +153,24 @@ class LuckyNumberWidgetProvider : AppWidgetProvider() {
|
|||||||
Resource.Success<LuckyNumber?>(null)
|
Resource.Success<LuckyNumber?>(null)
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
if (e.cause !is NoCurrentStudentException) {
|
|
||||||
Timber.e(e, "An error has occurred in lucky number provider")
|
Timber.e(e, "An error has occurred in lucky number provider")
|
||||||
}
|
|
||||||
Resource.Error(e)
|
Resource.Error(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getCorrectLayoutId(appWidgetId: Int, context: Context): Int {
|
private fun Bundle.getWidgetSize(context: Context): Pair<Int, Int> {
|
||||||
val savedTheme = sharedPref.getLong(getThemeWidgetKey(appWidgetId), 0)
|
val minWidth = getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH)
|
||||||
val isSystemDarkMode =
|
val maxWidth = getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH)
|
||||||
context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES
|
val minHeight = getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT)
|
||||||
|
val maxHeight = getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT)
|
||||||
|
|
||||||
return if (savedTheme == 1L || (savedTheme == 2L && isSystemDarkMode)) {
|
val orientation = context.resources.configuration.orientation
|
||||||
R.layout.widget_luckynumber_dark
|
val isPortrait = orientation == Configuration.ORIENTATION_PORTRAIT
|
||||||
|
|
||||||
|
return if (isPortrait) {
|
||||||
|
minWidth to maxHeight
|
||||||
} else {
|
} else {
|
||||||
R.layout.widget_luckynumber
|
maxWidth to minHeight
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,14 @@ package io.github.wulkanowy.ui.modules.main
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Build.VERSION_CODES.P
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
|
import android.view.ViewGroup.MarginLayoutParams
|
||||||
import androidx.activity.OnBackPressedCallback
|
import androidx.activity.OnBackPressedCallback
|
||||||
import androidx.activity.addCallback
|
import androidx.activity.addCallback
|
||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.*
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.preference.Preference
|
import androidx.preference.Preference
|
||||||
@ -27,6 +27,7 @@ import io.github.wulkanowy.databinding.DialogAdsConsentBinding
|
|||||||
import io.github.wulkanowy.ui.base.BaseActivity
|
import io.github.wulkanowy.ui.base.BaseActivity
|
||||||
import io.github.wulkanowy.ui.modules.Destination
|
import io.github.wulkanowy.ui.modules.Destination
|
||||||
import io.github.wulkanowy.ui.modules.account.accountquick.AccountQuickDialog
|
import io.github.wulkanowy.ui.modules.account.accountquick.AccountQuickDialog
|
||||||
|
import io.github.wulkanowy.ui.modules.settings.appearance.menuorder.AppMenuItem
|
||||||
import io.github.wulkanowy.utils.*
|
import io.github.wulkanowy.utils.*
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
@ -89,8 +90,16 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
|||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(ActivityMainBinding.inflate(layoutInflater).apply { binding = this }.root)
|
setContentView(ActivityMainBinding.inflate(layoutInflater).apply { binding = this }.root)
|
||||||
setSupportActionBar(binding.mainToolbar)
|
setSupportActionBar(binding.mainToolbar)
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
|
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||||
|
binding.mainAppBar.isLifted = true
|
||||||
|
}
|
||||||
|
initializeFragmentContainer()
|
||||||
|
|
||||||
this.savedInstanceState = savedInstanceState
|
this.savedInstanceState = savedInstanceState
|
||||||
messageContainer = binding.mainMessageContainer
|
messageContainer = binding.mainMessageContainer
|
||||||
|
messageAnchor = binding.mainMessageContainer
|
||||||
updateHelper.messageContainer = binding.mainFragmentContainer
|
updateHelper.messageContainer = binding.mainFragmentContainer
|
||||||
onBackCallback = onBackPressedDispatcher.addCallback(this, enabled = false) {
|
onBackCallback = onBackPressedDispatcher.addCallback(this, enabled = false) {
|
||||||
presenter.onBackPressed()
|
presenter.onBackPressed()
|
||||||
@ -124,13 +133,20 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun initView(startMenuIndex: Int, rootDestinations: List<Destination>) {
|
override fun initView(
|
||||||
|
startMenuIndex: Int,
|
||||||
|
rootAppMenuItems: List<AppMenuItem>,
|
||||||
|
rootUpdatedDestinations: List<Destination>
|
||||||
|
) {
|
||||||
initializeToolbar()
|
initializeToolbar()
|
||||||
initializeBottomNavigation(startMenuIndex)
|
initializeBottomNavigation(startMenuIndex, rootAppMenuItems)
|
||||||
initializeNavController(startMenuIndex, rootDestinations)
|
initializeNavController(startMenuIndex, rootUpdatedDestinations)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initializeNavController(startMenuIndex: Int, rootDestinations: List<Destination>) {
|
private fun initializeNavController(
|
||||||
|
startMenuIndex: Int,
|
||||||
|
rootUpdatedDestinations: List<Destination>
|
||||||
|
) {
|
||||||
with(navController) {
|
with(navController) {
|
||||||
setOnViewChangeListener { destinationView ->
|
setOnViewChangeListener { destinationView ->
|
||||||
presenter.onViewChange(destinationView)
|
presenter.onViewChange(destinationView)
|
||||||
@ -140,7 +156,7 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
fragmentHideStrategy = HIDE
|
fragmentHideStrategy = HIDE
|
||||||
rootFragments = rootDestinations.map { it.destinationFragment }
|
rootFragments = rootUpdatedDestinations.map { it.destinationFragment }
|
||||||
|
|
||||||
initialize(startMenuIndex, savedInstanceState)
|
initialize(startMenuIndex, savedInstanceState)
|
||||||
}
|
}
|
||||||
@ -156,17 +172,16 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initializeBottomNavigation(startMenuIndex: Int) {
|
private fun initializeBottomNavigation(
|
||||||
|
startMenuIndex: Int,
|
||||||
|
rootAppMenuItems: List<AppMenuItem>
|
||||||
|
) {
|
||||||
with(binding.mainBottomNav) {
|
with(binding.mainBottomNav) {
|
||||||
with(menu) {
|
with(menu) {
|
||||||
add(Menu.NONE, 0, Menu.NONE, R.string.dashboard_title)
|
rootAppMenuItems.forEachIndexed { index, item ->
|
||||||
.setIcon(R.drawable.ic_main_dashboard)
|
add(Menu.NONE, index, Menu.NONE, item.title)
|
||||||
add(Menu.NONE, 1, Menu.NONE, R.string.grade_title)
|
.setIcon(item.icon)
|
||||||
.setIcon(R.drawable.ic_main_grade)
|
}
|
||||||
add(Menu.NONE, 2, Menu.NONE, R.string.attendance_title)
|
|
||||||
.setIcon(R.drawable.ic_main_attendance)
|
|
||||||
add(Menu.NONE, 3, Menu.NONE, R.string.timetable_title)
|
|
||||||
.setIcon(R.drawable.ic_main_timetable)
|
|
||||||
add(Menu.NONE, 4, Menu.NONE, R.string.more_title)
|
add(Menu.NONE, 4, Menu.NONE, R.string.more_title)
|
||||||
.setIcon(R.drawable.ic_main_more)
|
.setIcon(R.drawable.ic_main_more)
|
||||||
}
|
}
|
||||||
@ -180,6 +195,17 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun initializeFragmentContainer() {
|
||||||
|
ViewCompat.setOnApplyWindowInsetsListener(binding.mainFragmentContainer) { view, insets ->
|
||||||
|
val bottomInsets = insets.getInsets(WindowInsetsCompat.Type.navigationBars())
|
||||||
|
|
||||||
|
view.updateLayoutParams<MarginLayoutParams> {
|
||||||
|
bottomMargin = if (binding.mainBottomNav.isVisible) 0 else bottomInsets.bottom
|
||||||
|
}
|
||||||
|
WindowInsetsCompat.CONSUMED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onPreferenceStartFragment(
|
override fun onPreferenceStartFragment(
|
||||||
caller: PreferenceFragmentCompat,
|
caller: PreferenceFragmentCompat,
|
||||||
pref: Preference
|
pref: Preference
|
||||||
@ -224,20 +250,9 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
|||||||
showDialogFragment(AccountQuickDialog.newInstance(studentWithSemesters))
|
showDialogFragment(AccountQuickDialog.newInstance(studentWithSemesters))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showActionBarElevation(show: Boolean) {
|
|
||||||
ViewCompat.setElevation(binding.mainToolbar, if (show) dpToPx(4f) else 0f)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun showBottomNavigation(show: Boolean) {
|
override fun showBottomNavigation(show: Boolean) {
|
||||||
binding.mainBottomNav.isVisible = show
|
binding.mainBottomNav.isVisible = show
|
||||||
|
binding.mainFragmentContainer.requestApplyInsets()
|
||||||
if (appInfo.systemVersion >= P) {
|
|
||||||
window.navigationBarColor = if (show) {
|
|
||||||
getThemeAttrColor(android.R.attr.navigationBarColor)
|
|
||||||
} else {
|
|
||||||
getThemeAttrColor(R.attr.colorSurface)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun openMoreDestination(destination: Destination) {
|
override fun openMoreDestination(destination: Destination) {
|
||||||
|
@ -14,9 +14,6 @@ import io.github.wulkanowy.ui.base.ErrorHandler
|
|||||||
import io.github.wulkanowy.ui.modules.Destination
|
import io.github.wulkanowy.ui.modules.Destination
|
||||||
import io.github.wulkanowy.ui.modules.account.AccountView
|
import io.github.wulkanowy.ui.modules.account.AccountView
|
||||||
import io.github.wulkanowy.ui.modules.account.accountdetails.AccountDetailsView
|
import io.github.wulkanowy.ui.modules.account.accountdetails.AccountDetailsView
|
||||||
import io.github.wulkanowy.ui.modules.grade.GradeView
|
|
||||||
import io.github.wulkanowy.ui.modules.message.MessageView
|
|
||||||
import io.github.wulkanowy.ui.modules.schoolandteachers.SchoolAndTeachersView
|
|
||||||
import io.github.wulkanowy.ui.modules.studentinfo.StudentInfoView
|
import io.github.wulkanowy.ui.modules.studentinfo.StudentInfoView
|
||||||
import io.github.wulkanowy.utils.AdsHelper
|
import io.github.wulkanowy.utils.AdsHelper
|
||||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||||
@ -42,17 +39,16 @@ class MainPresenter @Inject constructor(
|
|||||||
|
|
||||||
private var studentsWitSemesters: List<StudentWithSemesters>? = null
|
private var studentsWitSemesters: List<StudentWithSemesters>? = null
|
||||||
|
|
||||||
private val rootDestinationTypeList = listOf(
|
private val rootAppMenuItems = preferencesRepository.appMenuItemOrder
|
||||||
Destination.Type.DASHBOARD,
|
.sortedBy { it.order }
|
||||||
Destination.Type.GRADE,
|
.take(4)
|
||||||
Destination.Type.ATTENDANCE,
|
|
||||||
Destination.Type.TIMETABLE,
|
private val rootDestinationTypeList = rootAppMenuItems.map { it.destinationType }
|
||||||
Destination.Type.MORE
|
.plus(Destination.Type.MORE)
|
||||||
)
|
|
||||||
|
|
||||||
private val Destination?.startMenuIndex
|
private val Destination?.startMenuIndex
|
||||||
get() = when {
|
get() = when {
|
||||||
this == null -> preferencesRepository.startMenuIndex
|
this == null -> 0
|
||||||
destinationType in rootDestinationTypeList -> {
|
destinationType in rootDestinationTypeList -> {
|
||||||
rootDestinationTypeList.indexOf(destinationType)
|
rootDestinationTypeList.indexOf(destinationType)
|
||||||
}
|
}
|
||||||
@ -69,7 +65,7 @@ class MainPresenter @Inject constructor(
|
|||||||
if (it == initDestination?.destinationType) initDestination else it.defaultDestination
|
if (it == initDestination?.destinationType) initDestination else it.defaultDestination
|
||||||
}
|
}
|
||||||
|
|
||||||
view.initView(startMenuIndex, destinations)
|
view.initView(startMenuIndex, rootAppMenuItems, destinations)
|
||||||
if (initDestination != null && startMenuIndex == 4) {
|
if (initDestination != null && startMenuIndex == 4) {
|
||||||
view.openMoreDestination(initDestination)
|
view.openMoreDestination(initDestination)
|
||||||
}
|
}
|
||||||
@ -101,7 +97,6 @@ class MainPresenter @Inject constructor(
|
|||||||
fun onViewChange(destinationView: BaseView) {
|
fun onViewChange(destinationView: BaseView) {
|
||||||
view?.apply {
|
view?.apply {
|
||||||
showBottomNavigation(shouldShowBottomNavigation(destinationView))
|
showBottomNavigation(shouldShowBottomNavigation(destinationView))
|
||||||
showActionBarElevation(shouldShowActionBarElevation(destinationView))
|
|
||||||
currentViewTitle?.let { setViewTitle(it) }
|
currentViewTitle?.let { setViewTitle(it) }
|
||||||
currentViewSubtitle?.let { setViewSubTitle(it.ifBlank { null }) }
|
currentViewSubtitle?.let { setViewSubTitle(it.ifBlank { null }) }
|
||||||
currentStackSize?.let {
|
currentStackSize?.let {
|
||||||
@ -111,13 +106,6 @@ class MainPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun shouldShowActionBarElevation(destination: BaseView) = when (destination) {
|
|
||||||
is GradeView,
|
|
||||||
is MessageView,
|
|
||||||
is SchoolAndTeachersView -> false
|
|
||||||
else -> true
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun shouldShowBottomNavigation(destination: BaseView) = when (destination) {
|
private fun shouldShowBottomNavigation(destination: BaseView) = when (destination) {
|
||||||
is AccountView,
|
is AccountView,
|
||||||
is StudentInfoView,
|
is StudentInfoView,
|
||||||
|
@ -4,6 +4,7 @@ import io.github.wulkanowy.data.db.entities.Student
|
|||||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||||
import io.github.wulkanowy.ui.base.BaseView
|
import io.github.wulkanowy.ui.base.BaseView
|
||||||
import io.github.wulkanowy.ui.modules.Destination
|
import io.github.wulkanowy.ui.modules.Destination
|
||||||
|
import io.github.wulkanowy.ui.modules.settings.appearance.menuorder.AppMenuItem
|
||||||
|
|
||||||
interface MainView : BaseView {
|
interface MainView : BaseView {
|
||||||
|
|
||||||
@ -15,7 +16,11 @@ interface MainView : BaseView {
|
|||||||
|
|
||||||
val currentStackSize: Int?
|
val currentStackSize: Int?
|
||||||
|
|
||||||
fun initView(startMenuIndex: Int, rootDestinations: List<Destination>)
|
fun initView(
|
||||||
|
startMenuIndex: Int,
|
||||||
|
rootAppMenuItems: List<AppMenuItem>,
|
||||||
|
rootUpdatedDestinations: List<Destination>
|
||||||
|
)
|
||||||
|
|
||||||
fun switchMenuView(position: Int)
|
fun switchMenuView(position: Int)
|
||||||
|
|
||||||
@ -23,8 +28,6 @@ interface MainView : BaseView {
|
|||||||
|
|
||||||
fun showAccountPicker(studentWithSemesters: List<StudentWithSemesters>)
|
fun showAccountPicker(studentWithSemesters: List<StudentWithSemesters>)
|
||||||
|
|
||||||
fun showActionBarElevation(show: Boolean)
|
|
||||||
|
|
||||||
fun showBottomNavigation(show: Boolean)
|
fun showBottomNavigation(show: Boolean)
|
||||||
|
|
||||||
fun notifyMenuViewReselected()
|
fun notifyMenuViewReselected()
|
||||||
|
@ -15,6 +15,7 @@ import io.github.wulkanowy.data.enums.MessageFolder.*
|
|||||||
import io.github.wulkanowy.databinding.FragmentMessageBinding
|
import io.github.wulkanowy.databinding.FragmentMessageBinding
|
||||||
import io.github.wulkanowy.ui.base.BaseFragment
|
import io.github.wulkanowy.ui.base.BaseFragment
|
||||||
import io.github.wulkanowy.ui.base.BaseFragmentPagerAdapter
|
import io.github.wulkanowy.ui.base.BaseFragmentPagerAdapter
|
||||||
|
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||||
import io.github.wulkanowy.ui.modules.main.MainView
|
import io.github.wulkanowy.ui.modules.main.MainView
|
||||||
import io.github.wulkanowy.ui.modules.message.send.SendMessageActivity
|
import io.github.wulkanowy.ui.modules.message.send.SendMessageActivity
|
||||||
import io.github.wulkanowy.ui.modules.message.tab.MessageTabFragment
|
import io.github.wulkanowy.ui.modules.message.tab.MessageTabFragment
|
||||||
@ -24,7 +25,7 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class MessageFragment : BaseFragment<FragmentMessageBinding>(R.layout.fragment_message),
|
class MessageFragment : BaseFragment<FragmentMessageBinding>(R.layout.fragment_message),
|
||||||
MessageView, MainView.TitledView {
|
MessageView, MainView.TitledView, MainView.MainChildView {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var presenter: MessagePresenter
|
lateinit var presenter: MessagePresenter
|
||||||
@ -123,8 +124,12 @@ class MessageFragment : BaseFragment<FragmentMessageBinding>(R.layout.fragment_m
|
|||||||
presenter.onChildViewShowNewMessage(show)
|
presenter.onChildViewShowNewMessage(show)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onFragmentChanged() {
|
override fun onFragmentReselected() {
|
||||||
presenter.onFragmentChanged()
|
if (::presenter.isInitialized) presenter.onFragmentReselected()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFragmentChanged() {
|
||||||
|
if (::presenter.isInitialized) presenter.onFragmentChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun notifyChildLoadData(index: Int, forceRefresh: Boolean) {
|
override fun notifyChildLoadData(index: Int, forceRefresh: Boolean) {
|
||||||
@ -139,10 +144,19 @@ class MessageFragment : BaseFragment<FragmentMessageBinding>(R.layout.fragment_m
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun notifyChildParentReselected(index: Int) {
|
||||||
|
(pagerAdapter.getFragmentInstance(index) as? MessageTabFragment)
|
||||||
|
?.onParentReselected()
|
||||||
|
}
|
||||||
|
|
||||||
override fun openSendMessage() {
|
override fun openSendMessage() {
|
||||||
context?.let { it.startActivity(SendMessageActivity.getStartIntent(it)) }
|
context?.let { it.startActivity(SendMessageActivity.getStartIntent(it)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun popView() {
|
||||||
|
(activity as? MainActivity)?.popView()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
presenter.onDetachView()
|
presenter.onDetachView()
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
|
@ -39,6 +39,14 @@ class MessagePresenter @Inject constructor(
|
|||||||
view?.notifyChildrenFinishActionMode()
|
view?.notifyChildrenFinishActionMode()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onFragmentReselected() {
|
||||||
|
Timber.i("Message view is reselected")
|
||||||
|
view?.run {
|
||||||
|
popView()
|
||||||
|
notifyChildParentReselected(currentPageIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun onChildViewLoaded() {
|
fun onChildViewLoaded() {
|
||||||
view?.apply {
|
view?.apply {
|
||||||
showContent(true)
|
showContent(true)
|
||||||
|
@ -20,5 +20,9 @@ interface MessageView : BaseView {
|
|||||||
|
|
||||||
fun notifyChildrenFinishActionMode()
|
fun notifyChildrenFinishActionMode()
|
||||||
|
|
||||||
|
fun notifyChildParentReselected(index: Int)
|
||||||
|
|
||||||
fun openSendMessage()
|
fun openSendMessage()
|
||||||
|
|
||||||
|
fun popView()
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
package io.github.wulkanowy.ui.modules.message.mailboxchooser
|
package io.github.wulkanowy.ui.modules.message.mailboxchooser
|
||||||
|
|
||||||
|
import android.app.Dialog
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
import androidx.fragment.app.setFragmentResult
|
import androidx.fragment.app.setFragmentResult
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.data.db.entities.Mailbox
|
import io.github.wulkanowy.data.db.entities.Mailbox
|
||||||
import io.github.wulkanowy.databinding.DialogMailboxChooserBinding
|
import io.github.wulkanowy.databinding.DialogMailboxChooserBinding
|
||||||
@ -37,19 +37,19 @@ class MailboxChooserDialog : BaseDialogFragment<DialogMailboxChooserBinding>(),
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
setStyle(STYLE_NO_TITLE, 0)
|
return MaterialAlertDialogBuilder(requireContext(), theme)
|
||||||
|
.setView(
|
||||||
|
DialogMailboxChooserBinding.inflate(layoutInflater).apply { binding = this }.root
|
||||||
|
)
|
||||||
|
.create()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(
|
|
||||||
inflater: LayoutInflater,
|
|
||||||
container: ViewGroup?,
|
|
||||||
savedInstanceState: Bundle?
|
|
||||||
) = DialogMailboxChooserBinding.inflate(inflater).apply { binding = this }.root
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
presenter.onAttachView(
|
presenter.onAttachView(
|
||||||
view = this,
|
view = this,
|
||||||
requireMailbox = requireArguments().getBoolean(REQUIRED_KEY, false),
|
requireMailbox = requireArguments().getBoolean(REQUIRED_KEY, false),
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package io.github.wulkanowy.ui.modules.message.send
|
package io.github.wulkanowy.ui.modules.message.send
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.AlertDialog
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.Rect
|
import android.graphics.Rect
|
||||||
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.Spanned
|
import android.text.Spanned
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
@ -12,11 +12,14 @@ import android.view.MenuItem
|
|||||||
import android.view.TouchDelegate
|
import android.view.TouchDelegate
|
||||||
import android.view.View.GONE
|
import android.view.View.GONE
|
||||||
import android.view.View.VISIBLE
|
import android.view.View.VISIBLE
|
||||||
|
import android.view.ViewGroup
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import android.widget.Toast.LENGTH_LONG
|
import android.widget.Toast.LENGTH_LONG
|
||||||
import androidx.core.text.parseAsHtml
|
import androidx.core.text.parseAsHtml
|
||||||
import androidx.core.text.toHtml
|
import androidx.core.text.toHtml
|
||||||
|
import androidx.core.view.*
|
||||||
import androidx.core.widget.doOnTextChanged
|
import androidx.core.widget.doOnTextChanged
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.db.entities.Mailbox
|
import io.github.wulkanowy.data.db.entities.Mailbox
|
||||||
@ -24,8 +27,8 @@ import io.github.wulkanowy.data.db.entities.Message
|
|||||||
import io.github.wulkanowy.databinding.ActivitySendMessageBinding
|
import io.github.wulkanowy.databinding.ActivitySendMessageBinding
|
||||||
import io.github.wulkanowy.ui.base.BaseActivity
|
import io.github.wulkanowy.ui.base.BaseActivity
|
||||||
import io.github.wulkanowy.ui.modules.message.mailboxchooser.MailboxChooserDialog
|
import io.github.wulkanowy.ui.modules.message.mailboxchooser.MailboxChooserDialog
|
||||||
import io.github.wulkanowy.ui.modules.message.mailboxchooser.MailboxChooserDialog.Companion.MAILBOX_KEY
|
|
||||||
import io.github.wulkanowy.ui.modules.message.mailboxchooser.MailboxChooserDialog.Companion.LISTENER_KEY
|
import io.github.wulkanowy.ui.modules.message.mailboxchooser.MailboxChooserDialog.Companion.LISTENER_KEY
|
||||||
|
import io.github.wulkanowy.ui.modules.message.mailboxchooser.MailboxChooserDialog.Companion.MAILBOX_KEY
|
||||||
import io.github.wulkanowy.utils.dpToPx
|
import io.github.wulkanowy.utils.dpToPx
|
||||||
import io.github.wulkanowy.utils.hideSoftInput
|
import io.github.wulkanowy.utils.hideSoftInput
|
||||||
import io.github.wulkanowy.utils.nullableSerializable
|
import io.github.wulkanowy.utils.nullableSerializable
|
||||||
@ -99,6 +102,13 @@ class SendMessageActivity : BaseActivity<SendMessagePresenter, ActivitySendMessa
|
|||||||
)
|
)
|
||||||
setSupportActionBar(binding.sendMessageToolbar)
|
setSupportActionBar(binding.sendMessageToolbar)
|
||||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
|
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||||
|
binding.sendAppBar.isLifted = true
|
||||||
|
}
|
||||||
|
initializeMessageContainer()
|
||||||
|
|
||||||
messageContainer = binding.sendMessageContainer
|
messageContainer = binding.sendMessageContainer
|
||||||
|
|
||||||
formRecipientsData = binding.sendMessageTo.addedChipItems as List<RecipientChipItem>
|
formRecipientsData = binding.sendMessageTo.addedChipItems as List<RecipientChipItem>
|
||||||
@ -130,6 +140,17 @@ class SendMessageActivity : BaseActivity<SendMessagePresenter, ActivitySendMessa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun initializeMessageContainer() {
|
||||||
|
ViewCompat.setOnApplyWindowInsetsListener(binding.sendMessageScroll) { view, insets ->
|
||||||
|
val bottomInsets = insets.getInsets(WindowInsetsCompat.Type.navigationBars())
|
||||||
|
|
||||||
|
view.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||||
|
bottomMargin = bottomInsets.bottom
|
||||||
|
}
|
||||||
|
WindowInsetsCompat.CONSUMED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun onMessageSubjectChange(text: CharSequence?) {
|
private fun onMessageSubjectChange(text: CharSequence?) {
|
||||||
formSubjectValue = text.toString()
|
formSubjectValue = text.toString()
|
||||||
presenter.onMessageContentChange()
|
presenter.onMessageContentChange()
|
||||||
@ -252,7 +273,7 @@ class SendMessageActivity : BaseActivity<SendMessagePresenter, ActivitySendMessa
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun showMessageBackupDialog() {
|
override fun showMessageBackupDialog() {
|
||||||
AlertDialog.Builder(this)
|
MaterialAlertDialogBuilder(this)
|
||||||
.setTitle(R.string.message_title)
|
.setTitle(R.string.message_title)
|
||||||
.setMessage(presenter.getMessageBackupContent(presenter.getRecipientsNames()))
|
.setMessage(presenter.getMessageBackupContent(presenter.getRecipientsNames()))
|
||||||
.setPositiveButton(R.string.all_yes) { _, _ -> presenter.restoreMessageParts() }
|
.setPositiveButton(R.string.all_yes) { _, _ -> presenter.restoreMessageParts() }
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package io.github.wulkanowy.ui.modules.message.tab
|
package io.github.wulkanowy.ui.modules.message.tab
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.content.res.ColorStateList
|
import android.content.res.ColorStateList
|
||||||
import android.graphics.Typeface
|
import android.graphics.Typeface
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
@ -68,21 +69,23 @@ class MessageTabAdapter @Inject constructor() :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("PrivateResource")
|
||||||
private fun bindHeaderViewHolder(holder: HeaderViewHolder, position: Int) {
|
private fun bindHeaderViewHolder(holder: HeaderViewHolder, position: Int) {
|
||||||
val item = items[position] as MessageTabDataItem.FilterHeader
|
val item = items[position] as MessageTabDataItem.FilterHeader
|
||||||
|
val context = holder.binding.root.context
|
||||||
|
|
||||||
with(holder.binding) {
|
with(holder.binding) {
|
||||||
chipMailbox.text = item.selectedMailbox
|
chipMailbox.text =
|
||||||
?: root.context.getString(R.string.message_chip_all_mailboxes)
|
item.selectedMailbox ?: context.getString(R.string.message_chip_all_mailboxes)
|
||||||
chipMailbox.chipBackgroundColor = ColorStateList.valueOf(
|
chipMailbox.chipBackgroundColor = ColorStateList.valueOf(
|
||||||
if (item.selectedMailbox == null) {
|
if (item.selectedMailbox == null) {
|
||||||
root.context.getCompatColor(R.color.mtrl_choice_chip_background_color)
|
context.getCompatColor(R.color.m3_elevated_chip_background_color)
|
||||||
} else root.context.getThemeAttrColor(android.R.attr.colorPrimary, 64)
|
} else context.getThemeAttrColor(R.attr.colorPrimary, 64)
|
||||||
)
|
)
|
||||||
chipMailbox.setTextColor(
|
chipMailbox.setTextColor(
|
||||||
if (item.selectedMailbox == null) {
|
if (item.selectedMailbox == null) {
|
||||||
root.context.getThemeAttrColor(android.R.attr.textColorPrimary)
|
context.getThemeAttrColor(R.attr.colorOnSurfaceVariant)
|
||||||
} else root.context.getThemeAttrColor(android.R.attr.colorPrimary)
|
} else context.getThemeAttrColor(R.attr.colorPrimary)
|
||||||
)
|
)
|
||||||
chipMailbox.setOnClickListener { onMailboxClickListener() }
|
chipMailbox.setOnClickListener { onMailboxClickListener() }
|
||||||
|
|
||||||
|
@ -235,6 +235,10 @@ class MessageTabFragment : BaseFragment<FragmentMessageTabBinding>(R.layout.frag
|
|||||||
presenter.onParentFinishActionMode()
|
presenter.onParentFinishActionMode()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onParentReselected() {
|
||||||
|
presenter.onParentReselected()
|
||||||
|
}
|
||||||
|
|
||||||
private fun onChipChecked(chip: CompoundButton, isChecked: Boolean) {
|
private fun onChipChecked(chip: CompoundButton, isChecked: Boolean) {
|
||||||
when (chip.id) {
|
when (chip.id) {
|
||||||
R.id.chip_unread -> presenter.onUnreadFilterSelected(isChecked)
|
R.id.chip_unread -> presenter.onUnreadFilterSelected(isChecked)
|
||||||
|
@ -83,6 +83,14 @@ class MessageTabPresenter @Inject constructor(
|
|||||||
view?.showActionMode(false)
|
view?.showActionMode(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onParentReselected() {
|
||||||
|
view?.run {
|
||||||
|
if (!isViewEmpty) {
|
||||||
|
resetListPosition()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun onDestroyActionMode() {
|
fun onDestroyActionMode() {
|
||||||
isActionMode = false
|
isActionMode = false
|
||||||
messagesToDelete.clear()
|
messagesToDelete.clear()
|
||||||
|
@ -22,7 +22,7 @@ import javax.inject.Inject
|
|||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class MobileDeviceFragment :
|
class MobileDeviceFragment :
|
||||||
BaseFragment<FragmentMobileDeviceBinding>(R.layout.fragment_mobile_device), MobileDeviceView,
|
BaseFragment<FragmentMobileDeviceBinding>(R.layout.fragment_mobile_device), MobileDeviceView,
|
||||||
MainView.TitledView {
|
MainView.TitledView, MainView.MainChildView {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var presenter: MobileDevicePresenter
|
lateinit var presenter: MobileDevicePresenter
|
||||||
@ -135,6 +135,14 @@ class MobileDeviceFragment :
|
|||||||
(activity as? MainActivity)?.showDialogFragment(MobileDeviceTokenDialog.newInstance())
|
(activity as? MainActivity)?.showDialogFragment(MobileDeviceTokenDialog.newInstance())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onFragmentReselected() {
|
||||||
|
if (::presenter.isInitialized) presenter.onFragmentReselected()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun resetView() {
|
||||||
|
binding.mobileDevicesRecycler.smoothScrollToPosition(0)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
presenter.onDetachView()
|
presenter.onDetachView()
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
|
@ -129,4 +129,10 @@ class MobileDevicePresenter @Inject constructor(
|
|||||||
.onResourceError(errorHandler::dispatch)
|
.onResourceError(errorHandler::dispatch)
|
||||||
.launch("unregister")
|
.launch("unregister")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onFragmentReselected() {
|
||||||
|
if (view?.isViewEmpty == false) {
|
||||||
|
view?.resetView()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,4 +32,6 @@ interface MobileDeviceView : BaseView {
|
|||||||
fun setErrorDetails(message: String)
|
fun setErrorDetails(message: String)
|
||||||
|
|
||||||
fun showTokenDialog()
|
fun showTokenDialog()
|
||||||
|
|
||||||
|
fun resetView()
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
package io.github.wulkanowy.ui.modules.mobiledevice.token
|
package io.github.wulkanowy.ui.modules.mobiledevice.token
|
||||||
|
|
||||||
|
import android.app.Dialog
|
||||||
import android.content.ClipData
|
import android.content.ClipData
|
||||||
import android.content.ClipboardManager
|
import android.content.ClipboardManager
|
||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Base64
|
import android.util.Base64
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.View.GONE
|
import android.view.View.GONE
|
||||||
import android.view.View.VISIBLE
|
import android.view.View.VISIBLE
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.pojos.MobileDeviceToken
|
import io.github.wulkanowy.data.pojos.MobileDeviceToken
|
||||||
@ -31,17 +31,14 @@ class MobileDeviceTokenDialog : BaseDialogFragment<DialogMobileDeviceBinding>(),
|
|||||||
fun newInstance() = MobileDeviceTokenDialog()
|
fun newInstance() = MobileDeviceTokenDialog()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
super.onCreate(savedInstanceState)
|
return MaterialAlertDialogBuilder(requireContext(), theme)
|
||||||
setStyle(STYLE_NO_TITLE, 0)
|
.setView(
|
||||||
|
DialogMobileDeviceBinding.inflate(layoutInflater).apply { binding = this }.root
|
||||||
|
)
|
||||||
|
.create()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(
|
|
||||||
inflater: LayoutInflater,
|
|
||||||
container: ViewGroup?,
|
|
||||||
savedInstanceState: Bundle?
|
|
||||||
) = DialogMobileDeviceBinding.inflate(inflater).apply { binding = this }.root
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
presenter.onAttachView(this)
|
presenter.onAttachView(this)
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package io.github.wulkanowy.ui.modules.more
|
package io.github.wulkanowy.ui.modules.more
|
||||||
|
|
||||||
import android.graphics.drawable.Drawable
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
@ -9,9 +8,9 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
class MoreAdapter @Inject constructor() : RecyclerView.Adapter<MoreAdapter.ItemViewHolder>() {
|
class MoreAdapter @Inject constructor() : RecyclerView.Adapter<MoreAdapter.ItemViewHolder>() {
|
||||||
|
|
||||||
var items = emptyList<Pair<String, Drawable?>>()
|
var items = emptyList<MoreItem>()
|
||||||
|
|
||||||
var onClickListener: (name: String) -> Unit = {}
|
var onClickListener: (moreItem: MoreItem) -> Unit = {}
|
||||||
|
|
||||||
override fun getItemCount() = items.size
|
override fun getItemCount() = items.size
|
||||||
|
|
||||||
@ -20,13 +19,14 @@ class MoreAdapter @Inject constructor() : RecyclerView.Adapter<MoreAdapter.ItemV
|
|||||||
)
|
)
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
|
||||||
val (title, drawable) = items[position]
|
val item = items[position]
|
||||||
|
val context = holder.binding.root.context
|
||||||
|
|
||||||
with(holder.binding) {
|
with(holder.binding) {
|
||||||
moreItemTitle.text = title
|
moreItemTitle.text = context.getString(item.title)
|
||||||
moreItemImage.setImageDrawable(drawable)
|
moreItemImage.setImageResource(item.icon)
|
||||||
|
|
||||||
root.setOnClickListener { onClickListener(title) }
|
root.setOnClickListener { onClickListener(item) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package io.github.wulkanowy.ui.modules.more
|
package io.github.wulkanowy.ui.modules.more
|
||||||
|
|
||||||
import android.graphics.drawable.Drawable
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
@ -8,19 +7,10 @@ import dagger.hilt.android.AndroidEntryPoint
|
|||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.databinding.FragmentMoreBinding
|
import io.github.wulkanowy.databinding.FragmentMoreBinding
|
||||||
import io.github.wulkanowy.ui.base.BaseFragment
|
import io.github.wulkanowy.ui.base.BaseFragment
|
||||||
import io.github.wulkanowy.ui.modules.conference.ConferenceFragment
|
import io.github.wulkanowy.ui.modules.Destination
|
||||||
import io.github.wulkanowy.ui.modules.exam.ExamFragment
|
|
||||||
import io.github.wulkanowy.ui.modules.homework.HomeworkFragment
|
|
||||||
import io.github.wulkanowy.ui.modules.luckynumber.LuckyNumberFragment
|
|
||||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||||
import io.github.wulkanowy.ui.modules.main.MainView
|
import io.github.wulkanowy.ui.modules.main.MainView
|
||||||
import io.github.wulkanowy.ui.modules.message.MessageFragment
|
import io.github.wulkanowy.ui.modules.message.MessageFragment
|
||||||
import io.github.wulkanowy.ui.modules.mobiledevice.MobileDeviceFragment
|
|
||||||
import io.github.wulkanowy.ui.modules.note.NoteFragment
|
|
||||||
import io.github.wulkanowy.ui.modules.schoolandteachers.SchoolAndTeachersFragment
|
|
||||||
import io.github.wulkanowy.ui.modules.schoolannouncement.SchoolAnnouncementFragment
|
|
||||||
import io.github.wulkanowy.ui.modules.settings.SettingsFragment
|
|
||||||
import io.github.wulkanowy.utils.getCompatDrawable
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
@ -40,36 +30,6 @@ class MoreFragment : BaseFragment<FragmentMoreBinding>(R.layout.fragment_more),
|
|||||||
override val titleStringId: Int
|
override val titleStringId: Int
|
||||||
get() = R.string.more_title
|
get() = R.string.more_title
|
||||||
|
|
||||||
override val messagesRes: Pair<String, Drawable?>?
|
|
||||||
get() = context?.run { getString(R.string.message_title) to getCompatDrawable(R.drawable.ic_more_messages) }
|
|
||||||
|
|
||||||
override val homeworkRes: Pair<String, Drawable?>?
|
|
||||||
get() = context?.run { getString(R.string.homework_title) to getCompatDrawable(R.drawable.ic_more_homework) }
|
|
||||||
|
|
||||||
override val noteRes: Pair<String, Drawable?>?
|
|
||||||
get() = context?.run { getString(R.string.note_title) to getCompatDrawable(R.drawable.ic_more_note) }
|
|
||||||
|
|
||||||
override val conferencesRes: Pair<String, Drawable?>?
|
|
||||||
get() = context?.run { getString(R.string.conferences_title) to getCompatDrawable(R.drawable.ic_more_conferences) }
|
|
||||||
|
|
||||||
override val schoolAnnouncementRes: Pair<String, Drawable?>?
|
|
||||||
get() = context?.run { getString(R.string.school_announcement_title) to getCompatDrawable(R.drawable.ic_all_about) }
|
|
||||||
|
|
||||||
override val schoolAndTeachersRes: Pair<String, Drawable?>?
|
|
||||||
get() = context?.run { getString(R.string.schoolandteachers_title) to getCompatDrawable((R.drawable.ic_more_schoolandteachers)) }
|
|
||||||
|
|
||||||
override val mobileDevicesRes: Pair<String, Drawable?>?
|
|
||||||
get() = context?.run { getString(R.string.mobile_devices_title) to getCompatDrawable(R.drawable.ic_more_mobile_devices) }
|
|
||||||
|
|
||||||
override val settingsRes: Pair<String, Drawable?>?
|
|
||||||
get() = context?.run { getString(R.string.settings_title) to getCompatDrawable(R.drawable.ic_more_settings) }
|
|
||||||
|
|
||||||
override val examRes: Pair<String, Drawable?>?
|
|
||||||
get() = context?.run { getString(R.string.exam_title) to getCompatDrawable(R.drawable.ic_main_exam) }
|
|
||||||
|
|
||||||
override val luckyNumberRes: Pair<String, Drawable?>?
|
|
||||||
get() = context?.run { getString(R.string.lucky_number_title) to getCompatDrawable(R.drawable.ic_more_lucky_number) }
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
binding = FragmentMoreBinding.bind(view)
|
binding = FragmentMoreBinding.bind(view)
|
||||||
@ -94,57 +54,21 @@ class MoreFragment : BaseFragment<FragmentMoreBinding>(R.layout.fragment_more),
|
|||||||
?.onFragmentChanged()
|
?.onFragmentChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updateData(data: List<Pair<String, Drawable?>>) {
|
override fun updateData(data: List<MoreItem>) {
|
||||||
with(moreAdapter) {
|
with(moreAdapter) {
|
||||||
items = data
|
items = data
|
||||||
notifyDataSetChanged()
|
notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun openMessagesView() {
|
|
||||||
(activity as? MainActivity)?.pushView(MessageFragment.newInstance())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun openHomeworkView() {
|
|
||||||
(activity as? MainActivity)?.pushView(HomeworkFragment.newInstance())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun openNoteView() {
|
|
||||||
(activity as? MainActivity)?.pushView(NoteFragment.newInstance())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun openSchoolAnnouncementView() {
|
|
||||||
(activity as? MainActivity)?.pushView(SchoolAnnouncementFragment.newInstance())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun openConferencesView() {
|
|
||||||
(activity as? MainActivity)?.pushView(ConferenceFragment.newInstance())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun openSchoolAndTeachersView() {
|
|
||||||
(activity as? MainActivity)?.pushView(SchoolAndTeachersFragment.newInstance())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun openMobileDevicesView() {
|
|
||||||
(activity as? MainActivity)?.pushView(MobileDeviceFragment.newInstance())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun openSettingsView() {
|
|
||||||
(activity as? MainActivity)?.pushView(SettingsFragment.newInstance())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun openExamView() {
|
|
||||||
(activity as? MainActivity)?.pushView(ExamFragment.newInstance())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun openLuckyNumberView() {
|
|
||||||
(activity as? MainActivity)?.pushView(LuckyNumberFragment.newInstance())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun popView(depth: Int) {
|
override fun popView(depth: Int) {
|
||||||
(activity as? MainActivity)?.popView(depth)
|
(activity as? MainActivity)?.popView(depth)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun openView(destination: Destination) {
|
||||||
|
(activity as? MainActivity)?.pushView(destination.destinationFragment)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
presenter.onDetachView()
|
presenter.onDetachView()
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
|
@ -0,0 +1,12 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.more
|
||||||
|
|
||||||
|
import io.github.wulkanowy.ui.modules.Destination
|
||||||
|
|
||||||
|
data class MoreItem(
|
||||||
|
|
||||||
|
val icon: Int,
|
||||||
|
|
||||||
|
val title: Int,
|
||||||
|
|
||||||
|
val destination: Destination
|
||||||
|
)
|
@ -1,16 +1,24 @@
|
|||||||
package io.github.wulkanowy.ui.modules.more
|
package io.github.wulkanowy.ui.modules.more
|
||||||
|
|
||||||
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||||
import io.github.wulkanowy.ui.base.BasePresenter
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||||
|
import io.github.wulkanowy.ui.modules.Destination
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class MorePresenter @Inject constructor(
|
class MorePresenter @Inject constructor(
|
||||||
errorHandler: ErrorHandler,
|
errorHandler: ErrorHandler,
|
||||||
studentRepository: StudentRepository
|
studentRepository: StudentRepository,
|
||||||
|
preferencesRepository: PreferencesRepository
|
||||||
) : BasePresenter<MoreView>(errorHandler, studentRepository) {
|
) : BasePresenter<MoreView>(errorHandler, studentRepository) {
|
||||||
|
|
||||||
|
private val moreAppMenuItem = preferencesRepository.appMenuItemOrder
|
||||||
|
.sortedBy { it.order }
|
||||||
|
.drop(4)
|
||||||
|
|
||||||
override fun onAttachView(view: MoreView) {
|
override fun onAttachView(view: MoreView) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
view.initView()
|
view.initView()
|
||||||
@ -18,22 +26,10 @@ class MorePresenter @Inject constructor(
|
|||||||
loadData()
|
loadData()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onItemSelected(title: String) {
|
fun onItemSelected(moreItem: MoreItem) {
|
||||||
Timber.i("Select more item \"${title}\"")
|
Timber.i("Select more item \"${moreItem.destination.destinationType}\"")
|
||||||
view?.run {
|
|
||||||
when (title) {
|
view?.openView(moreItem.destination)
|
||||||
messagesRes?.first -> openMessagesView()
|
|
||||||
examRes?.first -> openExamView()
|
|
||||||
homeworkRes?.first -> openHomeworkView()
|
|
||||||
noteRes?.first -> openNoteView()
|
|
||||||
conferencesRes?.first -> openConferencesView()
|
|
||||||
schoolAnnouncementRes?.first -> openSchoolAnnouncementView()
|
|
||||||
schoolAndTeachersRes?.first -> openSchoolAndTeachersView()
|
|
||||||
mobileDevicesRes?.first -> openMobileDevicesView()
|
|
||||||
settingsRes?.first -> openSettingsView()
|
|
||||||
luckyNumberRes?.first -> openLuckyNumberView()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onViewReselected() {
|
fun onViewReselected() {
|
||||||
@ -43,19 +39,21 @@ class MorePresenter @Inject constructor(
|
|||||||
|
|
||||||
private fun loadData() {
|
private fun loadData() {
|
||||||
Timber.i("Load items for more view")
|
Timber.i("Load items for more view")
|
||||||
view?.run {
|
val moreItems = moreAppMenuItem.map {
|
||||||
updateData(listOfNotNull(
|
MoreItem(
|
||||||
messagesRes,
|
icon = it.icon,
|
||||||
examRes,
|
title = it.title,
|
||||||
homeworkRes,
|
destination = it.destinationType.defaultDestination
|
||||||
noteRes,
|
)
|
||||||
luckyNumberRes,
|
}
|
||||||
conferencesRes,
|
.plus(
|
||||||
schoolAnnouncementRes,
|
MoreItem(
|
||||||
schoolAndTeachersRes,
|
icon = R.drawable.ic_more_settings,
|
||||||
mobileDevicesRes,
|
title = R.string.settings_title,
|
||||||
settingsRes
|
destination = Destination.Settings
|
||||||
))
|
)
|
||||||
}
|
)
|
||||||
|
|
||||||
|
view?.updateData(moreItems)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,53 +1,15 @@
|
|||||||
package io.github.wulkanowy.ui.modules.more
|
package io.github.wulkanowy.ui.modules.more
|
||||||
|
|
||||||
import android.graphics.drawable.Drawable
|
|
||||||
import io.github.wulkanowy.ui.base.BaseView
|
import io.github.wulkanowy.ui.base.BaseView
|
||||||
|
import io.github.wulkanowy.ui.modules.Destination
|
||||||
|
|
||||||
interface MoreView : BaseView {
|
interface MoreView : BaseView {
|
||||||
|
|
||||||
val messagesRes: Pair<String, Drawable?>?
|
|
||||||
|
|
||||||
val homeworkRes: Pair<String, Drawable?>?
|
|
||||||
|
|
||||||
val noteRes: Pair<String, Drawable?>?
|
|
||||||
|
|
||||||
val conferencesRes: Pair<String, Drawable?>?
|
|
||||||
|
|
||||||
val schoolAnnouncementRes: Pair<String, Drawable?>?
|
|
||||||
|
|
||||||
val schoolAndTeachersRes: Pair<String, Drawable?>?
|
|
||||||
|
|
||||||
val mobileDevicesRes: Pair<String, Drawable?>?
|
|
||||||
|
|
||||||
val settingsRes: Pair<String, Drawable?>?
|
|
||||||
|
|
||||||
val examRes: Pair<String, Drawable?>?
|
|
||||||
|
|
||||||
val luckyNumberRes: Pair<String, Drawable?>?
|
|
||||||
|
|
||||||
fun initView()
|
fun initView()
|
||||||
|
|
||||||
fun updateData(data: List<Pair<String, Drawable?>>)
|
fun updateData(data: List<MoreItem>)
|
||||||
|
|
||||||
fun openSettingsView()
|
|
||||||
|
|
||||||
fun popView(depth: Int)
|
fun popView(depth: Int)
|
||||||
|
|
||||||
fun openMessagesView()
|
fun openView(destination: Destination)
|
||||||
|
|
||||||
fun openHomeworkView()
|
|
||||||
|
|
||||||
fun openNoteView()
|
|
||||||
|
|
||||||
fun openSchoolAnnouncementView()
|
|
||||||
|
|
||||||
fun openConferencesView()
|
|
||||||
|
|
||||||
fun openSchoolAndTeachersView()
|
|
||||||
|
|
||||||
fun openMobileDevicesView()
|
|
||||||
|
|
||||||
fun openExamView()
|
|
||||||
|
|
||||||
fun openLuckyNumberView()
|
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,24 @@
|
|||||||
package io.github.wulkanowy.ui.modules.note
|
package io.github.wulkanowy.ui.modules.note
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.Dialog
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
import androidx.fragment.app.DialogFragment
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.db.entities.Note
|
import io.github.wulkanowy.data.db.entities.Note
|
||||||
import io.github.wulkanowy.databinding.DialogNoteBinding
|
import io.github.wulkanowy.databinding.DialogNoteBinding
|
||||||
import io.github.wulkanowy.sdk.scrapper.notes.NoteCategory
|
import io.github.wulkanowy.sdk.scrapper.notes.NoteCategory
|
||||||
|
import io.github.wulkanowy.ui.base.BaseDialogFragment
|
||||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||||
import io.github.wulkanowy.utils.lifecycleAwareVariable
|
|
||||||
import io.github.wulkanowy.utils.serializable
|
import io.github.wulkanowy.utils.serializable
|
||||||
import io.github.wulkanowy.utils.toFormattedString
|
import io.github.wulkanowy.utils.toFormattedString
|
||||||
|
|
||||||
class NoteDialog : DialogFragment() {
|
@AndroidEntryPoint
|
||||||
|
class NoteDialog : BaseDialogFragment<DialogNoteBinding>() {
|
||||||
private var binding: DialogNoteBinding by lifecycleAwareVariable()
|
|
||||||
|
|
||||||
private lateinit var note: Note
|
private lateinit var note: Note
|
||||||
|
|
||||||
@ -34,15 +33,14 @@ class NoteDialog : DialogFragment() {
|
|||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setStyle(STYLE_NO_TITLE, 0)
|
|
||||||
note = requireArguments().serializable(ARGUMENT_KEY)
|
note = requireArguments().serializable(ARGUMENT_KEY)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
inflater: LayoutInflater,
|
return MaterialAlertDialogBuilder(requireContext(), theme)
|
||||||
container: ViewGroup?,
|
.setView(DialogNoteBinding.inflate(layoutInflater).apply { binding = this }.root)
|
||||||
savedInstanceState: Bundle?
|
.create()
|
||||||
) = DialogNoteBinding.inflate(inflater).apply { binding = this }.root
|
}
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
@ -18,7 +18,7 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class NoteFragment : BaseFragment<FragmentNoteBinding>(R.layout.fragment_note), NoteView,
|
class NoteFragment : BaseFragment<FragmentNoteBinding>(R.layout.fragment_note), NoteView,
|
||||||
MainView.TitledView {
|
MainView.TitledView, MainView.MainChildView {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var presenter: NotePresenter
|
lateinit var presenter: NotePresenter
|
||||||
@ -112,6 +112,14 @@ class NoteFragment : BaseFragment<FragmentNoteBinding>(R.layout.fragment_note),
|
|||||||
binding.noteSwipe.isRefreshing = show
|
binding.noteSwipe.isRefreshing = show
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onFragmentReselected() {
|
||||||
|
if (::presenter.isInitialized) presenter.onFragmentReselected()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun resetView() {
|
||||||
|
binding.noteRecycler.smoothScrollToPosition(0)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
presenter.onDetachView()
|
presenter.onDetachView()
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
|
@ -121,4 +121,10 @@ class NotePresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
.launch("update_note")
|
.launch("update_note")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onFragmentReselected() {
|
||||||
|
if (view?.isViewEmpty == false) {
|
||||||
|
view?.resetView()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,4 +30,6 @@ interface NoteView : BaseView {
|
|||||||
fun showRefresh(show: Boolean)
|
fun showRefresh(show: Boolean)
|
||||||
|
|
||||||
fun showNoteDialog(note: Note)
|
fun showNoteDialog(note: Note)
|
||||||
|
|
||||||
|
fun resetView()
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user