mirror of
https://github.com/wulkanowy/wulkanowy.git
synced 2025-01-31 20:02:45 +01:00
Merge branch 'release/2.5.0'
This commit is contained in:
commit
7b2c839775
4
.github/FUNDING.yml
vendored
Normal file
4
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
github: wulkanowy
|
||||||
|
custom: https://www.paypal.com/paypalme/wulkanowy
|
@ -27,8 +27,8 @@ android {
|
|||||||
testApplicationId "io.github.tests.wulkanowy"
|
testApplicationId "io.github.tests.wulkanowy"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 34
|
targetSdkVersion 34
|
||||||
versionCode 148
|
versionCode 149
|
||||||
versionName "2.4.2"
|
versionName "2.5.0"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
|
||||||
resValue "string", "app_name", "Wulkanowy"
|
resValue "string", "app_name", "Wulkanowy"
|
||||||
@ -164,8 +164,8 @@ play {
|
|||||||
defaultToAppBundles = false
|
defaultToAppBundles = false
|
||||||
track = 'production'
|
track = 'production'
|
||||||
releaseStatus = ReleaseStatus.IN_PROGRESS
|
releaseStatus = ReleaseStatus.IN_PROGRESS
|
||||||
userFraction = 0.99d
|
userFraction = 0.20d
|
||||||
updatePriority = 2
|
updatePriority = 1
|
||||||
enabled.set(false)
|
enabled.set(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,15 +187,15 @@ huaweiPublish {
|
|||||||
|
|
||||||
ext {
|
ext {
|
||||||
work_manager = "2.9.0"
|
work_manager = "2.9.0"
|
||||||
android_hilt = "1.1.0"
|
android_hilt = "1.2.0"
|
||||||
room = "2.6.1"
|
room = "2.6.1"
|
||||||
chucker = "4.0.0"
|
chucker = "4.0.0"
|
||||||
mockk = "1.13.9"
|
mockk = "1.13.10"
|
||||||
coroutines = "1.8.0"
|
coroutines = "1.8.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'io.github.wulkanowy:sdk:2.4.1'
|
implementation 'io.github.wulkanowy:sdk:2.5.0'
|
||||||
|
|
||||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4'
|
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4'
|
||||||
|
|
||||||
@ -246,13 +246,13 @@ dependencies {
|
|||||||
implementation 'com.github.Faierbel:slf4j-timber:2.0'
|
implementation 'com.github.Faierbel:slf4j-timber:2.0'
|
||||||
implementation 'com.github.bastienpaulfr:Treessence:1.1.2'
|
implementation 'com.github.bastienpaulfr:Treessence:1.1.2'
|
||||||
implementation "com.mikepenz:aboutlibraries-core:$about_libraries"
|
implementation "com.mikepenz:aboutlibraries-core:$about_libraries"
|
||||||
implementation 'io.coil-kt:coil:2.5.0'
|
implementation 'io.coil-kt:coil:2.6.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.9.1'
|
implementation 'com.fredporciuncula:flow-preferences:1.9.1'
|
||||||
implementation 'org.apache.commons:commons-text:1.11.0'
|
implementation 'org.apache.commons:commons-text:1.11.0'
|
||||||
|
|
||||||
playImplementation platform('com.google.firebase:firebase-bom:32.7.2')
|
playImplementation platform('com.google.firebase:firebase-bom:32.7.3')
|
||||||
playImplementation 'com.google.firebase:firebase-analytics'
|
playImplementation 'com.google.firebase:firebase-analytics'
|
||||||
playImplementation 'com.google.firebase:firebase-messaging'
|
playImplementation 'com.google.firebase:firebase-messaging'
|
||||||
playImplementation 'com.google.firebase:firebase-crashlytics:'
|
playImplementation 'com.google.firebase:firebase-crashlytics:'
|
||||||
|
2527
app/schemas/io.github.wulkanowy.data.db.AppDatabase/60.json
Normal file
2527
app/schemas/io.github.wulkanowy.data.db.AppDatabase/60.json
Normal file
File diff suppressed because it is too large
Load Diff
2533
app/schemas/io.github.wulkanowy.data.db.AppDatabase/61.json
Normal file
2533
app/schemas/io.github.wulkanowy.data.db.AppDatabase/61.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -54,5 +54,9 @@
|
|||||||
{
|
{
|
||||||
"displayName": "Antoni Paduch",
|
"displayName": "Antoni Paduch",
|
||||||
"githubUsername": "janAte1"
|
"githubUsername": "janAte1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"displayName": "Kamil Wąsik",
|
||||||
|
"githubUsername": "JestemKamil"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -38,13 +38,16 @@ internal class DataModule {
|
|||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
fun provideSdk(chuckerInterceptor: ChuckerInterceptor, remoteConfig: RemoteConfigHelper) =
|
fun provideSdk(
|
||||||
Sdk().apply {
|
chuckerInterceptor: ChuckerInterceptor,
|
||||||
|
remoteConfig: RemoteConfigHelper,
|
||||||
|
webkitCookieManagerProxy: WebkitCookieManagerProxy,
|
||||||
|
) = Sdk().apply {
|
||||||
androidVersion = android.os.Build.VERSION.RELEASE
|
androidVersion = android.os.Build.VERSION.RELEASE
|
||||||
buildTag = android.os.Build.MODEL
|
buildTag = android.os.Build.MODEL
|
||||||
userAgentTemplate = remoteConfig.userAgentTemplate
|
userAgentTemplate = remoteConfig.userAgentTemplate
|
||||||
setSimpleHttpLogger { Timber.d(it) }
|
setSimpleHttpLogger { Timber.d(it) }
|
||||||
setAdditionalCookieManager(WebkitCookieManagerProxy())
|
setAdditionalCookieManager(webkitCookieManagerProxy)
|
||||||
|
|
||||||
// for debug only
|
// for debug only
|
||||||
addInterceptor(chuckerInterceptor, network = true)
|
addInterceptor(chuckerInterceptor, network = true)
|
||||||
@ -254,6 +257,10 @@ internal class DataModule {
|
|||||||
@Provides
|
@Provides
|
||||||
fun provideAdminMessageDao(database: AppDatabase) = database.adminMessagesDao
|
fun provideAdminMessageDao(database: AppDatabase) = database.adminMessagesDao
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@Provides
|
||||||
|
fun provideMutesDao(database: AppDatabase) = database.mutedMessageSendersDao
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
fun provideGradeDescriptiveDao(database: AppDatabase) = database.gradeDescriptiveDao
|
fun provideGradeDescriptiveDao(database: AppDatabase) = database.gradeDescriptiveDao
|
||||||
|
@ -25,6 +25,7 @@ import io.github.wulkanowy.data.db.dao.MailboxDao
|
|||||||
import io.github.wulkanowy.data.db.dao.MessageAttachmentDao
|
import io.github.wulkanowy.data.db.dao.MessageAttachmentDao
|
||||||
import io.github.wulkanowy.data.db.dao.MessagesDao
|
import io.github.wulkanowy.data.db.dao.MessagesDao
|
||||||
import io.github.wulkanowy.data.db.dao.MobileDeviceDao
|
import io.github.wulkanowy.data.db.dao.MobileDeviceDao
|
||||||
|
import io.github.wulkanowy.data.db.dao.MutedMessageSendersDao
|
||||||
import io.github.wulkanowy.data.db.dao.NoteDao
|
import io.github.wulkanowy.data.db.dao.NoteDao
|
||||||
import io.github.wulkanowy.data.db.dao.NotificationDao
|
import io.github.wulkanowy.data.db.dao.NotificationDao
|
||||||
import io.github.wulkanowy.data.db.dao.RecipientDao
|
import io.github.wulkanowy.data.db.dao.RecipientDao
|
||||||
@ -56,6 +57,7 @@ import io.github.wulkanowy.data.db.entities.Mailbox
|
|||||||
import io.github.wulkanowy.data.db.entities.Message
|
import io.github.wulkanowy.data.db.entities.Message
|
||||||
import io.github.wulkanowy.data.db.entities.MessageAttachment
|
import io.github.wulkanowy.data.db.entities.MessageAttachment
|
||||||
import io.github.wulkanowy.data.db.entities.MobileDevice
|
import io.github.wulkanowy.data.db.entities.MobileDevice
|
||||||
|
import io.github.wulkanowy.data.db.entities.MutedMessageSender
|
||||||
import io.github.wulkanowy.data.db.entities.Note
|
import io.github.wulkanowy.data.db.entities.Note
|
||||||
import io.github.wulkanowy.data.db.entities.Notification
|
import io.github.wulkanowy.data.db.entities.Notification
|
||||||
import io.github.wulkanowy.data.db.entities.Recipient
|
import io.github.wulkanowy.data.db.entities.Recipient
|
||||||
@ -157,6 +159,7 @@ import javax.inject.Singleton
|
|||||||
SchoolAnnouncement::class,
|
SchoolAnnouncement::class,
|
||||||
Notification::class,
|
Notification::class,
|
||||||
AdminMessage::class,
|
AdminMessage::class,
|
||||||
|
MutedMessageSender::class,
|
||||||
GradeDescriptive::class,
|
GradeDescriptive::class,
|
||||||
],
|
],
|
||||||
autoMigrations = [
|
autoMigrations = [
|
||||||
@ -169,6 +172,8 @@ import javax.inject.Singleton
|
|||||||
AutoMigration(from = 56, to = 57, spec = Migration57::class),
|
AutoMigration(from = 56, to = 57, spec = Migration57::class),
|
||||||
AutoMigration(from = 57, to = 58, spec = Migration58::class),
|
AutoMigration(from = 57, to = 58, spec = Migration58::class),
|
||||||
AutoMigration(from = 58, to = 59),
|
AutoMigration(from = 58, to = 59),
|
||||||
|
AutoMigration(from = 59, to = 60),
|
||||||
|
AutoMigration(from = 60, to = 61),
|
||||||
],
|
],
|
||||||
version = AppDatabase.VERSION_SCHEMA,
|
version = AppDatabase.VERSION_SCHEMA,
|
||||||
exportSchema = true
|
exportSchema = true
|
||||||
@ -177,7 +182,7 @@ import javax.inject.Singleton
|
|||||||
abstract class AppDatabase : RoomDatabase() {
|
abstract class AppDatabase : RoomDatabase() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val VERSION_SCHEMA = 59
|
const val VERSION_SCHEMA = 61
|
||||||
|
|
||||||
fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf(
|
fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf(
|
||||||
Migration2(),
|
Migration2(),
|
||||||
@ -303,5 +308,7 @@ abstract class AppDatabase : RoomDatabase() {
|
|||||||
|
|
||||||
abstract val adminMessagesDao: AdminMessageDao
|
abstract val adminMessagesDao: AdminMessageDao
|
||||||
|
|
||||||
|
abstract val mutedMessageSendersDao: MutedMessageSendersDao
|
||||||
|
|
||||||
abstract val gradeDescriptiveDao: GradeDescriptiveDao
|
abstract val gradeDescriptiveDao: GradeDescriptiveDao
|
||||||
}
|
}
|
||||||
|
@ -2,24 +2,14 @@ package io.github.wulkanowy.data.db.dao
|
|||||||
|
|
||||||
import androidx.room.Dao
|
import androidx.room.Dao
|
||||||
import androidx.room.Query
|
import androidx.room.Query
|
||||||
import androidx.room.Transaction
|
|
||||||
import io.github.wulkanowy.data.db.entities.AdminMessage
|
import io.github.wulkanowy.data.db.entities.AdminMessage
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Dao
|
@Dao
|
||||||
abstract class AdminMessageDao : BaseDao<AdminMessage> {
|
interface AdminMessageDao : BaseDao<AdminMessage> {
|
||||||
|
|
||||||
@Query("SELECT * FROM AdminMessages")
|
@Query("SELECT * FROM AdminMessages")
|
||||||
abstract fun loadAll(): Flow<List<AdminMessage>>
|
fun loadAll(): Flow<List<AdminMessage>>
|
||||||
|
|
||||||
@Transaction
|
|
||||||
open suspend fun removeOldAndSaveNew(
|
|
||||||
oldMessages: List<AdminMessage>,
|
|
||||||
newMessages: List<AdminMessage>
|
|
||||||
) {
|
|
||||||
deleteAll(oldMessages)
|
|
||||||
insertAll(newMessages)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package io.github.wulkanowy.data.db.dao
|
|||||||
import androidx.room.Delete
|
import androidx.room.Delete
|
||||||
import androidx.room.Insert
|
import androidx.room.Insert
|
||||||
import androidx.room.OnConflictStrategy
|
import androidx.room.OnConflictStrategy
|
||||||
|
import androidx.room.Transaction
|
||||||
import androidx.room.Update
|
import androidx.room.Update
|
||||||
|
|
||||||
interface BaseDao<T> {
|
interface BaseDao<T> {
|
||||||
@ -15,4 +16,10 @@ interface BaseDao<T> {
|
|||||||
|
|
||||||
@Delete
|
@Delete
|
||||||
suspend fun deleteAll(items: List<T>)
|
suspend fun deleteAll(items: List<T>)
|
||||||
|
|
||||||
|
@Transaction
|
||||||
|
suspend fun removeOldAndSaveNew(oldItems: List<T>, newItems: List<T>) {
|
||||||
|
deleteAll(oldItems)
|
||||||
|
insertAll(newItems)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,15 +5,23 @@ import androidx.room.Query
|
|||||||
import androidx.room.Transaction
|
import androidx.room.Transaction
|
||||||
import io.github.wulkanowy.data.db.entities.Message
|
import io.github.wulkanowy.data.db.entities.Message
|
||||||
import io.github.wulkanowy.data.db.entities.MessageWithAttachment
|
import io.github.wulkanowy.data.db.entities.MessageWithAttachment
|
||||||
|
import io.github.wulkanowy.data.db.entities.MessageWithMutedAuthor
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
interface MessagesDao : BaseDao<Message> {
|
interface MessagesDao : BaseDao<Message> {
|
||||||
|
|
||||||
@Transaction
|
@Transaction
|
||||||
@Query("SELECT * FROM Messages WHERE message_global_key = :messageGlobalKey")
|
@Query("SELECT * FROM Messages WHERE message_global_key = :messageGlobalKey")
|
||||||
fun loadMessageWithAttachment(messageGlobalKey: String): Flow<MessageWithAttachment?>
|
fun loadMessageWithAttachment(messageGlobalKey: String): Flow<MessageWithAttachment?>
|
||||||
|
|
||||||
|
@Transaction
|
||||||
|
@Query("SELECT * FROM Messages WHERE mailbox_key = :mailboxKey AND folder_id = :folder ORDER BY date DESC")
|
||||||
|
fun loadMessagesWithMutedAuthor(mailboxKey: String, folder: Int): Flow<List<MessageWithMutedAuthor>>
|
||||||
|
|
||||||
|
@Transaction
|
||||||
|
@Query("SELECT * FROM Messages WHERE email = :email AND folder_id = :folder ORDER BY date DESC")
|
||||||
|
fun loadMessagesWithMutedAuthor(folder: Int, email: String): Flow<List<MessageWithMutedAuthor>>
|
||||||
|
|
||||||
@Query("SELECT * FROM Messages WHERE mailbox_key = :mailboxKey AND folder_id = :folder ORDER BY date DESC")
|
@Query("SELECT * FROM Messages WHERE mailbox_key = :mailboxKey AND folder_id = :folder ORDER BY date DESC")
|
||||||
fun loadAll(mailboxKey: String, folder: Int): Flow<List<Message>>
|
fun loadAll(mailboxKey: String, folder: Int): Flow<List<Message>>
|
||||||
|
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
package io.github.wulkanowy.data.db.dao
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Insert
|
||||||
|
import androidx.room.OnConflictStrategy
|
||||||
|
import androidx.room.Query
|
||||||
|
import io.github.wulkanowy.data.db.entities.MutedMessageSender
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface MutedMessageSendersDao : BaseDao<MutedMessageSender> {
|
||||||
|
|
||||||
|
@Query("SELECT COUNT(*) FROM MutedMessageSenders WHERE author = :author")
|
||||||
|
suspend fun checkMute(author: String): Boolean
|
||||||
|
|
||||||
|
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||||
|
suspend fun insertMute(mute: MutedMessageSender): Long
|
||||||
|
|
||||||
|
@Query("DELETE FROM MutedMessageSenders WHERE author = :author")
|
||||||
|
suspend fun deleteMute(author: String)
|
||||||
|
}
|
@ -15,5 +15,5 @@ interface TimetableDao : BaseDao<Timetable> {
|
|||||||
fun loadAll(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): Flow<List<Timetable>>
|
fun loadAll(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): Flow<List<Timetable>>
|
||||||
|
|
||||||
@Query("SELECT * FROM Timetable WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :from AND date <= :end")
|
@Query("SELECT * FROM Timetable WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :from AND date <= :end")
|
||||||
fun load(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): List<Timetable>
|
suspend fun load(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): List<Timetable>
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,15 @@ package io.github.wulkanowy.data.db.entities
|
|||||||
|
|
||||||
import androidx.room.Embedded
|
import androidx.room.Embedded
|
||||||
import androidx.room.Relation
|
import androidx.room.Relation
|
||||||
|
import java.io.Serializable
|
||||||
|
|
||||||
data class MessageWithAttachment(
|
data class MessageWithAttachment(
|
||||||
@Embedded
|
@Embedded
|
||||||
val message: Message,
|
val message: Message,
|
||||||
|
|
||||||
@Relation(parentColumn = "message_global_key", entityColumn = "message_global_key")
|
@Relation(parentColumn = "message_global_key", entityColumn = "message_global_key")
|
||||||
val attachments: List<MessageAttachment>
|
val attachments: List<MessageAttachment>,
|
||||||
)
|
|
||||||
|
@Relation(parentColumn = "correspondents", entityColumn = "author")
|
||||||
|
val mutedMessageSender: MutedMessageSender?,
|
||||||
|
) : Serializable
|
||||||
|
@ -0,0 +1,12 @@
|
|||||||
|
package io.github.wulkanowy.data.db.entities
|
||||||
|
|
||||||
|
import androidx.room.Embedded
|
||||||
|
import androidx.room.Relation
|
||||||
|
|
||||||
|
data class MessageWithMutedAuthor(
|
||||||
|
@Embedded
|
||||||
|
val message: Message,
|
||||||
|
|
||||||
|
@Relation(parentColumn = "correspondents", entityColumn = "author")
|
||||||
|
val mutedMessageSender: MutedMessageSender?,
|
||||||
|
)
|
@ -0,0 +1,15 @@
|
|||||||
|
package io.github.wulkanowy.data.db.entities
|
||||||
|
|
||||||
|
import androidx.room.ColumnInfo
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
import java.io.Serializable
|
||||||
|
|
||||||
|
@Entity(tableName = "MutedMessageSenders")
|
||||||
|
data class MutedMessageSender(
|
||||||
|
@ColumnInfo(name = "author")
|
||||||
|
val author: String,
|
||||||
|
) : Serializable {
|
||||||
|
@PrimaryKey(autoGenerate = true)
|
||||||
|
var id: Long = 0
|
||||||
|
}
|
@ -16,7 +16,9 @@ data class SchoolAnnouncement(
|
|||||||
|
|
||||||
val subject: String,
|
val subject: String,
|
||||||
|
|
||||||
val content: String
|
val content: String,
|
||||||
|
|
||||||
|
val author: String? = null,
|
||||||
) : Serializable {
|
) : Serializable {
|
||||||
|
|
||||||
@PrimaryKey(autoGenerate = true)
|
@PrimaryKey(autoGenerate = true)
|
||||||
|
@ -3,5 +3,10 @@ package io.github.wulkanowy.data.enums
|
|||||||
enum class MessageFolder(val id: Int = 1) {
|
enum class MessageFolder(val id: Int = 1) {
|
||||||
RECEIVED(1),
|
RECEIVED(1),
|
||||||
SENT(2),
|
SENT(2),
|
||||||
TRASHED(3)
|
TRASHED(3),
|
||||||
|
;
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun byId(id: Int) = entries.first { it.id == id }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,26 @@ package io.github.wulkanowy.data.mappers
|
|||||||
import io.github.wulkanowy.data.db.entities.SchoolAnnouncement
|
import io.github.wulkanowy.data.db.entities.SchoolAnnouncement
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.github.wulkanowy.sdk.pojo.DirectorInformation as SdkDirectorInformation
|
import io.github.wulkanowy.sdk.pojo.DirectorInformation as SdkDirectorInformation
|
||||||
|
import io.github.wulkanowy.sdk.pojo.LastAnnouncement as SdkLastAnnouncement
|
||||||
|
|
||||||
|
@JvmName("mapDirectorInformationToEntities")
|
||||||
fun List<SdkDirectorInformation>.mapToEntities(student: Student) = map {
|
fun List<SdkDirectorInformation>.mapToEntities(student: Student) = map {
|
||||||
SchoolAnnouncement(
|
SchoolAnnouncement(
|
||||||
userLoginId = student.userLoginId,
|
userLoginId = student.userLoginId,
|
||||||
date = it.date,
|
date = it.date,
|
||||||
subject = it.subject,
|
subject = it.subject,
|
||||||
content = it.content,
|
content = it.content,
|
||||||
|
author = null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmName("mapLastAnnouncementsToEntities")
|
||||||
|
fun List<SdkLastAnnouncement>.mapToEntities(student: Student) = map {
|
||||||
|
SchoolAnnouncement(
|
||||||
|
userLoginId = student.userLoginId,
|
||||||
|
date = it.date,
|
||||||
|
subject = it.subject,
|
||||||
|
content = it.content,
|
||||||
|
author = it.author,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -16,10 +16,8 @@ import io.github.wulkanowy.utils.monday
|
|||||||
import io.github.wulkanowy.utils.sunday
|
import io.github.wulkanowy.utils.sunday
|
||||||
import io.github.wulkanowy.utils.switchSemester
|
import io.github.wulkanowy.utils.switchSemester
|
||||||
import io.github.wulkanowy.utils.uniqueSubtract
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
import java.time.LocalTime
|
import java.time.LocalTime
|
||||||
@ -58,23 +56,22 @@ class AttendanceRepository @Inject constructor(
|
|||||||
attendanceDb.loadAll(semester.diaryId, semester.studentId, start.monday, end.sunday)
|
attendanceDb.loadAll(semester.diaryId, semester.studentId, start.monday, end.sunday)
|
||||||
},
|
},
|
||||||
fetch = {
|
fetch = {
|
||||||
val lessons = withContext(Dispatchers.IO) {
|
val lessons = timetableDb.load(
|
||||||
timetableDb.load(
|
|
||||||
semester.diaryId, semester.studentId, start.monday, end.sunday
|
semester.diaryId, semester.studentId, start.monday, end.sunday
|
||||||
)
|
)
|
||||||
}
|
|
||||||
sdk.init(student)
|
sdk.init(student)
|
||||||
.switchSemester(semester)
|
.switchSemester(semester)
|
||||||
.getAttendance(start.monday, end.sunday)
|
.getAttendance(start.monday, end.sunday)
|
||||||
.mapToEntities(semester, lessons)
|
.mapToEntities(semester, lessons)
|
||||||
},
|
},
|
||||||
saveFetchResult = { old, new ->
|
saveFetchResult = { old, new ->
|
||||||
attendanceDb.deleteAll(old uniqueSubtract new)
|
|
||||||
val attendanceToAdd = (new uniqueSubtract old).map { newAttendance ->
|
val attendanceToAdd = (new uniqueSubtract old).map { newAttendance ->
|
||||||
newAttendance.apply { if (notify) isNotified = false }
|
newAttendance.apply { if (notify) isNotified = false }
|
||||||
}
|
}
|
||||||
attendanceDb.insertAll(attendanceToAdd)
|
attendanceDb.removeOldAndSaveNew(
|
||||||
|
oldItems = old uniqueSubtract new,
|
||||||
|
newItems = attendanceToAdd,
|
||||||
|
)
|
||||||
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester, start, end))
|
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester, start, end))
|
||||||
},
|
},
|
||||||
filterResult = { it.filter { item -> item.date in start..end } }
|
filterResult = { it.filter { item -> item.date in start..end } }
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package io.github.wulkanowy.data.repositories
|
package io.github.wulkanowy.data.repositories
|
||||||
|
|
||||||
|
import androidx.room.withTransaction
|
||||||
|
import io.github.wulkanowy.data.db.AppDatabase
|
||||||
import io.github.wulkanowy.data.db.dao.AttendanceSummaryDao
|
import io.github.wulkanowy.data.db.dao.AttendanceSummaryDao
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
@ -20,6 +22,7 @@ class AttendanceSummaryRepository @Inject constructor(
|
|||||||
private val attendanceDb: AttendanceSummaryDao,
|
private val attendanceDb: AttendanceSummaryDao,
|
||||||
private val sdk: Sdk,
|
private val sdk: Sdk,
|
||||||
private val refreshHelper: AutoRefreshHelper,
|
private val refreshHelper: AutoRefreshHelper,
|
||||||
|
private val appDatabase: AppDatabase,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val saveFetchResultMutex = Mutex()
|
private val saveFetchResultMutex = Mutex()
|
||||||
@ -46,8 +49,10 @@ class AttendanceSummaryRepository @Inject constructor(
|
|||||||
.mapToEntities(semester, subjectId)
|
.mapToEntities(semester, subjectId)
|
||||||
},
|
},
|
||||||
saveFetchResult = { old, new ->
|
saveFetchResult = { old, new ->
|
||||||
|
appDatabase.withTransaction {
|
||||||
attendanceDb.deleteAll(old uniqueSubtract new)
|
attendanceDb.deleteAll(old uniqueSubtract new)
|
||||||
attendanceDb.insertAll(new uniqueSubtract old)
|
attendanceDb.insertAll(new uniqueSubtract old)
|
||||||
|
}
|
||||||
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester))
|
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -6,7 +6,13 @@ import io.github.wulkanowy.data.db.entities.Student
|
|||||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
import io.github.wulkanowy.data.mappers.mapToEntities
|
||||||
import io.github.wulkanowy.data.networkBoundResource
|
import io.github.wulkanowy.data.networkBoundResource
|
||||||
import io.github.wulkanowy.sdk.Sdk
|
import io.github.wulkanowy.sdk.Sdk
|
||||||
import io.github.wulkanowy.utils.*
|
import io.github.wulkanowy.utils.AutoRefreshHelper
|
||||||
|
import io.github.wulkanowy.utils.getRefreshKey
|
||||||
|
import io.github.wulkanowy.utils.init
|
||||||
|
import io.github.wulkanowy.utils.monday
|
||||||
|
import io.github.wulkanowy.utils.sunday
|
||||||
|
import io.github.wulkanowy.utils.switchSemester
|
||||||
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -53,8 +59,10 @@ class CompletedLessonsRepository @Inject constructor(
|
|||||||
.mapToEntities(semester)
|
.mapToEntities(semester)
|
||||||
},
|
},
|
||||||
saveFetchResult = { old, new ->
|
saveFetchResult = { old, new ->
|
||||||
completedLessonsDb.deleteAll(old uniqueSubtract new)
|
completedLessonsDb.removeOldAndSaveNew(
|
||||||
completedLessonsDb.insertAll(new uniqueSubtract old)
|
oldItems = old uniqueSubtract new,
|
||||||
|
newItems = new uniqueSubtract old,
|
||||||
|
)
|
||||||
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester, start, end))
|
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester, start, end))
|
||||||
},
|
},
|
||||||
filterResult = { it.filter { item -> item.date in start..end } }
|
filterResult = { it.filter { item -> item.date in start..end } }
|
||||||
|
@ -53,12 +53,12 @@ class ConferenceRepository @Inject constructor(
|
|||||||
.filter { it.date >= startDate }
|
.filter { it.date >= startDate }
|
||||||
},
|
},
|
||||||
saveFetchResult = { old, new ->
|
saveFetchResult = { old, new ->
|
||||||
val conferencesToSave = (new uniqueSubtract old).onEach {
|
conferenceDb.removeOldAndSaveNew(
|
||||||
|
oldItems = old uniqueSubtract new,
|
||||||
|
newItems = (new uniqueSubtract old).onEach {
|
||||||
if (notify) it.isNotified = false
|
if (notify) it.isNotified = false
|
||||||
}
|
},
|
||||||
|
)
|
||||||
conferenceDb.deleteAll(old uniqueSubtract new)
|
|
||||||
conferenceDb.insertAll(conferencesToSave)
|
|
||||||
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester))
|
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -62,12 +62,12 @@ class ExamRepository @Inject constructor(
|
|||||||
.mapToEntities(semester)
|
.mapToEntities(semester)
|
||||||
},
|
},
|
||||||
saveFetchResult = { old, new ->
|
saveFetchResult = { old, new ->
|
||||||
val examsToSave = (new uniqueSubtract old).onEach {
|
examDb.removeOldAndSaveNew(
|
||||||
|
oldItems = old uniqueSubtract new,
|
||||||
|
newItems = (new uniqueSubtract old).onEach {
|
||||||
if (notify) it.isNotified = false
|
if (notify) it.isNotified = false
|
||||||
}
|
},
|
||||||
|
)
|
||||||
examDb.deleteAll(old uniqueSubtract new)
|
|
||||||
examDb.insertAll(examsToSave)
|
|
||||||
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester, start, end))
|
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester, start, end))
|
||||||
},
|
},
|
||||||
filterResult = { it.filter { item -> item.date in start..end } }
|
filterResult = { it.filter { item -> item.date in start..end } }
|
||||||
|
@ -87,10 +87,12 @@ class GradeRepository @Inject constructor(
|
|||||||
new: List<GradeDescriptive>,
|
new: List<GradeDescriptive>,
|
||||||
notify: Boolean
|
notify: Boolean
|
||||||
) {
|
) {
|
||||||
gradeDescriptiveDb.deleteAll(old uniqueSubtract new)
|
gradeDescriptiveDb.removeOldAndSaveNew(
|
||||||
gradeDescriptiveDb.insertAll((new uniqueSubtract old).onEach {
|
oldItems = old uniqueSubtract new,
|
||||||
|
newItems = (new uniqueSubtract old).onEach {
|
||||||
if (notify) it.isNotified = false
|
if (notify) it.isNotified = false
|
||||||
})
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun refreshGradeDetails(
|
private suspend fun refreshGradeDetails(
|
||||||
@ -101,13 +103,16 @@ class GradeRepository @Inject constructor(
|
|||||||
) {
|
) {
|
||||||
val notifyBreakDate = oldGrades.maxByOrNull { it.date }?.date
|
val notifyBreakDate = oldGrades.maxByOrNull { it.date }?.date
|
||||||
?: student.registrationDate.toLocalDate()
|
?: student.registrationDate.toLocalDate()
|
||||||
gradeDb.deleteAll(oldGrades uniqueSubtract newDetails)
|
|
||||||
gradeDb.insertAll((newDetails uniqueSubtract oldGrades).onEach {
|
gradeDb.removeOldAndSaveNew(
|
||||||
|
oldItems = oldGrades uniqueSubtract newDetails,
|
||||||
|
newItems = (newDetails uniqueSubtract oldGrades).onEach {
|
||||||
if (it.date >= notifyBreakDate) it.apply {
|
if (it.date >= notifyBreakDate) it.apply {
|
||||||
isRead = false
|
isRead = false
|
||||||
if (notify) isNotified = false
|
if (notify) isNotified = false
|
||||||
}
|
}
|
||||||
})
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun refreshGradeSummaries(
|
private suspend fun refreshGradeSummaries(
|
||||||
@ -115,9 +120,23 @@ class GradeRepository @Inject constructor(
|
|||||||
newSummary: List<GradeSummary>,
|
newSummary: List<GradeSummary>,
|
||||||
notify: Boolean
|
notify: Boolean
|
||||||
) {
|
) {
|
||||||
gradeSummaryDb.deleteAll(oldSummaries uniqueSubtract newSummary)
|
gradeSummaryDb.removeOldAndSaveNew(
|
||||||
gradeSummaryDb.insertAll((newSummary uniqueSubtract oldSummaries).onEach { summary ->
|
oldItems = oldSummaries uniqueSubtract newSummary,
|
||||||
val oldSummary = oldSummaries.find { old -> old.subject == summary.subject }
|
newItems = (newSummary uniqueSubtract oldSummaries).onEach { summary ->
|
||||||
|
getGradeSummaryWithUpdatedNotificationState(
|
||||||
|
summary = summary,
|
||||||
|
oldSummary = oldSummaries.find { it.subject == summary.subject },
|
||||||
|
notify = notify,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getGradeSummaryWithUpdatedNotificationState(
|
||||||
|
summary: GradeSummary,
|
||||||
|
oldSummary: GradeSummary?,
|
||||||
|
notify: Boolean,
|
||||||
|
) {
|
||||||
summary.isPredictedGradeNotified = when {
|
summary.isPredictedGradeNotified = when {
|
||||||
summary.predictedGrade.isEmpty() -> true
|
summary.predictedGrade.isEmpty() -> true
|
||||||
notify && oldSummary?.predictedGrade != summary.predictedGrade -> false
|
notify && oldSummary?.predictedGrade != summary.predictedGrade -> false
|
||||||
@ -128,7 +147,6 @@ class GradeRepository @Inject constructor(
|
|||||||
notify && oldSummary?.finalGrade != summary.finalGrade -> false
|
notify && oldSummary?.finalGrade != summary.finalGrade -> false
|
||||||
else -> true
|
else -> true
|
||||||
}
|
}
|
||||||
|
|
||||||
summary.predictedGradeLastChange = when {
|
summary.predictedGradeLastChange = when {
|
||||||
oldSummary == null -> Instant.now()
|
oldSummary == null -> Instant.now()
|
||||||
summary.predictedGrade != oldSummary.predictedGrade -> Instant.now()
|
summary.predictedGrade != oldSummary.predictedGrade -> Instant.now()
|
||||||
@ -139,7 +157,6 @@ class GradeRepository @Inject constructor(
|
|||||||
summary.finalGrade != oldSummary.finalGrade -> Instant.now()
|
summary.finalGrade != oldSummary.finalGrade -> Instant.now()
|
||||||
else -> oldSummary.finalGradeLastChange
|
else -> oldSummary.finalGradeLastChange
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getUnreadGrades(semester: Semester): Flow<List<Grade>> {
|
fun getUnreadGrades(semester: Semester): Flow<List<Grade>> {
|
||||||
|
@ -19,7 +19,7 @@ import io.github.wulkanowy.utils.init
|
|||||||
import io.github.wulkanowy.utils.switchSemester
|
import io.github.wulkanowy.utils.switchSemester
|
||||||
import io.github.wulkanowy.utils.uniqueSubtract
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import java.util.*
|
import java.util.Locale
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@ -62,8 +62,10 @@ class GradeStatisticsRepository @Inject constructor(
|
|||||||
.mapToEntities(semester)
|
.mapToEntities(semester)
|
||||||
},
|
},
|
||||||
saveFetchResult = { old, new ->
|
saveFetchResult = { old, new ->
|
||||||
gradePartialStatisticsDb.deleteAll(old uniqueSubtract new)
|
gradePartialStatisticsDb.removeOldAndSaveNew(
|
||||||
gradePartialStatisticsDb.insertAll(new uniqueSubtract old)
|
oldItems = old uniqueSubtract new,
|
||||||
|
newItems = new uniqueSubtract old,
|
||||||
|
)
|
||||||
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(partialCacheKey, semester))
|
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(partialCacheKey, semester))
|
||||||
},
|
},
|
||||||
mapResult = { items ->
|
mapResult = { items ->
|
||||||
@ -80,6 +82,7 @@ class GradeStatisticsRepository @Inject constructor(
|
|||||||
)
|
)
|
||||||
listOf(summaryItem) + items
|
listOf(summaryItem) + items
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> items.filter { it.subject == subjectName }
|
else -> items.filter { it.subject == subjectName }
|
||||||
}.mapPartialToStatisticItems()
|
}.mapPartialToStatisticItems()
|
||||||
}
|
}
|
||||||
@ -107,8 +110,10 @@ class GradeStatisticsRepository @Inject constructor(
|
|||||||
.mapToEntities(semester)
|
.mapToEntities(semester)
|
||||||
},
|
},
|
||||||
saveFetchResult = { old, new ->
|
saveFetchResult = { old, new ->
|
||||||
gradeSemesterStatisticsDb.deleteAll(old uniqueSubtract new)
|
gradeSemesterStatisticsDb.removeOldAndSaveNew(
|
||||||
gradeSemesterStatisticsDb.insertAll(new uniqueSubtract old)
|
oldItems = old uniqueSubtract new,
|
||||||
|
newItems = new uniqueSubtract old,
|
||||||
|
)
|
||||||
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(semesterCacheKey, semester))
|
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(semesterCacheKey, semester))
|
||||||
},
|
},
|
||||||
mapResult = { items ->
|
mapResult = { items ->
|
||||||
@ -138,6 +143,7 @@ class GradeStatisticsRepository @Inject constructor(
|
|||||||
}
|
}
|
||||||
listOf(summaryItem) + itemsWithAverage
|
listOf(summaryItem) + itemsWithAverage
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> itemsWithAverage.filter { it.subject == subjectName }
|
else -> itemsWithAverage.filter { it.subject == subjectName }
|
||||||
}.mapSemesterToStatisticItems()
|
}.mapSemesterToStatisticItems()
|
||||||
}
|
}
|
||||||
@ -163,8 +169,10 @@ class GradeStatisticsRepository @Inject constructor(
|
|||||||
.mapToEntities(semester)
|
.mapToEntities(semester)
|
||||||
},
|
},
|
||||||
saveFetchResult = { old, new ->
|
saveFetchResult = { old, new ->
|
||||||
gradePointsStatisticsDb.deleteAll(old uniqueSubtract new)
|
gradePointsStatisticsDb.removeOldAndSaveNew(
|
||||||
gradePointsStatisticsDb.insertAll(new uniqueSubtract old)
|
oldItems = old uniqueSubtract new,
|
||||||
|
newItems = new uniqueSubtract old,
|
||||||
|
)
|
||||||
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(pointsCacheKey, semester))
|
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(pointsCacheKey, semester))
|
||||||
},
|
},
|
||||||
mapResult = { items ->
|
mapResult = { items ->
|
||||||
|
@ -61,14 +61,14 @@ class HomeworkRepository @Inject constructor(
|
|||||||
.mapToEntities(semester)
|
.mapToEntities(semester)
|
||||||
},
|
},
|
||||||
saveFetchResult = { old, new ->
|
saveFetchResult = { old, new ->
|
||||||
val homeWorkToSave = (new uniqueSubtract old).onEach {
|
|
||||||
if (notify) it.isNotified = false
|
|
||||||
}
|
|
||||||
val filteredOld = old.filterNot { it.isAddedByUser }
|
val filteredOld = old.filterNot { it.isAddedByUser }
|
||||||
|
|
||||||
homeworkDb.deleteAll(filteredOld uniqueSubtract new)
|
homeworkDb.removeOldAndSaveNew(
|
||||||
homeworkDb.insertAll(homeWorkToSave)
|
oldItems = filteredOld uniqueSubtract new,
|
||||||
|
newItems = (new uniqueSubtract old).onEach {
|
||||||
|
if (notify) it.isNotified = false
|
||||||
|
},
|
||||||
|
)
|
||||||
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester, start, end))
|
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester, start, end))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -18,7 +18,7 @@ import javax.inject.Singleton
|
|||||||
@Singleton
|
@Singleton
|
||||||
class LuckyNumberRepository @Inject constructor(
|
class LuckyNumberRepository @Inject constructor(
|
||||||
private val luckyNumberDb: LuckyNumberDao,
|
private val luckyNumberDb: LuckyNumberDao,
|
||||||
private val sdk: Sdk
|
private val sdk: Sdk,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val saveFetchResultMutex = Mutex()
|
private val saveFetchResultMutex = Mutex()
|
||||||
@ -39,11 +39,10 @@ class LuckyNumberRepository @Inject constructor(
|
|||||||
newLuckyNumber ?: return@networkBoundResource
|
newLuckyNumber ?: return@networkBoundResource
|
||||||
|
|
||||||
if (newLuckyNumber != oldLuckyNumber) {
|
if (newLuckyNumber != oldLuckyNumber) {
|
||||||
val updatedLuckNumberList =
|
luckyNumberDb.removeOldAndSaveNew(
|
||||||
listOf(newLuckyNumber.apply { if (notify) isNotified = false })
|
oldItems = listOfNotNull(oldLuckyNumber),
|
||||||
|
newItems = listOf(newLuckyNumber.apply { if (notify) isNotified = false }),
|
||||||
oldLuckyNumber?.let { luckyNumberDb.deleteAll(listOfNotNull(it)) }
|
)
|
||||||
luckyNumberDb.insertAll(updatedLuckNumberList)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -8,13 +8,17 @@ import io.github.wulkanowy.data.db.SharedPrefProvider
|
|||||||
import io.github.wulkanowy.data.db.dao.MailboxDao
|
import io.github.wulkanowy.data.db.dao.MailboxDao
|
||||||
import io.github.wulkanowy.data.db.dao.MessageAttachmentDao
|
import io.github.wulkanowy.data.db.dao.MessageAttachmentDao
|
||||||
import io.github.wulkanowy.data.db.dao.MessagesDao
|
import io.github.wulkanowy.data.db.dao.MessagesDao
|
||||||
|
import io.github.wulkanowy.data.db.dao.MutedMessageSendersDao
|
||||||
import io.github.wulkanowy.data.db.entities.Mailbox
|
import io.github.wulkanowy.data.db.entities.Mailbox
|
||||||
import io.github.wulkanowy.data.db.entities.Message
|
import io.github.wulkanowy.data.db.entities.Message
|
||||||
import io.github.wulkanowy.data.db.entities.MessageWithAttachment
|
import io.github.wulkanowy.data.db.entities.MessageWithAttachment
|
||||||
|
import io.github.wulkanowy.data.db.entities.MessageWithMutedAuthor
|
||||||
|
import io.github.wulkanowy.data.db.entities.MutedMessageSender
|
||||||
import io.github.wulkanowy.data.db.entities.Recipient
|
import io.github.wulkanowy.data.db.entities.Recipient
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.github.wulkanowy.data.enums.MessageFolder
|
import io.github.wulkanowy.data.enums.MessageFolder
|
||||||
import io.github.wulkanowy.data.enums.MessageFolder.RECEIVED
|
import io.github.wulkanowy.data.enums.MessageFolder.RECEIVED
|
||||||
|
import io.github.wulkanowy.data.enums.MessageFolder.SENT
|
||||||
import io.github.wulkanowy.data.enums.MessageFolder.TRASHED
|
import io.github.wulkanowy.data.enums.MessageFolder.TRASHED
|
||||||
import io.github.wulkanowy.data.mappers.mapFromEntities
|
import io.github.wulkanowy.data.mappers.mapFromEntities
|
||||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
import io.github.wulkanowy.data.mappers.mapToEntities
|
||||||
@ -22,6 +26,7 @@ import io.github.wulkanowy.data.networkBoundResource
|
|||||||
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.pojos.MessageDraft
|
import io.github.wulkanowy.data.pojos.MessageDraft
|
||||||
|
import io.github.wulkanowy.data.toFirstResult
|
||||||
import io.github.wulkanowy.data.waitForResult
|
import io.github.wulkanowy.data.waitForResult
|
||||||
import io.github.wulkanowy.domain.messages.GetMailboxByStudentUseCase
|
import io.github.wulkanowy.domain.messages.GetMailboxByStudentUseCase
|
||||||
import io.github.wulkanowy.sdk.Sdk
|
import io.github.wulkanowy.sdk.Sdk
|
||||||
@ -31,7 +36,6 @@ import io.github.wulkanowy.utils.getRefreshKey
|
|||||||
import io.github.wulkanowy.utils.init
|
import io.github.wulkanowy.utils.init
|
||||||
import io.github.wulkanowy.utils.uniqueSubtract
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.first
|
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
@ -42,6 +46,7 @@ import javax.inject.Singleton
|
|||||||
@Singleton
|
@Singleton
|
||||||
class MessageRepository @Inject constructor(
|
class MessageRepository @Inject constructor(
|
||||||
private val messagesDb: MessagesDao,
|
private val messagesDb: MessagesDao,
|
||||||
|
private val mutedMessageSendersDao: MutedMessageSendersDao,
|
||||||
private val messageAttachmentDao: MessageAttachmentDao,
|
private val messageAttachmentDao: MessageAttachmentDao,
|
||||||
private val sdk: Sdk,
|
private val sdk: Sdk,
|
||||||
@ApplicationContext private val context: Context,
|
@ApplicationContext private val context: Context,
|
||||||
@ -51,7 +56,6 @@ class MessageRepository @Inject constructor(
|
|||||||
private val mailboxDao: MailboxDao,
|
private val mailboxDao: MailboxDao,
|
||||||
private val getMailboxByStudentUseCase: GetMailboxByStudentUseCase,
|
private val getMailboxByStudentUseCase: GetMailboxByStudentUseCase,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val saveFetchResultMutex = Mutex()
|
private val saveFetchResultMutex = Mutex()
|
||||||
|
|
||||||
private val messagesCacheKey = "message"
|
private val messagesCacheKey = "message"
|
||||||
@ -63,7 +67,7 @@ class MessageRepository @Inject constructor(
|
|||||||
folder: MessageFolder,
|
folder: MessageFolder,
|
||||||
forceRefresh: Boolean,
|
forceRefresh: Boolean,
|
||||||
notify: Boolean = false,
|
notify: Boolean = false,
|
||||||
): Flow<Resource<List<Message>>> = networkBoundResource(
|
): Flow<Resource<List<MessageWithMutedAuthor>>> = networkBoundResource(
|
||||||
mutex = saveFetchResultMutex,
|
mutex = saveFetchResultMutex,
|
||||||
isResultEmpty = { it.isEmpty() },
|
isResultEmpty = { it.isEmpty() },
|
||||||
shouldFetch = {
|
shouldFetch = {
|
||||||
@ -74,8 +78,8 @@ class MessageRepository @Inject constructor(
|
|||||||
},
|
},
|
||||||
query = {
|
query = {
|
||||||
if (mailbox == null) {
|
if (mailbox == null) {
|
||||||
messagesDb.loadAll(folder.id, student.email)
|
messagesDb.loadMessagesWithMutedAuthor(folder.id, student.email)
|
||||||
} else messagesDb.loadAll(mailbox.globalKey, folder.id)
|
} else messagesDb.loadMessagesWithMutedAuthor(mailbox.globalKey, folder.id)
|
||||||
},
|
},
|
||||||
fetch = {
|
fetch = {
|
||||||
sdk.init(student).getMessages(
|
sdk.init(student).getMessages(
|
||||||
@ -83,12 +87,15 @@ class MessageRepository @Inject constructor(
|
|||||||
mailboxKey = mailbox?.globalKey,
|
mailboxKey = mailbox?.globalKey,
|
||||||
).mapToEntities(student, mailbox, mailboxDao.loadAll(student.email))
|
).mapToEntities(student, mailbox, mailboxDao.loadAll(student.email))
|
||||||
},
|
},
|
||||||
saveFetchResult = { old, new ->
|
saveFetchResult = { oldWithAuthors, new ->
|
||||||
messagesDb.deleteAll(old uniqueSubtract new)
|
val old = oldWithAuthors.map { it.message }
|
||||||
messagesDb.insertAll((new uniqueSubtract old).onEach {
|
messagesDb.removeOldAndSaveNew(
|
||||||
it.isNotified = !notify
|
oldItems = old uniqueSubtract new,
|
||||||
})
|
newItems = (new uniqueSubtract old).onEach {
|
||||||
|
val muted = isMuted(it.correspondents)
|
||||||
|
it.isNotified = !notify || muted
|
||||||
|
},
|
||||||
|
)
|
||||||
refreshHelper.updateLastRefreshTimestamp(
|
refreshHelper.updateLastRefreshTimestamp(
|
||||||
getRefreshKey(messagesCacheKey, mailbox, folder)
|
getRefreshKey(messagesCacheKey, mailbox, folder)
|
||||||
)
|
)
|
||||||
@ -106,9 +113,7 @@ class MessageRepository @Inject constructor(
|
|||||||
Timber.d("Message content in db empty: ${it.message.content.isBlank()}")
|
Timber.d("Message content in db empty: ${it.message.content.isBlank()}")
|
||||||
(it.message.unread && markAsRead) || it.message.content.isBlank()
|
(it.message.unread && markAsRead) || it.message.content.isBlank()
|
||||||
},
|
},
|
||||||
query = {
|
query = { messagesDb.loadMessageWithAttachment(message.messageGlobalKey) },
|
||||||
messagesDb.loadMessageWithAttachment(message.messageGlobalKey)
|
|
||||||
},
|
|
||||||
fetch = {
|
fetch = {
|
||||||
sdk.init(student).getMessageDetails(
|
sdk.init(student).getMessageDetails(
|
||||||
messageKey = it!!.message.messageGlobalKey,
|
messageKey = it!!.message.messageGlobalKey,
|
||||||
@ -152,17 +157,30 @@ class MessageRepository @Inject constructor(
|
|||||||
subject: String,
|
subject: String,
|
||||||
content: String,
|
content: String,
|
||||||
recipients: List<Recipient>,
|
recipients: List<Recipient>,
|
||||||
mailboxId: String,
|
mailbox: Mailbox,
|
||||||
) {
|
) {
|
||||||
sdk.init(student).sendMessage(
|
sdk.init(student).sendMessage(
|
||||||
subject = subject,
|
subject = subject,
|
||||||
content = content,
|
content = content,
|
||||||
recipients = recipients.mapFromEntities(),
|
recipients = recipients.mapFromEntities(),
|
||||||
mailboxId = mailboxId,
|
mailboxId = mailbox.globalKey,
|
||||||
)
|
)
|
||||||
|
refreshFolders(student, mailbox, listOf(SENT))
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun deleteMessages(student: Student, mailbox: Mailbox?, messages: List<Message>) {
|
suspend fun restoreMessages(student: Student, mailbox: Mailbox?, messages: List<Message>) {
|
||||||
|
sdk.init(student).restoreMessages(
|
||||||
|
messages = messages.map { it.messageGlobalKey },
|
||||||
|
)
|
||||||
|
|
||||||
|
refreshFolders(student, mailbox)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun deleteMessage(student: Student, message: Message) {
|
||||||
|
deleteMessages(student, listOf(message))
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun deleteMessages(student: Student, messages: List<Message>) {
|
||||||
val firstMessage = messages.first()
|
val firstMessage = messages.first()
|
||||||
sdk.init(student).deleteMessages(
|
sdk.init(student).deleteMessages(
|
||||||
messages = messages.map { it.messageGlobalKey },
|
messages = messages.map { it.messageGlobalKey },
|
||||||
@ -181,18 +199,24 @@ class MessageRepository @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
messagesDb.updateAll(deletedMessages)
|
messagesDb.updateAll(deletedMessages)
|
||||||
} else messagesDb.deleteAll(messages)
|
} else {
|
||||||
|
messagesDb.deleteAll(messages)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun refreshFolders(
|
||||||
|
student: Student,
|
||||||
|
mailbox: Mailbox?,
|
||||||
|
folders: List<MessageFolder> = MessageFolder.entries
|
||||||
|
) {
|
||||||
|
folders.forEach {
|
||||||
getMessages(
|
getMessages(
|
||||||
student = student,
|
student = student,
|
||||||
mailbox = mailbox,
|
mailbox = mailbox,
|
||||||
folder = TRASHED,
|
folder = it,
|
||||||
forceRefresh = true,
|
forceRefresh = true,
|
||||||
).first()
|
).toFirstResult()
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun deleteMessage(student: Student, mailbox: Mailbox?, message: Message) {
|
|
||||||
deleteMessages(student, mailbox, listOf(message))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getMailboxes(student: Student, forceRefresh: Boolean) = networkBoundResource(
|
suspend fun getMailboxes(student: Student, forceRefresh: Boolean) = networkBoundResource(
|
||||||
@ -236,4 +260,18 @@ class MessageRepository @Inject constructor(
|
|||||||
context.getString(R.string.pref_key_message_draft),
|
context.getString(R.string.pref_key_message_draft),
|
||||||
value?.let { json.encodeToString(it) }
|
value?.let { json.encodeToString(it) }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private suspend fun isMuted(author: String): Boolean {
|
||||||
|
return mutedMessageSendersDao.checkMute(author)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun muteMessage(author: String) {
|
||||||
|
if (isMuted(author)) return
|
||||||
|
mutedMessageSendersDao.insertMute(MutedMessageSender(author))
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun unmuteMessage(author: String) {
|
||||||
|
if (!isMuted(author)) return
|
||||||
|
mutedMessageSendersDao.deleteMute(author)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,9 +48,10 @@ class MobileDeviceRepository @Inject constructor(
|
|||||||
.mapToEntities(student)
|
.mapToEntities(student)
|
||||||
},
|
},
|
||||||
saveFetchResult = { old, new ->
|
saveFetchResult = { old, new ->
|
||||||
mobileDb.deleteAll(old uniqueSubtract new)
|
mobileDb.removeOldAndSaveNew(
|
||||||
mobileDb.insertAll(new uniqueSubtract old)
|
oldItems = old uniqueSubtract new,
|
||||||
|
newItems = new uniqueSubtract old,
|
||||||
|
)
|
||||||
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student))
|
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -7,7 +7,12 @@ import io.github.wulkanowy.data.db.entities.Student
|
|||||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
import io.github.wulkanowy.data.mappers.mapToEntities
|
||||||
import io.github.wulkanowy.data.networkBoundResource
|
import io.github.wulkanowy.data.networkBoundResource
|
||||||
import io.github.wulkanowy.sdk.Sdk
|
import io.github.wulkanowy.sdk.Sdk
|
||||||
import io.github.wulkanowy.utils.*
|
import io.github.wulkanowy.utils.AutoRefreshHelper
|
||||||
|
import io.github.wulkanowy.utils.getRefreshKey
|
||||||
|
import io.github.wulkanowy.utils.init
|
||||||
|
import io.github.wulkanowy.utils.switchSemester
|
||||||
|
import io.github.wulkanowy.utils.toLocalDate
|
||||||
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -46,14 +51,16 @@ class NoteRepository @Inject constructor(
|
|||||||
.mapToEntities(semester)
|
.mapToEntities(semester)
|
||||||
},
|
},
|
||||||
saveFetchResult = { old, new ->
|
saveFetchResult = { old, new ->
|
||||||
noteDb.deleteAll(old uniqueSubtract new)
|
val notesToAdd = (new uniqueSubtract old).onEach {
|
||||||
noteDb.insertAll((new uniqueSubtract old).onEach {
|
|
||||||
if (it.date >= student.registrationDate.toLocalDate()) it.apply {
|
if (it.date >= student.registrationDate.toLocalDate()) it.apply {
|
||||||
isRead = false
|
isRead = false
|
||||||
if (notify) isNotified = false
|
if (notify) isNotified = false
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
noteDb.removeOldAndSaveNew(
|
||||||
|
oldItems = old uniqueSubtract new,
|
||||||
|
newItems = notesToAdd,
|
||||||
|
)
|
||||||
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester))
|
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
package io.github.wulkanowy.data.repositories
|
package io.github.wulkanowy.data.repositories
|
||||||
|
|
||||||
import io.github.wulkanowy.data.db.dao.RecipientDao
|
import io.github.wulkanowy.data.db.dao.RecipientDao
|
||||||
import io.github.wulkanowy.data.db.entities.*
|
import io.github.wulkanowy.data.db.entities.Mailbox
|
||||||
|
import io.github.wulkanowy.data.db.entities.MailboxType
|
||||||
|
import io.github.wulkanowy.data.db.entities.Message
|
||||||
|
import io.github.wulkanowy.data.db.entities.Recipient
|
||||||
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
import io.github.wulkanowy.data.mappers.mapToEntities
|
||||||
import io.github.wulkanowy.sdk.Sdk
|
import io.github.wulkanowy.sdk.Sdk
|
||||||
import io.github.wulkanowy.utils.AutoRefreshHelper
|
import io.github.wulkanowy.utils.AutoRefreshHelper
|
||||||
@ -25,8 +29,10 @@ class RecipientRepository @Inject constructor(
|
|||||||
.mapToEntities(mailbox.globalKey)
|
.mapToEntities(mailbox.globalKey)
|
||||||
val old = recipientDb.loadAll(type, mailbox.globalKey)
|
val old = recipientDb.loadAll(type, mailbox.globalKey)
|
||||||
|
|
||||||
recipientDb.deleteAll(old uniqueSubtract new)
|
recipientDb.removeOldAndSaveNew(
|
||||||
recipientDb.insertAll(new uniqueSubtract old)
|
oldItems = old uniqueSubtract new,
|
||||||
|
newItems = new uniqueSubtract old,
|
||||||
|
)
|
||||||
|
|
||||||
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student))
|
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student))
|
||||||
}
|
}
|
||||||
|
@ -41,17 +41,18 @@ class SchoolAnnouncementRepository @Inject constructor(
|
|||||||
schoolAnnouncementDb.loadAll(student.userLoginId)
|
schoolAnnouncementDb.loadAll(student.userLoginId)
|
||||||
},
|
},
|
||||||
fetch = {
|
fetch = {
|
||||||
sdk.init(student)
|
val sdk = sdk.init(student)
|
||||||
.getDirectorInformation()
|
val lastAnnouncements = sdk.getLastAnnouncements().mapToEntities(student)
|
||||||
.mapToEntities(student)
|
val directorInformation = sdk.getDirectorInformation().mapToEntities(student)
|
||||||
|
lastAnnouncements + directorInformation
|
||||||
},
|
},
|
||||||
saveFetchResult = { old, new ->
|
saveFetchResult = { old, new ->
|
||||||
val schoolAnnouncementsToSave = (new uniqueSubtract old).onEach {
|
schoolAnnouncementDb.removeOldAndSaveNew(
|
||||||
|
oldItems = old uniqueSubtract new,
|
||||||
|
newItems = (new uniqueSubtract old).onEach {
|
||||||
if (notify) it.isNotified = false
|
if (notify) it.isNotified = false
|
||||||
}
|
},
|
||||||
|
)
|
||||||
schoolAnnouncementDb.deleteAll(old uniqueSubtract new)
|
|
||||||
schoolAnnouncementDb.insertAll(schoolAnnouncementsToSave)
|
|
||||||
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student))
|
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -47,10 +47,10 @@ class SchoolRepository @Inject constructor(
|
|||||||
},
|
},
|
||||||
saveFetchResult = { old, new ->
|
saveFetchResult = { old, new ->
|
||||||
if (old != null && new != old) {
|
if (old != null && new != old) {
|
||||||
with(schoolDb) {
|
schoolDb.removeOldAndSaveNew(
|
||||||
deleteAll(listOf(old))
|
oldItems = listOf(old),
|
||||||
insertAll(listOf(new))
|
newItems = listOf(new)
|
||||||
}
|
)
|
||||||
} else if (old == null) {
|
} else if (old == null) {
|
||||||
schoolDb.insertAll(listOf(new))
|
schoolDb.insertAll(listOf(new))
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,11 @@ import io.github.wulkanowy.data.db.entities.Semester
|
|||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
import io.github.wulkanowy.data.mappers.mapToEntities
|
||||||
import io.github.wulkanowy.sdk.Sdk
|
import io.github.wulkanowy.sdk.Sdk
|
||||||
import io.github.wulkanowy.utils.*
|
import io.github.wulkanowy.utils.DispatchersProvider
|
||||||
|
import io.github.wulkanowy.utils.getCurrentOrLast
|
||||||
|
import io.github.wulkanowy.utils.init
|
||||||
|
import io.github.wulkanowy.utils.isCurrent
|
||||||
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -15,7 +19,7 @@ import javax.inject.Singleton
|
|||||||
class SemesterRepository @Inject constructor(
|
class SemesterRepository @Inject constructor(
|
||||||
private val semesterDb: SemesterDao,
|
private val semesterDb: SemesterDao,
|
||||||
private val sdk: Sdk,
|
private val sdk: Sdk,
|
||||||
private val dispatchers: DispatchersProvider
|
private val dispatchers: DispatchersProvider,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
suspend fun getSemesters(
|
suspend fun getSemesters(
|
||||||
@ -45,6 +49,7 @@ class SemesterRepository @Inject constructor(
|
|||||||
0 == it.diaryId && 0 == it.kindergartenDiaryId
|
0 == it.diaryId && 0 == it.kindergartenDiaryId
|
||||||
} == true
|
} == true
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,8 +64,10 @@ class SemesterRepository @Inject constructor(
|
|||||||
if (new.isEmpty()) return Timber.i("Empty semester list!")
|
if (new.isEmpty()) return Timber.i("Empty semester list!")
|
||||||
|
|
||||||
val old = semesterDb.loadAll(student.studentId, student.classId)
|
val old = semesterDb.loadAll(student.studentId, student.classId)
|
||||||
semesterDb.deleteAll(old.uniqueSubtract(new))
|
semesterDb.removeOldAndSaveNew(
|
||||||
semesterDb.insertSemesters(new.uniqueSubtract(old))
|
oldItems = old uniqueSubtract new,
|
||||||
|
newItems = new uniqueSubtract old,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getCurrentSemester(student: Student, forceRefresh: Boolean = false) =
|
suspend fun getCurrentSemester(student: Student, forceRefresh: Boolean = false) =
|
||||||
|
@ -15,7 +15,7 @@ import javax.inject.Singleton
|
|||||||
@Singleton
|
@Singleton
|
||||||
class StudentInfoRepository @Inject constructor(
|
class StudentInfoRepository @Inject constructor(
|
||||||
private val studentInfoDao: StudentInfoDao,
|
private val studentInfoDao: StudentInfoDao,
|
||||||
private val sdk: Sdk
|
private val sdk: Sdk,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val saveFetchResultMutex = Mutex()
|
private val saveFetchResultMutex = Mutex()
|
||||||
@ -36,10 +36,10 @@ class StudentInfoRepository @Inject constructor(
|
|||||||
},
|
},
|
||||||
saveFetchResult = { old, new ->
|
saveFetchResult = { old, new ->
|
||||||
if (old != null && new != old) {
|
if (old != null && new != old) {
|
||||||
with(studentInfoDao) {
|
studentInfoDao.removeOldAndSaveNew(
|
||||||
deleteAll(listOf(old))
|
oldItems = listOf(old),
|
||||||
insertAll(listOf(new))
|
newItems = listOf(new),
|
||||||
}
|
)
|
||||||
} else if (old == null) {
|
} else if (old == null) {
|
||||||
studentInfoDao.insertAll(listOf(new))
|
studentInfoDao.insertAll(listOf(new))
|
||||||
}
|
}
|
||||||
|
@ -45,9 +45,10 @@ class SubjectRepository @Inject constructor(
|
|||||||
.mapToEntities(semester)
|
.mapToEntities(semester)
|
||||||
},
|
},
|
||||||
saveFetchResult = { old, new ->
|
saveFetchResult = { old, new ->
|
||||||
subjectDao.deleteAll(old uniqueSubtract new)
|
subjectDao.removeOldAndSaveNew(
|
||||||
subjectDao.insertAll(new uniqueSubtract old)
|
oldItems = old uniqueSubtract new,
|
||||||
|
newItems = new uniqueSubtract old
|
||||||
|
)
|
||||||
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester))
|
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -45,9 +45,10 @@ class TeacherRepository @Inject constructor(
|
|||||||
.mapToEntities(semester)
|
.mapToEntities(semester)
|
||||||
},
|
},
|
||||||
saveFetchResult = { old, new ->
|
saveFetchResult = { old, new ->
|
||||||
teacherDb.deleteAll(old uniqueSubtract new)
|
teacherDb.removeOldAndSaveNew(
|
||||||
teacherDb.insertAll(new uniqueSubtract old)
|
oldItems = old uniqueSubtract new,
|
||||||
|
newItems = new uniqueSubtract old,
|
||||||
|
)
|
||||||
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester))
|
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -3,13 +3,23 @@ package io.github.wulkanowy.data.repositories
|
|||||||
import io.github.wulkanowy.data.db.dao.TimetableAdditionalDao
|
import io.github.wulkanowy.data.db.dao.TimetableAdditionalDao
|
||||||
import io.github.wulkanowy.data.db.dao.TimetableDao
|
import io.github.wulkanowy.data.db.dao.TimetableDao
|
||||||
import io.github.wulkanowy.data.db.dao.TimetableHeaderDao
|
import io.github.wulkanowy.data.db.dao.TimetableHeaderDao
|
||||||
import io.github.wulkanowy.data.db.entities.*
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
|
import io.github.wulkanowy.data.db.entities.Timetable
|
||||||
|
import io.github.wulkanowy.data.db.entities.TimetableAdditional
|
||||||
|
import io.github.wulkanowy.data.db.entities.TimetableHeader
|
||||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
import io.github.wulkanowy.data.mappers.mapToEntities
|
||||||
import io.github.wulkanowy.data.networkBoundResource
|
import io.github.wulkanowy.data.networkBoundResource
|
||||||
import io.github.wulkanowy.data.pojos.TimetableFull
|
import io.github.wulkanowy.data.pojos.TimetableFull
|
||||||
import io.github.wulkanowy.sdk.Sdk
|
import io.github.wulkanowy.sdk.Sdk
|
||||||
import io.github.wulkanowy.services.alarm.TimetableNotificationSchedulerHelper
|
import io.github.wulkanowy.services.alarm.TimetableNotificationSchedulerHelper
|
||||||
import io.github.wulkanowy.utils.*
|
import io.github.wulkanowy.utils.AutoRefreshHelper
|
||||||
|
import io.github.wulkanowy.utils.getRefreshKey
|
||||||
|
import io.github.wulkanowy.utils.init
|
||||||
|
import io.github.wulkanowy.utils.monday
|
||||||
|
import io.github.wulkanowy.utils.sunday
|
||||||
|
import io.github.wulkanowy.utils.switchSemester
|
||||||
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
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
|
||||||
@ -121,12 +131,12 @@ class TimetableRepository @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getTimetableFromDatabase(
|
suspend fun getTimetableFromDatabase(
|
||||||
semester: Semester,
|
semester: Semester,
|
||||||
from: LocalDate,
|
start: LocalDate,
|
||||||
end: LocalDate
|
end: LocalDate
|
||||||
): Flow<List<Timetable>> {
|
): List<Timetable> {
|
||||||
return timetableDb.loadAll(semester.diaryId, semester.studentId, from, end)
|
return timetableDb.load(semester.diaryId, semester.studentId, start, end)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun updateTimetable(timetable: List<Timetable>) {
|
suspend fun updateTimetable(timetable: List<Timetable>) {
|
||||||
@ -144,8 +154,10 @@ class TimetableRepository @Inject constructor(
|
|||||||
new.apply { if (notify) isNotified = false }
|
new.apply { if (notify) isNotified = false }
|
||||||
}
|
}
|
||||||
|
|
||||||
timetableDb.deleteAll(lessonsToRemove)
|
timetableDb.removeOldAndSaveNew(
|
||||||
timetableDb.insertAll(lessonsToAdd)
|
oldItems = lessonsToRemove,
|
||||||
|
newItems = lessonsToAdd,
|
||||||
|
)
|
||||||
|
|
||||||
schedulerHelper.cancelScheduled(lessonsToRemove, student)
|
schedulerHelper.cancelScheduled(lessonsToRemove, student)
|
||||||
schedulerHelper.scheduleNotifications(lessonsToAdd, student)
|
schedulerHelper.scheduleNotifications(lessonsToAdd, student)
|
||||||
@ -156,13 +168,17 @@ class TimetableRepository @Inject constructor(
|
|||||||
new: List<TimetableAdditional>
|
new: List<TimetableAdditional>
|
||||||
) {
|
) {
|
||||||
val oldFiltered = old.filter { !it.isAddedByUser }
|
val oldFiltered = old.filter { !it.isAddedByUser }
|
||||||
timetableAdditionalDb.deleteAll(oldFiltered uniqueSubtract new)
|
timetableAdditionalDb.removeOldAndSaveNew(
|
||||||
timetableAdditionalDb.insertAll(new uniqueSubtract old)
|
oldItems = oldFiltered uniqueSubtract new,
|
||||||
|
newItems = new uniqueSubtract old,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun refreshDayHeaders(old: List<TimetableHeader>, new: List<TimetableHeader>) {
|
private suspend fun refreshDayHeaders(old: List<TimetableHeader>, new: List<TimetableHeader>) {
|
||||||
timetableHeaderDb.deleteAll(old uniqueSubtract new)
|
timetableHeaderDb.removeOldAndSaveNew(
|
||||||
timetableHeaderDb.insertAll(new uniqueSubtract old)
|
oldItems = old uniqueSubtract new,
|
||||||
|
newItems = new uniqueSubtract old,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getLastRefreshTimestamp(semester: Semester, start: LocalDate, end: LocalDate): Instant {
|
fun getLastRefreshTimestamp(semester: Semester, start: LocalDate, end: LocalDate): Instant {
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
package io.github.wulkanowy.domain.timetable
|
package io.github.wulkanowy.domain.timetable
|
||||||
|
|
||||||
import io.github.wulkanowy.data.dataOrNull
|
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
|
||||||
import io.github.wulkanowy.data.repositories.TimetableRepository
|
import io.github.wulkanowy.data.repositories.TimetableRepository
|
||||||
import io.github.wulkanowy.data.toFirstResult
|
|
||||||
import io.github.wulkanowy.utils.monday
|
import io.github.wulkanowy.utils.monday
|
||||||
import io.github.wulkanowy.utils.sunday
|
import io.github.wulkanowy.utils.sunday
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
@ -16,18 +13,14 @@ class IsStudentHasLessonsOnWeekendUseCase @Inject constructor(
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
suspend operator fun invoke(
|
suspend operator fun invoke(
|
||||||
student: Student,
|
|
||||||
semester: Semester,
|
semester: Semester,
|
||||||
currentDate: LocalDate = LocalDate.now(),
|
currentDate: LocalDate = LocalDate.now(),
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val lessons = timetableRepository.getTimetable(
|
val lessons = timetableRepository.getTimetableFromDatabase(
|
||||||
student = student,
|
|
||||||
semester = semester,
|
semester = semester,
|
||||||
start = currentDate.monday,
|
start = currentDate.monday,
|
||||||
end = currentDate.sunday,
|
end = currentDate.sunday,
|
||||||
forceRefresh = false,
|
)
|
||||||
timetableType = TimetableRepository.TimetableType.NORMAL
|
|
||||||
).toFirstResult().dataOrNull?.lessons.orEmpty()
|
|
||||||
return isWeekendHasLessonsUseCase(lessons)
|
return isWeekendHasLessonsUseCase(lessons)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ import io.github.wulkanowy.data.repositories.TimetableRepository
|
|||||||
import io.github.wulkanowy.data.waitForResult
|
import io.github.wulkanowy.data.waitForResult
|
||||||
import io.github.wulkanowy.services.sync.notifications.ChangeTimetableNotification
|
import io.github.wulkanowy.services.sync.notifications.ChangeTimetableNotification
|
||||||
import io.github.wulkanowy.utils.nextOrSameSchoolDay
|
import io.github.wulkanowy.utils.nextOrSameSchoolDay
|
||||||
import kotlinx.coroutines.flow.first
|
|
||||||
import java.time.LocalDate.now
|
import java.time.LocalDate.now
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@ -31,10 +30,9 @@ class TimetableWork @Inject constructor(
|
|||||||
|
|
||||||
timetableRepository.getTimetableFromDatabase(
|
timetableRepository.getTimetableFromDatabase(
|
||||||
semester = semester,
|
semester = semester,
|
||||||
from = startDate,
|
start = startDate,
|
||||||
end = endDate,
|
end = endDate,
|
||||||
)
|
)
|
||||||
.first()
|
|
||||||
.filterNot { it.isNotified }
|
.filterNot { it.isNotified }
|
||||||
.let {
|
.let {
|
||||||
if (it.isNotEmpty()) changeTimetableNotification.notify(it, student)
|
if (it.isNotEmpty()) changeTimetableNotification.notify(it, student)
|
||||||
|
@ -17,6 +17,8 @@ import io.github.wulkanowy.utils.FragmentLifecycleLogger
|
|||||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||||
import io.github.wulkanowy.utils.lifecycleAwareVariable
|
import io.github.wulkanowy.utils.lifecycleAwareVariable
|
||||||
import io.github.wulkanowy.utils.openInternetBrowser
|
import io.github.wulkanowy.utils.openInternetBrowser
|
||||||
|
import timber.log.Timber
|
||||||
|
import java.time.Instant
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
abstract class BaseActivity<T : BasePresenter<out BaseView>, VB : ViewBinding> :
|
abstract class BaseActivity<T : BasePresenter<out BaseView>, VB : ViewBinding> :
|
||||||
@ -36,6 +38,8 @@ abstract class BaseActivity<T : BasePresenter<out BaseView>, VB : ViewBinding> :
|
|||||||
|
|
||||||
abstract var presenter: T
|
abstract var presenter: T
|
||||||
|
|
||||||
|
private var lastDialogOpenTime = mutableMapOf<String, Instant>()
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
inject()
|
inject()
|
||||||
themeManager.applyActivityTheme(this)
|
themeManager.applyActivityTheme(this)
|
||||||
@ -70,6 +74,8 @@ abstract class BaseActivity<T : BasePresenter<out BaseView>, VB : ViewBinding> :
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun showExpiredCredentialsDialog() {
|
override fun showExpiredCredentialsDialog() {
|
||||||
|
if (!shouldShowDialog(DIALOG_ERROR_BAD_CREDENTIALS)) return
|
||||||
|
|
||||||
MaterialAlertDialogBuilder(this)
|
MaterialAlertDialogBuilder(this)
|
||||||
.setTitle(R.string.main_expired_credentials_title)
|
.setTitle(R.string.main_expired_credentials_title)
|
||||||
.setMessage(R.string.main_expired_credentials_description)
|
.setMessage(R.string.main_expired_credentials_description)
|
||||||
@ -83,6 +89,8 @@ abstract class BaseActivity<T : BasePresenter<out BaseView>, VB : ViewBinding> :
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun showDecryptionFailedDialog() {
|
override fun showDecryptionFailedDialog() {
|
||||||
|
if (!shouldShowDialog(DIALOG_ERROR_DECRYPTION_FAILED)) return
|
||||||
|
|
||||||
MaterialAlertDialogBuilder(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)
|
||||||
@ -119,4 +127,21 @@ abstract class BaseActivity<T : BasePresenter<out BaseView>, VB : ViewBinding> :
|
|||||||
protected open fun inject() {
|
protected open fun inject() {
|
||||||
throw UnsupportedOperationException()
|
throw UnsupportedOperationException()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun shouldShowDialog(name: String): Boolean {
|
||||||
|
val lastOpenTime = lastDialogOpenTime[name]
|
||||||
|
val now = Instant.now()
|
||||||
|
|
||||||
|
if (lastOpenTime != null && now.isBefore(lastOpenTime.plusSeconds(1))) {
|
||||||
|
Timber.i("Dialog $name was shown less than a second ago. Skip")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
lastDialogOpenTime[name] = Instant.now()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val DIALOG_ERROR_BAD_CREDENTIALS = "dialog_error_bad_credentials"
|
||||||
|
private const val DIALOG_ERROR_DECRYPTION_FAILED = "dialog_error_decryption_failed"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ open class ErrorHandler @Inject constructor(@ApplicationContext protected val co
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected open fun proceed(error: Throwable) {
|
protected open fun proceed(error: Throwable) {
|
||||||
showErrorMessage(context.resources.getErrorString(error), error)
|
showDefaultMessage(error)
|
||||||
when (error) {
|
when (error) {
|
||||||
is PasswordChangeRequiredException -> onPasswordChangeRequired(error.redirectUrl)
|
is PasswordChangeRequiredException -> onPasswordChangeRequired(error.redirectUrl)
|
||||||
is ScramblerException -> onDecryptionFailed()
|
is ScramblerException -> onDecryptionFailed()
|
||||||
@ -45,6 +45,10 @@ open class ErrorHandler @Inject constructor(@ApplicationContext protected val co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun showDefaultMessage(error: Throwable) {
|
||||||
|
showErrorMessage(context.resources.getErrorString(error), error)
|
||||||
|
}
|
||||||
|
|
||||||
open fun clear() {
|
open fun clear() {
|
||||||
showErrorMessage = { _, _ -> }
|
showErrorMessage = { _, _ -> }
|
||||||
onExpiredCredentials = {}
|
onExpiredCredentials = {}
|
||||||
|
@ -4,18 +4,14 @@ import android.annotation.SuppressLint
|
|||||||
import io.github.wulkanowy.data.*
|
import io.github.wulkanowy.data.*
|
||||||
import io.github.wulkanowy.data.db.entities.Attendance
|
import io.github.wulkanowy.data.db.entities.Attendance
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
|
||||||
import io.github.wulkanowy.data.db.entities.Timetable
|
|
||||||
import io.github.wulkanowy.data.repositories.AttendanceRepository
|
import io.github.wulkanowy.data.repositories.AttendanceRepository
|
||||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
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.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.utils.*
|
import io.github.wulkanowy.utils.*
|
||||||
import kotlinx.coroutines.flow.catch
|
import kotlinx.coroutines.flow.firstOrNull
|
||||||
import kotlinx.coroutines.flow.flow
|
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.time.DayOfWeek
|
import java.time.DayOfWeek
|
||||||
@ -210,7 +206,7 @@ class AttendancePresenter @Inject constructor(
|
|||||||
|
|
||||||
val semester = semesterRepository.getCurrentSemester(student)
|
val semester = semesterRepository.getCurrentSemester(student)
|
||||||
|
|
||||||
checkInitialAndCurrentDate(student, semester)
|
checkInitialAndCurrentDate(semester)
|
||||||
attendanceRepository.getAttendance(
|
attendanceRepository.getAttendance(
|
||||||
student = student,
|
student = student,
|
||||||
semester = semester,
|
semester = semester,
|
||||||
@ -266,15 +262,13 @@ class AttendancePresenter @Inject constructor(
|
|||||||
.launch()
|
.launch()
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun checkInitialAndCurrentDate(student: Student, semester: Semester) {
|
private suspend fun checkInitialAndCurrentDate(semester: Semester) {
|
||||||
if (initialDate == null) {
|
if (initialDate == null) {
|
||||||
val lessons = attendanceRepository.getAttendance(
|
val lessons = attendanceRepository.getAttendanceFromDatabase(
|
||||||
student = student,
|
|
||||||
semester = semester,
|
semester = semester,
|
||||||
start = now().monday,
|
start = now().monday,
|
||||||
end = now().sunday,
|
end = now().sunday,
|
||||||
forceRefresh = false,
|
).firstOrNull().orEmpty()
|
||||||
).toFirstResult().dataOrNull.orEmpty()
|
|
||||||
isWeekendHasLessons = isWeekendHasLessons(lessons)
|
isWeekendHasLessons = isWeekendHasLessons(lessons)
|
||||||
initialDate = getInitialDate(semester)
|
initialDate = getInitialDate(semester)
|
||||||
}
|
}
|
||||||
@ -316,6 +310,7 @@ class AttendancePresenter @Inject constructor(
|
|||||||
showContent(false)
|
showContent(false)
|
||||||
showExcuseButton(false)
|
showExcuseButton(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
is Resource.Success -> {
|
is Resource.Success -> {
|
||||||
Timber.i("Excusing for absence result: Success")
|
Timber.i("Excusing for absence result: Success")
|
||||||
analytics.logEvent("excuse_absence", "items" to attendanceToExcuseList.size)
|
analytics.logEvent("excuse_absence", "items" to attendanceToExcuseList.size)
|
||||||
@ -328,6 +323,7 @@ class AttendancePresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
loadData(forceRefresh = true)
|
loadData(forceRefresh = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
is Resource.Error -> {
|
is Resource.Error -> {
|
||||||
Timber.i("Excusing for absence result: An exception occurred")
|
Timber.i("Excusing for absence result: An exception occurred")
|
||||||
errorHandler.dispatch(it.error)
|
errorHandler.dispatch(it.error)
|
||||||
|
@ -62,7 +62,11 @@ class AuthPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
isSuccess
|
isSuccess
|
||||||
}
|
}
|
||||||
.onFailure { errorHandler.dispatch(it) }
|
.onFailure {
|
||||||
|
errorHandler.dispatch(it)
|
||||||
|
view?.showProgress(false)
|
||||||
|
view?.showContent(true)
|
||||||
|
}
|
||||||
.onSuccess {
|
.onSuccess {
|
||||||
if (it) {
|
if (it) {
|
||||||
view?.showSuccess(true)
|
view?.showSuccess(true)
|
||||||
|
@ -13,6 +13,7 @@ import io.github.wulkanowy.R
|
|||||||
import io.github.wulkanowy.databinding.DialogCaptchaBinding
|
import io.github.wulkanowy.databinding.DialogCaptchaBinding
|
||||||
import io.github.wulkanowy.sdk.Sdk
|
import io.github.wulkanowy.sdk.Sdk
|
||||||
import io.github.wulkanowy.ui.base.BaseDialogFragment
|
import io.github.wulkanowy.ui.base.BaseDialogFragment
|
||||||
|
import io.github.wulkanowy.utils.WebkitCookieManagerProxy
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@ -22,6 +23,9 @@ class CaptchaDialog : BaseDialogFragment<DialogCaptchaBinding>() {
|
|||||||
@Inject
|
@Inject
|
||||||
lateinit var sdk: Sdk
|
lateinit var sdk: Sdk
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var webkitCookieManagerProxy: WebkitCookieManagerProxy
|
||||||
|
|
||||||
private var webView: WebView? = null
|
private var webView: WebView? = null
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@ -80,6 +84,7 @@ class CaptchaDialog : BaseDialogFragment<DialogCaptchaBinding>() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
|
webkitCookieManagerProxy.webkitCookieManager?.flush()
|
||||||
webView?.destroy()
|
webView?.destroy()
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
|
@ -304,6 +304,7 @@ class DashboardPresenter @Inject constructor(
|
|||||||
forceRefresh = forceRefresh
|
forceRefresh = forceRefresh
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
.mapResourceData { it.map { messageWithAuthor -> messageWithAuthor.message } }
|
||||||
.onResourceError { errorHandler.dispatch(it) }
|
.onResourceError { errorHandler.dispatch(it) }
|
||||||
.takeIf { DashboardItem.Tile.MESSAGES in selectedTiles } ?: flowSuccess
|
.takeIf { DashboardItem.Tile.MESSAGES in selectedTiles } ?: flowSuccess
|
||||||
|
|
||||||
@ -438,7 +439,7 @@ class DashboardPresenter @Inject constructor(
|
|||||||
private fun loadLessons(student: Student, forceRefresh: Boolean) {
|
private fun loadLessons(student: Student, forceRefresh: Boolean) {
|
||||||
flatResourceFlow {
|
flatResourceFlow {
|
||||||
val semester = semesterRepository.getCurrentSemester(student)
|
val semester = semesterRepository.getCurrentSemester(student)
|
||||||
val date = when (isStudentHasLessonsOnWeekendUseCase(student, semester)) {
|
val date = when (isStudentHasLessonsOnWeekendUseCase(semester)) {
|
||||||
true -> LocalDate.now()
|
true -> LocalDate.now()
|
||||||
else -> LocalDate.now().nextOrSameSchoolDay
|
else -> LocalDate.now().nextOrSameSchoolDay
|
||||||
}
|
}
|
||||||
|
@ -159,7 +159,7 @@ class GradeAverageProvider @Inject constructor(
|
|||||||
?.updateModifiers(student, config).orEmpty()
|
?.updateModifiers(student, config).orEmpty()
|
||||||
|
|
||||||
(updatedSecondSemesterGrades + updatedFirstSemesterGrades).calcAverage(
|
(updatedSecondSemesterGrades + updatedFirstSemesterGrades).calcAverage(
|
||||||
config.isOptionalArithmeticAverage
|
isOptionalArithmeticAverage = config.isOptionalArithmeticAverage,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
secondSemesterSubject.average
|
secondSemesterSubject.average
|
||||||
@ -173,13 +173,21 @@ class GradeAverageProvider @Inject constructor(
|
|||||||
config: AverageCalcParams,
|
config: AverageCalcParams,
|
||||||
): Double {
|
): Double {
|
||||||
return if (!isAnyVulcanAverage || config.forceAverageCalc) {
|
return if (!isAnyVulcanAverage || config.forceAverageCalc) {
|
||||||
val divider = if (secondSemesterSubject.grades.any { it.weightValue > .0 }) 2 else 1
|
val isSecondSemesterHasWeightGrade = secondSemesterSubject.grades
|
||||||
|
.any { it.weightValue > .0 }
|
||||||
|
val isSecondSemesterHasArithmeticGrade = secondSemesterSubject.grades
|
||||||
|
.all { it.weightValue == .0 } && config.isOptionalArithmeticAverage
|
||||||
|
val isSecondSemesterHaveAverage =
|
||||||
|
isSecondSemesterHasWeightGrade || isSecondSemesterHasArithmeticGrade
|
||||||
|
|
||||||
|
val divider = if (isSecondSemesterHaveAverage) 2 else 1
|
||||||
val secondSemesterAverage = secondSemesterSubject.grades
|
val secondSemesterAverage = secondSemesterSubject.grades
|
||||||
.updateModifiers(student, config)
|
.updateModifiers(student, config)
|
||||||
.calcAverage(config.isOptionalArithmeticAverage)
|
.calcAverage(isOptionalArithmeticAverage = config.isOptionalArithmeticAverage)
|
||||||
val firstSemesterAverage = firstSemesterSubject?.grades
|
val firstSemesterAverage = firstSemesterSubject?.grades
|
||||||
?.updateModifiers(student, config)
|
?.updateModifiers(student, config)
|
||||||
?.calcAverage(config.isOptionalArithmeticAverage) ?: secondSemesterAverage
|
?.calcAverage(isOptionalArithmeticAverage = config.isOptionalArithmeticAverage)
|
||||||
|
?: secondSemesterAverage
|
||||||
|
|
||||||
(secondSemesterAverage + firstSemesterAverage) / divider
|
(secondSemesterAverage + firstSemesterAverage) / divider
|
||||||
} else {
|
} else {
|
||||||
@ -225,7 +233,7 @@ class GradeAverageProvider @Inject constructor(
|
|||||||
subject = summary.subject,
|
subject = summary.subject,
|
||||||
average = if (!isAnyAverage || params.forceAverageCalc) {
|
average = if (!isAnyAverage || params.forceAverageCalc) {
|
||||||
grades.updateModifiers(student, params)
|
grades.updateModifiers(student, params)
|
||||||
.calcAverage(params.isOptionalArithmeticAverage)
|
.calcAverage(isOptionalArithmeticAverage = params.isOptionalArithmeticAverage)
|
||||||
} else summary.average,
|
} else summary.average,
|
||||||
points = summary.pointsSum,
|
points = summary.pointsSum,
|
||||||
summary = summary,
|
summary = summary,
|
||||||
@ -286,8 +294,13 @@ class GradeAverageProvider @Inject constructor(
|
|||||||
proposedPoints = "",
|
proposedPoints = "",
|
||||||
finalPoints = "",
|
finalPoints = "",
|
||||||
pointsSum = "",
|
pointsSum = "",
|
||||||
average = if (calcAverage) details.updateModifiers(student, params)
|
average = when {
|
||||||
.calcAverage(params.isOptionalArithmeticAverage) else .0
|
calcAverage -> details
|
||||||
|
.updateModifiers(student, params)
|
||||||
|
.calcAverage(isOptionalArithmeticAverage = params.isOptionalArithmeticAverage)
|
||||||
|
|
||||||
|
else -> .0
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ 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.domain.adminmessage.GetAppropriateAdminMessageUseCase
|
import io.github.wulkanowy.domain.adminmessage.GetAppropriateAdminMessageUseCase
|
||||||
|
import io.github.wulkanowy.sdk.scrapper.login.InvalidSymbolException
|
||||||
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
|
||||||
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
|
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
|
||||||
@ -204,6 +205,9 @@ class LoginFormPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
.onResourceError {
|
.onResourceError {
|
||||||
loginErrorHandler.dispatch(it)
|
loginErrorHandler.dispatch(it)
|
||||||
|
if (it is InvalidSymbolException) {
|
||||||
|
loginErrorHandler.showDefaultMessage(it)
|
||||||
|
}
|
||||||
lastError = it
|
lastError = it
|
||||||
view?.showContact(true)
|
view?.showContact(true)
|
||||||
analytics.logEvent(
|
analytics.logEvent(
|
||||||
|
@ -50,12 +50,15 @@ class MessagePreviewAdapter @Inject constructor() :
|
|||||||
ViewType.MESSAGE.id -> MessageViewHolder(
|
ViewType.MESSAGE.id -> MessageViewHolder(
|
||||||
ItemMessagePreviewBinding.inflate(inflater, parent, false)
|
ItemMessagePreviewBinding.inflate(inflater, parent, false)
|
||||||
)
|
)
|
||||||
|
|
||||||
ViewType.DIVIDER.id -> DividerViewHolder(
|
ViewType.DIVIDER.id -> DividerViewHolder(
|
||||||
ItemMessageDividerBinding.inflate(inflater, parent, false)
|
ItemMessageDividerBinding.inflate(inflater, parent, false)
|
||||||
)
|
)
|
||||||
|
|
||||||
ViewType.ATTACHMENT.id -> AttachmentViewHolder(
|
ViewType.ATTACHMENT.id -> AttachmentViewHolder(
|
||||||
ItemMessageAttachmentBinding.inflate(inflater, parent, false)
|
ItemMessageAttachmentBinding.inflate(inflater, parent, false)
|
||||||
)
|
)
|
||||||
|
|
||||||
else -> throw IllegalStateException()
|
else -> throw IllegalStateException()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -66,6 +69,7 @@ class MessagePreviewAdapter @Inject constructor() :
|
|||||||
holder,
|
holder,
|
||||||
requireNotNull(messageWithAttachment).message
|
requireNotNull(messageWithAttachment).message
|
||||||
)
|
)
|
||||||
|
|
||||||
is AttachmentViewHolder -> bindAttachment(
|
is AttachmentViewHolder -> bindAttachment(
|
||||||
holder,
|
holder,
|
||||||
requireNotNull(messageWithAttachment).attachments[position - 2]
|
requireNotNull(messageWithAttachment).attachments[position - 2]
|
||||||
@ -82,9 +86,11 @@ class MessagePreviewAdapter @Inject constructor() :
|
|||||||
recipientCount > 1 -> {
|
recipientCount > 1 -> {
|
||||||
context.getString(R.string.message_read_by, message.readBy, recipientCount)
|
context.getString(R.string.message_read_by, message.readBy, recipientCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
message.readBy == 1 || (isReceived && !message.unread) -> {
|
message.readBy == 1 || (isReceived && !message.unread) -> {
|
||||||
context.getString(R.string.message_read, context.getString(R.string.all_yes))
|
context.getString(R.string.message_read, context.getString(R.string.all_yes))
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> context.getString(R.string.message_read, context.getString(R.string.all_no))
|
else -> context.getString(R.string.message_read, context.getString(R.string.all_no))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,18 +44,33 @@ class MessagePreviewFragment :
|
|||||||
|
|
||||||
private var menuForwardButton: MenuItem? = null
|
private var menuForwardButton: MenuItem? = null
|
||||||
|
|
||||||
|
private var menuRestoreButton: MenuItem? = null
|
||||||
|
|
||||||
private var menuDeleteButton: MenuItem? = null
|
private var menuDeleteButton: MenuItem? = null
|
||||||
|
|
||||||
|
private var menuDeleteForeverButton: MenuItem? = null
|
||||||
|
|
||||||
private var menuShareButton: MenuItem? = null
|
private var menuShareButton: MenuItem? = null
|
||||||
|
|
||||||
private var menuPrintButton: MenuItem? = null
|
private var menuPrintButton: MenuItem? = null
|
||||||
|
|
||||||
|
private var menuMuteButton: MenuItem? = null
|
||||||
|
|
||||||
override val titleStringId: Int
|
override val titleStringId: Int
|
||||||
get() = R.string.message_title
|
get() = R.string.message_title
|
||||||
|
|
||||||
override val deleteMessageSuccessString: String
|
override val deleteMessageSuccessString: String
|
||||||
get() = getString(R.string.message_delete_success)
|
get() = getString(R.string.message_delete_success)
|
||||||
|
|
||||||
|
override val muteMessageSuccessString: String
|
||||||
|
get() = getString(R.string.message_mute_success)
|
||||||
|
|
||||||
|
override val unmuteMessageSuccessString: String
|
||||||
|
get() = getString(R.string.message_unmute_success)
|
||||||
|
|
||||||
|
override val restoreMessageSuccessString: String
|
||||||
|
get() = getString(R.string.message_restore_success)
|
||||||
|
|
||||||
override val messageNoSubjectString: String
|
override val messageNoSubjectString: String
|
||||||
get() = getString(R.string.message_no_subject)
|
get() = getString(R.string.message_no_subject)
|
||||||
|
|
||||||
@ -103,9 +118,12 @@ class MessagePreviewFragment :
|
|||||||
inflater.inflate(R.menu.action_menu_message_preview, menu)
|
inflater.inflate(R.menu.action_menu_message_preview, menu)
|
||||||
menuReplyButton = menu.findItem(R.id.messagePreviewMenuReply)
|
menuReplyButton = menu.findItem(R.id.messagePreviewMenuReply)
|
||||||
menuForwardButton = menu.findItem(R.id.messagePreviewMenuForward)
|
menuForwardButton = menu.findItem(R.id.messagePreviewMenuForward)
|
||||||
|
menuRestoreButton = menu.findItem(R.id.messagePreviewMenuRestore)
|
||||||
menuDeleteButton = menu.findItem(R.id.messagePreviewMenuDelete)
|
menuDeleteButton = menu.findItem(R.id.messagePreviewMenuDelete)
|
||||||
|
menuDeleteForeverButton = menu.findItem(R.id.messagePreviewMenuDeleteForever)
|
||||||
menuShareButton = menu.findItem(R.id.messagePreviewMenuShare)
|
menuShareButton = menu.findItem(R.id.messagePreviewMenuShare)
|
||||||
menuPrintButton = menu.findItem(R.id.messagePreviewMenuPrint)
|
menuPrintButton = menu.findItem(R.id.messagePreviewMenuPrint)
|
||||||
|
menuMuteButton = menu.findItem(R.id.messagePreviewMenuMute)
|
||||||
presenter.onCreateOptionsMenu()
|
presenter.onCreateOptionsMenu()
|
||||||
|
|
||||||
menu.findItem(R.id.mainMenuAccount).isVisible = false
|
menu.findItem(R.id.mainMenuAccount).isVisible = false
|
||||||
@ -115,9 +133,12 @@ class MessagePreviewFragment :
|
|||||||
return when (item.itemId) {
|
return when (item.itemId) {
|
||||||
R.id.messagePreviewMenuReply -> presenter.onReply()
|
R.id.messagePreviewMenuReply -> presenter.onReply()
|
||||||
R.id.messagePreviewMenuForward -> presenter.onForward()
|
R.id.messagePreviewMenuForward -> presenter.onForward()
|
||||||
|
R.id.messagePreviewMenuRestore -> presenter.onMessageRestore()
|
||||||
R.id.messagePreviewMenuDelete -> presenter.onMessageDelete()
|
R.id.messagePreviewMenuDelete -> presenter.onMessageDelete()
|
||||||
|
R.id.messagePreviewMenuDeleteForever -> presenter.onMessageDelete()
|
||||||
R.id.messagePreviewMenuShare -> presenter.onShare()
|
R.id.messagePreviewMenuShare -> presenter.onShare()
|
||||||
R.id.messagePreviewMenuPrint -> presenter.onPrint()
|
R.id.messagePreviewMenuPrint -> presenter.onPrint()
|
||||||
|
R.id.messagePreviewMenuMute -> presenter.onMute()
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -129,6 +150,11 @@ class MessagePreviewFragment :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun updateMuteToggleButton(isMuted: Boolean) {
|
||||||
|
menuMuteButton?.setTitle(if (isMuted) R.string.message_unmute else R.string.message_mute)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
override fun showProgress(show: Boolean) {
|
override fun showProgress(show: Boolean) {
|
||||||
binding.messagePreviewProgress.visibility = if (show) VISIBLE else GONE
|
binding.messagePreviewProgress.visibility = if (show) VISIBLE else GONE
|
||||||
}
|
}
|
||||||
@ -137,20 +163,15 @@ class MessagePreviewFragment :
|
|||||||
binding.messagePreviewRecycler.visibility = if (show) VISIBLE else GONE
|
binding.messagePreviewRecycler.visibility = if (show) VISIBLE else GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showOptions(show: Boolean, isReplayable: Boolean) {
|
override fun showOptions(show: Boolean, isReplayable: Boolean, isRestorable: Boolean) {
|
||||||
menuReplyButton?.isVisible = isReplayable
|
menuReplyButton?.isVisible = show && isReplayable
|
||||||
menuForwardButton?.isVisible = show
|
menuForwardButton?.isVisible = show
|
||||||
menuDeleteButton?.isVisible = show
|
menuRestoreButton?.isVisible = show && isRestorable
|
||||||
|
menuDeleteButton?.isVisible = show && !isRestorable
|
||||||
|
menuDeleteForeverButton?.isVisible = show && isRestorable
|
||||||
menuShareButton?.isVisible = show
|
menuShareButton?.isVisible = show
|
||||||
menuPrintButton?.isVisible = show
|
menuPrintButton?.isVisible = show
|
||||||
}
|
menuMuteButton?.isVisible = show && isReplayable
|
||||||
|
|
||||||
override fun setDeletedOptionsLabels() {
|
|
||||||
menuDeleteButton?.setTitle(R.string.message_delete_forever)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setNotDeletedOptionsLabels() {
|
|
||||||
menuDeleteButton?.setTitle(R.string.message_move_to_trash)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showErrorView(show: Boolean) {
|
override fun showErrorView(show: Boolean) {
|
||||||
@ -213,7 +234,7 @@ class MessagePreviewFragment :
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onSaveInstanceState(outState: Bundle) {
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
outState.putSerializable(MESSAGE_ID_KEY, presenter.message)
|
outState.putSerializable(MESSAGE_ID_KEY, presenter.messageWithAttachments)
|
||||||
super.onSaveInstanceState(outState)
|
super.onSaveInstanceState(outState)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ import androidx.core.text.parseAsHtml
|
|||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.*
|
import io.github.wulkanowy.data.*
|
||||||
import io.github.wulkanowy.data.db.entities.Message
|
import io.github.wulkanowy.data.db.entities.Message
|
||||||
import io.github.wulkanowy.data.db.entities.MessageAttachment
|
import io.github.wulkanowy.data.db.entities.MessageWithAttachment
|
||||||
import io.github.wulkanowy.data.enums.MessageFolder
|
import io.github.wulkanowy.data.enums.MessageFolder
|
||||||
import io.github.wulkanowy.data.repositories.MessageRepository
|
import io.github.wulkanowy.data.repositories.MessageRepository
|
||||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
@ -14,9 +14,11 @@ 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.utils.AnalyticsHelper
|
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||||
import io.github.wulkanowy.utils.toFormattedString
|
import io.github.wulkanowy.utils.toFormattedString
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
import kotlin.time.Duration.Companion.seconds
|
||||||
|
|
||||||
class MessagePreviewPresenter @Inject constructor(
|
class MessagePreviewPresenter @Inject constructor(
|
||||||
errorHandler: ErrorHandler,
|
errorHandler: ErrorHandler,
|
||||||
@ -26,9 +28,7 @@ class MessagePreviewPresenter @Inject constructor(
|
|||||||
private val analytics: AnalyticsHelper
|
private val analytics: AnalyticsHelper
|
||||||
) : BasePresenter<MessagePreviewView>(errorHandler, studentRepository) {
|
) : BasePresenter<MessagePreviewView>(errorHandler, studentRepository) {
|
||||||
|
|
||||||
var message: Message? = null
|
var messageWithAttachments: MessageWithAttachment? = null
|
||||||
|
|
||||||
var attachments: List<MessageAttachment>? = null
|
|
||||||
|
|
||||||
private lateinit var lastError: Throwable
|
private lateinit var lastError: Throwable
|
||||||
|
|
||||||
@ -38,7 +38,6 @@ class MessagePreviewPresenter @Inject constructor(
|
|||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
view.initView()
|
view.initView()
|
||||||
errorHandler.showErrorMessage = ::showErrorViewOnError
|
errorHandler.showErrorMessage = ::showErrorViewOnError
|
||||||
this.message = message
|
|
||||||
loadData(requireNotNull(message))
|
loadData(requireNotNull(message))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,25 +65,24 @@ class MessagePreviewPresenter @Inject constructor(
|
|||||||
.logResourceStatus("message ${messageToLoad.messageId} preview")
|
.logResourceStatus("message ${messageToLoad.messageId} preview")
|
||||||
.onResourceData {
|
.onResourceData {
|
||||||
if (it != null) {
|
if (it != null) {
|
||||||
message = it.message
|
messageWithAttachments = it
|
||||||
attachments = it.attachments
|
|
||||||
view?.apply {
|
view?.apply {
|
||||||
setMessageWithAttachment(it)
|
setMessageWithAttachment(it)
|
||||||
showContent(true)
|
showContent(true)
|
||||||
initOptions()
|
initOptions()
|
||||||
|
updateMuteToggleButton(isMuted = it.mutedMessageSender != null)
|
||||||
if (preferencesRepository.isIncognitoMode && it.message.unread) {
|
if (preferencesRepository.isIncognitoMode && it.message.unread) {
|
||||||
showMessage(R.string.message_incognito_description)
|
showMessage(R.string.message_incognito_description)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
delay(1.seconds)
|
||||||
view?.run {
|
view?.run {
|
||||||
showMessage(messageNotExists)
|
showMessage(messageNotExists)
|
||||||
popView()
|
popView()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}.onResourceSuccess {
|
||||||
.onResourceSuccess {
|
|
||||||
if (it != null) {
|
if (it != null) {
|
||||||
analytics.logEvent(
|
analytics.logEvent(
|
||||||
"load_item",
|
"load_item",
|
||||||
@ -92,31 +90,28 @@ class MessagePreviewPresenter @Inject constructor(
|
|||||||
"length" to it.message.content.length
|
"length" to it.message.content.length
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}.onResourceNotLoading { view?.showProgress(false) }.onResourceError {
|
||||||
.onResourceNotLoading { view?.showProgress(false) }
|
|
||||||
.onResourceError {
|
|
||||||
retryCallback = { onMessageLoadRetry(messageToLoad) }
|
retryCallback = { onMessageLoadRetry(messageToLoad) }
|
||||||
errorHandler.dispatch(it)
|
errorHandler.dispatch(it)
|
||||||
}
|
}.launch()
|
||||||
.launch()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onReply(): Boolean {
|
fun onReply(): Boolean {
|
||||||
return if (message != null) {
|
return if (messageWithAttachments?.message != null) {
|
||||||
view?.openMessageReply(message)
|
view?.openMessageReply(messageWithAttachments?.message)
|
||||||
true
|
true
|
||||||
} else false
|
} else false
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onForward(): Boolean {
|
fun onForward(): Boolean {
|
||||||
return if (message != null) {
|
return if (messageWithAttachments?.message != null) {
|
||||||
view?.openMessageForward(message)
|
view?.openMessageForward(messageWithAttachments?.message)
|
||||||
true
|
true
|
||||||
} else false
|
} else false
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onShare(): Boolean {
|
fun onShare(): Boolean {
|
||||||
val message = message ?: return false
|
val message = messageWithAttachments?.message ?: return false
|
||||||
val subject = message.subject.ifBlank { view?.messageNoSubjectString.orEmpty() }
|
val subject = message.subject.ifBlank { view?.messageNoSubjectString.orEmpty() }
|
||||||
|
|
||||||
val text = buildString {
|
val text = buildString {
|
||||||
@ -129,11 +124,13 @@ class MessagePreviewPresenter @Inject constructor(
|
|||||||
|
|
||||||
appendLine(message.content.parseAsHtml())
|
appendLine(message.content.parseAsHtml())
|
||||||
|
|
||||||
if (!attachments.isNullOrEmpty()) {
|
if (!messageWithAttachments?.attachments.isNullOrEmpty()) {
|
||||||
appendLine()
|
appendLine()
|
||||||
appendLine("Załączniki:")
|
appendLine("Załączniki:")
|
||||||
|
|
||||||
append(attachments.orEmpty().joinToString(separator = "\n") { attachment ->
|
append(
|
||||||
|
messageWithAttachments?.attachments.orEmpty()
|
||||||
|
.joinToString(separator = "\n") { attachment ->
|
||||||
"${attachment.filename}: ${attachment.url}"
|
"${attachment.filename}: ${attachment.url}"
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -148,7 +145,7 @@ class MessagePreviewPresenter @Inject constructor(
|
|||||||
|
|
||||||
@SuppressLint("NewApi")
|
@SuppressLint("NewApi")
|
||||||
fun onPrint(): Boolean {
|
fun onPrint(): Boolean {
|
||||||
val message = message ?: return false
|
val message = messageWithAttachments?.message ?: return false
|
||||||
val subject = message.subject.ifBlank { view?.messageNoSubjectString.orEmpty() }
|
val subject = message.subject.ifBlank { view?.messageNoSubjectString.orEmpty() }
|
||||||
|
|
||||||
val dateString = message.date.toFormattedString("yyyy-MM-dd HH:mm:ss")
|
val dateString = message.date.toFormattedString("yyyy-MM-dd HH:mm:ss")
|
||||||
@ -159,8 +156,7 @@ class MessagePreviewPresenter @Inject constructor(
|
|||||||
append("<div><h4>Od</h4>${message.sender}</div>")
|
append("<div><h4>Od</h4>${message.sender}</div>")
|
||||||
append("<div><h4>DO</h4>${message.recipients}</div>")
|
append("<div><h4>DO</h4>${message.recipients}</div>")
|
||||||
}
|
}
|
||||||
val messageContent = "<p>${message.content}</p>"
|
val messageContent = "<p>${message.content}</p>".replace(Regex("[\\n\\r]{2,}"), "</p><p>")
|
||||||
.replace(Regex("[\\n\\r]{2,}"), "</p><p>")
|
|
||||||
.replace(Regex("[\\n\\r]"), "<br>")
|
.replace(Regex("[\\n\\r]"), "<br>")
|
||||||
|
|
||||||
val jobName = buildString {
|
val jobName = buildString {
|
||||||
@ -171,9 +167,7 @@ class MessagePreviewPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
view?.apply {
|
view?.apply {
|
||||||
val html = printHTML
|
val html = printHTML.replace("%SUBJECT%", subject).replace("%CONTENT%", messageContent)
|
||||||
.replace("%SUBJECT%", subject)
|
|
||||||
.replace("%CONTENT%", messageContent)
|
|
||||||
.replace("%INFO%", infoContent)
|
.replace("%INFO%", infoContent)
|
||||||
printDocument(html, jobName)
|
printDocument(html, jobName)
|
||||||
}
|
}
|
||||||
@ -181,29 +175,64 @@ class MessagePreviewPresenter @Inject constructor(
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun deleteMessage() {
|
private fun restoreMessage() {
|
||||||
message ?: return
|
val message = messageWithAttachments?.message ?: return
|
||||||
|
|
||||||
view?.run {
|
view?.run {
|
||||||
showContent(false)
|
showContent(false)
|
||||||
showProgress(true)
|
showProgress(true)
|
||||||
showOptions(show = false, isReplayable = false)
|
showOptions(
|
||||||
|
show = false,
|
||||||
|
isReplayable = false,
|
||||||
|
isRestorable = false,
|
||||||
|
)
|
||||||
showErrorView(false)
|
showErrorView(false)
|
||||||
}
|
}
|
||||||
|
Timber.i("Restore message ${message.messageGlobalKey}")
|
||||||
Timber.i("Delete message ${message?.messageGlobalKey}")
|
|
||||||
|
|
||||||
presenterScope.launch {
|
presenterScope.launch {
|
||||||
runCatching {
|
runCatching {
|
||||||
val student = studentRepository.getCurrentStudent(decryptPass = true)
|
val student = studentRepository.getCurrentStudent(decryptPass = true)
|
||||||
val mailbox = messageRepository.getMailboxByStudent(student)
|
val mailbox = messageRepository.getMailboxByStudent(student)
|
||||||
messageRepository.deleteMessage(student, mailbox, message!!)
|
messageRepository.restoreMessages(student, mailbox, listOfNotNull(message))
|
||||||
}
|
}
|
||||||
.onFailure {
|
.onFailure {
|
||||||
retryCallback = { onMessageDelete() }
|
retryCallback = { onMessageRestore() }
|
||||||
errorHandler.dispatch(it)
|
errorHandler.dispatch(it)
|
||||||
}
|
}
|
||||||
.onSuccess {
|
.onSuccess {
|
||||||
|
view?.run {
|
||||||
|
showMessage(restoreMessageSuccessString)
|
||||||
|
popView()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
view?.showProgress(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun deleteMessage() {
|
||||||
|
messageWithAttachments?.message ?: return
|
||||||
|
|
||||||
|
view?.run {
|
||||||
|
showContent(false)
|
||||||
|
showProgress(true)
|
||||||
|
showOptions(
|
||||||
|
show = false,
|
||||||
|
isReplayable = false,
|
||||||
|
isRestorable = false,
|
||||||
|
)
|
||||||
|
showErrorView(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
Timber.i("Delete message ${messageWithAttachments?.message?.messageGlobalKey}")
|
||||||
|
|
||||||
|
presenterScope.launch {
|
||||||
|
runCatching {
|
||||||
|
val student = studentRepository.getCurrentStudent(decryptPass = true)
|
||||||
|
messageRepository.deleteMessage(student, messageWithAttachments?.message!!)
|
||||||
|
}.onFailure {
|
||||||
|
retryCallback = { onMessageDelete() }
|
||||||
|
errorHandler.dispatch(it)
|
||||||
|
}.onSuccess {
|
||||||
view?.run {
|
view?.run {
|
||||||
showMessage(deleteMessageSuccessString)
|
showMessage(deleteMessageSuccessString)
|
||||||
popView()
|
popView()
|
||||||
@ -224,6 +253,11 @@ class MessagePreviewPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onMessageRestore(): Boolean {
|
||||||
|
restoreMessage()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
fun onMessageDelete(): Boolean {
|
fun onMessageDelete(): Boolean {
|
||||||
deleteMessage()
|
deleteMessage()
|
||||||
return true
|
return true
|
||||||
@ -232,20 +266,39 @@ class MessagePreviewPresenter @Inject constructor(
|
|||||||
private fun initOptions() {
|
private fun initOptions() {
|
||||||
view?.apply {
|
view?.apply {
|
||||||
showOptions(
|
showOptions(
|
||||||
show = message != null,
|
show = messageWithAttachments?.message != null,
|
||||||
isReplayable = message?.folderId != MessageFolder.SENT.id,
|
isReplayable = messageWithAttachments?.message?.folderId == MessageFolder.RECEIVED.id,
|
||||||
|
isRestorable = messageWithAttachments?.message?.folderId == MessageFolder.TRASHED.id,
|
||||||
)
|
)
|
||||||
message?.let {
|
|
||||||
when (it.folderId == MessageFolder.TRASHED.id) {
|
|
||||||
true -> setDeletedOptionsLabels()
|
|
||||||
false -> setNotDeletedOptionsLabels()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onCreateOptionsMenu() {
|
fun onCreateOptionsMenu() {
|
||||||
initOptions()
|
initOptions()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onMute(): Boolean {
|
||||||
|
val message = messageWithAttachments?.message ?: return false
|
||||||
|
val isMuted = messageWithAttachments?.mutedMessageSender != null
|
||||||
|
|
||||||
|
presenterScope.launch {
|
||||||
|
runCatching {
|
||||||
|
when (isMuted) {
|
||||||
|
true -> {
|
||||||
|
messageRepository.unmuteMessage(message.correspondents)
|
||||||
|
view?.run { showMessage(unmuteMessageSuccessString) }
|
||||||
|
}
|
||||||
|
|
||||||
|
false -> {
|
||||||
|
messageRepository.muteMessage(message.correspondents)
|
||||||
|
view?.run { showMessage(muteMessageSuccessString) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.onFailure {
|
||||||
|
errorHandler.dispatch(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
view?.updateMuteToggleButton(isMuted)
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,12 @@ interface MessagePreviewView : BaseView {
|
|||||||
|
|
||||||
val deleteMessageSuccessString: String
|
val deleteMessageSuccessString: String
|
||||||
|
|
||||||
|
val muteMessageSuccessString: String
|
||||||
|
|
||||||
|
val unmuteMessageSuccessString: String
|
||||||
|
|
||||||
|
val restoreMessageSuccessString: String
|
||||||
|
|
||||||
val messageNoSubjectString: String
|
val messageNoSubjectString: String
|
||||||
|
|
||||||
val printHTML: String
|
val printHTML: String
|
||||||
@ -19,6 +25,8 @@ interface MessagePreviewView : BaseView {
|
|||||||
|
|
||||||
fun setMessageWithAttachment(item: MessageWithAttachment)
|
fun setMessageWithAttachment(item: MessageWithAttachment)
|
||||||
|
|
||||||
|
fun updateMuteToggleButton(isMuted: Boolean)
|
||||||
|
|
||||||
fun showProgress(show: Boolean)
|
fun showProgress(show: Boolean)
|
||||||
|
|
||||||
fun showContent(show: Boolean)
|
fun showContent(show: Boolean)
|
||||||
@ -29,11 +37,7 @@ interface MessagePreviewView : BaseView {
|
|||||||
|
|
||||||
fun setErrorRetryCallback(callback: () -> Unit)
|
fun setErrorRetryCallback(callback: () -> Unit)
|
||||||
|
|
||||||
fun showOptions(show: Boolean, isReplayable: Boolean)
|
fun showOptions(show: Boolean, isReplayable: Boolean, isRestorable: Boolean)
|
||||||
|
|
||||||
fun setDeletedOptionsLabels()
|
|
||||||
|
|
||||||
fun setNotDeletedOptionsLabels()
|
|
||||||
|
|
||||||
fun openMessageReply(message: Message?)
|
fun openMessageReply(message: Message?)
|
||||||
|
|
||||||
|
@ -203,7 +203,7 @@ class SendMessagePresenter @Inject constructor(
|
|||||||
subject = subject,
|
subject = subject,
|
||||||
content = content,
|
content = content,
|
||||||
recipients = recipients,
|
recipients = recipients,
|
||||||
mailboxId = mailbox.globalKey,
|
mailbox = mailbox,
|
||||||
)
|
)
|
||||||
}.logResourceStatus("sending message").onEach {
|
}.logResourceStatus("sending message").onEach {
|
||||||
when (it) {
|
when (it) {
|
||||||
|
@ -18,8 +18,7 @@ import io.github.wulkanowy.utils.getThemeAttrColor
|
|||||||
import io.github.wulkanowy.utils.toFormattedString
|
import io.github.wulkanowy.utils.toFormattedString
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class MessageTabAdapter @Inject constructor() :
|
class MessageTabAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||||
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
|
||||||
|
|
||||||
lateinit var onItemClickListener: (MessageTabDataItem.MessageItem, position: Int) -> Unit
|
lateinit var onItemClickListener: (MessageTabDataItem.MessageItem, position: Int) -> Unit
|
||||||
|
|
||||||
@ -52,10 +51,11 @@ class MessageTabAdapter @Inject constructor() :
|
|||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||||
val inflater = LayoutInflater.from(parent.context)
|
val inflater = LayoutInflater.from(parent.context)
|
||||||
|
|
||||||
return when (MessageItemViewType.values()[viewType]) {
|
return when (MessageItemViewType.entries[viewType]) {
|
||||||
MessageItemViewType.FILTERS -> HeaderViewHolder(
|
MessageItemViewType.FILTERS -> HeaderViewHolder(
|
||||||
ItemMessageChipsBinding.inflate(inflater, parent, false)
|
ItemMessageChipsBinding.inflate(inflater, parent, false)
|
||||||
)
|
)
|
||||||
|
|
||||||
MessageItemViewType.MESSAGE -> ItemViewHolder(
|
MessageItemViewType.MESSAGE -> ItemViewHolder(
|
||||||
ItemMessageBinding.inflate(inflater, parent, false)
|
ItemMessageBinding.inflate(inflater, parent, false)
|
||||||
)
|
)
|
||||||
@ -137,7 +137,12 @@ class MessageTabAdapter @Inject constructor() :
|
|||||||
ImageViewCompat.setImageTintList(this, ColorStateList.valueOf(currentTextColor))
|
ImageViewCompat.setImageTintList(this, ColorStateList.valueOf(currentTextColor))
|
||||||
isVisible = message.hasAttachments
|
isVisible = message.hasAttachments
|
||||||
}
|
}
|
||||||
messageItemUnreadIndicator.isVisible = message.unread
|
messageItemUnreadIndicator.isVisible = message.unread || item.isMuted
|
||||||
|
|
||||||
|
when (item.isMuted) {
|
||||||
|
true -> messageItemUnreadIndicator.setImageResource(R.drawable.ic_notifications_off)
|
||||||
|
else -> messageItemUnreadIndicator.setImageResource(R.drawable.ic_circle_notification)
|
||||||
|
}
|
||||||
|
|
||||||
root.setOnClickListener {
|
root.setOnClickListener {
|
||||||
holder.bindingAdapterPosition.let {
|
holder.bindingAdapterPosition.let {
|
||||||
@ -165,8 +170,7 @@ class MessageTabAdapter @Inject constructor() :
|
|||||||
RecyclerView.ViewHolder(binding.root)
|
RecyclerView.ViewHolder(binding.root)
|
||||||
|
|
||||||
private class MessageTabDiffUtil(
|
private class MessageTabDiffUtil(
|
||||||
private val old: List<MessageTabDataItem>,
|
private val old: List<MessageTabDataItem>, private val new: List<MessageTabDataItem>
|
||||||
private val new: List<MessageTabDataItem>
|
|
||||||
) : DiffUtil.Callback() {
|
) : DiffUtil.Callback() {
|
||||||
|
|
||||||
override fun getOldListSize(): Int = old.size
|
override fun getOldListSize(): Int = old.size
|
||||||
|
@ -6,6 +6,7 @@ sealed class MessageTabDataItem(val viewType: MessageItemViewType) {
|
|||||||
|
|
||||||
data class MessageItem(
|
data class MessageItem(
|
||||||
val message: Message,
|
val message: Message,
|
||||||
|
val isMuted: Boolean,
|
||||||
val isSelected: Boolean,
|
val isSelected: Boolean,
|
||||||
val isActionMode: Boolean
|
val isActionMode: Boolean
|
||||||
) : MessageTabDataItem(MessageItemViewType.MESSAGE)
|
) : MessageTabDataItem(MessageItemViewType.MESSAGE)
|
||||||
|
@ -5,7 +5,9 @@ import android.view.Menu
|
|||||||
import android.view.MenuInflater
|
import android.view.MenuInflater
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.View.*
|
import android.view.View.GONE
|
||||||
|
import android.view.View.INVISIBLE
|
||||||
|
import android.view.View.VISIBLE
|
||||||
import android.widget.CompoundButton
|
import android.widget.CompoundButton
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import androidx.appcompat.view.ActionMode
|
import androidx.appcompat.view.ActionMode
|
||||||
@ -64,10 +66,12 @@ class MessageTabFragment : BaseFragment<FragmentMessageTabBinding>(R.layout.frag
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
|
override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
|
||||||
if (presenter.folder == MessageFolder.TRASHED) {
|
val isTrashFolder = presenter.folder == MessageFolder.TRASHED
|
||||||
val menuItem = menu.findItem(R.id.messageTabContextMenuDelete)
|
|
||||||
menuItem.setTitle(R.string.message_delete_forever)
|
menu.findItem(R.id.messageTabContextMenuDelete).setVisible(!isTrashFolder)
|
||||||
}
|
menu.findItem(R.id.messageTabContextMenuDeleteForever).setVisible(isTrashFolder)
|
||||||
|
menu.findItem(R.id.messageTabContextMenuRestore).setVisible(isTrashFolder)
|
||||||
|
|
||||||
return presenter.onPrepareActionMode()
|
return presenter.onPrepareActionMode()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,6 +83,8 @@ class MessageTabFragment : BaseFragment<FragmentMessageTabBinding>(R.layout.frag
|
|||||||
override fun onActionItemClicked(mode: ActionMode, menu: MenuItem): Boolean {
|
override fun onActionItemClicked(mode: ActionMode, menu: MenuItem): Boolean {
|
||||||
when (menu.itemId) {
|
when (menu.itemId) {
|
||||||
R.id.messageTabContextMenuDelete -> presenter.onActionModeSelectDelete()
|
R.id.messageTabContextMenuDelete -> presenter.onActionModeSelectDelete()
|
||||||
|
R.id.messageTabContextMenuRestore -> presenter.onActionModeSelectRestore()
|
||||||
|
R.id.messageTabContextMenuDeleteForever -> presenter.onActionModeSelectDelete()
|
||||||
R.id.messageTabContextMenuSelectAll -> presenter.onActionModeSelectCheckAll()
|
R.id.messageTabContextMenuSelectAll -> presenter.onActionModeSelectCheckAll()
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
@ -4,6 +4,7 @@ import io.github.wulkanowy.R
|
|||||||
import io.github.wulkanowy.data.*
|
import io.github.wulkanowy.data.*
|
||||||
import io.github.wulkanowy.data.db.entities.Mailbox
|
import io.github.wulkanowy.data.db.entities.Mailbox
|
||||||
import io.github.wulkanowy.data.db.entities.Message
|
import io.github.wulkanowy.data.db.entities.Message
|
||||||
|
import io.github.wulkanowy.data.db.entities.MessageWithMutedAuthor
|
||||||
import io.github.wulkanowy.data.enums.MessageFolder
|
import io.github.wulkanowy.data.enums.MessageFolder
|
||||||
import io.github.wulkanowy.data.repositories.MessageRepository
|
import io.github.wulkanowy.data.repositories.MessageRepository
|
||||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||||
@ -39,7 +40,7 @@ class MessageTabPresenter @Inject constructor(
|
|||||||
private var mailboxes: List<Mailbox> = emptyList()
|
private var mailboxes: List<Mailbox> = emptyList()
|
||||||
private var selectedMailbox: Mailbox? = null
|
private var selectedMailbox: Mailbox? = null
|
||||||
|
|
||||||
private var messages = emptyList<Message>()
|
private var messages = emptyList<MessageWithMutedAuthor>()
|
||||||
|
|
||||||
private val searchChannel = Channel<String>()
|
private val searchChannel = Channel<String>()
|
||||||
|
|
||||||
@ -120,8 +121,27 @@ class MessageTabPresenter @Inject constructor(
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onActionModeSelectRestore() {
|
||||||
|
Timber.i("Restore ${messagesToDelete.size} messages")
|
||||||
|
val messageList = messagesToDelete.toList()
|
||||||
|
|
||||||
|
presenterScope.launch {
|
||||||
|
view?.run {
|
||||||
|
showProgress(true)
|
||||||
|
showContent(false)
|
||||||
|
showActionMode(false)
|
||||||
|
}
|
||||||
|
runCatching {
|
||||||
|
val student = studentRepository.getCurrentStudent(true)
|
||||||
|
messageRepository.restoreMessages(student, selectedMailbox, messageList)
|
||||||
|
}
|
||||||
|
.onFailure(errorHandler::dispatch)
|
||||||
|
.onSuccess { view?.showMessage(R.string.message_messages_restored) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun onActionModeSelectDelete() {
|
fun onActionModeSelectDelete() {
|
||||||
Timber.i("Delete ${messagesToDelete.size} messages)")
|
Timber.i("Delete ${messagesToDelete.size} messages")
|
||||||
val messageList = messagesToDelete.toList()
|
val messageList = messagesToDelete.toList()
|
||||||
|
|
||||||
presenterScope.launch {
|
presenterScope.launch {
|
||||||
@ -133,7 +153,7 @@ class MessageTabPresenter @Inject constructor(
|
|||||||
|
|
||||||
runCatching {
|
runCatching {
|
||||||
val student = studentRepository.getCurrentStudent(true)
|
val student = studentRepository.getCurrentStudent(true)
|
||||||
messageRepository.deleteMessages(student, selectedMailbox, messageList)
|
messageRepository.deleteMessages(student, messageList)
|
||||||
}
|
}
|
||||||
.onFailure(errorHandler::dispatch)
|
.onFailure(errorHandler::dispatch)
|
||||||
.onSuccess { view?.showMessage(R.string.message_messages_deleted) }
|
.onSuccess { view?.showMessage(R.string.message_messages_deleted) }
|
||||||
@ -141,7 +161,7 @@ class MessageTabPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun onActionModeSelectCheckAll() {
|
fun onActionModeSelectCheckAll() {
|
||||||
val messagesToSelect = getFilteredData()
|
val messagesToSelect = getFilteredData().map { it.message }
|
||||||
val isAllSelected = messagesToDelete.containsAll(messagesToSelect)
|
val isAllSelected = messagesToDelete.containsAll(messagesToSelect)
|
||||||
|
|
||||||
if (isAllSelected) {
|
if (isAllSelected) {
|
||||||
@ -188,7 +208,7 @@ class MessageTabPresenter @Inject constructor(
|
|||||||
view?.showActionMode(false)
|
view?.showActionMode(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
val filteredData = getFilteredData()
|
val filteredData = getFilteredData().map { it.message }
|
||||||
|
|
||||||
view?.run {
|
view?.run {
|
||||||
updateActionModeTitle(messagesToDelete.size)
|
updateActionModeTitle(messagesToDelete.size)
|
||||||
@ -320,25 +340,31 @@ class MessageTabPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getFilteredData(): List<Message> {
|
private fun getFilteredData(): List<MessageWithMutedAuthor> {
|
||||||
if (lastSearchQuery.trim().isEmpty()) {
|
if (lastSearchQuery.trim().isEmpty()) {
|
||||||
val sortedMessages = messages.sortedByDescending { it.date }
|
val sortedMessages = messages.sortedByDescending { it.message.date }
|
||||||
return when {
|
return when {
|
||||||
(onlyUnread == true) && onlyWithAttachments -> sortedMessages.filter { it.unread == onlyUnread && it.hasAttachments == onlyWithAttachments }
|
(onlyUnread == true) && onlyWithAttachments -> sortedMessages.filter {
|
||||||
(onlyUnread == true) -> sortedMessages.filter { it.unread == onlyUnread }
|
it.message.unread == onlyUnread && it.message.hasAttachments == onlyWithAttachments
|
||||||
onlyWithAttachments -> sortedMessages.filter { it.hasAttachments == onlyWithAttachments }
|
}
|
||||||
|
|
||||||
|
(onlyUnread == true) -> sortedMessages.filter { it.message.unread == onlyUnread }
|
||||||
|
onlyWithAttachments -> sortedMessages.filter { it.message.hasAttachments == onlyWithAttachments }
|
||||||
else -> sortedMessages
|
else -> sortedMessages
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val sortedMessages = messages
|
val sortedMessages = messages
|
||||||
.map { it to calculateMatchRatio(it, lastSearchQuery) }
|
.map { it to calculateMatchRatio(it.message, lastSearchQuery) }
|
||||||
.sortedWith(compareBy<Pair<Message, Int>> { -it.second }.thenByDescending { it.first.date })
|
.sortedWith(compareBy<Pair<MessageWithMutedAuthor, Int>> { -it.second }.thenByDescending { it.first.message.date })
|
||||||
.filter { it.second > 6000 }
|
.filter { it.second > 6000 }
|
||||||
.map { it.first }
|
.map { it.first }
|
||||||
return when {
|
return when {
|
||||||
(onlyUnread == true) && onlyWithAttachments -> sortedMessages.filter { it.unread == onlyUnread && it.hasAttachments == onlyWithAttachments }
|
(onlyUnread == true) && onlyWithAttachments -> sortedMessages.filter {
|
||||||
(onlyUnread == true) -> sortedMessages.filter { it.unread == onlyUnread }
|
it.message.unread == onlyUnread && it.message.hasAttachments == onlyWithAttachments
|
||||||
onlyWithAttachments -> sortedMessages.filter { it.hasAttachments == onlyWithAttachments }
|
}
|
||||||
|
|
||||||
|
(onlyUnread == true) -> sortedMessages.filter { it.message.unread == onlyUnread }
|
||||||
|
onlyWithAttachments -> sortedMessages.filter { it.message.hasAttachments == onlyWithAttachments }
|
||||||
else -> sortedMessages
|
else -> sortedMessages
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -367,8 +393,9 @@ class MessageTabPresenter @Inject constructor(
|
|||||||
|
|
||||||
addAll(data.map { message ->
|
addAll(data.map { message ->
|
||||||
MessageTabDataItem.MessageItem(
|
MessageTabDataItem.MessageItem(
|
||||||
message = message,
|
message = message.message,
|
||||||
isSelected = messagesToDelete.any { it.messageGlobalKey == message.messageGlobalKey },
|
isMuted = message.mutedMessageSender != null,
|
||||||
|
isSelected = messagesToDelete.any { it.messageGlobalKey == message.message.messageGlobalKey },
|
||||||
isActionMode = isActionMode
|
isActionMode = isActionMode
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -2,6 +2,7 @@ package io.github.wulkanowy.ui.modules.schoolannouncement
|
|||||||
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.view.isVisible
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import io.github.wulkanowy.data.db.entities.SchoolAnnouncement
|
import io.github.wulkanowy.data.db.entities.SchoolAnnouncement
|
||||||
import io.github.wulkanowy.databinding.ItemSchoolAnnouncementBinding
|
import io.github.wulkanowy.databinding.ItemSchoolAnnouncementBinding
|
||||||
@ -29,6 +30,10 @@ class SchoolAnnouncementAdapter @Inject constructor() :
|
|||||||
schoolAnnouncementItemDate.text = item.date.toFormattedString()
|
schoolAnnouncementItemDate.text = item.date.toFormattedString()
|
||||||
schoolAnnouncementItemType.text = item.subject
|
schoolAnnouncementItemType.text = item.subject
|
||||||
schoolAnnouncementItemContent.text = item.content.parseUonetHtml()
|
schoolAnnouncementItemContent.text = item.content.parseUonetHtml()
|
||||||
|
with(schoolAnnouncementItemAuthor) {
|
||||||
|
text = item.author
|
||||||
|
isVisible = !item.author.isNullOrBlank()
|
||||||
|
}
|
||||||
|
|
||||||
root.setOnClickListener { onItemClickListener(item) }
|
root.setOnClickListener { onItemClickListener(item) }
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package io.github.wulkanowy.ui.modules.timetable
|
|||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
|
||||||
import io.github.wulkanowy.data.db.entities.Timetable
|
import io.github.wulkanowy.data.db.entities.Timetable
|
||||||
import io.github.wulkanowy.data.enums.TimetableGapsMode.BETWEEN_AND_BEFORE_LESSONS
|
import io.github.wulkanowy.data.enums.TimetableGapsMode.BETWEEN_AND_BEFORE_LESSONS
|
||||||
import io.github.wulkanowy.data.enums.TimetableGapsMode.NO_GAPS
|
import io.github.wulkanowy.data.enums.TimetableGapsMode.NO_GAPS
|
||||||
@ -150,7 +149,7 @@ class TimetablePresenter @Inject constructor(
|
|||||||
val student = studentRepository.getCurrentStudent()
|
val student = studentRepository.getCurrentStudent()
|
||||||
val semester = semesterRepository.getCurrentSemester(student)
|
val semester = semesterRepository.getCurrentSemester(student)
|
||||||
|
|
||||||
checkInitialAndCurrentDate(student, semester)
|
checkInitialAndCurrentDate(semester)
|
||||||
timetableRepository.getTimetable(
|
timetableRepository.getTimetable(
|
||||||
student = student,
|
student = student,
|
||||||
semester = semester,
|
semester = semester,
|
||||||
@ -194,9 +193,9 @@ class TimetablePresenter @Inject constructor(
|
|||||||
.launch()
|
.launch()
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun checkInitialAndCurrentDate(student: Student, semester: Semester) {
|
private suspend fun checkInitialAndCurrentDate(semester: Semester) {
|
||||||
if (initialDate == null) {
|
if (initialDate == null) {
|
||||||
isWeekendHasLessons = isStudentHasLessonsOnWeekendUseCase(student, semester)
|
isWeekendHasLessons = isStudentHasLessonsOnWeekendUseCase(semester)
|
||||||
initialDate = getInitialDate(semester)
|
initialDate = getInitialDate(semester)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,11 +3,13 @@ package io.github.wulkanowy.utils
|
|||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.sdk.exception.FeatureNotAvailableException
|
import io.github.wulkanowy.sdk.exception.FeatureNotAvailableException
|
||||||
|
import io.github.wulkanowy.sdk.scrapper.exception.AccountInactiveException
|
||||||
import io.github.wulkanowy.sdk.scrapper.exception.CloudflareVerificationException
|
import io.github.wulkanowy.sdk.scrapper.exception.CloudflareVerificationException
|
||||||
import io.github.wulkanowy.sdk.scrapper.exception.FeatureDisabledException
|
import io.github.wulkanowy.sdk.scrapper.exception.FeatureDisabledException
|
||||||
import io.github.wulkanowy.sdk.scrapper.exception.ScrapperException
|
import io.github.wulkanowy.sdk.scrapper.exception.ScrapperException
|
||||||
import io.github.wulkanowy.sdk.scrapper.exception.ServiceUnavailableException
|
import io.github.wulkanowy.sdk.scrapper.exception.ServiceUnavailableException
|
||||||
import io.github.wulkanowy.sdk.scrapper.exception.VulcanException
|
import io.github.wulkanowy.sdk.scrapper.exception.VulcanException
|
||||||
|
import io.github.wulkanowy.sdk.scrapper.login.BadCredentialsException
|
||||||
import io.github.wulkanowy.sdk.scrapper.login.NotLoggedInException
|
import io.github.wulkanowy.sdk.scrapper.login.NotLoggedInException
|
||||||
import io.github.wulkanowy.sdk.scrapper.login.PasswordChangeRequiredException
|
import io.github.wulkanowy.sdk.scrapper.login.PasswordChangeRequiredException
|
||||||
import okhttp3.internal.http2.StreamResetException
|
import okhttp3.internal.http2.StreamResetException
|
||||||
@ -33,6 +35,8 @@ fun Resources.getErrorString(error: Throwable): String = when (error) {
|
|||||||
is ServiceUnavailableException -> R.string.error_service_unavailable
|
is ServiceUnavailableException -> R.string.error_service_unavailable
|
||||||
is FeatureDisabledException -> R.string.error_feature_disabled
|
is FeatureDisabledException -> R.string.error_feature_disabled
|
||||||
is FeatureNotAvailableException -> R.string.error_feature_not_available
|
is FeatureNotAvailableException -> R.string.error_feature_not_available
|
||||||
|
is BadCredentialsException -> R.string.error_password_invalid
|
||||||
|
is AccountInactiveException -> R.string.error_account_inactive
|
||||||
is VulcanException -> R.string.error_unknown_uonet
|
is VulcanException -> R.string.error_unknown_uonet
|
||||||
is ScrapperException -> R.string.error_unknown_app
|
is ScrapperException -> R.string.error_unknown_app
|
||||||
is CloudflareVerificationException -> R.string.error_cloudflare_captcha
|
is CloudflareVerificationException -> R.string.error_cloudflare_captcha
|
||||||
|
@ -5,17 +5,21 @@ import java.net.CookiePolicy
|
|||||||
import java.net.CookieStore
|
import java.net.CookieStore
|
||||||
import java.net.HttpCookie
|
import java.net.HttpCookie
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
import android.webkit.CookieManager as WebkitCookieManager
|
import android.webkit.CookieManager as WebkitCookieManager
|
||||||
import java.net.CookieManager as JavaCookieManager
|
import java.net.CookieManager as JavaCookieManager
|
||||||
|
|
||||||
class WebkitCookieManagerProxy : JavaCookieManager(null, CookiePolicy.ACCEPT_ALL) {
|
@Singleton
|
||||||
|
class WebkitCookieManagerProxy @Inject constructor() :
|
||||||
|
JavaCookieManager(null, CookiePolicy.ACCEPT_ALL) {
|
||||||
|
|
||||||
private val webkitCookieManager: WebkitCookieManager? = getWebkitCookieManager()
|
val webkitCookieManager: WebkitCookieManager? = getCookieManager()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see [https://stackoverflow.com/a/70354583/6695449]
|
* @see [https://stackoverflow.com/a/70354583/6695449]
|
||||||
*/
|
*/
|
||||||
private fun getWebkitCookieManager(): WebkitCookieManager? {
|
private fun getCookieManager(): WebkitCookieManager? {
|
||||||
return try {
|
return try {
|
||||||
WebkitCookieManager.getInstance()
|
WebkitCookieManager.getInstance()
|
||||||
} catch (e: AndroidRuntimeException) {
|
} catch (e: AndroidRuntimeException) {
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
Wersja 2.4.2
|
Wersja 2.5.0
|
||||||
|
|
||||||
- naprawiliśmy crash przy przełączaniu uczniów, motywów i języków
|
— dodaliśmy wyświetlanie ogłoszeń
|
||||||
- naprawiliśmy crash przy dodawaniu dodatkowych lekcji
|
— dodaliśmy opcję przywracania wiadomości z kosza
|
||||||
- naprawiliśmy obsługę błędów widżetach
|
— dodaliśmy opcję wyciszania nadawców wiadomości
|
||||||
|
— naprawiliśmy opcjonalne liczenie średniej arytmetycznej, kiedy brak ocen z wagą w drugim semestrze
|
||||||
|
— usprawniliśmy ładowanie frekwencji i planu lekcji
|
||||||
|
— naprawiliśmy usprawiedliwianie nieobecności i autoryzację u użytkowników eduOne
|
||||||
|
— zmieniliśmy komunikat o zmienionym haśle
|
||||||
|
|
||||||
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases
|
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases
|
||||||
|
10
app/src/main/res/drawable/ic_circle_notification.xml
Normal file
10
app/src/main/res/drawable/ic_circle_notification.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="oval">
|
||||||
|
|
||||||
|
<solid android:color="@color/colorPrimary" />
|
||||||
|
|
||||||
|
<size
|
||||||
|
android:width="10dp"
|
||||||
|
android:height="10dp" />
|
||||||
|
</shape>
|
@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#fff"
|
||||||
|
android:pathData="M14.12,10.47L12,12.59l-2.13,-2.12 -1.41,1.41L10.59,14l-2.12,2.12 1.41,1.41L12,15.41l2.12,2.12 1.41,-1.41L13.41,14l2.12,-2.12zM15.5,4l-1,-1h-5l-1,1H5v2h14V4zM6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM8,9h8v10H8V9z" />
|
||||||
|
</vector>
|
9
app/src/main/res/drawable/ic_menu_message_restore.xml
Normal file
9
app/src/main/res/drawable/ic_menu_message_restore.xml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#fff"
|
||||||
|
android:pathData="M15.5,4l-1,-1h-5l-1,1L5,4v2h14L19,4zM6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2L18,7L6,7v12zM8,14L8,9h8v10L8,19v-5zM10,18h4v-4h2l-4,-4 -4,4h2z" />
|
||||||
|
</vector>
|
5
app/src/main/res/drawable/ic_notifications_off.xml
Normal file
5
app/src/main/res/drawable/ic_notifications_off.xml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<vector android:height="17dp" android:tint="#000000"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="17dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M20,18.69L7.84,6.14 5.27,3.49 4,4.76l2.8,2.8v0.01c-0.52,0.99 -0.8,2.16 -0.8,3.42v5l-2,2v1h13.73l2,2L21,19.72l-1,-1.03zM12,22c1.11,0 2,-0.89 2,-2h-4c0,1.11 0.89,2 2,2zM18,14.68L18,11c0,-3.08 -1.64,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68c-0.15,0.03 -0.29,0.08 -0.42,0.12 -0.1,0.03 -0.2,0.07 -0.3,0.11h-0.01c-0.01,0 -0.01,0 -0.02,0.01 -0.23,0.09 -0.46,0.2 -0.68,0.31 0,0 -0.01,0 -0.01,0.01L18,14.68z"/>
|
||||||
|
</vector>
|
@ -16,7 +16,7 @@
|
|||||||
<com.google.android.material.appbar.MaterialToolbar
|
<com.google.android.material.appbar.MaterialToolbar
|
||||||
android:id="@+id/main_toolbar"
|
android:id="@+id/main_toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize" />
|
android:layout_height="wrap_content" />
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
<androidx.fragment.app.FragmentContainerView
|
<androidx.fragment.app.FragmentContainerView
|
||||||
|
@ -85,7 +85,7 @@
|
|||||||
android:id="@+id/accountEditDetailsSave"
|
android:id="@+id/accountEditDetailsSave"
|
||||||
style="@style/Widget.Material3.Button.TextButton.Dialog"
|
style="@style/Widget.Material3.Button.TextButton.Dialog"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="36dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="24dp"
|
android:layout_marginTop="24dp"
|
||||||
android:layout_marginEnd="24dp"
|
android:layout_marginEnd="24dp"
|
||||||
android:layout_marginBottom="24dp"
|
android:layout_marginBottom="24dp"
|
||||||
@ -93,6 +93,7 @@
|
|||||||
android:insetTop="0dp"
|
android:insetTop="0dp"
|
||||||
android:insetRight="0dp"
|
android:insetRight="0dp"
|
||||||
android:insetBottom="0dp"
|
android:insetBottom="0dp"
|
||||||
|
android:minHeight="36dp"
|
||||||
android:text="@string/all_save"
|
android:text="@string/all_save"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
@ -102,7 +103,7 @@
|
|||||||
android:id="@+id/accountEditDetailsCancel"
|
android:id="@+id/accountEditDetailsCancel"
|
||||||
style="@style/Widget.Material3.Button.TextButton.Dialog"
|
style="@style/Widget.Material3.Button.TextButton.Dialog"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="36dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="24dp"
|
android:layout_marginTop="24dp"
|
||||||
android:layout_marginEnd="8dp"
|
android:layout_marginEnd="8dp"
|
||||||
android:layout_marginBottom="24dp"
|
android:layout_marginBottom="24dp"
|
||||||
@ -110,6 +111,7 @@
|
|||||||
android:insetTop="0dp"
|
android:insetTop="0dp"
|
||||||
android:insetRight="0dp"
|
android:insetRight="0dp"
|
||||||
android:insetBottom="0dp"
|
android:insetBottom="0dp"
|
||||||
|
android:minHeight="36dp"
|
||||||
android:text="@android:string/cancel"
|
android:text="@android:string/cancel"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toStartOf="@id/accountEditDetailsSave"
|
app:layout_constraintEnd_toStartOf="@id/accountEditDetailsSave"
|
||||||
|
@ -113,7 +113,7 @@
|
|||||||
android:id="@+id/additionalLessonDialogClose"
|
android:id="@+id/additionalLessonDialogClose"
|
||||||
style="@style/Widget.Material3.Button.TextButton.Dialog"
|
style="@style/Widget.Material3.Button.TextButton.Dialog"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="36dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_vertical"
|
android:layout_gravity="center_vertical"
|
||||||
android:layout_marginTop="24dp"
|
android:layout_marginTop="24dp"
|
||||||
android:layout_marginEnd="8dp"
|
android:layout_marginEnd="8dp"
|
||||||
@ -122,6 +122,7 @@
|
|||||||
android:insetTop="0dp"
|
android:insetTop="0dp"
|
||||||
android:insetRight="0dp"
|
android:insetRight="0dp"
|
||||||
android:insetBottom="0dp"
|
android:insetBottom="0dp"
|
||||||
|
android:minHeight="36dp"
|
||||||
android:text="@string/all_close"
|
android:text="@string/all_close"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/additionalLessonDialogAdd"
|
app:layout_constraintEnd_toStartOf="@+id/additionalLessonDialogAdd"
|
||||||
@ -131,7 +132,7 @@
|
|||||||
android:id="@+id/additionalLessonDialogAdd"
|
android:id="@+id/additionalLessonDialogAdd"
|
||||||
style="@style/Widget.Material3.Button.TextButton.Dialog"
|
style="@style/Widget.Material3.Button.TextButton.Dialog"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="36dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_vertical"
|
android:layout_gravity="center_vertical"
|
||||||
android:layout_marginTop="24dp"
|
android:layout_marginTop="24dp"
|
||||||
android:layout_marginBottom="24dp"
|
android:layout_marginBottom="24dp"
|
||||||
@ -139,6 +140,7 @@
|
|||||||
android:insetTop="0dp"
|
android:insetTop="0dp"
|
||||||
android:insetRight="0dp"
|
android:insetRight="0dp"
|
||||||
android:insetBottom="0dp"
|
android:insetBottom="0dp"
|
||||||
|
android:minHeight="36dp"
|
||||||
android:text="@string/all_add"
|
android:text="@string/all_add"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
@ -150,7 +150,7 @@
|
|||||||
android:id="@+id/attendanceDialogClose"
|
android:id="@+id/attendanceDialogClose"
|
||||||
style="@style/Widget.Material3.Button.TextButton.Dialog"
|
style="@style/Widget.Material3.Button.TextButton.Dialog"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="36dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="24dp"
|
android:layout_marginTop="24dp"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:layout_marginBottom="24dp"
|
android:layout_marginBottom="24dp"
|
||||||
@ -158,6 +158,7 @@
|
|||||||
android:insetTop="0dp"
|
android:insetTop="0dp"
|
||||||
android:insetRight="0dp"
|
android:insetRight="0dp"
|
||||||
android:insetBottom="0dp"
|
android:insetBottom="0dp"
|
||||||
|
android:minHeight="36dp"
|
||||||
android:text="@string/all_close"
|
android:text="@string/all_close"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
@ -7,15 +7,18 @@
|
|||||||
tools:context=".ui.modules.captcha.CaptchaDialog">
|
tools:context=".ui.modules.captcha.CaptchaDialog">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
android:id="@+id/captcha_title"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="20dp"
|
android:layout_marginHorizontal="20dp"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
|
android:paddingVertical="10dp"
|
||||||
android:text="@string/captcha_dialog_title"
|
android:text="@string/captcha_dialog_title"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/captcha_close"
|
app:layout_constraintBottom_toBottomOf="@id/captcha_close"
|
||||||
app:layout_constraintEnd_toStartOf="@id/captcha_refresh"
|
app:layout_constraintEnd_toStartOf="@id/captcha_refresh"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintVertical_bias="0" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/captcha_refresh"
|
android:id="@+id/captcha_refresh"
|
||||||
@ -41,11 +44,29 @@
|
|||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.Barrier
|
||||||
|
android:id="@+id/captcha_toolbar"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:barrierDirection="bottom"
|
||||||
|
app:constraint_referenced_ids="captcha_title,captcha_close,captcha_refresh" />
|
||||||
|
|
||||||
<WebView
|
<WebView
|
||||||
android:id="@+id/captcha_webview"
|
android:id="@+id/captcha_webview"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="0dp"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/captcha_description"
|
||||||
|
app:layout_constraintDimensionRatio="1"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/captcha_toolbar" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/captcha_description"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingHorizontal="20dp"
|
||||||
|
android:paddingVertical="10dp"
|
||||||
|
android:text="@string/captcha_dialog_description"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/captcha_close" />
|
app:layout_constraintTop_toBottomOf="@id/captcha_webview" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
@ -181,7 +181,7 @@
|
|||||||
android:id="@+id/conferenceDialogClose"
|
android:id="@+id/conferenceDialogClose"
|
||||||
style="@style/Widget.Material3.Button.TextButton.Dialog"
|
style="@style/Widget.Material3.Button.TextButton.Dialog"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="36dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="24dp"
|
android:layout_marginTop="24dp"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:layout_marginBottom="24dp"
|
android:layout_marginBottom="24dp"
|
||||||
@ -189,6 +189,7 @@
|
|||||||
android:insetTop="0dp"
|
android:insetTop="0dp"
|
||||||
android:insetRight="0dp"
|
android:insetRight="0dp"
|
||||||
android:insetBottom="0dp"
|
android:insetBottom="0dp"
|
||||||
|
android:minHeight="36dp"
|
||||||
android:text="@string/all_close"
|
android:text="@string/all_close"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
@ -220,7 +220,7 @@
|
|||||||
android:id="@+id/examDialogAddToCalendar"
|
android:id="@+id/examDialogAddToCalendar"
|
||||||
style="@style/Widget.Material3.Button.TextButton.Dialog"
|
style="@style/Widget.Material3.Button.TextButton.Dialog"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="36dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginEnd="8dp"
|
android:layout_marginEnd="8dp"
|
||||||
android:layout_marginBottom="24dp"
|
android:layout_marginBottom="24dp"
|
||||||
android:contentDescription="@string/all_add_to_calendar"
|
android:contentDescription="@string/all_add_to_calendar"
|
||||||
@ -228,6 +228,7 @@
|
|||||||
android:insetTop="0dp"
|
android:insetTop="0dp"
|
||||||
android:insetRight="0dp"
|
android:insetRight="0dp"
|
||||||
android:insetBottom="0dp"
|
android:insetBottom="0dp"
|
||||||
|
android:minHeight="36dp"
|
||||||
android:text="@string/all_add"
|
android:text="@string/all_add"
|
||||||
app:icon="@drawable/ic_calendar_all"
|
app:icon="@drawable/ic_calendar_all"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
@ -237,7 +238,7 @@
|
|||||||
android:id="@+id/examDialogClose"
|
android:id="@+id/examDialogClose"
|
||||||
style="@style/Widget.Material3.Button.TextButton.Dialog"
|
style="@style/Widget.Material3.Button.TextButton.Dialog"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="36dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="24dp"
|
android:layout_marginTop="24dp"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:layout_marginBottom="24dp"
|
android:layout_marginBottom="24dp"
|
||||||
@ -245,6 +246,7 @@
|
|||||||
android:insetTop="0dp"
|
android:insetTop="0dp"
|
||||||
android:insetRight="0dp"
|
android:insetRight="0dp"
|
||||||
android:insetBottom="0dp"
|
android:insetBottom="0dp"
|
||||||
|
android:minHeight="36dp"
|
||||||
android:text="@string/all_close"
|
android:text="@string/all_close"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
@ -212,7 +212,7 @@
|
|||||||
android:id="@+id/gradeDialogClose"
|
android:id="@+id/gradeDialogClose"
|
||||||
style="@style/Widget.Material3.Button.TextButton.Dialog"
|
style="@style/Widget.Material3.Button.TextButton.Dialog"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="36dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_below="@+id/gradeDialogColorValue"
|
android:layout_below="@+id/gradeDialogColorValue"
|
||||||
android:layout_alignParentRight="true"
|
android:layout_alignParentRight="true"
|
||||||
android:layout_marginTop="24dp"
|
android:layout_marginTop="24dp"
|
||||||
@ -222,6 +222,7 @@
|
|||||||
android:insetTop="0dp"
|
android:insetTop="0dp"
|
||||||
android:insetRight="0dp"
|
android:insetRight="0dp"
|
||||||
android:insetBottom="0dp"
|
android:insetBottom="0dp"
|
||||||
|
android:minHeight="36dp"
|
||||||
android:text="@string/all_close" />
|
android:text="@string/all_close" />
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
android:id="@+id/homeworkDialogRead"
|
android:id="@+id/homeworkDialogRead"
|
||||||
style="@style/Widget.Material3.Button.TextButton.Dialog"
|
style="@style/Widget.Material3.Button.TextButton.Dialog"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="36dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_vertical"
|
android:layout_gravity="center_vertical"
|
||||||
android:layout_marginEnd="8dp"
|
android:layout_marginEnd="8dp"
|
||||||
android:layout_marginBottom="24dp"
|
android:layout_marginBottom="24dp"
|
||||||
@ -35,6 +35,7 @@
|
|||||||
android:insetTop="0dp"
|
android:insetTop="0dp"
|
||||||
android:insetRight="0dp"
|
android:insetRight="0dp"
|
||||||
android:insetBottom="0dp"
|
android:insetBottom="0dp"
|
||||||
|
android:minHeight="36dp"
|
||||||
android:text="@string/homework_mark_as_done"
|
android:text="@string/homework_mark_as_done"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/homeworkDialogClose" />
|
app:layout_constraintEnd_toStartOf="@+id/homeworkDialogClose" />
|
||||||
@ -43,13 +44,14 @@
|
|||||||
android:id="@+id/homeworkDialogClose"
|
android:id="@+id/homeworkDialogClose"
|
||||||
style="@style/Widget.Material3.Button.TextButton.Dialog"
|
style="@style/Widget.Material3.Button.TextButton.Dialog"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="36dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginEnd="24dp"
|
android:layout_marginEnd="24dp"
|
||||||
android:layout_marginBottom="24dp"
|
android:layout_marginBottom="24dp"
|
||||||
android:insetLeft="0dp"
|
android:insetLeft="0dp"
|
||||||
android:insetTop="0dp"
|
android:insetTop="0dp"
|
||||||
android:insetRight="0dp"
|
android:insetRight="0dp"
|
||||||
android:insetBottom="0dp"
|
android:insetBottom="0dp"
|
||||||
|
android:minHeight="36dp"
|
||||||
android:text="@string/all_close"
|
android:text="@string/all_close"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent" />
|
app:layout_constraintEnd_toEndOf="parent" />
|
||||||
|
@ -94,7 +94,7 @@
|
|||||||
android:id="@+id/homeworkDialogClose"
|
android:id="@+id/homeworkDialogClose"
|
||||||
style="@style/Widget.Material3.Button.TextButton.Dialog"
|
style="@style/Widget.Material3.Button.TextButton.Dialog"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="36dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_vertical"
|
android:layout_gravity="center_vertical"
|
||||||
android:layout_marginTop="24dp"
|
android:layout_marginTop="24dp"
|
||||||
android:layout_marginEnd="8dp"
|
android:layout_marginEnd="8dp"
|
||||||
@ -103,6 +103,7 @@
|
|||||||
android:insetTop="0dp"
|
android:insetTop="0dp"
|
||||||
android:insetRight="0dp"
|
android:insetRight="0dp"
|
||||||
android:insetBottom="0dp"
|
android:insetBottom="0dp"
|
||||||
|
android:minHeight="36dp"
|
||||||
android:text="@string/all_close"
|
android:text="@string/all_close"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/homeworkDialogAdd"
|
app:layout_constraintEnd_toStartOf="@+id/homeworkDialogAdd"
|
||||||
@ -112,13 +113,14 @@
|
|||||||
android:id="@+id/homeworkDialogAdd"
|
android:id="@+id/homeworkDialogAdd"
|
||||||
style="@style/Widget.Material3.Button.TextButton.Dialog"
|
style="@style/Widget.Material3.Button.TextButton.Dialog"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="36dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="24dp"
|
android:layout_marginTop="24dp"
|
||||||
android:layout_marginBottom="24dp"
|
android:layout_marginBottom="24dp"
|
||||||
android:insetLeft="0dp"
|
android:insetLeft="0dp"
|
||||||
android:insetTop="0dp"
|
android:insetTop="0dp"
|
||||||
android:insetRight="0dp"
|
android:insetRight="0dp"
|
||||||
android:insetBottom="0dp"
|
android:insetBottom="0dp"
|
||||||
|
android:minHeight="36dp"
|
||||||
android:text="@string/all_add"
|
android:text="@string/all_add"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
@ -212,7 +212,7 @@
|
|||||||
android:id="@+id/completedLessonDialogClose"
|
android:id="@+id/completedLessonDialogClose"
|
||||||
style="@style/Widget.Material3.Button.TextButton.Dialog"
|
style="@style/Widget.Material3.Button.TextButton.Dialog"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="36dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="24dp"
|
android:layout_marginTop="24dp"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:layout_marginBottom="24dp"
|
android:layout_marginBottom="24dp"
|
||||||
@ -220,6 +220,7 @@
|
|||||||
android:insetTop="0dp"
|
android:insetTop="0dp"
|
||||||
android:insetRight="0dp"
|
android:insetRight="0dp"
|
||||||
android:insetBottom="0dp"
|
android:insetBottom="0dp"
|
||||||
|
android:minHeight="36dp"
|
||||||
android:text="@string/all_close"
|
android:text="@string/all_close"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
@ -18,10 +18,10 @@
|
|||||||
android:layout_marginTop="24dp"
|
android:layout_marginTop="24dp"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:contentDescription="@string/mobile_device_qr"
|
android:contentDescription="@string/mobile_device_qr"
|
||||||
tools:src="@tools:sample/avatars"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:src="@tools:sample/avatars" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/mobileDeviceDialogTokenTitle"
|
android:id="@+id/mobileDeviceDialogTokenTitle"
|
||||||
@ -66,6 +66,7 @@
|
|||||||
app:layout_constraintHorizontal_bias="0"
|
app:layout_constraintHorizontal_bias="0"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/mobileDeviceDialogTokenValue" />
|
app:layout_constraintTop_toBottomOf="@+id/mobileDeviceDialogTokenValue" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/mobileDeviceDialogSymbolValue"
|
android:id="@+id/mobileDeviceDialogSymbolValue"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
@ -113,7 +114,7 @@
|
|||||||
android:id="@+id/mobileDeviceDialogClose"
|
android:id="@+id/mobileDeviceDialogClose"
|
||||||
style="@style/Widget.Material3.Button.TextButton.Dialog"
|
style="@style/Widget.Material3.Button.TextButton.Dialog"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="36dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="24dp"
|
android:layout_marginTop="24dp"
|
||||||
android:layout_marginEnd="24dp"
|
android:layout_marginEnd="24dp"
|
||||||
android:layout_marginBottom="24dp"
|
android:layout_marginBottom="24dp"
|
||||||
@ -121,6 +122,7 @@
|
|||||||
android:insetTop="0dp"
|
android:insetTop="0dp"
|
||||||
android:insetRight="0dp"
|
android:insetRight="0dp"
|
||||||
android:insetBottom="0dp"
|
android:insetBottom="0dp"
|
||||||
|
android:minHeight="36dp"
|
||||||
android:text="@string/all_close"
|
android:text="@string/all_close"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
@ -131,19 +133,19 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:visibility="invisible"
|
android:visibility="invisible"
|
||||||
tools:visibility="visible"
|
app:constraint_referenced_ids="mobileDeviceQr,mobileDeviceDialogTokenTitle,mobileDeviceDialogTokenValue,mobileDeviceDialogSymbolTitle,mobileDeviceDialogSymbolValue,mobileDeviceDialogPinTitle,mobileDeviceDialogPinValue,mobileDeviceDialogClose"
|
||||||
app:constraint_referenced_ids="mobileDeviceQr,mobileDeviceDialogTokenTitle,mobileDeviceDialogTokenValue,mobileDeviceDialogSymbolTitle,mobileDeviceDialogSymbolValue,mobileDeviceDialogPinTitle,mobileDeviceDialogPinValue,mobileDeviceDialogClose" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<com.google.android.material.progressindicator.CircularProgressIndicator
|
<com.google.android.material.progressindicator.CircularProgressIndicator
|
||||||
android:id="@+id/mobileDeviceDialogProgress"
|
android:id="@+id/mobileDeviceDialogProgress"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:indeterminate="true"
|
android:indeterminate="true"
|
||||||
tools:visibility="invisible"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent" />
|
tools:visibility="invisible" />
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
</androidx.core.widget.NestedScrollView>
|
</androidx.core.widget.NestedScrollView>
|
||||||
|
@ -180,7 +180,7 @@
|
|||||||
android:id="@+id/noteDialogClose"
|
android:id="@+id/noteDialogClose"
|
||||||
style="@style/Widget.Material3.Button.TextButton.Dialog"
|
style="@style/Widget.Material3.Button.TextButton.Dialog"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="36dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="24dp"
|
android:layout_marginTop="24dp"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:layout_marginBottom="24dp"
|
android:layout_marginBottom="24dp"
|
||||||
@ -188,6 +188,7 @@
|
|||||||
android:insetTop="0dp"
|
android:insetTop="0dp"
|
||||||
android:insetRight="0dp"
|
android:insetRight="0dp"
|
||||||
android:insetBottom="0dp"
|
android:insetBottom="0dp"
|
||||||
|
android:minHeight="36dp"
|
||||||
android:text="@string/all_close"
|
android:text="@string/all_close"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
@ -122,7 +122,7 @@
|
|||||||
android:id="@+id/announcementDialogClose"
|
android:id="@+id/announcementDialogClose"
|
||||||
style="@style/Widget.Material3.Button.TextButton.Dialog"
|
style="@style/Widget.Material3.Button.TextButton.Dialog"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="36dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="24dp"
|
android:layout_marginTop="24dp"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:layout_marginBottom="24dp"
|
android:layout_marginBottom="24dp"
|
||||||
@ -130,6 +130,7 @@
|
|||||||
android:insetTop="0dp"
|
android:insetTop="0dp"
|
||||||
android:insetRight="0dp"
|
android:insetRight="0dp"
|
||||||
android:insetBottom="0dp"
|
android:insetBottom="0dp"
|
||||||
|
android:minHeight="36dp"
|
||||||
android:text="@string/all_close"
|
android:text="@string/all_close"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
@ -263,7 +263,7 @@
|
|||||||
android:id="@+id/timetableDialogClose"
|
android:id="@+id/timetableDialogClose"
|
||||||
style="@style/Widget.Material3.Button.TextButton.Dialog"
|
style="@style/Widget.Material3.Button.TextButton.Dialog"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="36dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="24dp"
|
android:layout_marginTop="24dp"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:layout_marginBottom="24dp"
|
android:layout_marginBottom="24dp"
|
||||||
@ -271,6 +271,7 @@
|
|||||||
android:insetTop="0dp"
|
android:insetTop="0dp"
|
||||||
android:insetRight="0dp"
|
android:insetRight="0dp"
|
||||||
android:insetBottom="0dp"
|
android:insetBottom="0dp"
|
||||||
|
android:minHeight="36dp"
|
||||||
android:text="@string/all_close"
|
android:text="@string/all_close"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
@ -45,6 +45,9 @@
|
|||||||
android:textColor="?android:textColorSecondary"
|
android:textColor="?android:textColorSecondary"
|
||||||
android:textSize="12sp"
|
android:textSize="12sp"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/gradeHeaderPointsSum"
|
||||||
|
app:layout_constraintHorizontal_bias="0"
|
||||||
|
app:layout_constraintHorizontal_chainStyle="packed"
|
||||||
app:layout_constraintStart_toStartOf="@id/gradeHeaderSubject"
|
app:layout_constraintStart_toStartOf="@id/gradeHeaderSubject"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/gradeHeaderSubject"
|
app:layout_constraintTop_toBottomOf="@+id/gradeHeaderSubject"
|
||||||
tools:text="Average: 6,00" />
|
tools:text="Average: 6,00" />
|
||||||
@ -55,8 +58,12 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="10dp"
|
android:layout_marginStart="10dp"
|
||||||
android:layout_marginTop="5dp"
|
android:layout_marginTop="5dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="1"
|
||||||
android:textColor="?android:textColorSecondary"
|
android:textColor="?android:textColorSecondary"
|
||||||
android:textSize="12sp"
|
android:textSize="12sp"
|
||||||
|
app:layout_constrainedWidth="true"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/gradeHeaderNumber"
|
||||||
app:layout_constraintStart_toEndOf="@+id/gradeHeaderAverage"
|
app:layout_constraintStart_toEndOf="@+id/gradeHeaderAverage"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/gradeHeaderSubject"
|
app:layout_constraintTop_toBottomOf="@+id/gradeHeaderSubject"
|
||||||
tools:text="Points: 123/200 (61,5%)" />
|
tools:text="Points: 123/200 (61,5%)" />
|
||||||
@ -67,8 +74,13 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="10dp"
|
android:layout_marginStart="10dp"
|
||||||
android:layout_marginTop="5dp"
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="1"
|
||||||
android:textColor="?android:textColorSecondary"
|
android:textColor="?android:textColorSecondary"
|
||||||
android:textSize="12sp"
|
android:textSize="12sp"
|
||||||
|
app:layout_constrainedWidth="true"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toEndOf="@+id/gradeHeaderPointsSum"
|
app:layout_constraintStart_toEndOf="@+id/gradeHeaderPointsSum"
|
||||||
app:layout_constraintTop_toBottomOf="@id/gradeHeaderSubject"
|
app:layout_constraintTop_toBottomOf="@id/gradeHeaderSubject"
|
||||||
tools:text="12 grades" />
|
tools:text="12 grades" />
|
||||||
@ -85,6 +97,9 @@
|
|||||||
android:paddingRight="5dp"
|
android:paddingRight="5dp"
|
||||||
android:textColor="?colorOnPrimary"
|
android:textColor="?colorOnPrimary"
|
||||||
android:textSize="14sp"
|
android:textSize="14sp"
|
||||||
|
app:autoSizeMaxTextSize="16dp"
|
||||||
|
app:autoSizeMinTextSize="10dp"
|
||||||
|
app:autoSizeTextType="uniform"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
@ -81,9 +81,9 @@
|
|||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/messageItemUnreadIndicator"
|
android:id="@+id/messageItemUnreadIndicator"
|
||||||
android:layout_width="10dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="10dp"
|
android:layout_height="wrap_content"
|
||||||
android:src="@drawable/ic_circle"
|
android:src="@drawable/ic_circle_notification"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/messageItemDate"
|
app:layout_constraintBottom_toBottomOf="@id/messageItemDate"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="@id/messageItemDate"
|
app:layout_constraintTop_toTopOf="@id/messageItemDate"
|
||||||
|
@ -11,27 +11,41 @@
|
|||||||
android:id="@+id/schoolAnnouncementItemDate"
|
android:id="@+id/schoolAnnouncementItemDate"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="15dp"
|
android:layout_marginHorizontal="15dp"
|
||||||
android:layout_marginTop="10dp"
|
android:layout_marginTop="10dp"
|
||||||
android:layout_marginEnd="10dp"
|
|
||||||
android:textColor="?android:textColorSecondary"
|
android:textColor="?android:textColorSecondary"
|
||||||
android:textSize="15sp"
|
android:textSize="15sp"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toStartOf="@id/schoolAnnouncementItemAuthor"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:text="@tools:sample/date/ddmmyy" />
|
tools:text="@tools:sample/date/ddmmyy" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/schoolAnnouncementItemAuthor"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="15dp"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:layout_marginEnd="10dp"
|
||||||
|
android:gravity="end"
|
||||||
|
android:textColor="?android:textColorSecondary"
|
||||||
|
android:textSize="15sp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/schoolAnnouncementItemDate"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:text="@tools:sample/full_names" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/schoolAnnouncementItemType"
|
android:id="@+id/schoolAnnouncementItemType"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="5dp"
|
android:layout_marginHorizontal="15dp"
|
||||||
android:layout_marginBottom="5dp"
|
android:layout_marginVertical="5dp"
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:maxLines="2"
|
android:maxLines="2"
|
||||||
android:textSize="16sp"
|
android:textSize="16sp"
|
||||||
app:layout_constraintEnd_toEndOf="@id/schoolAnnouncementItemDate"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="@id/schoolAnnouncementItemDate"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/schoolAnnouncementItemDate"
|
app:layout_constraintTop_toBottomOf="@id/schoolAnnouncementItemDate"
|
||||||
app:layout_goneMarginEnd="0dp"
|
app:layout_goneMarginEnd="0dp"
|
||||||
tools:text="@tools:sample/lorem" />
|
tools:text="@tools:sample/lorem" />
|
||||||
@ -40,6 +54,7 @@
|
|||||||
android:id="@+id/schoolAnnouncementItemContent"
|
android:id="@+id/schoolAnnouncementItemContent"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="15dp"
|
||||||
android:layout_marginTop="5dp"
|
android:layout_marginTop="5dp"
|
||||||
android:layout_marginBottom="15dp"
|
android:layout_marginBottom="15dp"
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
@ -47,8 +62,8 @@
|
|||||||
android:maxLines="2"
|
android:maxLines="2"
|
||||||
android:textSize="14sp"
|
android:textSize="14sp"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="@+id/schoolAnnouncementItemType"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="@id/schoolAnnouncementItemDate"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/schoolAnnouncementItemType"
|
app:layout_constraintTop_toBottomOf="@id/schoolAnnouncementItemType"
|
||||||
tools:text="@tools:sample/lorem/random" />
|
tools:text="@tools:sample/lorem/random" />
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/relativeLayout2"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="?selectableItemBackground"
|
android:background="?selectableItemBackground"
|
||||||
@ -15,15 +14,17 @@
|
|||||||
android:id="@+id/timetableItemNumber"
|
android:id="@+id/timetableItemNumber"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:minWidth="40dp"
|
|
||||||
android:minHeight="40dp"
|
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:includeFontPadding="false"
|
android:includeFontPadding="false"
|
||||||
android:maxLength="2"
|
android:maxLength="2"
|
||||||
|
android:minWidth="40dp"
|
||||||
|
android:minHeight="40dp"
|
||||||
android:textColor="?android:textColorPrimary"
|
android:textColor="?android:textColorPrimary"
|
||||||
android:textSize="32sp"
|
android:textSize="32sp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintVertical_bias="0"
|
||||||
tools:text="5" />
|
tools:text="5" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
@ -38,7 +39,7 @@
|
|||||||
android:textSize="15sp"
|
android:textSize="15sp"
|
||||||
app:layout_constraintEnd_toStartOf="@id/timetableItemTimeBarrier"
|
app:layout_constraintEnd_toStartOf="@id/timetableItemTimeBarrier"
|
||||||
app:layout_constraintStart_toEndOf="@+id/timetableItemTimeStart"
|
app:layout_constraintStart_toEndOf="@+id/timetableItemTimeStart"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="@id/timetableItemTimeStart"
|
||||||
tools:text="@tools:sample/lorem" />
|
tools:text="@tools:sample/lorem" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
@ -49,8 +50,11 @@
|
|||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
android:textColor="?android:textColorSecondary"
|
android:textColor="?android:textColorSecondary"
|
||||||
android:textSize="13sp"
|
android:textSize="13sp"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/timetableItemTimeFinish"
|
||||||
app:layout_constraintStart_toEndOf="@id/timetableItemNumber"
|
app:layout_constraintStart_toEndOf="@id/timetableItemNumber"
|
||||||
app:layout_constraintTop_toTopOf="@id/timetableItemNumber"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintVertical_bias="0"
|
||||||
|
app:layout_constraintVertical_chainStyle="packed"
|
||||||
tools:text="11:11" />
|
tools:text="11:11" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
@ -58,11 +62,13 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="8dp"
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
android:textColor="?android:textColorSecondary"
|
android:textColor="?android:textColorSecondary"
|
||||||
android:textSize="13sp"
|
android:textSize="13sp"
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/timetableItemNumber"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintStart_toEndOf="@id/timetableItemNumber"
|
app:layout_constraintStart_toEndOf="@id/timetableItemNumber"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/timetableItemTimeStart"
|
||||||
tools:text="12:00" />
|
tools:text="12:00" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
@ -70,11 +76,16 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="10dp"
|
android:layout_marginStart="10dp"
|
||||||
|
android:layout_marginEnd="0dp"
|
||||||
|
android:ellipsize="end"
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
android:textColor="?android:textColorSecondary"
|
android:textColor="?android:textColorSecondary"
|
||||||
android:textSize="13sp"
|
android:textSize="13sp"
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/timetableItemNumber"
|
app:layout_constraintEnd_toStartOf="@id/timetableItemGroup"
|
||||||
|
app:layout_constraintHorizontal_bias="0"
|
||||||
|
app:layout_constraintHorizontal_chainStyle="packed"
|
||||||
app:layout_constraintStart_toEndOf="@+id/timetableItemTimeStart"
|
app:layout_constraintStart_toEndOf="@+id/timetableItemTimeStart"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/timetableItemTimeFinish"
|
||||||
tools:text="22"
|
tools:text="22"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
@ -83,13 +94,14 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="10dp"
|
android:layout_marginStart="10dp"
|
||||||
android:layout_marginTop="0dp"
|
android:layout_marginEnd="0dp"
|
||||||
android:layout_marginEnd="5dp"
|
android:ellipsize="end"
|
||||||
|
android:maxLines="1"
|
||||||
android:textColor="?android:textColorSecondary"
|
android:textColor="?android:textColorSecondary"
|
||||||
android:textSize="13sp"
|
android:textSize="13sp"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/timetableItemTeacher"
|
app:layout_constraintEnd_toStartOf="@+id/timetableItemTeacher"
|
||||||
app:layout_constraintStart_toEndOf="@+id/timetableItemRoom"
|
app:layout_constraintStart_toEndOf="@+id/timetableItemRoom"
|
||||||
app:layout_constraintTop_toTopOf="@+id/timetableItemTimeFinish"
|
app:layout_constraintTop_toTopOf="@id/timetableItemTimeFinish"
|
||||||
tools:text="(2/2)"
|
tools:text="(2/2)"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
@ -98,13 +110,15 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="10dp"
|
android:layout_marginStart="10dp"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="8dp"
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
android:textColor="?android:textColorSecondary"
|
android:textColor="?android:textColorSecondary"
|
||||||
android:textSize="13sp"
|
android:textSize="13sp"
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/timetableItemNumber"
|
app:layout_constrainedWidth="true"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toEndOf="@id/timetableItemGroup"
|
app:layout_constraintStart_toEndOf="@id/timetableItemGroup"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/timetableItemTimeFinish"
|
||||||
tools:text="Agata Kowalska - Błaszczyk"
|
tools:text="Agata Kowalska - Błaszczyk"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
@ -118,8 +132,8 @@
|
|||||||
android:textColor="?colorTimetableChange"
|
android:textColor="?colorTimetableChange"
|
||||||
android:textSize="13sp"
|
android:textSize="13sp"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toEndOf="@+id/timetableItemTeacher"
|
app:layout_constraintStart_toEndOf="@id/timetableItemTimeFinish"
|
||||||
app:layout_constraintTop_toTopOf="@+id/timetableItemTimeFinish"
|
app:layout_constraintTop_toTopOf="@id/timetableItemTimeFinish"
|
||||||
tools:text="Lekcja odwołana: uczniowie zwolnieni do domu"
|
tools:text="Lekcja odwołana: uczniowie zwolnieni do domu"
|
||||||
tools:visibility="gone" />
|
tools:visibility="gone" />
|
||||||
|
|
||||||
@ -168,7 +182,7 @@
|
|||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
app:backgroundTint="?colorPrimary"
|
app:backgroundTint="?colorPrimary"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="@id/timetableItemTimeStart"
|
||||||
tools:text="jeszcze 15 min"
|
tools:text="jeszcze 15 min"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/dashboard_small_grade_subitem_value"
|
android:id="@+id/dashboard_small_grade_subitem_value"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
@ -10,7 +11,11 @@
|
|||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:maxLength="5"
|
android:maxLength="5"
|
||||||
android:minWidth="20dp"
|
android:minWidth="20dp"
|
||||||
|
android:padding="1dp"
|
||||||
android:textColor="@android:color/white"
|
android:textColor="@android:color/white"
|
||||||
android:textSize="12sp"
|
android:textSize="12sp"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
|
app:autoSizeMaxTextSize="14dp"
|
||||||
|
app:autoSizeMinTextSize="10dp"
|
||||||
|
app:autoSizeTextType="uniform"
|
||||||
tools:text="6" />
|
tools:text="6" />
|
||||||
|
@ -29,6 +29,13 @@
|
|||||||
android:title="@string/message_forward"
|
android:title="@string/message_forward"
|
||||||
app:iconTint="@color/material_on_surface_emphasis_medium"
|
app:iconTint="@color/material_on_surface_emphasis_medium"
|
||||||
app:showAsAction="ifRoom" />
|
app:showAsAction="ifRoom" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/messagePreviewMenuRestore"
|
||||||
|
android:icon="@drawable/ic_menu_message_restore"
|
||||||
|
android:orderInCategory="1"
|
||||||
|
android:title="@string/message_restore_from_trash"
|
||||||
|
app:iconTint="@color/material_on_surface_emphasis_medium"
|
||||||
|
app:showAsAction="ifRoom" />
|
||||||
<item
|
<item
|
||||||
android:id="@+id/messagePreviewMenuDelete"
|
android:id="@+id/messagePreviewMenuDelete"
|
||||||
android:icon="@drawable/ic_menu_message_delete"
|
android:icon="@drawable/ic_menu_message_delete"
|
||||||
@ -36,4 +43,18 @@
|
|||||||
android:title="@string/message_move_to_trash"
|
android:title="@string/message_move_to_trash"
|
||||||
app:iconTint="@color/material_on_surface_emphasis_medium"
|
app:iconTint="@color/material_on_surface_emphasis_medium"
|
||||||
app:showAsAction="ifRoom" />
|
app:showAsAction="ifRoom" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/messagePreviewMenuDeleteForever"
|
||||||
|
android:icon="@drawable/ic_menu_message_delete_forever"
|
||||||
|
android:orderInCategory="1"
|
||||||
|
android:title="@string/message_delete_forever"
|
||||||
|
app:iconTint="@color/material_on_surface_emphasis_medium"
|
||||||
|
app:showAsAction="ifRoom" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/messagePreviewMenuMute"
|
||||||
|
android:icon="@drawable/ic_settings_notifications"
|
||||||
|
android:orderInCategory="1"
|
||||||
|
android:title="@string/message_mute"
|
||||||
|
app:iconTint="@color/material_on_surface_emphasis_medium"
|
||||||
|
app:showAsAction="ifRoom" />
|
||||||
</menu>
|
</menu>
|
||||||
|
@ -1,6 +1,13 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
<item
|
||||||
|
android:id="@+id/messageTabContextMenuRestore"
|
||||||
|
android:icon="@drawable/ic_menu_message_restore"
|
||||||
|
android:orderInCategory="1"
|
||||||
|
android:title="@string/message_restore_from_trash"
|
||||||
|
app:iconTint="@color/material_on_surface_emphasis_medium"
|
||||||
|
app:showAsAction="always" />
|
||||||
<item
|
<item
|
||||||
android:id="@+id/messageTabContextMenuDelete"
|
android:id="@+id/messageTabContextMenuDelete"
|
||||||
android:icon="@drawable/ic_menu_message_delete"
|
android:icon="@drawable/ic_menu_message_delete"
|
||||||
@ -8,6 +15,13 @@
|
|||||||
android:title="@string/message_move_to_trash"
|
android:title="@string/message_move_to_trash"
|
||||||
app:iconTint="@color/material_on_surface_emphasis_medium"
|
app:iconTint="@color/material_on_surface_emphasis_medium"
|
||||||
app:showAsAction="always" />
|
app:showAsAction="always" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/messageTabContextMenuDeleteForever"
|
||||||
|
android:icon="@drawable/ic_menu_message_delete_forever"
|
||||||
|
android:orderInCategory="1"
|
||||||
|
android:title="@string/message_delete_forever"
|
||||||
|
app:iconTint="@color/material_on_surface_emphasis_medium"
|
||||||
|
app:showAsAction="always" />
|
||||||
<item
|
<item
|
||||||
android:id="@+id/messageTabContextMenuSelectAll"
|
android:id="@+id/messageTabContextMenuSelectAll"
|
||||||
android:icon="@drawable/ic_message_select_all"
|
android:icon="@drawable/ic_message_select_all"
|
||||||
|
@ -56,7 +56,7 @@
|
|||||||
<string name="login_invalid_email">Neplatný e-mail</string>
|
<string name="login_invalid_email">Neplatný e-mail</string>
|
||||||
<string name="login_invalid_login">Místo e-mailu použijte přiřazené přihlašovací údaje</string>
|
<string name="login_invalid_login">Místo e-mailu použijte přiřazené přihlašovací údaje</string>
|
||||||
<string name="login_invalid_custom_email">Použijte přiřazené přihlašovací nebo e-mail v @%1$s</string>
|
<string name="login_invalid_custom_email">Použijte přiřazené přihlašovací nebo e-mail v @%1$s</string>
|
||||||
<string name="login_invalid_domain_suffix">Invalid domain suffix</string>
|
<string name="login_invalid_domain_suffix">Neplatná přípona domény</string>
|
||||||
<string name="login_invalid_symbol">Neplatný symbol. Pokud jej nemůžete najít, kontaktujte školu</string>
|
<string name="login_invalid_symbol">Neplatný symbol. Pokud jej nemůžete najít, kontaktujte školu</string>
|
||||||
<string name="login_invalid_symbol_definitely">Nevymýšlejte si! Pokud symbol nemůžete najít, kontaktujte školu</string>
|
<string name="login_invalid_symbol_definitely">Nevymýšlejte si! Pokud symbol nemůžete najít, kontaktujte školu</string>
|
||||||
<string name="login_incorrect_symbol">Žák nebyl nalezen. Zkontrolujte správnost symbolu a vybrané varianty deníku UONET+</string>
|
<string name="login_incorrect_symbol">Žák nebyl nalezen. Zkontrolujte správnost symbolu a vybrané varianty deníku UONET+</string>
|
||||||
@ -98,8 +98,8 @@
|
|||||||
<string name="main_log_in">Přihlásit se</string>
|
<string name="main_log_in">Přihlásit se</string>
|
||||||
<string name="main_session_expired">Relace vypršela</string>
|
<string name="main_session_expired">Relace vypršela</string>
|
||||||
<string name="main_session_relogin">Relace vypršela. Přihlaste se prosím znovu</string>
|
<string name="main_session_relogin">Relace vypršela. Přihlaste se prosím znovu</string>
|
||||||
<string name="main_expired_credentials_description">Heslo k vašemu účtu bylo změněno. Musíte se znovu přihlásit do Wulkanového</string>
|
<string name="main_expired_credentials_title">Heslo vypršelo nebo bylo změněno</string>
|
||||||
<string name="main_expired_credentials_title">Heslo bylo změněno</string>
|
<string name="main_expired_credentials_description">Platnost hesla k vašemu účtu vypršela nebo bylo změněno. Budete se muset znovu přihlásit do Wulkanového</string>
|
||||||
<string name="main_support_title">Podpora aplikace</string>
|
<string name="main_support_title">Podpora aplikace</string>
|
||||||
<string name="main_support_description">Líbí se Vám tato aplikace? Podpořte její vývoj tím, že povolíte neinvazivní reklamy, které můžete kdykoliv vypnout</string>
|
<string name="main_support_description">Líbí se Vám tato aplikace? Podpořte její vývoj tím, že povolíte neinvazivní reklamy, které můžete kdykoliv vypnout</string>
|
||||||
<string name="main_support_positive">Zapnout reklamy</string>
|
<string name="main_support_positive">Zapnout reklamy</string>
|
||||||
@ -336,8 +336,10 @@
|
|||||||
<string name="message_forward">Poslat dále</string>
|
<string name="message_forward">Poslat dále</string>
|
||||||
<string name="message_select_all">Vybrat vše</string>
|
<string name="message_select_all">Vybrat vše</string>
|
||||||
<string name="message_unselect_all">Odznačit vše</string>
|
<string name="message_unselect_all">Odznačit vše</string>
|
||||||
|
<string name="message_restore_from_trash">Obnovit z koše</string>
|
||||||
<string name="message_move_to_trash">Přesunout do koše</string>
|
<string name="message_move_to_trash">Přesunout do koše</string>
|
||||||
<string name="message_delete_forever">Odstranit natrvalo</string>
|
<string name="message_delete_forever">Odstranit natrvalo</string>
|
||||||
|
<string name="message_restore_success">Zpráva úspěšně obnovena</string>
|
||||||
<string name="message_delete_success">Zpráva byla úspěšně odstraněna</string>
|
<string name="message_delete_success">Zpráva byla úspěšně odstraněna</string>
|
||||||
<string name="message_mailbox_type_student">žák</string>
|
<string name="message_mailbox_type_student">žák</string>
|
||||||
<string name="message_mailbox_type_parent">rodič</string>
|
<string name="message_mailbox_type_parent">rodič</string>
|
||||||
@ -383,6 +385,7 @@
|
|||||||
<item quantity="other">%1$d vybraných</item>
|
<item quantity="other">%1$d vybraných</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="message_messages_deleted">Zprávy odstraněné</string>
|
<string name="message_messages_deleted">Zprávy odstraněné</string>
|
||||||
|
<string name="message_messages_restored">Obnovené zprávy</string>
|
||||||
<string name="message_mailbox_chooser_title">Vyberte poštovní schránku</string>
|
<string name="message_mailbox_chooser_title">Vyberte poštovní schránku</string>
|
||||||
<string name="message_incognito_mode_on">Anonymní režim je zapnutý</string>
|
<string name="message_incognito_mode_on">Anonymní režim je zapnutý</string>
|
||||||
<string name="message_incognito_description">Díky anonymnímu režimu není odesílatel upozorněn, když si zprávu přečtete</string>
|
<string name="message_incognito_description">Díky anonymnímu režimu není odesílatel upozorněn, když si zprávu přečtete</string>
|
||||||
@ -849,13 +852,16 @@
|
|||||||
<string name="auth_description">Pro provoz aplikace potřebujeme potvrdit vaši identitu. Zadejte PESEL žáka <b>%1$s</b> v níže uvedeném poli</string>
|
<string name="auth_description">Pro provoz aplikace potřebujeme potvrdit vaši identitu. Zadejte PESEL žáka <b>%1$s</b> v níže uvedeném poli</string>
|
||||||
<string name="auth_button_skip">Zatím přeskočit</string>
|
<string name="auth_button_skip">Zatím přeskočit</string>
|
||||||
<!--Captcha-->
|
<!--Captcha-->
|
||||||
<string name="captcha_dialog_title">Probíhá ověřování. Počkejte…</string>
|
<string name="captcha_dialog_title">VULCAN\'s website requires verification</string>
|
||||||
|
<string name="captcha_dialog_description"><b>Why am I seeing this?</b>\nThe register website from which Wulkanowy downloads data displays the same screen as above, so Wulkanowy must also show it to be able to download data from this website. There\'s no way around it</string>
|
||||||
<string name="captcha_verified_message">Úspěšně ověřeno</string>
|
<string name="captcha_verified_message">Úspěšně ověřeno</string>
|
||||||
<!--Errors-->
|
<!--Errors-->
|
||||||
<string name="error_no_internet">Žádné internetové připojení</string>
|
<string name="error_no_internet">Žádné internetové připojení</string>
|
||||||
<string name="error_invalid_device_datetime">Vyskytla se chyba. Zkontrolujte hodiny svého zařízení</string>
|
<string name="error_invalid_device_datetime">Vyskytla se chyba. Zkontrolujte hodiny svého zařízení</string>
|
||||||
|
<string name="error_account_inactive">Tento účet je neaktivní. Zkuste se znovu přihlásit</string>
|
||||||
<string name="error_timeout">Nelze se připojit ke deníku. Servery mohou být přetíženy. Prosím zkuste to znovu později</string>
|
<string name="error_timeout">Nelze se připojit ke deníku. Servery mohou být přetíženy. Prosím zkuste to znovu později</string>
|
||||||
<string name="error_login_failed">Načítání dat se nezdařilo. Prosím zkuste to znovu později</string>
|
<string name="error_login_failed">Načítání dat se nezdařilo. Prosím zkuste to znovu později</string>
|
||||||
|
<string name="error_password_invalid">Vaše heslo vypršelo nebo bylo změněno. Přihlaste se znovu</string>
|
||||||
<string name="error_password_change_required">Je vyžadována změna hesla pro deník</string>
|
<string name="error_password_change_required">Je vyžadována změna hesla pro deník</string>
|
||||||
<string name="error_service_unavailable">Probíhá údržba deníku UONET+. Zkuste to později znovu</string>
|
<string name="error_service_unavailable">Probíhá údržba deníku UONET+. Zkuste to později znovu</string>
|
||||||
<string name="error_unknown_uonet">Neznámá chyba deniku UONET+. Prosím zkuste to znovu později</string>
|
<string name="error_unknown_uonet">Neznámá chyba deniku UONET+. Prosím zkuste to znovu později</string>
|
||||||
@ -865,4 +871,9 @@
|
|||||||
<string name="error_feature_disabled">Funkce je deaktivována přes vaší školou</string>
|
<string name="error_feature_disabled">Funkce je deaktivována přes vaší školou</string>
|
||||||
<string name="error_feature_not_available">Funkce není k dispozici. Přihlaste se v jiném režimu než Mobile API</string>
|
<string name="error_feature_not_available">Funkce není k dispozici. Přihlaste se v jiném režimu než Mobile API</string>
|
||||||
<string name="error_field_required">Toto pole je povinné</string>
|
<string name="error_field_required">Toto pole je povinné</string>
|
||||||
|
<!-- Mute system -->
|
||||||
|
<string name="message_mute">Ztlumit</string>
|
||||||
|
<string name="message_unmute">Zrušit ztlumení</string>
|
||||||
|
<string name="message_mute_success">Ztlumili jste tohoto uživatele</string>
|
||||||
|
<string name="message_unmute_success">Zrušili jste ztlumení tohoto uživatele</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -98,8 +98,8 @@
|
|||||||
<string name="main_log_in">Anmelden</string>
|
<string name="main_log_in">Anmelden</string>
|
||||||
<string name="main_session_expired">Die Sitzung ist abgelaufen</string>
|
<string name="main_session_expired">Die Sitzung ist abgelaufen</string>
|
||||||
<string name="main_session_relogin">Die Sitzung ist abgelaufen, bitte loggen Sie sich erneut ein</string>
|
<string name="main_session_relogin">Die Sitzung ist abgelaufen, bitte loggen Sie sich erneut ein</string>
|
||||||
<string name="main_expired_credentials_description">Your account password has been changed. You need to log in to Wulkanowy again</string>
|
<string name="main_expired_credentials_title">Password has expired or been changed</string>
|
||||||
<string name="main_expired_credentials_title">Password changed</string>
|
<string name="main_expired_credentials_description">Your account password has expired or been changed. You will need to log in to Wulkanowy again</string>
|
||||||
<string name="main_support_title">Anwendungsunterstützung</string>
|
<string name="main_support_title">Anwendungsunterstützung</string>
|
||||||
<string name="main_support_description">Gefällt Ihnen diese App? Unterstützen Sie ihre Entwicklung, indem Sie nicht-invasive Werbung aktivieren, die Sie jederzeit deaktivieren können</string>
|
<string name="main_support_description">Gefällt Ihnen diese App? Unterstützen Sie ihre Entwicklung, indem Sie nicht-invasive Werbung aktivieren, die Sie jederzeit deaktivieren können</string>
|
||||||
<string name="main_support_positive">Werbung aktivieren</string>
|
<string name="main_support_positive">Werbung aktivieren</string>
|
||||||
@ -296,8 +296,10 @@
|
|||||||
<string name="message_forward">Weiterleiten</string>
|
<string name="message_forward">Weiterleiten</string>
|
||||||
<string name="message_select_all">Alle auswählen</string>
|
<string name="message_select_all">Alle auswählen</string>
|
||||||
<string name="message_unselect_all">Alle abwählen</string>
|
<string name="message_unselect_all">Alle abwählen</string>
|
||||||
|
<string name="message_restore_from_trash">Restore from trash</string>
|
||||||
<string name="message_move_to_trash">In Papierkorb verschieben</string>
|
<string name="message_move_to_trash">In Papierkorb verschieben</string>
|
||||||
<string name="message_delete_forever">Dauerhaft löschen</string>
|
<string name="message_delete_forever">Dauerhaft löschen</string>
|
||||||
|
<string name="message_restore_success">Message restored successfully</string>
|
||||||
<string name="message_delete_success">Nachricht erfolgreich gelöscht</string>
|
<string name="message_delete_success">Nachricht erfolgreich gelöscht</string>
|
||||||
<string name="message_mailbox_type_student">schüler</string>
|
<string name="message_mailbox_type_student">schüler</string>
|
||||||
<string name="message_mailbox_type_parent">Eltern</string>
|
<string name="message_mailbox_type_parent">Eltern</string>
|
||||||
@ -335,6 +337,7 @@
|
|||||||
<item quantity="other">%1$d ausgewählt</item>
|
<item quantity="other">%1$d ausgewählt</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="message_messages_deleted">Nachrichten gelöscht</string>
|
<string name="message_messages_deleted">Nachrichten gelöscht</string>
|
||||||
|
<string name="message_messages_restored">Messages restored</string>
|
||||||
<string name="message_mailbox_chooser_title">Postfach auswählen</string>
|
<string name="message_mailbox_chooser_title">Postfach auswählen</string>
|
||||||
<string name="message_incognito_mode_on">Incognito mode is on</string>
|
<string name="message_incognito_mode_on">Incognito mode is on</string>
|
||||||
<string name="message_incognito_description">Thanks to incognito mode sender is not notified when you read the message</string>
|
<string name="message_incognito_description">Thanks to incognito mode sender is not notified when you read the message</string>
|
||||||
@ -755,13 +758,16 @@
|
|||||||
<string name="auth_description">To operate the application, we need to confirm your identity. Please enter the student\'s PESEL <b>%1$s</b> in the field below</string>
|
<string name="auth_description">To operate the application, we need to confirm your identity. Please enter the student\'s PESEL <b>%1$s</b> in the field below</string>
|
||||||
<string name="auth_button_skip">Skip for now</string>
|
<string name="auth_button_skip">Skip for now</string>
|
||||||
<!--Captcha-->
|
<!--Captcha-->
|
||||||
<string name="captcha_dialog_title">Verification is in progress. Wait…</string>
|
<string name="captcha_dialog_title">VULCAN\'s website requires verification</string>
|
||||||
|
<string name="captcha_dialog_description"><b>Why am I seeing this?</b>\nThe register website from which Wulkanowy downloads data displays the same screen as above, so Wulkanowy must also show it to be able to download data from this website. There\'s no way around it</string>
|
||||||
<string name="captcha_verified_message">Verified successfully</string>
|
<string name="captcha_verified_message">Verified successfully</string>
|
||||||
<!--Errors-->
|
<!--Errors-->
|
||||||
<string name="error_no_internet">Keine Internetverbindung</string>
|
<string name="error_no_internet">Keine Internetverbindung</string>
|
||||||
<string name="error_invalid_device_datetime">Es ist ein Fehler aufgetreten. Überprüfen Sie Ihre Geräteuhr</string>
|
<string name="error_invalid_device_datetime">Es ist ein Fehler aufgetreten. Überprüfen Sie Ihre Geräteuhr</string>
|
||||||
|
<string name="error_account_inactive">This account is inactive. Try logging in again</string>
|
||||||
<string name="error_timeout">Registrierungsverbindung fehlgeschlagen. Server können überlastet sein. Bitte versuchen Sie es später noch einmal</string>
|
<string name="error_timeout">Registrierungsverbindung fehlgeschlagen. Server können überlastet sein. Bitte versuchen Sie es später noch einmal</string>
|
||||||
<string name="error_login_failed">Das Laden der Daten ist fehlgeschlagen. Bitte versuchen Sie es später noch einmal</string>
|
<string name="error_login_failed">Das Laden der Daten ist fehlgeschlagen. Bitte versuchen Sie es später noch einmal</string>
|
||||||
|
<string name="error_password_invalid">Your password has expired or been changed. Please log in again</string>
|
||||||
<string name="error_password_change_required">Passwortänderung für Registrierung erforderlich</string>
|
<string name="error_password_change_required">Passwortänderung für Registrierung erforderlich</string>
|
||||||
<string name="error_service_unavailable">Wartung im Gange UONET + Klassenbuch. Versuchen Sie es später noch einmal</string>
|
<string name="error_service_unavailable">Wartung im Gange UONET + Klassenbuch. Versuchen Sie es später noch einmal</string>
|
||||||
<string name="error_unknown_uonet">Unbekannter UONET + Registerfehler. Versuchen Sie es später erneut</string>
|
<string name="error_unknown_uonet">Unbekannter UONET + Registerfehler. Versuchen Sie es später erneut</string>
|
||||||
@ -771,4 +777,9 @@
|
|||||||
<string name="error_feature_disabled">Funktion, die von Ihrer Schule deaktiviert wurde</string>
|
<string name="error_feature_disabled">Funktion, die von Ihrer Schule deaktiviert wurde</string>
|
||||||
<string name="error_feature_not_available">Feature in diesem Modus nicht verfügbar</string>
|
<string name="error_feature_not_available">Feature in diesem Modus nicht verfügbar</string>
|
||||||
<string name="error_field_required">Dieses Feld ist erforderlich</string>
|
<string name="error_field_required">Dieses Feld ist erforderlich</string>
|
||||||
|
<!-- Mute system -->
|
||||||
|
<string name="message_mute">Mute</string>
|
||||||
|
<string name="message_unmute">Unmute</string>
|
||||||
|
<string name="message_mute_success">You have muted this user</string>
|
||||||
|
<string name="message_unmute_success">You have unmuted this user</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -98,8 +98,8 @@
|
|||||||
<string name="main_log_in">Zaloguj się</string>
|
<string name="main_log_in">Zaloguj się</string>
|
||||||
<string name="main_session_expired">Sesja wygasła</string>
|
<string name="main_session_expired">Sesja wygasła</string>
|
||||||
<string name="main_session_relogin">Sesja wygasła, zaloguj się ponownie</string>
|
<string name="main_session_relogin">Sesja wygasła, zaloguj się ponownie</string>
|
||||||
<string name="main_expired_credentials_description">Hasło do Twojego konta zostało zmienione. Musisz zalogować się ponownie do Wulkanowego</string>
|
<string name="main_expired_credentials_title">Hasło wygasło lub zostało zmienione</string>
|
||||||
<string name="main_expired_credentials_title">Hasło zostało zmienione</string>
|
<string name="main_expired_credentials_description">Hasło do twojego konta wygasło lub zostało zmienione. Musisz zalogować się ponownie do Wulkanowego</string>
|
||||||
<string name="main_support_title">Wparcie aplikacji</string>
|
<string name="main_support_title">Wparcie aplikacji</string>
|
||||||
<string name="main_support_description">Podoba Ci się ta aplikacja? Wspieraj jej rozwój poprzez włączenie nieinwazyjnych reklam, które możesz wyłączyć w dowolnym momencie</string>
|
<string name="main_support_description">Podoba Ci się ta aplikacja? Wspieraj jej rozwój poprzez włączenie nieinwazyjnych reklam, które możesz wyłączyć w dowolnym momencie</string>
|
||||||
<string name="main_support_positive">Włącz reklamy</string>
|
<string name="main_support_positive">Włącz reklamy</string>
|
||||||
@ -336,8 +336,10 @@
|
|||||||
<string name="message_forward">Prześlij dalej</string>
|
<string name="message_forward">Prześlij dalej</string>
|
||||||
<string name="message_select_all">Zaznacz wszystkie</string>
|
<string name="message_select_all">Zaznacz wszystkie</string>
|
||||||
<string name="message_unselect_all">Odznacz wszystkie</string>
|
<string name="message_unselect_all">Odznacz wszystkie</string>
|
||||||
|
<string name="message_restore_from_trash">Przywróć z kosza</string>
|
||||||
<string name="message_move_to_trash">Przenieś do kosza</string>
|
<string name="message_move_to_trash">Przenieś do kosza</string>
|
||||||
<string name="message_delete_forever">Usuń trwale</string>
|
<string name="message_delete_forever">Usuń trwale</string>
|
||||||
|
<string name="message_restore_success">Wiadomość przywrócona pomyślnie</string>
|
||||||
<string name="message_delete_success">Wiadomość usunięta pomyślnie</string>
|
<string name="message_delete_success">Wiadomość usunięta pomyślnie</string>
|
||||||
<string name="message_mailbox_type_student">uczeń</string>
|
<string name="message_mailbox_type_student">uczeń</string>
|
||||||
<string name="message_mailbox_type_parent">rodzic</string>
|
<string name="message_mailbox_type_parent">rodzic</string>
|
||||||
@ -383,6 +385,7 @@
|
|||||||
<item quantity="other">%1$d wybranych</item>
|
<item quantity="other">%1$d wybranych</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="message_messages_deleted">Wiadomości zostały usunięte</string>
|
<string name="message_messages_deleted">Wiadomości zostały usunięte</string>
|
||||||
|
<string name="message_messages_restored">Wiadomości przywrócone</string>
|
||||||
<string name="message_mailbox_chooser_title">Wybierz skrzynkę</string>
|
<string name="message_mailbox_chooser_title">Wybierz skrzynkę</string>
|
||||||
<string name="message_incognito_mode_on">Tryb incognito jest włączony</string>
|
<string name="message_incognito_mode_on">Tryb incognito jest włączony</string>
|
||||||
<string name="message_incognito_description">Dzięki trybowi incognito nadawca nie zobaczy, że przeczytałeś tę wiadomość</string>
|
<string name="message_incognito_description">Dzięki trybowi incognito nadawca nie zobaczy, że przeczytałeś tę wiadomość</string>
|
||||||
@ -849,13 +852,16 @@
|
|||||||
<string name="auth_description">Rodzicu, musimy mieć pewność, że Twój adres e-mail został powiązany z prawidłowym kontem ucznia. W celu autoryzacji konta podaj numer PESEL ucznia <b>%1$s</b> w polu poniżej</string>
|
<string name="auth_description">Rodzicu, musimy mieć pewność, że Twój adres e-mail został powiązany z prawidłowym kontem ucznia. W celu autoryzacji konta podaj numer PESEL ucznia <b>%1$s</b> w polu poniżej</string>
|
||||||
<string name="auth_button_skip">Na razie pomiń</string>
|
<string name="auth_button_skip">Na razie pomiń</string>
|
||||||
<!--Captcha-->
|
<!--Captcha-->
|
||||||
<string name="captcha_dialog_title">Trwa weryfikacja. Czekaj…</string>
|
<string name="captcha_dialog_title">Strona dziennika VULCAN wymaga weryfikacji</string>
|
||||||
|
<string name="captcha_dialog_description"><b>Dlaczego to widzę?</b>\nStrona internetowa dziennika, z której Wulkanowy pobiera dane, wyświetla ten sam ekran jak powyżej, więc Wulkanowy musi również ją pokazać, aby móc pobrać dane z tej witryny. Nie da się tego obejść</string>
|
||||||
<string name="captcha_verified_message">Pomyślnie zweryfikowano</string>
|
<string name="captcha_verified_message">Pomyślnie zweryfikowano</string>
|
||||||
<!--Errors-->
|
<!--Errors-->
|
||||||
<string name="error_no_internet">Brak połączenia z internetem</string>
|
<string name="error_no_internet">Brak połączenia z internetem</string>
|
||||||
<string name="error_invalid_device_datetime">Wystąpił błąd. Sprawdź poprawność daty w urządzeniu</string>
|
<string name="error_invalid_device_datetime">Wystąpił błąd. Sprawdź poprawność daty w urządzeniu</string>
|
||||||
|
<string name="error_account_inactive">Konto jest nieaktywne. Spróbuj zalogować się ponownie</string>
|
||||||
<string name="error_timeout">Nie udało się połączyć z dziennikiem. Serwery mogą być przeciążone. Spróbuj ponownie później</string>
|
<string name="error_timeout">Nie udało się połączyć z dziennikiem. Serwery mogą być przeciążone. Spróbuj ponownie później</string>
|
||||||
<string name="error_login_failed">Ładowanie danych nie powiodło się. Spróbuj ponownie później</string>
|
<string name="error_login_failed">Ładowanie danych nie powiodło się. Spróbuj ponownie później</string>
|
||||||
|
<string name="error_password_invalid">Twoje hasło wygasło lub zostało zmienione. Zaloguj się ponownie</string>
|
||||||
<string name="error_password_change_required">Wymagana zmiana hasła do dziennika</string>
|
<string name="error_password_change_required">Wymagana zmiana hasła do dziennika</string>
|
||||||
<string name="error_service_unavailable">Trwa przerwa techniczna dziennika UONET+. Spróbuj ponownie później</string>
|
<string name="error_service_unavailable">Trwa przerwa techniczna dziennika UONET+. Spróbuj ponownie później</string>
|
||||||
<string name="error_unknown_uonet">Nieznany błąd dziennika UONET+. Spróbuj ponownie później</string>
|
<string name="error_unknown_uonet">Nieznany błąd dziennika UONET+. Spróbuj ponownie później</string>
|
||||||
@ -865,4 +871,9 @@
|
|||||||
<string name="error_feature_disabled">Funkcja wyłączona przez szkołę</string>
|
<string name="error_feature_disabled">Funkcja wyłączona przez szkołę</string>
|
||||||
<string name="error_feature_not_available">Funkcja niedostępna. Zaloguj się w trybie innym niż Mobilne API</string>
|
<string name="error_feature_not_available">Funkcja niedostępna. Zaloguj się w trybie innym niż Mobilne API</string>
|
||||||
<string name="error_field_required">To pole jest wymagane</string>
|
<string name="error_field_required">To pole jest wymagane</string>
|
||||||
|
<!-- Mute system -->
|
||||||
|
<string name="message_mute">Wycisz</string>
|
||||||
|
<string name="message_unmute">Wyłącz wyciszenie</string>
|
||||||
|
<string name="message_mute_success">Wyciszyleś tego użytkownika</string>
|
||||||
|
<string name="message_unmute_success">Wyłączyłeś wyciszenie tego użytkownika</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -98,8 +98,8 @@
|
|||||||
<string name="main_log_in">Войти</string>
|
<string name="main_log_in">Войти</string>
|
||||||
<string name="main_session_expired">Сеанс истёк</string>
|
<string name="main_session_expired">Сеанс истёк</string>
|
||||||
<string name="main_session_relogin">Сеанс истёк, авторизуйтесь снова</string>
|
<string name="main_session_relogin">Сеанс истёк, авторизуйтесь снова</string>
|
||||||
<string name="main_expired_credentials_description">Your account password has been changed. You need to log in to Wulkanowy again</string>
|
<string name="main_expired_credentials_title">Password has expired or been changed</string>
|
||||||
<string name="main_expired_credentials_title">Password changed</string>
|
<string name="main_expired_credentials_description">Your account password has expired or been changed. You will need to log in to Wulkanowy again</string>
|
||||||
<string name="main_support_title">Поддержка приложения</string>
|
<string name="main_support_title">Поддержка приложения</string>
|
||||||
<string name="main_support_description">Вам нравится это приложение? Поддержите его разработку, включив неинвазивную рекламу, которую можно отключить в любое время</string>
|
<string name="main_support_description">Вам нравится это приложение? Поддержите его разработку, включив неинвазивную рекламу, которую можно отключить в любое время</string>
|
||||||
<string name="main_support_positive">Включить рекламу</string>
|
<string name="main_support_positive">Включить рекламу</string>
|
||||||
@ -336,8 +336,10 @@
|
|||||||
<string name="message_forward">Переслать</string>
|
<string name="message_forward">Переслать</string>
|
||||||
<string name="message_select_all">Выбрать все</string>
|
<string name="message_select_all">Выбрать все</string>
|
||||||
<string name="message_unselect_all">Отменить выбор</string>
|
<string name="message_unselect_all">Отменить выбор</string>
|
||||||
|
<string name="message_restore_from_trash">Restore from trash</string>
|
||||||
<string name="message_move_to_trash">Перенести в корзину</string>
|
<string name="message_move_to_trash">Перенести в корзину</string>
|
||||||
<string name="message_delete_forever">Удалить навсегда</string>
|
<string name="message_delete_forever">Удалить навсегда</string>
|
||||||
|
<string name="message_restore_success">Message restored successfully</string>
|
||||||
<string name="message_delete_success">Сообщение успешно удалено</string>
|
<string name="message_delete_success">Сообщение успешно удалено</string>
|
||||||
<string name="message_mailbox_type_student">ученик</string>
|
<string name="message_mailbox_type_student">ученик</string>
|
||||||
<string name="message_mailbox_type_parent">родитель</string>
|
<string name="message_mailbox_type_parent">родитель</string>
|
||||||
@ -383,6 +385,7 @@
|
|||||||
<item quantity="other">%1$d выбрано</item>
|
<item quantity="other">%1$d выбрано</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="message_messages_deleted">Сообщение удалено</string>
|
<string name="message_messages_deleted">Сообщение удалено</string>
|
||||||
|
<string name="message_messages_restored">Messages restored</string>
|
||||||
<string name="message_mailbox_chooser_title">Выбрать почтовый ящик</string>
|
<string name="message_mailbox_chooser_title">Выбрать почтовый ящик</string>
|
||||||
<string name="message_incognito_mode_on">Incognito mode is on</string>
|
<string name="message_incognito_mode_on">Incognito mode is on</string>
|
||||||
<string name="message_incognito_description">Thanks to incognito mode sender is not notified when you read the message</string>
|
<string name="message_incognito_description">Thanks to incognito mode sender is not notified when you read the message</string>
|
||||||
@ -849,13 +852,16 @@
|
|||||||
<string name="auth_description">Для работы приложения нам необходимо подтвердить вашу личность. Введите PESEL учащегося <b>%1$s</b> в поле ниже</string>
|
<string name="auth_description">Для работы приложения нам необходимо подтвердить вашу личность. Введите PESEL учащегося <b>%1$s</b> в поле ниже</string>
|
||||||
<string name="auth_button_skip">Пропустить сейчас</string>
|
<string name="auth_button_skip">Пропустить сейчас</string>
|
||||||
<!--Captcha-->
|
<!--Captcha-->
|
||||||
<string name="captcha_dialog_title">Verification is in progress. Wait…</string>
|
<string name="captcha_dialog_title">VULCAN\'s website requires verification</string>
|
||||||
|
<string name="captcha_dialog_description"><b>Why am I seeing this?</b>\nThe register website from which Wulkanowy downloads data displays the same screen as above, so Wulkanowy must also show it to be able to download data from this website. There\'s no way around it</string>
|
||||||
<string name="captcha_verified_message">Verified successfully</string>
|
<string name="captcha_verified_message">Verified successfully</string>
|
||||||
<!--Errors-->
|
<!--Errors-->
|
||||||
<string name="error_no_internet">Интернет-соединение отсутствует</string>
|
<string name="error_no_internet">Интернет-соединение отсутствует</string>
|
||||||
<string name="error_invalid_device_datetime">Произошла ошибка. Проверьте время на вашем устройстве</string>
|
<string name="error_invalid_device_datetime">Произошла ошибка. Проверьте время на вашем устройстве</string>
|
||||||
|
<string name="error_account_inactive">This account is inactive. Try logging in again</string>
|
||||||
<string name="error_timeout">Не удалось подключиться к дневнику. Возможно, сервера перегружены, повторите попытку позже</string>
|
<string name="error_timeout">Не удалось подключиться к дневнику. Возможно, сервера перегружены, повторите попытку позже</string>
|
||||||
<string name="error_login_failed">Не удалось загрузить данные, повторите попытку позже</string>
|
<string name="error_login_failed">Не удалось загрузить данные, повторите попытку позже</string>
|
||||||
|
<string name="error_password_invalid">Your password has expired or been changed. Please log in again</string>
|
||||||
<string name="error_password_change_required">Необходимо изменить пароль дневника</string>
|
<string name="error_password_change_required">Необходимо изменить пароль дневника</string>
|
||||||
<string name="error_service_unavailable">UONET+ проводит техническое обслуживание, повторите попытку позже</string>
|
<string name="error_service_unavailable">UONET+ проводит техническое обслуживание, повторите попытку позже</string>
|
||||||
<string name="error_unknown_uonet">Неизвестная ошибка дневника UONET+, повторите попытку позже</string>
|
<string name="error_unknown_uonet">Неизвестная ошибка дневника UONET+, повторите попытку позже</string>
|
||||||
@ -865,4 +871,9 @@
|
|||||||
<string name="error_feature_disabled">Функция отключена вашей школой</string>
|
<string name="error_feature_disabled">Функция отключена вашей школой</string>
|
||||||
<string name="error_feature_not_available">Функция недоступна в режиме Mobile API. Воспользуйтесь другим режимом</string>
|
<string name="error_feature_not_available">Функция недоступна в режиме Mobile API. Воспользуйтесь другим режимом</string>
|
||||||
<string name="error_field_required">Это поле обязательно</string>
|
<string name="error_field_required">Это поле обязательно</string>
|
||||||
|
<!-- Mute system -->
|
||||||
|
<string name="message_mute">Mute</string>
|
||||||
|
<string name="message_unmute">Unmute</string>
|
||||||
|
<string name="message_mute_success">You have muted this user</string>
|
||||||
|
<string name="message_unmute_success">You have unmuted this user</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -56,7 +56,7 @@
|
|||||||
<string name="login_invalid_email">Neplatný e-mail</string>
|
<string name="login_invalid_email">Neplatný e-mail</string>
|
||||||
<string name="login_invalid_login">Namiesto e-mailu použite priradené prihlasovacie údaje</string>
|
<string name="login_invalid_login">Namiesto e-mailu použite priradené prihlasovacie údaje</string>
|
||||||
<string name="login_invalid_custom_email">Použite priradené prihlasovacie alebo e-mail v @%1$s</string>
|
<string name="login_invalid_custom_email">Použite priradené prihlasovacie alebo e-mail v @%1$s</string>
|
||||||
<string name="login_invalid_domain_suffix">Invalid domain suffix</string>
|
<string name="login_invalid_domain_suffix">Neplatná prípona domény</string>
|
||||||
<string name="login_invalid_symbol">Neplatný symbol. Pokiaľ ho nemôžete nájsť, kontaktujte školu</string>
|
<string name="login_invalid_symbol">Neplatný symbol. Pokiaľ ho nemôžete nájsť, kontaktujte školu</string>
|
||||||
<string name="login_invalid_symbol_definitely">Nevymýšľajte si! Pokiaľ symbol nemôžete nájsť, kontaktujte školu</string>
|
<string name="login_invalid_symbol_definitely">Nevymýšľajte si! Pokiaľ symbol nemôžete nájsť, kontaktujte školu</string>
|
||||||
<string name="login_incorrect_symbol">Žiak nebol nájdený. Skontrolujte správnosť symbolu a vybrané varianty denníka UONET+</string>
|
<string name="login_incorrect_symbol">Žiak nebol nájdený. Skontrolujte správnosť symbolu a vybrané varianty denníka UONET+</string>
|
||||||
@ -98,8 +98,8 @@
|
|||||||
<string name="main_log_in">Prihlásiť sa</string>
|
<string name="main_log_in">Prihlásiť sa</string>
|
||||||
<string name="main_session_expired">Relácia vypršala</string>
|
<string name="main_session_expired">Relácia vypršala</string>
|
||||||
<string name="main_session_relogin">Relácia vypršala. Prihláste sa prosím znovu</string>
|
<string name="main_session_relogin">Relácia vypršala. Prihláste sa prosím znovu</string>
|
||||||
<string name="main_expired_credentials_description">Heslo k vášmu účtu bolo zmenené. Musíte sa znovu prihlásiť do Wulkanového</string>
|
<string name="main_expired_credentials_title">Heslo vypršalo alebo bolo zmenené</string>
|
||||||
<string name="main_expired_credentials_title">Heslo bolo zmenené</string>
|
<string name="main_expired_credentials_description">Platnosť hesla k vášmu účtu vypršala alebo bolo zmenené. Budete sa musieť znova prihlásiť do Wulkanového</string>
|
||||||
<string name="main_support_title">Podpora aplikácie</string>
|
<string name="main_support_title">Podpora aplikácie</string>
|
||||||
<string name="main_support_description">Páči sa Vám táto aplikácia? Podporte jej vývoj tým, že povolíte neinvazívne reklamy, ktoré môžete kedykoľvek vypnúť</string>
|
<string name="main_support_description">Páči sa Vám táto aplikácia? Podporte jej vývoj tým, že povolíte neinvazívne reklamy, ktoré môžete kedykoľvek vypnúť</string>
|
||||||
<string name="main_support_positive">Zapnúť reklamy</string>
|
<string name="main_support_positive">Zapnúť reklamy</string>
|
||||||
@ -336,8 +336,10 @@
|
|||||||
<string name="message_forward">Poslať ďalej</string>
|
<string name="message_forward">Poslať ďalej</string>
|
||||||
<string name="message_select_all">Vybrať všetko</string>
|
<string name="message_select_all">Vybrať všetko</string>
|
||||||
<string name="message_unselect_all">Odznačiť všetko</string>
|
<string name="message_unselect_all">Odznačiť všetko</string>
|
||||||
|
<string name="message_restore_from_trash">Obnoviť z koša</string>
|
||||||
<string name="message_move_to_trash">Presunúť do koša</string>
|
<string name="message_move_to_trash">Presunúť do koša</string>
|
||||||
<string name="message_delete_forever">Odstrániť natrvalo</string>
|
<string name="message_delete_forever">Odstrániť natrvalo</string>
|
||||||
|
<string name="message_restore_success">Správa úspešne obnovená</string>
|
||||||
<string name="message_delete_success">Správa bola úspešne odstránená</string>
|
<string name="message_delete_success">Správa bola úspešne odstránená</string>
|
||||||
<string name="message_mailbox_type_student">žiak</string>
|
<string name="message_mailbox_type_student">žiak</string>
|
||||||
<string name="message_mailbox_type_parent">rodič</string>
|
<string name="message_mailbox_type_parent">rodič</string>
|
||||||
@ -383,6 +385,7 @@
|
|||||||
<item quantity="other">%1$d vybraných</item>
|
<item quantity="other">%1$d vybraných</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="message_messages_deleted">Správy odstránené</string>
|
<string name="message_messages_deleted">Správy odstránené</string>
|
||||||
|
<string name="message_messages_restored">Obnovené správy</string>
|
||||||
<string name="message_mailbox_chooser_title">Vyberte poštovú schránku</string>
|
<string name="message_mailbox_chooser_title">Vyberte poštovú schránku</string>
|
||||||
<string name="message_incognito_mode_on">Režim inkognito je zapnutý</string>
|
<string name="message_incognito_mode_on">Režim inkognito je zapnutý</string>
|
||||||
<string name="message_incognito_description">Vďaka inkognito režimu nie je odosielateľ upozornený, keď si správu prečítate</string>
|
<string name="message_incognito_description">Vďaka inkognito režimu nie je odosielateľ upozornený, keď si správu prečítate</string>
|
||||||
@ -849,13 +852,16 @@
|
|||||||
<string name="auth_description">Na prevádzku aplikácie potrebujeme potvrdiť vašu identitu. Zadajte PESEL žiaka <b>%1$s</b> v nižšie uvedenom poli</string>
|
<string name="auth_description">Na prevádzku aplikácie potrebujeme potvrdiť vašu identitu. Zadajte PESEL žiaka <b>%1$s</b> v nižšie uvedenom poli</string>
|
||||||
<string name="auth_button_skip">Zatiaľ preskočiť</string>
|
<string name="auth_button_skip">Zatiaľ preskočiť</string>
|
||||||
<!--Captcha-->
|
<!--Captcha-->
|
||||||
<string name="captcha_dialog_title">Overovanie prebieha. Počkajte…</string>
|
<string name="captcha_dialog_title">VULCAN\'s website requires verification</string>
|
||||||
|
<string name="captcha_dialog_description"><b>Why am I seeing this?</b>\nThe register website from which Wulkanowy downloads data displays the same screen as above, so Wulkanowy must also show it to be able to download data from this website. There\'s no way around it</string>
|
||||||
<string name="captcha_verified_message">Úspešne overené</string>
|
<string name="captcha_verified_message">Úspešne overené</string>
|
||||||
<!--Errors-->
|
<!--Errors-->
|
||||||
<string name="error_no_internet">Žiadne internetové pripojenie</string>
|
<string name="error_no_internet">Žiadne internetové pripojenie</string>
|
||||||
<string name="error_invalid_device_datetime">Vyskytla sa chyba. Skontrolujte hodiny svojho zariadenia</string>
|
<string name="error_invalid_device_datetime">Vyskytla sa chyba. Skontrolujte hodiny svojho zariadenia</string>
|
||||||
|
<string name="error_account_inactive">Tento účet je neaktívny. Skúste sa znova prihlásiť</string>
|
||||||
<string name="error_timeout">Nedá sa pripojiť ku denníku. Servery môžu byť preťažené. Prosím skúste to znova neskôr</string>
|
<string name="error_timeout">Nedá sa pripojiť ku denníku. Servery môžu byť preťažené. Prosím skúste to znova neskôr</string>
|
||||||
<string name="error_login_failed">Načítanie údajov zlyhalo. Skúste neskôr prosím</string>
|
<string name="error_login_failed">Načítanie údajov zlyhalo. Skúste neskôr prosím</string>
|
||||||
|
<string name="error_password_invalid">Vaše heslo vypršalo alebo bolo zmenené. Prihláste sa znova</string>
|
||||||
<string name="error_password_change_required">Je vyžadovaná zmena hesla pre denník</string>
|
<string name="error_password_change_required">Je vyžadovaná zmena hesla pre denník</string>
|
||||||
<string name="error_service_unavailable">Prebieha údržba denníka UONET+. Skúste to neskôr znova</string>
|
<string name="error_service_unavailable">Prebieha údržba denníka UONET+. Skúste to neskôr znova</string>
|
||||||
<string name="error_unknown_uonet">Neznáma chyba dennika UONET+. Prosím skúste to znova neskôr</string>
|
<string name="error_unknown_uonet">Neznáma chyba dennika UONET+. Prosím skúste to znova neskôr</string>
|
||||||
@ -865,4 +871,9 @@
|
|||||||
<string name="error_feature_disabled">Funkcia je deaktivovaná cez vašou školou</string>
|
<string name="error_feature_disabled">Funkcia je deaktivovaná cez vašou školou</string>
|
||||||
<string name="error_feature_not_available">Funkcia nie je k dispozícii. Prihláste sa v inom režime než Mobile API</string>
|
<string name="error_feature_not_available">Funkcia nie je k dispozícii. Prihláste sa v inom režime než Mobile API</string>
|
||||||
<string name="error_field_required">Toto pole je povinné</string>
|
<string name="error_field_required">Toto pole je povinné</string>
|
||||||
|
<!-- Mute system -->
|
||||||
|
<string name="message_mute">Stlmiť</string>
|
||||||
|
<string name="message_unmute">Zrušiť stlmenie</string>
|
||||||
|
<string name="message_mute_success">Stlmili ste tohto používateľa</string>
|
||||||
|
<string name="message_unmute_success">Zrušili ste stlmenie tohto používateľa</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -56,7 +56,7 @@
|
|||||||
<string name="login_invalid_email">Недійсна адреса e-mail</string>
|
<string name="login_invalid_email">Недійсна адреса e-mail</string>
|
||||||
<string name="login_invalid_login">Використовуйте призначений логін замість адреси e-mail</string>
|
<string name="login_invalid_login">Використовуйте призначений логін замість адреси e-mail</string>
|
||||||
<string name="login_invalid_custom_email">Використовуйте призначений логін або адресу e-mail в @%1$s</string>
|
<string name="login_invalid_custom_email">Використовуйте призначений логін або адресу e-mail в @%1$s</string>
|
||||||
<string name="login_invalid_domain_suffix">Invalid domain suffix</string>
|
<string name="login_invalid_domain_suffix">Невірний суфікс домену</string>
|
||||||
<string name="login_invalid_symbol">Некоректний символ. Якщо ви не можете знайти його, будь ласка, зв\'яжіться зі школою</string>
|
<string name="login_invalid_symbol">Некоректний символ. Якщо ви не можете знайти його, будь ласка, зв\'яжіться зі школою</string>
|
||||||
<string name="login_invalid_symbol_definitely">Не вигадуйте! Якщо ви не можете знайти його, будь ласка, зв\'яжіться зі школою</string>
|
<string name="login_invalid_symbol_definitely">Не вигадуйте! Якщо ви не можете знайти його, будь ласка, зв\'яжіться зі школою</string>
|
||||||
<string name="login_incorrect_symbol">Студента не знайдено. Перевірте symbol та обраний тип щоденника UONET+</string>
|
<string name="login_incorrect_symbol">Студента не знайдено. Перевірте symbol та обраний тип щоденника UONET+</string>
|
||||||
@ -98,8 +98,8 @@
|
|||||||
<string name="main_log_in">Увійти</string>
|
<string name="main_log_in">Увійти</string>
|
||||||
<string name="main_session_expired">Минув термін дії сесії</string>
|
<string name="main_session_expired">Минув термін дії сесії</string>
|
||||||
<string name="main_session_relogin">Минув термін дії сесії, авторизуйтеся знову</string>
|
<string name="main_session_relogin">Минув термін дії сесії, авторизуйтеся знову</string>
|
||||||
<string name="main_expired_credentials_description">Пароль вашого облікового запису був змінений. Ви повинні увійти в Wulkanowy знову</string>
|
<string name="main_expired_credentials_title">Термін дії пароля закінчився або його було змінено</string>
|
||||||
<string name="main_expired_credentials_title">Пароль змінено</string>
|
<string name="main_expired_credentials_description">Термін дії пароля для вашого облікового запису закінчився або було змінено. Необхідно зайти в Wulkanowy знову</string>
|
||||||
<string name="main_support_title">Підтримка додатку</string>
|
<string name="main_support_title">Підтримка додатку</string>
|
||||||
<string name="main_support_description">Вам подобається цей додаток? Підтримайте його розвиток, увімкнувши неінвазивну рекламу, яку ви можете відключити в будь-який час</string>
|
<string name="main_support_description">Вам подобається цей додаток? Підтримайте його розвиток, увімкнувши неінвазивну рекламу, яку ви можете відключити в будь-який час</string>
|
||||||
<string name="main_support_positive">Увімкнути рекламу</string>
|
<string name="main_support_positive">Увімкнути рекламу</string>
|
||||||
@ -336,8 +336,10 @@
|
|||||||
<string name="message_forward">Переслати</string>
|
<string name="message_forward">Переслати</string>
|
||||||
<string name="message_select_all">Вибрати всі</string>
|
<string name="message_select_all">Вибрати всі</string>
|
||||||
<string name="message_unselect_all">Відмінити вибір</string>
|
<string name="message_unselect_all">Відмінити вибір</string>
|
||||||
|
<string name="message_restore_from_trash">Відновити зі смітника</string>
|
||||||
<string name="message_move_to_trash">Перемістити до кошика</string>
|
<string name="message_move_to_trash">Перемістити до кошика</string>
|
||||||
<string name="message_delete_forever">Видалити назавжди</string>
|
<string name="message_delete_forever">Видалити назавжди</string>
|
||||||
|
<string name="message_restore_success">Повідомлення успішно відновлено</string>
|
||||||
<string name="message_delete_success">Лист було успішно видалено</string>
|
<string name="message_delete_success">Лист було успішно видалено</string>
|
||||||
<string name="message_mailbox_type_student">учень</string>
|
<string name="message_mailbox_type_student">учень</string>
|
||||||
<string name="message_mailbox_type_parent">родич</string>
|
<string name="message_mailbox_type_parent">родич</string>
|
||||||
@ -383,6 +385,7 @@
|
|||||||
<item quantity="other">%1$d вибрано</item>
|
<item quantity="other">%1$d вибрано</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="message_messages_deleted">Листи видалено</string>
|
<string name="message_messages_deleted">Листи видалено</string>
|
||||||
|
<string name="message_messages_restored">Повідомлення відновлені</string>
|
||||||
<string name="message_mailbox_chooser_title">Вибрати поштову скриньку</string>
|
<string name="message_mailbox_chooser_title">Вибрати поштову скриньку</string>
|
||||||
<string name="message_incognito_mode_on">Режим анонімності включено</string>
|
<string name="message_incognito_mode_on">Режим анонімності включено</string>
|
||||||
<string name="message_incognito_description">Завдяки режиму анонімності, відправник не буде сповіщений коли ви прочитаєте повідомлення</string>
|
<string name="message_incognito_description">Завдяки режиму анонімності, відправник не буде сповіщений коли ви прочитаєте повідомлення</string>
|
||||||
@ -849,13 +852,16 @@
|
|||||||
<string name="auth_description">Для роботи програми нам потрібно підтвердити вашу особу. Будь ласка, введіть число PESEL <b>%1$s</b> студента в поле нижче</string>
|
<string name="auth_description">Для роботи програми нам потрібно підтвердити вашу особу. Будь ласка, введіть число PESEL <b>%1$s</b> студента в поле нижче</string>
|
||||||
<string name="auth_button_skip">Поки що пропустити</string>
|
<string name="auth_button_skip">Поки що пропустити</string>
|
||||||
<!--Captcha-->
|
<!--Captcha-->
|
||||||
<string name="captcha_dialog_title">Верифікація в процесі. Чекайте…</string>
|
<string name="captcha_dialog_title">Веб-сайт VULCAN потребує підтвердження</string>
|
||||||
|
<string name="captcha_dialog_description"><b>Чому я це бачу?</b>\nСайт реєстру, з якого Wulkanowy завантажує дані, відображає той самий екран, що й вище, тому Wulkanowy також повинен показувати його, щоб мати змогу завантажувати дані з цього сайту. Це неможливо обійти</string>
|
||||||
<string name="captcha_verified_message">Верифікація завершена</string>
|
<string name="captcha_verified_message">Верифікація завершена</string>
|
||||||
<!--Errors-->
|
<!--Errors-->
|
||||||
<string name="error_no_internet">Немає з\'єднання з інтернетом</string>
|
<string name="error_no_internet">Немає з\'єднання з інтернетом</string>
|
||||||
<string name="error_invalid_device_datetime">Сталася помилка. Перевірте годинник пристрою</string>
|
<string name="error_invalid_device_datetime">Сталася помилка. Перевірте годинник пристрою</string>
|
||||||
|
<string name="error_account_inactive">Цей обліковий запис неактивний. Спробуйте увійти ще раз</string>
|
||||||
<string name="error_timeout">Помилка підключення до щоденнику. Сервери можуть бути перевантажені, спробуйте пізніше</string>
|
<string name="error_timeout">Помилка підключення до щоденнику. Сервери можуть бути перевантажені, спробуйте пізніше</string>
|
||||||
<string name="error_login_failed">Помилка завантаження даних, спробуйте пізніше</string>
|
<string name="error_login_failed">Помилка завантаження даних, спробуйте пізніше</string>
|
||||||
|
<string name="error_password_invalid">Термін дії вашого пароля минув або був змінений. Будь ласка увійдіть знову</string>
|
||||||
<string name="error_password_change_required">Необхідна зміна пароля щоденника</string>
|
<string name="error_password_change_required">Необхідна зміна пароля щоденника</string>
|
||||||
<string name="error_service_unavailable">UONET+ проводить технічне осблуговування, спробуйте пізніше</string>
|
<string name="error_service_unavailable">UONET+ проводить технічне осблуговування, спробуйте пізніше</string>
|
||||||
<string name="error_unknown_uonet">Невідома помилка щоденника UONET+, спробуйте пізніше</string>
|
<string name="error_unknown_uonet">Невідома помилка щоденника UONET+, спробуйте пізніше</string>
|
||||||
@ -865,4 +871,9 @@
|
|||||||
<string name="error_feature_disabled">Функція вимкнена вашою школою</string>
|
<string name="error_feature_disabled">Функція вимкнена вашою школою</string>
|
||||||
<string name="error_feature_not_available">Функція недоступна в режимі Mobile API. Увійдіть в інший режим</string>
|
<string name="error_feature_not_available">Функція недоступна в режимі Mobile API. Увійдіть в інший режим</string>
|
||||||
<string name="error_field_required">Це поле обовʼязкове</string>
|
<string name="error_field_required">Це поле обовʼязкове</string>
|
||||||
|
<!-- Mute system -->
|
||||||
|
<string name="message_mute">Вимкнути сповіщення</string>
|
||||||
|
<string name="message_unmute">Ввімкнути сповіщення</string>
|
||||||
|
<string name="message_mute_success">Ви ігноруєте цього користувача</string>
|
||||||
|
<string name="message_unmute_success">Ви не ігноруєте цього користувача</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -66,7 +66,7 @@
|
|||||||
<item>gminaulanmajorat</item>
|
<item>gminaulanmajorat</item>
|
||||||
<item>gminaozorkow</item>
|
<item>gminaozorkow</item>
|
||||||
<item>gminalopiennikgorny</item>
|
<item>gminalopiennikgorny</item>
|
||||||
<item>warszawa</item>
|
<item>saas1</item>
|
||||||
<item>powiatwulkanowy</item>
|
<item>powiatwulkanowy</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
</resources>
|
</resources>
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -109,8 +109,8 @@
|
|||||||
<string name="main_log_in">Log in</string>
|
<string name="main_log_in">Log in</string>
|
||||||
<string name="main_session_expired">Session expired</string>
|
<string name="main_session_expired">Session expired</string>
|
||||||
<string name="main_session_relogin">Session expired, log in again</string>
|
<string name="main_session_relogin">Session expired, log in again</string>
|
||||||
<string name="main_expired_credentials_description">Your account password has been changed. You need to log in to Wulkanowy again</string>
|
<string name="main_expired_credentials_title">Password has expired or been changed</string>
|
||||||
<string name="main_expired_credentials_title">Password changed</string>
|
<string name="main_expired_credentials_description">Your account password has expired or been changed. You will need to log in to Wulkanowy again</string>
|
||||||
<string name="main_support_title">Application support</string>
|
<string name="main_support_title">Application support</string>
|
||||||
<string name="main_support_description">Do you like this app? Support its development by enabling non-invasive ads that you can disable at any time</string>
|
<string name="main_support_description">Do you like this app? Support its development by enabling non-invasive ads that you can disable at any time</string>
|
||||||
<string name="main_support_positive">Enable ads</string>
|
<string name="main_support_positive">Enable ads</string>
|
||||||
@ -325,8 +325,10 @@
|
|||||||
<string name="message_forward">Forward</string>
|
<string name="message_forward">Forward</string>
|
||||||
<string name="message_select_all">Select all</string>
|
<string name="message_select_all">Select all</string>
|
||||||
<string name="message_unselect_all">Unselect all</string>
|
<string name="message_unselect_all">Unselect all</string>
|
||||||
|
<string name="message_restore_from_trash">Restore from trash</string>
|
||||||
<string name="message_move_to_trash">Move to trash</string>
|
<string name="message_move_to_trash">Move to trash</string>
|
||||||
<string name="message_delete_forever">Delete permanently</string>
|
<string name="message_delete_forever">Delete permanently</string>
|
||||||
|
<string name="message_restore_success">Message restored successfully</string>
|
||||||
<string name="message_delete_success">Message deleted successfully</string>
|
<string name="message_delete_success">Message deleted successfully</string>
|
||||||
<string name="message_mailbox_type_student">student</string>
|
<string name="message_mailbox_type_student">student</string>
|
||||||
<string name="message_mailbox_type_parent">parent</string>
|
<string name="message_mailbox_type_parent">parent</string>
|
||||||
@ -364,6 +366,7 @@
|
|||||||
<item quantity="other">%1$d selected</item>
|
<item quantity="other">%1$d selected</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="message_messages_deleted">Messages deleted</string>
|
<string name="message_messages_deleted">Messages deleted</string>
|
||||||
|
<string name="message_messages_restored">Messages restored</string>
|
||||||
<string name="message_mailbox_chooser_title">Choose mailbox</string>
|
<string name="message_mailbox_chooser_title">Choose mailbox</string>
|
||||||
<string name="message_incognito_mode_on">Incognito mode is on</string>
|
<string name="message_incognito_mode_on">Incognito mode is on</string>
|
||||||
<string name="message_incognito_description">Thanks to incognito mode sender is not notified when you read the message</string>
|
<string name="message_incognito_description">Thanks to incognito mode sender is not notified when you read the message</string>
|
||||||
@ -845,15 +848,18 @@
|
|||||||
|
|
||||||
|
|
||||||
<!--Captcha-->
|
<!--Captcha-->
|
||||||
<string name="captcha_dialog_title">Verification is in progress. Wait…</string>
|
<string name="captcha_dialog_title">VULCAN\'s website requires verification</string>
|
||||||
|
<string name="captcha_dialog_description"><b>Why am I seeing this?</b>\nThe register website from which Wulkanowy downloads data displays the same screen as above, so Wulkanowy must also show it to be able to download data from this website. There\'s no way around it</string>
|
||||||
<string name="captcha_verified_message">Verified successfully</string>
|
<string name="captcha_verified_message">Verified successfully</string>
|
||||||
|
|
||||||
|
|
||||||
<!--Errors-->
|
<!--Errors-->
|
||||||
<string name="error_no_internet">No internet connection</string>
|
<string name="error_no_internet">No internet connection</string>
|
||||||
<string name="error_invalid_device_datetime">An error occurred. Check your device clock</string>
|
<string name="error_invalid_device_datetime">An error occurred. Check your device clock</string>
|
||||||
|
<string name="error_account_inactive">This account is inactive. Try logging in again</string>
|
||||||
<string name="error_timeout">Connection to register failed. Servers can be overloaded. Please try again later</string>
|
<string name="error_timeout">Connection to register failed. Servers can be overloaded. Please try again later</string>
|
||||||
<string name="error_login_failed">Loading data failed. Please try again later</string>
|
<string name="error_login_failed">Loading data failed. Please try again later</string>
|
||||||
|
<string name="error_password_invalid">Your password has expired or been changed. Please log in again</string>
|
||||||
<string name="error_password_change_required">Register password change required</string>
|
<string name="error_password_change_required">Register password change required</string>
|
||||||
<string name="error_service_unavailable">Maintenance underway UONET + register. Try again later</string>
|
<string name="error_service_unavailable">Maintenance underway UONET + register. Try again later</string>
|
||||||
<string name="error_unknown_uonet">Unknown UONET + register error. Try again later</string>
|
<string name="error_unknown_uonet">Unknown UONET + register error. Try again later</string>
|
||||||
@ -863,4 +869,10 @@
|
|||||||
<string name="error_feature_disabled">Feature disabled by your school</string>
|
<string name="error_feature_disabled">Feature disabled by your school</string>
|
||||||
<string name="error_feature_not_available">Feature not available. Login in a mode other than Mobile API</string>
|
<string name="error_feature_not_available">Feature not available. Login in a mode other than Mobile API</string>
|
||||||
<string name="error_field_required">This field is required</string>
|
<string name="error_field_required">This field is required</string>
|
||||||
|
|
||||||
|
<!-- Mute system -->
|
||||||
|
<string name="message_mute">Mute</string>
|
||||||
|
<string name="message_unmute">Unmute</string>
|
||||||
|
<string name="message_mute_success">You have muted this user</string>
|
||||||
|
<string name="message_unmute_success">You have unmuted this user</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -10,11 +10,17 @@ import io.github.wulkanowy.getSemesterEntity
|
|||||||
import io.github.wulkanowy.getStudentEntity
|
import io.github.wulkanowy.getStudentEntity
|
||||||
import io.github.wulkanowy.sdk.Sdk
|
import io.github.wulkanowy.sdk.Sdk
|
||||||
import io.github.wulkanowy.utils.AutoRefreshHelper
|
import io.github.wulkanowy.utils.AutoRefreshHelper
|
||||||
import io.mockk.*
|
import io.mockk.MockKAnnotations
|
||||||
|
import io.mockk.Runs
|
||||||
|
import io.mockk.coEvery
|
||||||
|
import io.mockk.coVerify
|
||||||
|
import io.mockk.every
|
||||||
import io.mockk.impl.annotations.MockK
|
import io.mockk.impl.annotations.MockK
|
||||||
import io.mockk.impl.annotations.SpyK
|
import io.mockk.impl.annotations.SpyK
|
||||||
|
import io.mockk.just
|
||||||
import kotlinx.coroutines.flow.flowOf
|
import kotlinx.coroutines.flow.flowOf
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
@ -61,26 +67,36 @@ class AttendanceRepositoryTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `force refresh without difference`() {
|
fun `force refresh without difference`() = runTest {
|
||||||
// prepare
|
// prepare
|
||||||
coEvery { sdk.getAttendance(startDate, endDate) } returns remoteList
|
coEvery { sdk.getAttendance(startDate, endDate) } returns remoteList
|
||||||
coEvery { attendanceDb.loadAll(1, 1, startDate, endDate) } returnsMany listOf(
|
coEvery { attendanceDb.loadAll(1, 1, startDate, endDate) } returnsMany listOf(
|
||||||
flowOf(remoteList.mapToEntities(semester, emptyList())),
|
flowOf(remoteList.mapToEntities(semester, emptyList())),
|
||||||
flowOf(remoteList.mapToEntities(semester, emptyList()))
|
flowOf(remoteList.mapToEntities(semester, emptyList()))
|
||||||
)
|
)
|
||||||
coEvery { attendanceDb.insertAll(any()) } returns listOf(1, 2, 3)
|
coEvery { attendanceDb.removeOldAndSaveNew(any(), any()) } just Runs
|
||||||
coEvery { attendanceDb.deleteAll(any()) } just Runs
|
|
||||||
|
|
||||||
// execute
|
// execute
|
||||||
val res = runBlocking { attendanceRepository.getAttendance(student, semester, startDate, endDate, true).toFirstResult() }
|
val res = attendanceRepository.getAttendance(
|
||||||
|
student = student,
|
||||||
|
semester = semester,
|
||||||
|
start = startDate,
|
||||||
|
end = endDate,
|
||||||
|
forceRefresh = true,
|
||||||
|
).toFirstResult()
|
||||||
|
|
||||||
|
|
||||||
// verify
|
// verify
|
||||||
assertEquals(null, res.errorOrNull)
|
assertEquals(null, res.errorOrNull)
|
||||||
assertEquals(2, res.dataOrNull?.size)
|
assertEquals(2, res.dataOrNull?.size)
|
||||||
coVerify { sdk.getAttendance(startDate, endDate) }
|
coVerify { sdk.getAttendance(startDate, endDate) }
|
||||||
coVerify { attendanceDb.loadAll(1, 1, startDate, endDate) }
|
coVerify { attendanceDb.loadAll(1, 1, startDate, endDate) }
|
||||||
coVerify { attendanceDb.insertAll(match { it.isEmpty() }) }
|
coVerify {
|
||||||
coVerify { attendanceDb.deleteAll(match { it.isEmpty() }) }
|
attendanceDb.removeOldAndSaveNew(
|
||||||
|
oldItems = match { it.isEmpty() },
|
||||||
|
newItems = match { it.isEmpty() },
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -89,14 +105,23 @@ class AttendanceRepositoryTest {
|
|||||||
coEvery { sdk.getAttendance(startDate, endDate) } returns remoteList
|
coEvery { sdk.getAttendance(startDate, endDate) } returns remoteList
|
||||||
coEvery { attendanceDb.loadAll(1, 1, startDate, endDate) } returnsMany listOf(
|
coEvery { attendanceDb.loadAll(1, 1, startDate, endDate) } returnsMany listOf(
|
||||||
flowOf(remoteList.dropLast(1).mapToEntities(semester, emptyList())),
|
flowOf(remoteList.dropLast(1).mapToEntities(semester, emptyList())),
|
||||||
flowOf(remoteList.dropLast(1).mapToEntities(semester, emptyList())), // after fetch end before save result
|
flowOf(
|
||||||
|
remoteList.dropLast(1).mapToEntities(semester, emptyList())
|
||||||
|
), // after fetch end before save result
|
||||||
flowOf(remoteList.mapToEntities(semester, emptyList()))
|
flowOf(remoteList.mapToEntities(semester, emptyList()))
|
||||||
)
|
)
|
||||||
coEvery { attendanceDb.insertAll(any()) } returns listOf(1, 2, 3)
|
coEvery { attendanceDb.removeOldAndSaveNew(any(), any()) } just Runs
|
||||||
coEvery { attendanceDb.deleteAll(any()) } just Runs
|
|
||||||
|
|
||||||
// execute
|
// execute
|
||||||
val res = runBlocking { attendanceRepository.getAttendance(student, semester, startDate, endDate, true).toFirstResult() }
|
val res = runBlocking {
|
||||||
|
attendanceRepository.getAttendance(
|
||||||
|
student,
|
||||||
|
semester,
|
||||||
|
startDate,
|
||||||
|
endDate,
|
||||||
|
true
|
||||||
|
).toFirstResult()
|
||||||
|
}
|
||||||
|
|
||||||
// verify
|
// verify
|
||||||
assertEquals(null, res.errorOrNull)
|
assertEquals(null, res.errorOrNull)
|
||||||
@ -104,11 +129,13 @@ class AttendanceRepositoryTest {
|
|||||||
coVerify { sdk.getAttendance(startDate, endDate) }
|
coVerify { sdk.getAttendance(startDate, endDate) }
|
||||||
coVerify { attendanceDb.loadAll(1, 1, startDate, endDate) }
|
coVerify { attendanceDb.loadAll(1, 1, startDate, endDate) }
|
||||||
coVerify {
|
coVerify {
|
||||||
attendanceDb.insertAll(match {
|
attendanceDb.removeOldAndSaveNew(
|
||||||
|
oldItems = match { it.isEmpty() },
|
||||||
|
newItems = match {
|
||||||
it.size == 1 && it[0] == remoteList.mapToEntities(semester, emptyList())[1]
|
it.size == 1 && it[0] == remoteList.mapToEntities(semester, emptyList())[1]
|
||||||
})
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
coVerify { attendanceDb.deleteAll(match { it.isEmpty() }) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -117,25 +144,39 @@ class AttendanceRepositoryTest {
|
|||||||
coEvery { sdk.getAttendance(startDate, endDate) } returns remoteList.dropLast(1)
|
coEvery { sdk.getAttendance(startDate, endDate) } returns remoteList.dropLast(1)
|
||||||
coEvery { attendanceDb.loadAll(1, 1, startDate, endDate) } returnsMany listOf(
|
coEvery { attendanceDb.loadAll(1, 1, startDate, endDate) } returnsMany listOf(
|
||||||
flowOf(remoteList.mapToEntities(semester, emptyList())),
|
flowOf(remoteList.mapToEntities(semester, emptyList())),
|
||||||
flowOf(remoteList.mapToEntities(semester, emptyList())), // after fetch end before save result
|
flowOf(
|
||||||
|
remoteList.mapToEntities(
|
||||||
|
semester,
|
||||||
|
emptyList()
|
||||||
|
)
|
||||||
|
), // after fetch end before save result
|
||||||
flowOf(remoteList.dropLast(1).mapToEntities(semester, emptyList()))
|
flowOf(remoteList.dropLast(1).mapToEntities(semester, emptyList()))
|
||||||
)
|
)
|
||||||
coEvery { attendanceDb.insertAll(any()) } returns listOf(1, 2, 3)
|
coEvery { attendanceDb.removeOldAndSaveNew(any(), any()) } just Runs
|
||||||
coEvery { attendanceDb.deleteAll(any()) } just Runs
|
|
||||||
|
|
||||||
// execute
|
// execute
|
||||||
val res = runBlocking { attendanceRepository.getAttendance(student, semester, startDate, endDate, true).toFirstResult() }
|
val res = runBlocking {
|
||||||
|
attendanceRepository.getAttendance(
|
||||||
|
student,
|
||||||
|
semester,
|
||||||
|
startDate,
|
||||||
|
endDate,
|
||||||
|
true
|
||||||
|
).toFirstResult()
|
||||||
|
}
|
||||||
|
|
||||||
// verify
|
// verify
|
||||||
assertEquals(null, res.errorOrNull)
|
assertEquals(null, res.errorOrNull)
|
||||||
assertEquals(1, res.dataOrNull?.size)
|
assertEquals(1, res.dataOrNull?.size)
|
||||||
coVerify { sdk.getAttendance(startDate, endDate) }
|
coVerify { sdk.getAttendance(startDate, endDate) }
|
||||||
coVerify { attendanceDb.loadAll(1, 1, startDate, endDate) }
|
coVerify { attendanceDb.loadAll(1, 1, startDate, endDate) }
|
||||||
coVerify { attendanceDb.insertAll(match { it.isEmpty() }) }
|
|
||||||
coVerify {
|
coVerify {
|
||||||
attendanceDb.deleteAll(match {
|
attendanceDb.removeOldAndSaveNew(
|
||||||
|
oldItems = match {
|
||||||
it.size == 1 && it[0] == remoteList.mapToEntities(semester, emptyList())[1]
|
it.size == 1 && it[0] == remoteList.mapToEntities(semester, emptyList())[1]
|
||||||
})
|
},
|
||||||
|
newItems = emptyList(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,11 +9,16 @@ import io.github.wulkanowy.getSemesterEntity
|
|||||||
import io.github.wulkanowy.getStudentEntity
|
import io.github.wulkanowy.getStudentEntity
|
||||||
import io.github.wulkanowy.sdk.Sdk
|
import io.github.wulkanowy.sdk.Sdk
|
||||||
import io.github.wulkanowy.utils.AutoRefreshHelper
|
import io.github.wulkanowy.utils.AutoRefreshHelper
|
||||||
import io.mockk.*
|
import io.mockk.MockKAnnotations
|
||||||
|
import io.mockk.Runs
|
||||||
|
import io.mockk.coEvery
|
||||||
|
import io.mockk.coVerify
|
||||||
|
import io.mockk.every
|
||||||
import io.mockk.impl.annotations.MockK
|
import io.mockk.impl.annotations.MockK
|
||||||
import io.mockk.impl.annotations.SpyK
|
import io.mockk.impl.annotations.SpyK
|
||||||
|
import io.mockk.just
|
||||||
import kotlinx.coroutines.flow.flowOf
|
import kotlinx.coroutines.flow.flowOf
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
@ -52,46 +57,28 @@ class CompletedLessonsRepositoryTest {
|
|||||||
MockKAnnotations.init(this)
|
MockKAnnotations.init(this)
|
||||||
every { refreshHelper.shouldBeRefreshed(any()) } returns false
|
every { refreshHelper.shouldBeRefreshed(any()) } returns false
|
||||||
|
|
||||||
completedLessonRepository = CompletedLessonsRepository(completedLessonDb, sdk, refreshHelper)
|
completedLessonRepository =
|
||||||
|
CompletedLessonsRepository(completedLessonDb, sdk, refreshHelper)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `force refresh without difference`() {
|
fun `force refresh without difference`() = runTest {
|
||||||
// prepare
|
// prepare
|
||||||
coEvery { sdk.getCompletedLessons(startDate, endDate) } returns remoteList
|
coEvery { sdk.getCompletedLessons(startDate, endDate) } returns remoteList
|
||||||
coEvery { completedLessonDb.loadAll(1, 1, startDate, endDate) } returnsMany listOf(
|
coEvery { completedLessonDb.loadAll(1, 1, startDate, endDate) } returnsMany listOf(
|
||||||
flowOf(remoteList.mapToEntities(semester)),
|
flowOf(remoteList.mapToEntities(semester)),
|
||||||
flowOf(remoteList.mapToEntities(semester))
|
flowOf(remoteList.mapToEntities(semester))
|
||||||
)
|
)
|
||||||
coEvery { completedLessonDb.insertAll(any()) } returns listOf(1, 2, 3)
|
coEvery { completedLessonDb.removeOldAndSaveNew(any(), any()) } just Runs
|
||||||
coEvery { completedLessonDb.deleteAll(any()) } just Runs
|
|
||||||
|
|
||||||
// execute
|
// execute
|
||||||
val res = runBlocking { completedLessonRepository.getCompletedLessons(student, semester, startDate, endDate, true).toFirstResult() }
|
val res = completedLessonRepository.getCompletedLessons(
|
||||||
|
student = student,
|
||||||
// verify
|
semester = semester,
|
||||||
assertEquals(null, res.errorOrNull)
|
start = startDate,
|
||||||
assertEquals(2, res.dataOrNull?.size)
|
end = endDate,
|
||||||
coVerify { sdk.getCompletedLessons(startDate, endDate) }
|
forceRefresh = true,
|
||||||
coVerify { completedLessonDb.loadAll(1, 1, startDate, endDate) }
|
).toFirstResult()
|
||||||
coVerify { completedLessonDb.insertAll(match { it.isEmpty() }) }
|
|
||||||
coVerify { completedLessonDb.deleteAll(match { it.isEmpty() }) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `force refresh with more items in remote`() {
|
|
||||||
// prepare
|
|
||||||
coEvery { sdk.getCompletedLessons(startDate, endDate) } returns remoteList
|
|
||||||
coEvery { completedLessonDb.loadAll(1, 1, startDate, endDate) } returnsMany listOf(
|
|
||||||
flowOf(remoteList.dropLast(1).mapToEntities(semester)),
|
|
||||||
flowOf(remoteList.dropLast(1).mapToEntities(semester)), // after fetch end before save result
|
|
||||||
flowOf(remoteList.mapToEntities(semester))
|
|
||||||
)
|
|
||||||
coEvery { completedLessonDb.insertAll(any()) } returns listOf(1, 2, 3)
|
|
||||||
coEvery { completedLessonDb.deleteAll(any()) } just Runs
|
|
||||||
|
|
||||||
// execute
|
|
||||||
val res = runBlocking { completedLessonRepository.getCompletedLessons(student, semester, startDate, endDate, true).toFirstResult() }
|
|
||||||
|
|
||||||
// verify
|
// verify
|
||||||
assertEquals(null, res.errorOrNull)
|
assertEquals(null, res.errorOrNull)
|
||||||
@ -99,15 +86,52 @@ class CompletedLessonsRepositoryTest {
|
|||||||
coVerify { sdk.getCompletedLessons(startDate, endDate) }
|
coVerify { sdk.getCompletedLessons(startDate, endDate) }
|
||||||
coVerify { completedLessonDb.loadAll(1, 1, startDate, endDate) }
|
coVerify { completedLessonDb.loadAll(1, 1, startDate, endDate) }
|
||||||
coVerify {
|
coVerify {
|
||||||
completedLessonDb.insertAll(match {
|
completedLessonDb.removeOldAndSaveNew(
|
||||||
it.size == 1 && it[0] == remoteList.mapToEntities(semester)[1]
|
oldItems = match { it.isEmpty() },
|
||||||
})
|
newItems = match { it.isEmpty() },
|
||||||
|
)
|
||||||
}
|
}
|
||||||
coVerify { completedLessonDb.deleteAll(match { it.isEmpty() }) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `force refresh with more items in local`() {
|
fun `force refresh with more items in remote`() = runTest {
|
||||||
|
// prepare
|
||||||
|
coEvery { sdk.getCompletedLessons(startDate, endDate) } returns remoteList
|
||||||
|
coEvery { completedLessonDb.loadAll(1, 1, startDate, endDate) } returnsMany listOf(
|
||||||
|
flowOf(remoteList.dropLast(1).mapToEntities(semester)),
|
||||||
|
flowOf(
|
||||||
|
remoteList.dropLast(1).mapToEntities(semester)
|
||||||
|
), // after fetch end before save result
|
||||||
|
flowOf(remoteList.mapToEntities(semester))
|
||||||
|
)
|
||||||
|
coEvery { completedLessonDb.removeOldAndSaveNew(any(), any()) } just Runs
|
||||||
|
|
||||||
|
// execute
|
||||||
|
val res = completedLessonRepository.getCompletedLessons(
|
||||||
|
student = student,
|
||||||
|
semester = semester,
|
||||||
|
start = startDate,
|
||||||
|
end = endDate,
|
||||||
|
forceRefresh = true
|
||||||
|
).toFirstResult()
|
||||||
|
|
||||||
|
// verify
|
||||||
|
assertEquals(null, res.errorOrNull)
|
||||||
|
assertEquals(2, res.dataOrNull?.size)
|
||||||
|
coVerify { sdk.getCompletedLessons(startDate, endDate) }
|
||||||
|
coVerify { completedLessonDb.loadAll(1, 1, startDate, endDate) }
|
||||||
|
coVerify {
|
||||||
|
completedLessonDb.removeOldAndSaveNew(
|
||||||
|
oldItems = match { it.isEmpty() },
|
||||||
|
newItems = match {
|
||||||
|
it.size == 1 && it[0] == remoteList.mapToEntities(semester)[1]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `force refresh with more items in local`() = runTest {
|
||||||
// prepare
|
// prepare
|
||||||
coEvery { sdk.getCompletedLessons(startDate, endDate) } returns remoteList.dropLast(1)
|
coEvery { sdk.getCompletedLessons(startDate, endDate) } returns remoteList.dropLast(1)
|
||||||
coEvery { completedLessonDb.loadAll(1, 1, startDate, endDate) } returnsMany listOf(
|
coEvery { completedLessonDb.loadAll(1, 1, startDate, endDate) } returnsMany listOf(
|
||||||
@ -115,22 +139,29 @@ class CompletedLessonsRepositoryTest {
|
|||||||
flowOf(remoteList.mapToEntities(semester)), // after fetch end before save result
|
flowOf(remoteList.mapToEntities(semester)), // after fetch end before save result
|
||||||
flowOf(remoteList.dropLast(1).mapToEntities(semester))
|
flowOf(remoteList.dropLast(1).mapToEntities(semester))
|
||||||
)
|
)
|
||||||
coEvery { completedLessonDb.insertAll(any()) } returns listOf(1, 2, 3)
|
coEvery { completedLessonDb.removeOldAndSaveNew(any(), any()) } just Runs
|
||||||
coEvery { completedLessonDb.deleteAll(any()) } just Runs
|
|
||||||
|
|
||||||
// execute
|
// execute
|
||||||
val res = runBlocking { completedLessonRepository.getCompletedLessons(student, semester, startDate, endDate, true).toFirstResult() }
|
val res = completedLessonRepository.getCompletedLessons(
|
||||||
|
student = student,
|
||||||
|
semester = semester,
|
||||||
|
start = startDate,
|
||||||
|
end = endDate,
|
||||||
|
forceRefresh = true,
|
||||||
|
).toFirstResult()
|
||||||
|
|
||||||
// verify
|
// verify
|
||||||
assertEquals(null, res.errorOrNull)
|
assertEquals(null, res.errorOrNull)
|
||||||
assertEquals(1, res.dataOrNull?.size)
|
assertEquals(1, res.dataOrNull?.size)
|
||||||
coVerify { sdk.getCompletedLessons(startDate, endDate) }
|
coVerify { sdk.getCompletedLessons(startDate, endDate) }
|
||||||
coVerify { completedLessonDb.loadAll(1, 1, startDate, endDate) }
|
coVerify { completedLessonDb.loadAll(1, 1, startDate, endDate) }
|
||||||
coVerify { completedLessonDb.insertAll(match { it.isEmpty() }) }
|
|
||||||
coVerify {
|
coVerify {
|
||||||
completedLessonDb.deleteAll(match {
|
completedLessonDb.removeOldAndSaveNew(
|
||||||
|
oldItems = match {
|
||||||
it.size == 1 && it[0] == remoteList.mapToEntities(semester)[1]
|
it.size == 1 && it[0] == remoteList.mapToEntities(semester)[1]
|
||||||
})
|
},
|
||||||
|
newItems = match { it.isEmpty() },
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,11 +9,17 @@ import io.github.wulkanowy.getSemesterEntity
|
|||||||
import io.github.wulkanowy.getStudentEntity
|
import io.github.wulkanowy.getStudentEntity
|
||||||
import io.github.wulkanowy.sdk.Sdk
|
import io.github.wulkanowy.sdk.Sdk
|
||||||
import io.github.wulkanowy.utils.AutoRefreshHelper
|
import io.github.wulkanowy.utils.AutoRefreshHelper
|
||||||
import io.mockk.*
|
import io.mockk.MockKAnnotations
|
||||||
|
import io.mockk.Runs
|
||||||
|
import io.mockk.coEvery
|
||||||
|
import io.mockk.coVerify
|
||||||
|
import io.mockk.every
|
||||||
import io.mockk.impl.annotations.MockK
|
import io.mockk.impl.annotations.MockK
|
||||||
import io.mockk.impl.annotations.SpyK
|
import io.mockk.impl.annotations.SpyK
|
||||||
|
import io.mockk.just
|
||||||
import kotlinx.coroutines.flow.flowOf
|
import kotlinx.coroutines.flow.flowOf
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
@ -64,35 +70,42 @@ class ExamRemoteTest {
|
|||||||
flowOf(remoteList.mapToEntities(semester)),
|
flowOf(remoteList.mapToEntities(semester)),
|
||||||
flowOf(remoteList.mapToEntities(semester))
|
flowOf(remoteList.mapToEntities(semester))
|
||||||
)
|
)
|
||||||
coEvery { examDb.insertAll(any()) } returns listOf(1, 2, 3)
|
coEvery { examDb.removeOldAndSaveNew(any(), any()) } just Runs
|
||||||
coEvery { examDb.deleteAll(any()) } just Runs
|
|
||||||
|
|
||||||
// execute
|
// execute
|
||||||
val res = runBlocking { examRepository.getExams(student, semester, startDate, endDate, true).toFirstResult() }
|
val res = runBlocking {
|
||||||
|
examRepository.getExams(student, semester, startDate, endDate, true).toFirstResult()
|
||||||
|
}
|
||||||
|
|
||||||
// verify
|
// verify
|
||||||
assertEquals(null, res.errorOrNull)
|
assertEquals(null, res.errorOrNull)
|
||||||
assertEquals(2, res.dataOrNull?.size)
|
assertEquals(2, res.dataOrNull?.size)
|
||||||
coVerify { sdk.getExams(startDate, realEndDate) }
|
coVerify { sdk.getExams(startDate, realEndDate) }
|
||||||
coVerify { examDb.loadAll(1, 1, startDate, realEndDate) }
|
coVerify { examDb.loadAll(1, 1, startDate, realEndDate) }
|
||||||
coVerify { examDb.insertAll(match { it.isEmpty() }) }
|
coVerify { examDb.removeOldAndSaveNew(emptyList(), emptyList()) }
|
||||||
coVerify { examDb.deleteAll(match { it.isEmpty() }) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `force refresh with more items in remote`() {
|
fun `force refresh with more items in remote`() = runTest {
|
||||||
// prepare
|
// prepare
|
||||||
coEvery { sdk.getExams(startDate, realEndDate) } returns remoteList
|
coEvery { sdk.getExams(startDate, realEndDate) } returns remoteList
|
||||||
coEvery { examDb.loadAll(1, 1, startDate, realEndDate) } returnsMany listOf(
|
coEvery { examDb.loadAll(1, 1, startDate, realEndDate) } returnsMany listOf(
|
||||||
flowOf(remoteList.dropLast(1).mapToEntities(semester)),
|
flowOf(remoteList.dropLast(1).mapToEntities(semester)),
|
||||||
flowOf(remoteList.dropLast(1).mapToEntities(semester)), // after fetch end before save result
|
flowOf(
|
||||||
|
remoteList.dropLast(1).mapToEntities(semester)
|
||||||
|
), // after fetch end before save result
|
||||||
flowOf(remoteList.mapToEntities(semester))
|
flowOf(remoteList.mapToEntities(semester))
|
||||||
)
|
)
|
||||||
coEvery { examDb.insertAll(any()) } returns listOf(1, 2, 3)
|
coEvery { examDb.removeOldAndSaveNew(any(), any()) } just Runs
|
||||||
coEvery { examDb.deleteAll(any()) } just Runs
|
|
||||||
|
|
||||||
// execute
|
// execute
|
||||||
val res = runBlocking { examRepository.getExams(student, semester, startDate, endDate, true).toFirstResult() }
|
val res = examRepository.getExams(
|
||||||
|
student = student,
|
||||||
|
semester = semester,
|
||||||
|
start = startDate,
|
||||||
|
end = endDate,
|
||||||
|
forceRefresh = true,
|
||||||
|
).toFirstResult()
|
||||||
|
|
||||||
// verify
|
// verify
|
||||||
assertEquals(null, res.errorOrNull)
|
assertEquals(null, res.errorOrNull)
|
||||||
@ -100,15 +113,17 @@ class ExamRemoteTest {
|
|||||||
coVerify { sdk.getExams(startDate, realEndDate) }
|
coVerify { sdk.getExams(startDate, realEndDate) }
|
||||||
coVerify { examDb.loadAll(1, 1, startDate, realEndDate) }
|
coVerify { examDb.loadAll(1, 1, startDate, realEndDate) }
|
||||||
coVerify {
|
coVerify {
|
||||||
examDb.insertAll(match {
|
examDb.removeOldAndSaveNew(
|
||||||
|
oldItems = emptyList(),
|
||||||
|
newItems = match {
|
||||||
it.size == 1 && it[0] == remoteList.mapToEntities(semester)[1]
|
it.size == 1 && it[0] == remoteList.mapToEntities(semester)[1]
|
||||||
})
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
coVerify { examDb.deleteAll(match { it.isEmpty() }) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `force refresh with more items in local`() {
|
fun `force refresh with more items in local`() = runTest {
|
||||||
// prepare
|
// prepare
|
||||||
coEvery { sdk.getExams(startDate, realEndDate) } returns remoteList.dropLast(1)
|
coEvery { sdk.getExams(startDate, realEndDate) } returns remoteList.dropLast(1)
|
||||||
coEvery { examDb.loadAll(1, 1, startDate, realEndDate) } returnsMany listOf(
|
coEvery { examDb.loadAll(1, 1, startDate, realEndDate) } returnsMany listOf(
|
||||||
@ -116,22 +131,27 @@ class ExamRemoteTest {
|
|||||||
flowOf(remoteList.mapToEntities(semester)), // after fetch end before save result
|
flowOf(remoteList.mapToEntities(semester)), // after fetch end before save result
|
||||||
flowOf(remoteList.dropLast(1).mapToEntities(semester))
|
flowOf(remoteList.dropLast(1).mapToEntities(semester))
|
||||||
)
|
)
|
||||||
coEvery { examDb.insertAll(any()) } returns listOf(1, 2, 3)
|
coEvery { examDb.removeOldAndSaveNew(any(), any()) } just Runs
|
||||||
coEvery { examDb.deleteAll(any()) } just Runs
|
|
||||||
|
|
||||||
// execute
|
// execute
|
||||||
val res = runBlocking { examRepository.getExams(student, semester, startDate, endDate, true).toFirstResult() }
|
val res = examRepository.getExams(
|
||||||
|
student = student,
|
||||||
|
semester = semester,
|
||||||
|
start = startDate,
|
||||||
|
end = endDate,
|
||||||
|
forceRefresh = true,
|
||||||
|
).toFirstResult()
|
||||||
|
|
||||||
// verify
|
// verify
|
||||||
assertEquals(null, res.errorOrNull)
|
assertEquals(null, res.errorOrNull)
|
||||||
assertEquals(1, res.dataOrNull?.size)
|
assertEquals(1, res.dataOrNull?.size)
|
||||||
coVerify { sdk.getExams(startDate, realEndDate) }
|
coVerify { sdk.getExams(startDate, realEndDate) }
|
||||||
coVerify { examDb.loadAll(1, 1, startDate, realEndDate) }
|
coVerify { examDb.loadAll(1, 1, startDate, realEndDate) }
|
||||||
coVerify { examDb.insertAll(match { it.isEmpty() }) }
|
|
||||||
coVerify {
|
coVerify {
|
||||||
examDb.deleteAll(match {
|
examDb.removeOldAndSaveNew(
|
||||||
it.size == 1 && it[0] == remoteList.mapToEntities(semester)[1]
|
oldItems = match { it.size == 1 && it[0] == remoteList.mapToEntities(semester)[1] },
|
||||||
})
|
newItems = emptyList()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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