forked from github/wulkanowy-mirror
Merge branch 'release/2.1.0'
This commit is contained in:
commit
af346842a3
@ -1,8 +1,11 @@
|
||||
import com.github.triplet.gradle.androidpublisher.ReleaseStatus
|
||||
import ru.cian.huawei.publish.ReleaseNote
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlinx-serialization'
|
||||
apply plugin: 'kotlin-parcelize'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
apply plugin: 'com.google.devtools.ksp'
|
||||
apply plugin: 'dagger.hilt.android.plugin'
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
apply plugin: 'com.google.firebase.crashlytics'
|
||||
@ -10,21 +13,22 @@ apply plugin: 'com.github.triplet.play'
|
||||
apply plugin: 'ru.cian.huawei-publish'
|
||||
apply plugin: 'com.mikepenz.aboutlibraries.plugin'
|
||||
apply plugin: 'com.huawei.agconnect'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
apply from: 'jacoco.gradle'
|
||||
apply from: 'sonarqube.gradle'
|
||||
apply from: 'hooks.gradle'
|
||||
|
||||
android {
|
||||
namespace 'io.github.wulkanowy'
|
||||
compileSdkVersion 33
|
||||
compileSdk 33
|
||||
|
||||
defaultConfig {
|
||||
applicationId "io.github.wulkanowy"
|
||||
testApplicationId "io.github.tests.wulkanowy"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 33
|
||||
versionCode 130
|
||||
versionName "2.0.8"
|
||||
versionCode 131
|
||||
versionName "2.1.0"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
resValue "string", "app_name", "Wulkanowy"
|
||||
@ -33,14 +37,6 @@ android {
|
||||
firebase_enabled: project.hasProperty("enableFirebase"),
|
||||
admob_project_id: ""
|
||||
]
|
||||
javaCompileOptions {
|
||||
annotationProcessorOptions {
|
||||
arguments += [
|
||||
"room.schemaLocation": "$projectDir/schemas".toString(),
|
||||
"room.incremental" : "true"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
buildConfigField "String", "SINGLE_SUPPORT_AD_ID", "null"
|
||||
buildConfigField "String", "DASHBOARD_TILE_AD_ID", "null"
|
||||
@ -85,7 +81,7 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
flavorDimensions "platform"
|
||||
flavorDimensions += "platform"
|
||||
|
||||
productFlavors {
|
||||
hms {
|
||||
@ -124,20 +120,20 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
testOptions.unitTests {
|
||||
includeAndroidResources = true
|
||||
testOptions {
|
||||
unitTests.includeAndroidResources = true
|
||||
// workaround HMS test errors https://github.com/robolectric/robolectric/issues/2750
|
||||
all { jvmArgs '-noverify' }
|
||||
unitTests.all { jvmArgs '-noverify' }
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
coreLibraryDesugaringEnabled true
|
||||
sourceCompatibility JavaVersion.VERSION_11
|
||||
targetCompatibility JavaVersion.VERSION_11
|
||||
sourceCompatibility JavaVersion.VERSION_17
|
||||
targetCompatibility JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = "11"
|
||||
jvmTarget = "17"
|
||||
freeCompilerArgs += ["-opt-in=kotlin.RequiresOptIn", "-Xjvm-default=all"]
|
||||
}
|
||||
|
||||
@ -156,17 +152,16 @@ android {
|
||||
kapt {
|
||||
correctErrorTypes true
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvmToolchain(11)
|
||||
ksp {
|
||||
arg("room.schemaLocation", "$projectDir/schemas".toString())
|
||||
}
|
||||
|
||||
play {
|
||||
defaultToAppBundles = false
|
||||
track = 'production'
|
||||
releaseStatus = com.github.triplet.gradle.androidpublisher.ReleaseStatus.IN_PROGRESS
|
||||
releaseStatus = ReleaseStatus.IN_PROGRESS
|
||||
userFraction = 0.25d
|
||||
updatePriority = 1
|
||||
updatePriority = 3
|
||||
enabled.set(false)
|
||||
}
|
||||
|
||||
@ -177,7 +172,7 @@ huaweiPublish {
|
||||
buildFormat = "aab"
|
||||
deployType = "publish"
|
||||
releaseNotes = [
|
||||
new ru.cian.huawei.publish.ReleaseNote(
|
||||
new ReleaseNote(
|
||||
"pl-PL",
|
||||
"$projectDir/src/main/play/release-notes/pl-PL/default.txt"
|
||||
)
|
||||
@ -189,14 +184,14 @@ huaweiPublish {
|
||||
ext {
|
||||
work_manager = "2.8.1"
|
||||
android_hilt = "1.0.0"
|
||||
room = "2.5.1"
|
||||
room = "2.5.2"
|
||||
chucker = "3.5.2"
|
||||
mockk = "1.13.5"
|
||||
coroutines = "1.7.1"
|
||||
mockk = "1.13.7"
|
||||
coroutines = "1.7.3"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'io.github.wulkanowy:sdk:2.0.8'
|
||||
implementation 'io.github.wulkanowy:sdk:2.1.0'
|
||||
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.3'
|
||||
|
||||
@ -207,11 +202,11 @@ dependencies {
|
||||
implementation 'androidx.core:core-splashscreen:1.0.1'
|
||||
implementation "androidx.activity:activity-ktx:1.7.2"
|
||||
implementation "androidx.appcompat:appcompat:1.6.1"
|
||||
implementation "androidx.fragment:fragment-ktx:1.5.7"
|
||||
implementation "androidx.fragment:fragment-ktx:1.6.1"
|
||||
implementation "androidx.annotation:annotation:1.6.0"
|
||||
|
||||
implementation "androidx.preference:preference-ktx:1.2.0"
|
||||
implementation "androidx.recyclerview:recyclerview:1.3.0"
|
||||
implementation "androidx.preference:preference-ktx:1.2.1"
|
||||
implementation "androidx.recyclerview:recyclerview:1.3.1"
|
||||
implementation "androidx.viewpager2:viewpager2:1.1.0-beta02"
|
||||
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
|
||||
implementation "androidx.constraintlayout:constraintlayout:2.1.4"
|
||||
@ -228,7 +223,7 @@ dependencies {
|
||||
|
||||
implementation "androidx.room:room-runtime:$room"
|
||||
implementation "androidx.room:room-ktx:$room"
|
||||
kapt "androidx.room:room-compiler:$room"
|
||||
ksp "androidx.room:room-compiler:$room"
|
||||
|
||||
implementation "com.google.dagger:hilt-android:$hilt_version"
|
||||
kapt "com.google.dagger:hilt-android-compiler:$hilt_version"
|
||||
@ -252,17 +247,17 @@ dependencies {
|
||||
implementation 'com.fredporciuncula:flow-preferences:1.9.1'
|
||||
implementation 'org.apache.commons:commons-text:1.10.0'
|
||||
|
||||
playImplementation platform('com.google.firebase:firebase-bom:32.1.0')
|
||||
playImplementation platform('com.google.firebase:firebase-bom:32.2.2')
|
||||
playImplementation 'com.google.firebase:firebase-analytics-ktx'
|
||||
playImplementation 'com.google.firebase:firebase-messaging:'
|
||||
playImplementation 'com.google.firebase:firebase-crashlytics:'
|
||||
playImplementation 'com.google.firebase:firebase-config-ktx'
|
||||
playImplementation 'com.google.android.play:core:1.10.3'
|
||||
playImplementation 'com.google.android.play:core-ktx:1.8.1'
|
||||
playImplementation 'com.google.android.gms:play-services-ads:22.1.0'
|
||||
playImplementation 'com.google.android.gms:play-services-ads:22.2.0'
|
||||
|
||||
hmsImplementation 'com.huawei.hms:hianalytics:6.10.0.301'
|
||||
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.9.0.300'
|
||||
hmsImplementation 'com.huawei.hms:hianalytics:6.10.0.303'
|
||||
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.9.1.300'
|
||||
|
||||
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker"
|
||||
|
||||
|
2443
app/schemas/io.github.wulkanowy.data.db.AppDatabase/57.json
Normal file
2443
app/schemas/io.github.wulkanowy.data.db.AppDatabase/57.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -50,5 +50,9 @@
|
||||
{
|
||||
"displayName": "Tomasz F.",
|
||||
"githubUsername": "Pengwius"
|
||||
},
|
||||
{
|
||||
"displayName": "Antoni Paduch",
|
||||
"githubUsername": "janAte1"
|
||||
}
|
||||
]
|
||||
|
@ -148,7 +148,7 @@ inline fun <ResultType, RequestType, T> networkBoundResource(
|
||||
crossinline saveFetchResult: suspend (old: ResultType, new: RequestType) -> Unit,
|
||||
crossinline onFetchFailed: (Throwable) -> Unit = { },
|
||||
crossinline shouldFetch: (ResultType) -> Boolean = { true },
|
||||
crossinline mapResult: (ResultType) -> T
|
||||
crossinline mapResult: (ResultType) -> T,
|
||||
) = flow {
|
||||
emit(Resource.Loading())
|
||||
|
||||
|
@ -50,6 +50,7 @@ import javax.inject.Singleton
|
||||
AutoMigration(from = 51, to = 52),
|
||||
AutoMigration(from = 54, to = 55, spec = Migration55::class),
|
||||
AutoMigration(from = 55, to = 56),
|
||||
AutoMigration(from = 56, to = 57, spec = Migration57::class),
|
||||
],
|
||||
version = AppDatabase.VERSION_SCHEMA,
|
||||
exportSchema = true
|
||||
@ -58,7 +59,7 @@ import javax.inject.Singleton
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
|
||||
companion object {
|
||||
const val VERSION_SCHEMA = 56
|
||||
const val VERSION_SCHEMA = 57
|
||||
|
||||
fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf(
|
||||
Migration2(),
|
||||
|
@ -1,6 +1,7 @@
|
||||
package io.github.wulkanowy.data.db
|
||||
|
||||
import androidx.room.TypeConverter
|
||||
import io.github.wulkanowy.data.enums.MessageType
|
||||
import io.github.wulkanowy.ui.modules.Destination
|
||||
import io.github.wulkanowy.utils.toTimestamp
|
||||
import kotlinx.serialization.SerializationException
|
||||
@ -68,4 +69,9 @@ class Converters {
|
||||
@TypeConverter
|
||||
fun stringToDestination(destination: String): Destination = json.decodeFromString(destination)
|
||||
|
||||
@TypeConverter
|
||||
fun messageTypesToString(types: List<MessageType>): String = json.encodeToString(types)
|
||||
|
||||
@TypeConverter
|
||||
fun stringToMessageTypes(text: String): List<MessageType> = json.decodeFromString(text)
|
||||
}
|
||||
|
@ -22,4 +22,4 @@ abstract class AdminMessageDao : BaseDao<AdminMessage> {
|
||||
deleteAll(oldMessages)
|
||||
insertAll(newMessages)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package io.github.wulkanowy.data.db.entities
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import io.github.wulkanowy.data.enums.MessageType
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
@ -33,7 +34,8 @@ data class AdminMessage(
|
||||
|
||||
val priority: String,
|
||||
|
||||
val type: String,
|
||||
@ColumnInfo(name = "types", defaultValue = "[]")
|
||||
val types: List<MessageType> = emptyList(),
|
||||
|
||||
@ColumnInfo(name = "is_dismissible")
|
||||
val isDismissible: Boolean = false
|
||||
|
@ -0,0 +1,10 @@
|
||||
package io.github.wulkanowy.data.db.migrations
|
||||
|
||||
import androidx.room.DeleteColumn
|
||||
import androidx.room.migration.AutoMigrationSpec
|
||||
|
||||
@DeleteColumn(
|
||||
tableName = "AdminMessages",
|
||||
columnName = "type",
|
||||
)
|
||||
class Migration57 : AutoMigrationSpec
|
@ -0,0 +1,9 @@
|
||||
package io.github.wulkanowy.data.enums
|
||||
|
||||
enum class MessageType {
|
||||
GENERAL_MESSAGE,
|
||||
DASHBOARD_MESSAGE,
|
||||
LOGIN_MESSAGE,
|
||||
PASS_RESET_MESSAGE,
|
||||
ERROR_OVERRIDE,
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package io.github.wulkanowy.data.enums
|
||||
|
||||
enum class TimetableGapsMode(val value: String) {
|
||||
NO_GAPS("no_gaps"),
|
||||
BETWEEN_LESSONS("between"),
|
||||
BETWEEN_AND_BEFORE_LESSONS("before_and_between");
|
||||
|
||||
companion object {
|
||||
fun getByValue(value: String) = entries.find { it.value == value } ?: BETWEEN_LESSONS
|
||||
}
|
||||
}
|
@ -1,10 +1,11 @@
|
||||
package io.github.wulkanowy.data.repositories
|
||||
|
||||
import io.github.wulkanowy.data.Resource
|
||||
import io.github.wulkanowy.data.api.AdminMessageService
|
||||
import io.github.wulkanowy.data.db.dao.AdminMessageDao
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.db.entities.AdminMessage
|
||||
import io.github.wulkanowy.data.networkBoundResource
|
||||
import io.github.wulkanowy.utils.AppInfo
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
@ -13,34 +14,20 @@ import javax.inject.Singleton
|
||||
class AdminMessageRepository @Inject constructor(
|
||||
private val adminMessageService: AdminMessageService,
|
||||
private val adminMessageDao: AdminMessageDao,
|
||||
private val appInfo: AppInfo
|
||||
) {
|
||||
|
||||
private val saveFetchResultMutex = Mutex()
|
||||
|
||||
suspend fun getAdminMessages(student: Student) = networkBoundResource(
|
||||
mutex = saveFetchResultMutex,
|
||||
isResultEmpty = { it == null },
|
||||
query = { adminMessageDao.loadAll() },
|
||||
fetch = { adminMessageService.getAdminMessages() },
|
||||
shouldFetch = { true },
|
||||
saveFetchResult = { oldItems, newItems ->
|
||||
adminMessageDao.removeOldAndSaveNew(oldItems, newItems)
|
||||
},
|
||||
showSavedOnLoading = false,
|
||||
mapResult = { adminMessages ->
|
||||
adminMessages.filter { adminMessage ->
|
||||
val isCorrectRegister = adminMessage.targetRegisterHost?.let {
|
||||
student.scrapperBaseUrl.contains(it, true)
|
||||
} ?: true
|
||||
val isCorrectFlavor =
|
||||
adminMessage.targetFlavor?.equals(appInfo.buildFlavor, true) ?: true
|
||||
val isCorrectMaxVersion =
|
||||
adminMessage.versionMax?.let { it >= appInfo.versionCode } ?: true
|
||||
val isCorrectMinVersion =
|
||||
adminMessage.versionMin?.let { it <= appInfo.versionCode } ?: true
|
||||
|
||||
isCorrectRegister && isCorrectFlavor && isCorrectMaxVersion && isCorrectMinVersion
|
||||
}.maxByOrNull { it.id }
|
||||
}
|
||||
)
|
||||
fun getAdminMessages(): Flow<Resource<List<AdminMessage>>> =
|
||||
networkBoundResource(
|
||||
mutex = saveFetchResultMutex,
|
||||
isResultEmpty = { false },
|
||||
query = { adminMessageDao.loadAll() },
|
||||
fetch = { adminMessageService.getAdminMessages() },
|
||||
shouldFetch = { true },
|
||||
saveFetchResult = { oldItems, newItems ->
|
||||
adminMessageDao.removeOldAndSaveNew(oldItems, newItems)
|
||||
},
|
||||
showSavedOnLoading = false,
|
||||
)
|
||||
}
|
||||
|
@ -3,18 +3,26 @@ package io.github.wulkanowy.data.repositories
|
||||
import android.content.Context
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.*
|
||||
import io.github.wulkanowy.data.Resource
|
||||
import io.github.wulkanowy.data.db.SharedPrefProvider
|
||||
import io.github.wulkanowy.data.db.dao.MailboxDao
|
||||
import io.github.wulkanowy.data.db.dao.MessageAttachmentDao
|
||||
import io.github.wulkanowy.data.db.dao.MessagesDao
|
||||
import io.github.wulkanowy.data.db.entities.*
|
||||
import io.github.wulkanowy.data.db.entities.Mailbox
|
||||
import io.github.wulkanowy.data.db.entities.Message
|
||||
import io.github.wulkanowy.data.db.entities.MessageWithAttachment
|
||||
import io.github.wulkanowy.data.db.entities.Recipient
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.enums.MessageFolder
|
||||
import io.github.wulkanowy.data.enums.MessageFolder.RECEIVED
|
||||
import io.github.wulkanowy.data.enums.MessageFolder.TRASHED
|
||||
import io.github.wulkanowy.data.mappers.mapFromEntities
|
||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
||||
import io.github.wulkanowy.data.networkBoundResource
|
||||
import io.github.wulkanowy.data.onResourceError
|
||||
import io.github.wulkanowy.data.onResourceSuccess
|
||||
import io.github.wulkanowy.data.pojos.MessageDraft
|
||||
import io.github.wulkanowy.data.waitForResult
|
||||
import io.github.wulkanowy.domain.messages.GetMailboxByStudentUseCase
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.sdk.pojo.Folder
|
||||
@ -25,7 +33,6 @@ import io.github.wulkanowy.utils.uniqueSubtract
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import timber.log.Timber
|
||||
@ -97,7 +104,7 @@ class MessageRepository @Inject constructor(
|
||||
shouldFetch = {
|
||||
checkNotNull(it) { "This message no longer exist!" }
|
||||
Timber.d("Message content in db empty: ${it.message.content.isBlank()}")
|
||||
it.message.unread || it.message.content.isBlank()
|
||||
(it.message.unread && markAsRead) || it.message.content.isBlank()
|
||||
},
|
||||
query = {
|
||||
messagesDb.loadMessageWithAttachment(message.messageGlobalKey)
|
||||
@ -113,7 +120,10 @@ class MessageRepository @Inject constructor(
|
||||
messagesDb.updateAll(
|
||||
listOf(old.message.apply {
|
||||
id = message.id
|
||||
unread = !markAsRead
|
||||
unread = when {
|
||||
markAsRead -> false
|
||||
else -> unread
|
||||
}
|
||||
sender = new.sender
|
||||
recipients = new.recipients.singleOrNull() ?: "Wielu adresatów"
|
||||
content = content.ifBlank { new.content }
|
||||
@ -123,7 +133,7 @@ class MessageRepository @Inject constructor(
|
||||
items = new.attachments.mapToEntities(message.messageGlobalKey),
|
||||
)
|
||||
|
||||
Timber.d("Message ${message.messageId} with blank content: ${old.message.content.isBlank()}, marked as read")
|
||||
Timber.d("Message ${message.messageId} with blank content: ${old.message.content.isBlank()}, marked as read: $markAsRead")
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -15,7 +15,6 @@ import io.github.wulkanowy.ui.modules.grade.GradeAverageMode
|
||||
import io.github.wulkanowy.ui.modules.settings.appearance.menuorder.AppMenuItem
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import java.time.Instant
|
||||
@ -201,6 +200,14 @@ class PreferencesRepository @Inject constructor(
|
||||
R.bool.pref_default_timetable_show_timers
|
||||
)
|
||||
|
||||
val showTimetableGaps: TimetableGapsMode
|
||||
get() = TimetableGapsMode.getByValue(
|
||||
getString(
|
||||
R.string.pref_key_timetable_show_gaps,
|
||||
R.string.pref_default_timetable_show_gaps
|
||||
)
|
||||
)
|
||||
|
||||
val showSubjectsWithoutGrades: Boolean
|
||||
get() = getBoolean(
|
||||
R.string.pref_key_subjects_without_grades,
|
||||
@ -343,6 +350,12 @@ class PreferencesRepository @Inject constructor(
|
||||
)
|
||||
}
|
||||
|
||||
var isIncognitoMode: Boolean
|
||||
get() = getBoolean(R.string.pref_key_incognito_moge, R.bool.pref_default_incognito_mode)
|
||||
set(value) = sharedPref.edit {
|
||||
putBoolean(context.getString(R.string.pref_key_incognito_moge), value)
|
||||
}
|
||||
|
||||
var installationId: String
|
||||
get() = sharedPref.getString(PREF_KEY_INSTALLATION_ID, null).orEmpty()
|
||||
private set(value) = sharedPref.edit { putString(PREF_KEY_INSTALLATION_ID, value) }
|
||||
|
@ -41,7 +41,7 @@ class SemesterRepository @Inject constructor(
|
||||
|
||||
val isRefreshOnModeChangeRequired = when {
|
||||
Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.HEBE -> {
|
||||
semesters.firstOrNull { it.isCurrent }?.let {
|
||||
semesters.firstOrNull { it.isCurrent() }?.let {
|
||||
0 == it.diaryId && 0 == it.kindergartenDiaryId
|
||||
} == true
|
||||
}
|
||||
@ -49,7 +49,7 @@ class SemesterRepository @Inject constructor(
|
||||
}
|
||||
|
||||
val isRefreshOnNoCurrentAppropriate =
|
||||
refreshOnNoCurrent && !semesters.any { semester -> semester.isCurrent }
|
||||
refreshOnNoCurrent && !semesters.any { semester -> semester.isCurrent() }
|
||||
|
||||
return forceRefresh || isNoSemesters || isRefreshOnModeChangeRequired || isRefreshOnNoCurrentAppropriate
|
||||
}
|
||||
|
@ -0,0 +1,64 @@
|
||||
package io.github.wulkanowy.domain.adminmessage
|
||||
|
||||
import io.github.wulkanowy.data.Resource
|
||||
import io.github.wulkanowy.data.db.entities.AdminMessage
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.enums.MessageType
|
||||
import io.github.wulkanowy.data.mapResourceData
|
||||
import io.github.wulkanowy.data.repositories.AdminMessageRepository
|
||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||
import io.github.wulkanowy.utils.AppInfo
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import javax.inject.Inject
|
||||
|
||||
class GetAppropriateAdminMessageUseCase @Inject constructor(
|
||||
private val adminMessageRepository: AdminMessageRepository,
|
||||
private val preferencesRepository: PreferencesRepository,
|
||||
private val appInfo: AppInfo
|
||||
) {
|
||||
|
||||
operator fun invoke(student: Student, type: MessageType): Flow<Resource<AdminMessage?>> {
|
||||
return invoke(student.scrapperBaseUrl, type)
|
||||
}
|
||||
|
||||
operator fun invoke(scrapperBaseUrl: String, type: MessageType): Flow<Resource<AdminMessage?>> {
|
||||
return adminMessageRepository.getAdminMessages().mapResourceData { adminMessages ->
|
||||
adminMessages
|
||||
.asSequence()
|
||||
.filter { it.isNotDismissed() }
|
||||
.filter { it.isVersionMatch() }
|
||||
.filter { it.isRegisterHostMatch(scrapperBaseUrl) }
|
||||
.filter { it.isFlavorMatch() }
|
||||
.filter { it.isTypeMatch(type) }
|
||||
.maxByOrNull { it.id }
|
||||
}
|
||||
}
|
||||
|
||||
private fun AdminMessage.isNotDismissed(): Boolean {
|
||||
return id !in preferencesRepository.dismissedAdminMessageIds
|
||||
}
|
||||
|
||||
private fun AdminMessage.isRegisterHostMatch(scrapperBaseUrl: String): Boolean {
|
||||
return targetRegisterHost?.let {
|
||||
scrapperBaseUrl.contains(it, true)
|
||||
} ?: true
|
||||
}
|
||||
|
||||
private fun AdminMessage.isFlavorMatch(): Boolean {
|
||||
return targetFlavor?.equals(appInfo.buildFlavor, true) ?: true
|
||||
}
|
||||
|
||||
private fun AdminMessage.isVersionMatch(): Boolean {
|
||||
val isCorrectMaxVersion = versionMax?.let { it >= appInfo.versionCode } ?: true
|
||||
val isCorrectMinVersion = versionMin?.let { it <= appInfo.versionCode } ?: true
|
||||
|
||||
return isCorrectMaxVersion && isCorrectMinVersion
|
||||
}
|
||||
|
||||
private fun AdminMessage.isTypeMatch(messageType: MessageType): Boolean {
|
||||
if (messageType in types) return true
|
||||
if (MessageType.GENERAL_MESSAGE in types) return true
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ import android.content.Intent
|
||||
import android.widget.RemoteViewsService
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import io.github.wulkanowy.data.db.SharedPrefProvider
|
||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||
import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.data.repositories.TimetableRepository
|
||||
@ -26,10 +27,19 @@ class TimetableWidgetService : RemoteViewsService() {
|
||||
@Inject
|
||||
lateinit var sharedPref: SharedPrefProvider
|
||||
|
||||
@Inject
|
||||
lateinit var prefRepository: PreferencesRepository
|
||||
|
||||
override fun onGetViewFactory(intent: Intent?): RemoteViewsFactory {
|
||||
Timber.d("TimetableWidgetFactory created")
|
||||
return TimetableWidgetFactory(
|
||||
timetableRepo, studentRepo, semesterRepo, sharedPref, applicationContext, intent
|
||||
timetableRepository = timetableRepo,
|
||||
studentRepository = studentRepo,
|
||||
semesterRepository = semesterRepo,
|
||||
sharedPref = sharedPref,
|
||||
prefRepository = prefRepository,
|
||||
context = applicationContext,
|
||||
intent = intent,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package io.github.wulkanowy.ui.modules.dashboard
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import io.github.wulkanowy.ui.modules.dashboard.adapters.DashboardAdapter
|
||||
import io.github.wulkanowy.ui.modules.dashboard.viewholders.AdminMessageViewHolder
|
||||
import java.util.*
|
||||
|
||||
class DashboardItemMoveCallback(
|
||||
@ -55,5 +56,5 @@ class DashboardItemMoveCallback(
|
||||
}
|
||||
|
||||
private val RecyclerView.ViewHolder.isAdminMessageOrAccountItem: Boolean
|
||||
get() = this is DashboardAdapter.AdminMessageViewHolder || this is DashboardAdapter.AccountViewHolder
|
||||
get() = this is AdminMessageViewHolder || this is DashboardAdapter.AccountViewHolder
|
||||
}
|
||||
|
@ -5,7 +5,9 @@ import io.github.wulkanowy.data.db.entities.AdminMessage
|
||||
import io.github.wulkanowy.data.db.entities.LuckyNumber
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.enums.MessageFolder
|
||||
import io.github.wulkanowy.data.enums.MessageType
|
||||
import io.github.wulkanowy.data.repositories.*
|
||||
import io.github.wulkanowy.domain.adminmessage.GetAppropriateAdminMessageUseCase
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.AdsHelper
|
||||
@ -32,7 +34,7 @@ class DashboardPresenter @Inject constructor(
|
||||
private val conferenceRepository: ConferenceRepository,
|
||||
private val preferencesRepository: PreferencesRepository,
|
||||
private val schoolAnnouncementRepository: SchoolAnnouncementRepository,
|
||||
private val adminMessageRepository: AdminMessageRepository,
|
||||
private val getAppropriateAdminMessageUseCase: GetAppropriateAdminMessageUseCase,
|
||||
private val adsHelper: AdsHelper
|
||||
) : BasePresenter<DashboardView>(errorHandler, studentRepository) {
|
||||
|
||||
@ -159,19 +161,23 @@ class DashboardPresenter @Inject constructor(
|
||||
DashboardItem.Type.ACCOUNT -> {
|
||||
updateData(DashboardItem.Account(student), forceRefresh)
|
||||
}
|
||||
|
||||
DashboardItem.Type.HORIZONTAL_GROUP -> {
|
||||
loadHorizontalGroup(student, forceRefresh)
|
||||
}
|
||||
|
||||
DashboardItem.Type.LESSONS -> loadLessons(student, forceRefresh)
|
||||
DashboardItem.Type.GRADES -> loadGrades(student, forceRefresh)
|
||||
DashboardItem.Type.HOMEWORK -> loadHomework(student, forceRefresh)
|
||||
DashboardItem.Type.ANNOUNCEMENTS -> {
|
||||
loadSchoolAnnouncements(student, forceRefresh)
|
||||
}
|
||||
|
||||
DashboardItem.Type.EXAMS -> loadExams(student, forceRefresh)
|
||||
DashboardItem.Type.CONFERENCES -> {
|
||||
loadConferences(student, forceRefresh)
|
||||
}
|
||||
|
||||
DashboardItem.Type.ADS -> loadAds(forceRefresh)
|
||||
DashboardItem.Type.ADMIN_MESSAGE -> loadAdminMessage(student, forceRefresh)
|
||||
}
|
||||
@ -355,6 +361,7 @@ class DashboardPresenter @Inject constructor(
|
||||
firstLoadedItemList += DashboardItem.Type.GRADES
|
||||
}
|
||||
}
|
||||
|
||||
is Resource.Success -> {
|
||||
Timber.i("Loading dashboard grades result: Success")
|
||||
updateData(
|
||||
@ -365,6 +372,7 @@ class DashboardPresenter @Inject constructor(
|
||||
forceRefresh
|
||||
)
|
||||
}
|
||||
|
||||
is Resource.Error -> {
|
||||
Timber.i("Loading dashboard grades result: An exception occurred")
|
||||
errorHandler.dispatch(it.error)
|
||||
@ -402,12 +410,14 @@ class DashboardPresenter @Inject constructor(
|
||||
firstLoadedItemList += DashboardItem.Type.LESSONS
|
||||
}
|
||||
}
|
||||
|
||||
is Resource.Success -> {
|
||||
Timber.i("Loading dashboard lessons result: Success")
|
||||
updateData(
|
||||
DashboardItem.Lessons(it.data), forceRefresh
|
||||
)
|
||||
}
|
||||
|
||||
is Resource.Error -> {
|
||||
Timber.i("Loading dashboard lessons result: An exception occurred")
|
||||
errorHandler.dispatch(it.error)
|
||||
@ -457,10 +467,12 @@ class DashboardPresenter @Inject constructor(
|
||||
firstLoadedItemList += DashboardItem.Type.HOMEWORK
|
||||
}
|
||||
}
|
||||
|
||||
is Resource.Success -> {
|
||||
Timber.i("Loading dashboard homework result: Success")
|
||||
updateData(DashboardItem.Homework(it.data), forceRefresh)
|
||||
}
|
||||
|
||||
is Resource.Error -> {
|
||||
Timber.i("Loading dashboard homework result: An exception occurred")
|
||||
errorHandler.dispatch(it.error)
|
||||
@ -489,10 +501,12 @@ class DashboardPresenter @Inject constructor(
|
||||
firstLoadedItemList += DashboardItem.Type.ANNOUNCEMENTS
|
||||
}
|
||||
}
|
||||
|
||||
is Resource.Success -> {
|
||||
Timber.i("Loading dashboard announcements result: Success")
|
||||
updateData(DashboardItem.Announcements(it.data), forceRefresh)
|
||||
}
|
||||
|
||||
is Resource.Error -> {
|
||||
Timber.i("Loading dashboard announcements result: An exception occurred")
|
||||
errorHandler.dispatch(it.error)
|
||||
@ -530,10 +544,12 @@ class DashboardPresenter @Inject constructor(
|
||||
firstLoadedItemList += DashboardItem.Type.EXAMS
|
||||
}
|
||||
}
|
||||
|
||||
is Resource.Success -> {
|
||||
Timber.i("Loading dashboard exams result: Success")
|
||||
updateData(DashboardItem.Exams(it.data), forceRefresh)
|
||||
}
|
||||
|
||||
is Resource.Error -> {
|
||||
Timber.i("Loading dashboard exams result: An exception occurred")
|
||||
errorHandler.dispatch(it.error)
|
||||
@ -569,10 +585,12 @@ class DashboardPresenter @Inject constructor(
|
||||
firstLoadedItemList += DashboardItem.Type.CONFERENCES
|
||||
}
|
||||
}
|
||||
|
||||
is Resource.Success -> {
|
||||
Timber.i("Loading dashboard conferences result: Success")
|
||||
updateData(DashboardItem.Conferences(it.data), forceRefresh)
|
||||
}
|
||||
|
||||
is Resource.Error -> {
|
||||
Timber.i("Loading dashboard conferences result: An exception occurred")
|
||||
errorHandler.dispatch(it.error)
|
||||
@ -584,12 +602,12 @@ class DashboardPresenter @Inject constructor(
|
||||
}
|
||||
|
||||
private fun loadAdminMessage(student: Student, forceRefresh: Boolean) {
|
||||
flatResourceFlow { adminMessageRepository.getAdminMessages(student) }
|
||||
.filter {
|
||||
val data = it.dataOrNull ?: return@filter true
|
||||
val isDismissed = data.id in preferencesRepository.dismissedAdminMessageIds
|
||||
!isDismissed
|
||||
}
|
||||
flatResourceFlow {
|
||||
getAppropriateAdminMessageUseCase(
|
||||
student = student,
|
||||
type = MessageType.DASHBOARD_MESSAGE,
|
||||
)
|
||||
}
|
||||
.onEach {
|
||||
when (it) {
|
||||
is Resource.Loading -> {
|
||||
@ -597,6 +615,7 @@ class DashboardPresenter @Inject constructor(
|
||||
if (forceRefresh) return@onEach
|
||||
updateData(DashboardItem.AdminMessages(), forceRefresh)
|
||||
}
|
||||
|
||||
is Resource.Success -> {
|
||||
Timber.i("Loading dashboard admin message result: Success")
|
||||
updateData(
|
||||
@ -604,6 +623,7 @@ class DashboardPresenter @Inject constructor(
|
||||
forceRefresh = forceRefresh
|
||||
)
|
||||
}
|
||||
|
||||
is Resource.Error -> {
|
||||
Timber.i("Loading dashboard admin message result: An exception occurred")
|
||||
Timber.e(it.error)
|
||||
|
@ -1,8 +1,6 @@
|
||||
package io.github.wulkanowy.ui.modules.dashboard.adapters
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.Color
|
||||
import android.graphics.Typeface
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
@ -24,6 +22,7 @@ import io.github.wulkanowy.data.db.entities.TimetableHeader
|
||||
import io.github.wulkanowy.data.enums.GradeColorTheme
|
||||
import io.github.wulkanowy.databinding.*
|
||||
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
|
||||
import io.github.wulkanowy.ui.modules.dashboard.viewholders.AdminMessageViewHolder
|
||||
import io.github.wulkanowy.utils.*
|
||||
import timber.log.Timber
|
||||
import java.time.Duration
|
||||
@ -109,7 +108,9 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
||||
ItemDashboardConferencesBinding.inflate(inflater, parent, false)
|
||||
)
|
||||
DashboardItem.Type.ADMIN_MESSAGE.ordinal -> AdminMessageViewHolder(
|
||||
ItemDashboardAdminMessageBinding.inflate(inflater, parent, false)
|
||||
ItemDashboardAdminMessageBinding.inflate(inflater, parent, false),
|
||||
onAdminMessageDismissClickListener = onAdminMessageDismissClickListener,
|
||||
onAdminMessageClickListener = onAdminMessageClickListener,
|
||||
)
|
||||
DashboardItem.Type.ADS.ordinal -> AdsViewHolder(
|
||||
ItemDashboardAdsBinding.inflate(inflater, parent, false)
|
||||
@ -128,7 +129,7 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
||||
is AnnouncementsViewHolder -> bindAnnouncementsViewHolder(holder, position)
|
||||
is ExamsViewHolder -> bindExamsViewHolder(holder, position)
|
||||
is ConferencesViewHolder -> bindConferencesViewHolder(holder, position)
|
||||
is AdminMessageViewHolder -> bindAdminMessage(holder, position)
|
||||
is AdminMessageViewHolder -> holder.bind((items[position] as DashboardItem.AdminMessages).adminMessage)
|
||||
is AdsViewHolder -> bindAdsViewHolder(holder, position)
|
||||
}
|
||||
}
|
||||
@ -733,39 +734,6 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindAdminMessage(adminMessageViewHolder: AdminMessageViewHolder, position: Int) {
|
||||
val item = (items[position] as DashboardItem.AdminMessages).adminMessage ?: return
|
||||
val context = adminMessageViewHolder.binding.root.context
|
||||
val (backgroundColor, textColor) = when (item.priority) {
|
||||
"HIGH" -> {
|
||||
context.getThemeAttrColor(R.attr.colorMessageHigh) to
|
||||
context.getThemeAttrColor(R.attr.colorOnMessageHigh)
|
||||
}
|
||||
"MEDIUM" -> {
|
||||
context.getThemeAttrColor(R.attr.colorMessageMedium) to Color.BLACK
|
||||
}
|
||||
else -> null to context.getThemeAttrColor(R.attr.colorOnSurface)
|
||||
}
|
||||
|
||||
with(adminMessageViewHolder.binding) {
|
||||
dashboardAdminMessageItemTitle.text = item.title
|
||||
dashboardAdminMessageItemTitle.setTextColor(textColor)
|
||||
dashboardAdminMessageItemDescription.text = item.content
|
||||
dashboardAdminMessageItemDescription.setTextColor(textColor)
|
||||
dashboardAdminMessageItemIcon.setColorFilter(textColor)
|
||||
dashboardAdminMessageItemDismiss.isVisible = item.isDismissible
|
||||
dashboardAdminMessageItemDismiss.setTextColor(textColor)
|
||||
dashboardAdminMessageItemDismiss.setOnClickListener {
|
||||
onAdminMessageDismissClickListener(item)
|
||||
}
|
||||
|
||||
root.setCardBackgroundColor(backgroundColor?.let { ColorStateList.valueOf(it) })
|
||||
item.destinationUrl?.let { url ->
|
||||
root.setOnClickListener { onAdminMessageClickListener(url) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindAdsViewHolder(adsViewHolder: AdsViewHolder, position: Int) {
|
||||
val item = (items[position] as DashboardItem.Ads).adBanner ?: return
|
||||
val binding = adsViewHolder.binding
|
||||
@ -819,9 +787,6 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
||||
val adapter by lazy { DashboardConferencesAdapter() }
|
||||
}
|
||||
|
||||
class AdminMessageViewHolder(val binding: ItemDashboardAdminMessageBinding) :
|
||||
RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
class AdsViewHolder(val binding: ItemDashboardAdsBinding) :
|
||||
RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
|
@ -0,0 +1,52 @@
|
||||
package io.github.wulkanowy.ui.modules.dashboard.viewholders
|
||||
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.Color
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.AdminMessage
|
||||
import io.github.wulkanowy.databinding.ItemDashboardAdminMessageBinding
|
||||
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
|
||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||
|
||||
class AdminMessageViewHolder(
|
||||
private val binding: ItemDashboardAdminMessageBinding,
|
||||
private val onAdminMessageDismissClickListener: (AdminMessage) -> Unit,
|
||||
private val onAdminMessageClickListener: (String?) -> Unit,
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
fun bind(item: AdminMessage?) {
|
||||
item ?: return
|
||||
|
||||
val context = binding.root.context
|
||||
val (backgroundColor, textColor) = when (item.priority) {
|
||||
"HIGH" -> {
|
||||
context.getThemeAttrColor(R.attr.colorMessageHigh) to
|
||||
context.getThemeAttrColor(R.attr.colorOnMessageHigh)
|
||||
}
|
||||
"MEDIUM" -> {
|
||||
context.getThemeAttrColor(R.attr.colorMessageMedium) to Color.BLACK
|
||||
}
|
||||
else -> null to context.getThemeAttrColor(R.attr.colorOnSurface)
|
||||
}
|
||||
|
||||
with(binding) {
|
||||
dashboardAdminMessageItemTitle.text = item.title
|
||||
dashboardAdminMessageItemTitle.setTextColor(textColor)
|
||||
dashboardAdminMessageItemDescription.text = item.content
|
||||
dashboardAdminMessageItemDescription.setTextColor(textColor)
|
||||
dashboardAdminMessageItemIcon.setColorFilter(textColor)
|
||||
dashboardAdminMessageItemDismiss.isVisible = item.isDismissible
|
||||
dashboardAdminMessageItemDismiss.setTextColor(textColor)
|
||||
dashboardAdminMessageItemDismiss.setOnClickListener {
|
||||
onAdminMessageDismissClickListener(item)
|
||||
}
|
||||
|
||||
root.setCardBackgroundColor(backgroundColor?.let { ColorStateList.valueOf(it) })
|
||||
item.destinationUrl?.let { url ->
|
||||
root.setOnClickListener { onAdminMessageClickListener(url) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -9,10 +9,12 @@ import androidx.core.view.isVisible
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.AdminMessage
|
||||
import io.github.wulkanowy.data.pojos.RegisterUser
|
||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||
import io.github.wulkanowy.databinding.FragmentLoginFormBinding
|
||||
import io.github.wulkanowy.ui.base.BaseFragment
|
||||
import io.github.wulkanowy.ui.modules.dashboard.viewholders.AdminMessageViewHolder
|
||||
import io.github.wulkanowy.ui.modules.login.LoginActivity
|
||||
import io.github.wulkanowy.ui.modules.login.LoginData
|
||||
import io.github.wulkanowy.utils.*
|
||||
@ -207,6 +209,19 @@ class LoginFormFragment : BaseFragment<FragmentLoginFormBinding>(R.layout.fragme
|
||||
binding.loginFormContainer.visibility = if (show) VISIBLE else GONE
|
||||
}
|
||||
|
||||
override fun showAdminMessage(message: AdminMessage?) {
|
||||
AdminMessageViewHolder(
|
||||
binding = binding.loginFormMessage,
|
||||
onAdminMessageDismissClickListener = presenter::onAdminMessageDismissed,
|
||||
onAdminMessageClickListener = presenter::onAdminMessageSelected,
|
||||
).bind(message)
|
||||
binding.loginFormMessage.root.isVisible = message != null
|
||||
}
|
||||
|
||||
override fun openInternetBrowser(url: String) {
|
||||
requireContext().openInternetBrowser(url)
|
||||
}
|
||||
|
||||
override fun showDomainSuffixInput(show: Boolean) {
|
||||
binding.loginFormDomainSuffixLayout.isVisible = show
|
||||
}
|
||||
|
@ -1,13 +1,19 @@
|
||||
package io.github.wulkanowy.ui.modules.login.form
|
||||
|
||||
import androidx.core.net.toUri
|
||||
import io.github.wulkanowy.data.db.entities.AdminMessage
|
||||
import io.github.wulkanowy.data.enums.MessageType
|
||||
import io.github.wulkanowy.data.flatResourceFlow
|
||||
import io.github.wulkanowy.data.logResourceStatus
|
||||
import io.github.wulkanowy.data.onResourceData
|
||||
import io.github.wulkanowy.data.onResourceError
|
||||
import io.github.wulkanowy.data.onResourceLoading
|
||||
import io.github.wulkanowy.data.onResourceNotLoading
|
||||
import io.github.wulkanowy.data.onResourceSuccess
|
||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.data.resourceFlow
|
||||
import io.github.wulkanowy.domain.adminmessage.GetAppropriateAdminMessageUseCase
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.modules.login.LoginData
|
||||
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
|
||||
@ -22,7 +28,9 @@ class LoginFormPresenter @Inject constructor(
|
||||
studentRepository: StudentRepository,
|
||||
private val loginErrorHandler: LoginErrorHandler,
|
||||
private val appInfo: AppInfo,
|
||||
private val analytics: AnalyticsHelper
|
||||
private val analytics: AnalyticsHelper,
|
||||
private val getAppropriateAdminMessageUseCase: GetAppropriateAdminMessageUseCase,
|
||||
private val preferencesRepository: PreferencesRepository,
|
||||
) : BasePresenter<LoginFormView>(loginErrorHandler, studentRepository) {
|
||||
|
||||
private var lastError: Throwable? = null
|
||||
@ -41,6 +49,31 @@ class LoginFormPresenter @Inject constructor(
|
||||
Timber.i("Entered wrong username or password")
|
||||
}
|
||||
}
|
||||
|
||||
reloadAdminMessage()
|
||||
}
|
||||
|
||||
private fun reloadAdminMessage() {
|
||||
flatResourceFlow {
|
||||
getAppropriateAdminMessageUseCase(
|
||||
scrapperBaseUrl = view?.formHostValue.orEmpty(),
|
||||
type = MessageType.LOGIN_MESSAGE,
|
||||
)
|
||||
}
|
||||
.logResourceStatus("load login admin message")
|
||||
.onResourceData { view?.showAdminMessage(it) }
|
||||
.onResourceError { view?.showAdminMessage(null) }
|
||||
.launch()
|
||||
}
|
||||
|
||||
fun onAdminMessageSelected(url: String?) {
|
||||
url?.let { view?.openInternetBrowser(it) }
|
||||
}
|
||||
|
||||
fun onAdminMessageDismissed(adminMessage: AdminMessage) {
|
||||
preferencesRepository.dismissedAdminMessageIds += adminMessage.id
|
||||
|
||||
view?.showAdminMessage(null)
|
||||
}
|
||||
|
||||
fun onPrivacyLinkClick() {
|
||||
@ -63,6 +96,7 @@ class LoginFormPresenter @Inject constructor(
|
||||
}
|
||||
updateCustomDomainSuffixVisibility()
|
||||
updateUsernameLabel()
|
||||
reloadAdminMessage()
|
||||
}
|
||||
}
|
||||
|
||||
@ -103,7 +137,9 @@ class LoginFormPresenter @Inject constructor(
|
||||
val email = view?.formUsernameValue.orEmpty().trim()
|
||||
val password = view?.formPassValue.orEmpty().trim()
|
||||
val host = view?.formHostValue.orEmpty().trim()
|
||||
val domainSuffix = view?.formDomainSuffix.orEmpty().trim()
|
||||
val domainSuffix = view?.formDomainSuffix.orEmpty().trim().takeIf {
|
||||
"customSuffix" in host
|
||||
}.orEmpty()
|
||||
val symbol = view?.formHostSymbol.orEmpty().trim()
|
||||
|
||||
if (!validateCredentials(email, password, host)) return
|
||||
|
@ -1,5 +1,6 @@
|
||||
package io.github.wulkanowy.ui.modules.login.form
|
||||
|
||||
import io.github.wulkanowy.data.db.entities.AdminMessage
|
||||
import io.github.wulkanowy.data.pojos.RegisterUser
|
||||
import io.github.wulkanowy.ui.base.BaseView
|
||||
import io.github.wulkanowy.ui.modules.login.LoginData
|
||||
@ -58,6 +59,10 @@ interface LoginFormView : BaseView {
|
||||
|
||||
fun showContent(show: Boolean)
|
||||
|
||||
fun showAdminMessage(message: AdminMessage?)
|
||||
|
||||
fun openInternetBrowser(url: String)
|
||||
|
||||
fun showDomainSuffixInput(show: Boolean)
|
||||
|
||||
fun showOtherOptionsButton(show: Boolean)
|
||||
|
@ -11,7 +11,9 @@ import androidx.core.view.updateMargins
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.enums.MessageFolder.*
|
||||
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.databinding.FragmentMessageBinding
|
||||
import io.github.wulkanowy.ui.base.BaseFragment
|
||||
import io.github.wulkanowy.ui.base.BaseFragmentPagerAdapter
|
||||
@ -49,6 +51,7 @@ class MessageFragment : BaseFragment<FragmentMessageBinding>(R.layout.fragment_m
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
binding = FragmentMessageBinding.bind(view)
|
||||
messageContainer = binding.messageViewPager
|
||||
presenter.onAttachView(this)
|
||||
}
|
||||
|
||||
@ -95,6 +98,10 @@ class MessageFragment : BaseFragment<FragmentMessageBinding>(R.layout.fragment_m
|
||||
binding.messageProgress.visibility = if (show) VISIBLE else INVISIBLE
|
||||
}
|
||||
|
||||
override fun showMessage(messageId: Int) {
|
||||
showMessage(getString(messageId))
|
||||
}
|
||||
|
||||
override fun showNewMessage(show: Boolean) {
|
||||
binding.openSendMessageButton.run {
|
||||
if (show) show() else hide()
|
||||
|
@ -1,5 +1,7 @@
|
||||
package io.github.wulkanowy.ui.modules.message
|
||||
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
@ -9,7 +11,8 @@ import javax.inject.Inject
|
||||
|
||||
class MessagePresenter @Inject constructor(
|
||||
errorHandler: ErrorHandler,
|
||||
studentRepository: StudentRepository
|
||||
studentRepository: StudentRepository,
|
||||
private val preferencesRepository: PreferencesRepository,
|
||||
) : BasePresenter<MessageView>(errorHandler, studentRepository) {
|
||||
|
||||
override fun onAttachView(view: MessageView) {
|
||||
@ -19,6 +22,14 @@ class MessagePresenter @Inject constructor(
|
||||
Timber.i("Message view was initialized")
|
||||
loadData()
|
||||
}
|
||||
|
||||
showIncognitoModeReminderMessage()
|
||||
}
|
||||
|
||||
private fun showIncognitoModeReminderMessage() {
|
||||
if (preferencesRepository.isIncognitoMode) {
|
||||
view?.showMessage(R.string.message_incognito_mode_on)
|
||||
}
|
||||
}
|
||||
|
||||
fun onPageSelected(index: Int) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
package io.github.wulkanowy.ui.modules.message
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import io.github.wulkanowy.ui.base.BaseView
|
||||
|
||||
interface MessageView : BaseView {
|
||||
@ -12,6 +13,8 @@ interface MessageView : BaseView {
|
||||
|
||||
fun showProgress(show: Boolean)
|
||||
|
||||
fun showMessage(@StringRes messageId: Int)
|
||||
|
||||
fun showNewMessage(show: Boolean)
|
||||
|
||||
fun showTabLayout(show: Boolean)
|
||||
|
@ -12,6 +12,7 @@ import android.view.View.VISIBLE
|
||||
import android.webkit.WebResourceRequest
|
||||
import android.webkit.WebView
|
||||
import android.webkit.WebViewClient
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
@ -164,6 +165,10 @@ class MessagePreviewFragment :
|
||||
binding.messagePreviewErrorRetry.setOnClickListener { callback() }
|
||||
}
|
||||
|
||||
override fun showMessage(@StringRes messageId: Int) {
|
||||
showMessage(getString(messageId))
|
||||
}
|
||||
|
||||
override fun openMessageReply(message: Message?) {
|
||||
context?.let { it.startActivity(SendMessageActivity.getStartIntent(it, message, true)) }
|
||||
}
|
||||
|
@ -2,11 +2,13 @@ package io.github.wulkanowy.ui.modules.message.preview
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import androidx.core.text.parseAsHtml
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.*
|
||||
import io.github.wulkanowy.data.db.entities.Message
|
||||
import io.github.wulkanowy.data.db.entities.MessageAttachment
|
||||
import io.github.wulkanowy.data.enums.MessageFolder
|
||||
import io.github.wulkanowy.data.repositories.MessageRepository
|
||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
@ -20,6 +22,7 @@ class MessagePreviewPresenter @Inject constructor(
|
||||
errorHandler: ErrorHandler,
|
||||
studentRepository: StudentRepository,
|
||||
private val messageRepository: MessageRepository,
|
||||
private val preferencesRepository: PreferencesRepository,
|
||||
private val analytics: AnalyticsHelper
|
||||
) : BasePresenter<MessagePreviewView>(errorHandler, studentRepository) {
|
||||
|
||||
@ -54,7 +57,11 @@ class MessagePreviewPresenter @Inject constructor(
|
||||
private fun loadData(messageToLoad: Message) {
|
||||
flatResourceFlow {
|
||||
val student = studentRepository.getCurrentStudent()
|
||||
messageRepository.getMessage(student, messageToLoad, true)
|
||||
messageRepository.getMessage(
|
||||
student = student,
|
||||
message = messageToLoad,
|
||||
markAsRead = !preferencesRepository.isIncognitoMode,
|
||||
)
|
||||
}
|
||||
.logResourceStatus("message ${messageToLoad.messageId} preview")
|
||||
.onResourceData {
|
||||
@ -65,6 +72,10 @@ class MessagePreviewPresenter @Inject constructor(
|
||||
setMessageWithAttachment(it)
|
||||
showContent(true)
|
||||
initOptions()
|
||||
|
||||
if (preferencesRepository.isIncognitoMode && it.message.unread) {
|
||||
showMessage(R.string.message_incognito_description)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
view?.run {
|
||||
|
@ -1,5 +1,6 @@
|
||||
package io.github.wulkanowy.ui.modules.message.preview
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import io.github.wulkanowy.data.db.entities.Message
|
||||
import io.github.wulkanowy.data.db.entities.MessageWithAttachment
|
||||
import io.github.wulkanowy.ui.base.BaseView
|
||||
@ -43,4 +44,6 @@ interface MessagePreviewView : BaseView {
|
||||
fun popView()
|
||||
|
||||
fun printDocument(html: String, jobName: String)
|
||||
|
||||
fun showMessage(@StringRes messageId: Int)
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.View.*
|
||||
import android.widget.CompoundButton
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.core.os.bundleOf
|
||||
@ -134,14 +135,20 @@ class MessageTabFragment : BaseFragment<FragmentMessageTabBinding>(R.layout.frag
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
@Suppress("DEPRECATION")
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater)
|
||||
inflater.inflate(R.menu.action_menu_message_tab, menu)
|
||||
|
||||
val searchView = menu.findItem(R.id.action_search).actionView as SearchView
|
||||
searchView.queryHint = getString(R.string.all_search_hint)
|
||||
searchView.maxWidth = Int.MAX_VALUE
|
||||
initializeSearchView(menu)
|
||||
}
|
||||
|
||||
private fun initializeSearchView(menu: Menu) {
|
||||
val searchView = (menu.findItem(R.id.action_search).actionView as SearchView).apply {
|
||||
queryHint = getString(R.string.all_search_hint)
|
||||
maxWidth = Int.MAX_VALUE
|
||||
}
|
||||
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
|
||||
override fun onQueryTextSubmit(query: String) = false
|
||||
override fun onQueryTextChange(query: String): Boolean {
|
||||
@ -207,8 +214,8 @@ class MessageTabFragment : BaseFragment<FragmentMessageTabBinding>(R.layout.frag
|
||||
binding.messageTabSwipe.isRefreshing = show
|
||||
}
|
||||
|
||||
override fun showMessagesDeleted() {
|
||||
showMessage(getString(R.string.message_messages_deleted))
|
||||
override fun showMessage(@StringRes messageId: Int) {
|
||||
showMessage(getString(messageId))
|
||||
}
|
||||
|
||||
override fun notifyParentShowNewMessage(show: Boolean) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
package io.github.wulkanowy.ui.modules.message.tab
|
||||
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.*
|
||||
import io.github.wulkanowy.data.db.entities.Mailbox
|
||||
import io.github.wulkanowy.data.db.entities.Message
|
||||
@ -26,7 +27,7 @@ class MessageTabPresenter @Inject constructor(
|
||||
errorHandler: ErrorHandler,
|
||||
studentRepository: StudentRepository,
|
||||
private val messageRepository: MessageRepository,
|
||||
private val analytics: AnalyticsHelper
|
||||
private val analytics: AnalyticsHelper,
|
||||
) : BasePresenter<MessageTabView>(errorHandler, studentRepository) {
|
||||
|
||||
lateinit var folder: MessageFolder
|
||||
@ -135,7 +136,7 @@ class MessageTabPresenter @Inject constructor(
|
||||
messageRepository.deleteMessages(student, selectedMailbox, messageList)
|
||||
}
|
||||
.onFailure(errorHandler::dispatch)
|
||||
.onSuccess { view?.showMessagesDeleted() }
|
||||
.onSuccess { view?.showMessage(R.string.message_messages_deleted) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package io.github.wulkanowy.ui.modules.message.tab
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import io.github.wulkanowy.data.db.entities.Mailbox
|
||||
import io.github.wulkanowy.data.db.entities.Message
|
||||
import io.github.wulkanowy.ui.base.BaseView
|
||||
@ -26,7 +27,7 @@ interface MessageTabView : BaseView {
|
||||
|
||||
fun showEmpty(show: Boolean)
|
||||
|
||||
fun showMessagesDeleted()
|
||||
fun showMessage(@StringRes messageId: Int)
|
||||
|
||||
fun showErrorView(show: Boolean)
|
||||
|
||||
|
@ -12,7 +12,9 @@ import androidx.recyclerview.widget.RecyclerView
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.Timetable
|
||||
import io.github.wulkanowy.databinding.ItemTimetableBinding
|
||||
import io.github.wulkanowy.databinding.ItemTimetableEmptyBinding
|
||||
import io.github.wulkanowy.databinding.ItemTimetableSmallBinding
|
||||
import io.github.wulkanowy.utils.getPlural
|
||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import javax.inject.Inject
|
||||
@ -29,9 +31,14 @@ class TimetableAdapter @Inject constructor() :
|
||||
TimetableItemType.SMALL -> SmallViewHolder(
|
||||
ItemTimetableSmallBinding.inflate(inflater, parent, false)
|
||||
)
|
||||
|
||||
TimetableItemType.NORMAL -> NormalViewHolder(
|
||||
ItemTimetableBinding.inflate(inflater, parent, false)
|
||||
)
|
||||
|
||||
TimetableItemType.EMPTY -> EmptyViewHolder(
|
||||
ItemTimetableEmptyBinding.inflate(inflater, parent, false)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,12 +47,12 @@ class TimetableAdapter @Inject constructor() :
|
||||
position: Int,
|
||||
payloads: MutableList<Any>
|
||||
) {
|
||||
if (payloads.isEmpty()) return super.onBindViewHolder(holder, position, payloads)
|
||||
|
||||
if (holder is NormalViewHolder) updateTimeLeft(
|
||||
binding = holder.binding,
|
||||
timeLeft = (getItem(position) as TimetableItem.Normal).timeLeft,
|
||||
)
|
||||
if (payloads.isNotEmpty() && holder is NormalViewHolder) {
|
||||
updateTimeLeft(
|
||||
binding = holder.binding,
|
||||
timeLeft = (getItem(position) as TimetableItem.Normal).timeLeft,
|
||||
)
|
||||
} else super.onBindViewHolder(holder, position, payloads)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
@ -54,10 +61,16 @@ class TimetableAdapter @Inject constructor() :
|
||||
binding = holder.binding,
|
||||
item = getItem(position) as TimetableItem.Small,
|
||||
)
|
||||
|
||||
is NormalViewHolder -> bindNormalView(
|
||||
binding = holder.binding,
|
||||
item = getItem(position) as TimetableItem.Normal,
|
||||
)
|
||||
|
||||
is EmptyViewHolder -> bindEmptyView(
|
||||
binding = holder.binding,
|
||||
item = getItem(position) as TimetableItem.Empty,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -100,6 +113,19 @@ class TimetableAdapter @Inject constructor() :
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindEmptyView(binding: ItemTimetableEmptyBinding, item: TimetableItem.Empty) {
|
||||
with(binding) {
|
||||
timetableEmptyItemNumber.text = when (item.numFrom) {
|
||||
item.numTo -> item.numFrom.toString()
|
||||
else -> "${item.numFrom}-${item.numTo}"
|
||||
}
|
||||
timetableEmptyItemSubject.text = timetableEmptyItemSubject.context.getPlural(
|
||||
R.plurals.timetable_no_lesson,
|
||||
item.numTo - item.numFrom + 1
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateTimeLeft(binding: ItemTimetableBinding, timeLeft: TimeLeft?) {
|
||||
with(binding) {
|
||||
when {
|
||||
@ -137,6 +163,7 @@ class TimetableAdapter @Inject constructor() :
|
||||
timetableItemTimeLeft.visibility = VISIBLE
|
||||
timetableItemTimeLeft.text = root.context.getString(R.string.timetable_finished)
|
||||
}
|
||||
|
||||
else -> {
|
||||
timetableItemTimeUntil.visibility = GONE
|
||||
timetableItemTimeLeft.visibility = GONE
|
||||
@ -191,7 +218,8 @@ class TimetableAdapter @Inject constructor() :
|
||||
)
|
||||
} else {
|
||||
timetableItemDescription.visibility = GONE
|
||||
timetableItemRoom.isVisible = lesson.room.isNotBlank() || lesson.roomOld.isNotBlank()
|
||||
timetableItemRoom.isVisible =
|
||||
lesson.room.isNotBlank() || lesson.roomOld.isNotBlank()
|
||||
timetableItemGroup.isVisible = item.showGroupsInPlan && lesson.group.isNotBlank()
|
||||
timetableItemTeacher.visibility = VISIBLE
|
||||
}
|
||||
@ -274,6 +302,9 @@ class TimetableAdapter @Inject constructor() :
|
||||
private class SmallViewHolder(val binding: ItemTimetableSmallBinding) :
|
||||
RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
private class EmptyViewHolder(val binding: ItemTimetableEmptyBinding) :
|
||||
RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
companion object {
|
||||
private val differ = object : DiffUtil.ItemCallback<TimetableItem>() {
|
||||
override fun areItemsTheSame(oldItem: TimetableItem, newItem: TimetableItem): Boolean =
|
||||
@ -281,9 +312,11 @@ class TimetableAdapter @Inject constructor() :
|
||||
oldItem is TimetableItem.Small && newItem is TimetableItem.Small -> {
|
||||
oldItem.lesson.start == newItem.lesson.start
|
||||
}
|
||||
|
||||
oldItem is TimetableItem.Normal && newItem is TimetableItem.Normal -> {
|
||||
oldItem.lesson.start == newItem.lesson.start
|
||||
}
|
||||
|
||||
else -> oldItem == newItem
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,11 @@ sealed class TimetableItem(val type: TimetableItemType) {
|
||||
val timeLeft: TimeLeft?,
|
||||
val onClick: (Timetable) -> Unit,
|
||||
) : TimetableItem(TimetableItemType.NORMAL)
|
||||
|
||||
data class Empty(
|
||||
val numFrom: Int,
|
||||
val numTo: Int
|
||||
) : TimetableItem(TimetableItemType.EMPTY)
|
||||
}
|
||||
|
||||
data class TimeLeft(
|
||||
@ -27,4 +32,5 @@ data class TimeLeft(
|
||||
enum class TimetableItemType {
|
||||
SMALL,
|
||||
NORMAL,
|
||||
EMPTY
|
||||
}
|
||||
|
@ -1,23 +1,44 @@
|
||||
package io.github.wulkanowy.ui.modules.timetable
|
||||
|
||||
import io.github.wulkanowy.data.*
|
||||
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.NO_GAPS
|
||||
import io.github.wulkanowy.data.enums.TimetableMode
|
||||
import io.github.wulkanowy.data.flatResourceFlow
|
||||
import io.github.wulkanowy.data.logResourceStatus
|
||||
import io.github.wulkanowy.data.onResourceData
|
||||
import io.github.wulkanowy.data.onResourceError
|
||||
import io.github.wulkanowy.data.onResourceIntermediate
|
||||
import io.github.wulkanowy.data.onResourceNotLoading
|
||||
import io.github.wulkanowy.data.onResourceSuccess
|
||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||
import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||
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.ErrorHandler
|
||||
import io.github.wulkanowy.utils.*
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.capitalise
|
||||
import io.github.wulkanowy.utils.getLastSchoolDayIfHoliday
|
||||
import io.github.wulkanowy.utils.isHolidays
|
||||
import io.github.wulkanowy.utils.isJustFinished
|
||||
import io.github.wulkanowy.utils.isShowTimeUntil
|
||||
import io.github.wulkanowy.utils.left
|
||||
import io.github.wulkanowy.utils.nextOrSameSchoolDay
|
||||
import io.github.wulkanowy.utils.nextSchoolDay
|
||||
import io.github.wulkanowy.utils.previousSchoolDay
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import io.github.wulkanowy.utils.until
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import timber.log.Timber
|
||||
import java.time.Instant
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalDate.*
|
||||
import java.util.*
|
||||
import java.time.LocalDate.now
|
||||
import java.time.LocalDate.of
|
||||
import java.time.LocalDate.ofEpochDay
|
||||
import java.util.Timer
|
||||
import javax.inject.Inject
|
||||
import kotlin.concurrent.timer
|
||||
|
||||
@ -192,16 +213,38 @@ class TimetablePresenter @Inject constructor(
|
||||
compareBy({ item -> item.number }, { item -> !item.isStudentPlan })
|
||||
)
|
||||
|
||||
return filteredItems.mapIndexed { i, it ->
|
||||
if (it.isStudentPlan) TimetableItem.Normal(
|
||||
lesson = it,
|
||||
showGroupsInPlan = prefRepository.showGroupsInPlan,
|
||||
timeLeft = filteredItems.getTimeLeftForLesson(it, i),
|
||||
onClick = ::onTimetableItemSelected
|
||||
) else TimetableItem.Small(
|
||||
lesson = it,
|
||||
onClick = ::onTimetableItemSelected
|
||||
)
|
||||
var prevNum = when (prefRepository.showTimetableGaps) {
|
||||
BETWEEN_AND_BEFORE_LESSONS -> 0
|
||||
else -> null
|
||||
}
|
||||
return buildList {
|
||||
filteredItems.forEachIndexed { i, it ->
|
||||
if (prefRepository.showTimetableGaps != NO_GAPS && prevNum != null && it.number > prevNum!! + 1) {
|
||||
val emptyLesson = TimetableItem.Empty(
|
||||
numFrom = prevNum!! + 1,
|
||||
numTo = it.number - 1
|
||||
)
|
||||
add(emptyLesson)
|
||||
}
|
||||
|
||||
if (it.isStudentPlan) {
|
||||
val normalLesson = TimetableItem.Normal(
|
||||
lesson = it,
|
||||
showGroupsInPlan = prefRepository.showGroupsInPlan,
|
||||
timeLeft = filteredItems.getTimeLeftForLesson(it, i),
|
||||
onClick = ::onTimetableItemSelected
|
||||
)
|
||||
add(normalLesson)
|
||||
} else {
|
||||
val smallLesson = TimetableItem.Small(
|
||||
lesson = it,
|
||||
onClick = ::onTimetableItemSelected
|
||||
)
|
||||
add(smallLesson)
|
||||
}
|
||||
|
||||
prevNum = it.number
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,9 @@ import io.github.wulkanowy.data.db.SharedPrefProvider
|
||||
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.enums.TimetableGapsMode.BETWEEN_AND_BEFORE_LESSONS
|
||||
import io.github.wulkanowy.data.enums.TimetableGapsMode.NO_GAPS
|
||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||
import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.data.repositories.TimetableRepository
|
||||
@ -24,6 +27,7 @@ import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider.Co
|
||||
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider.Companion.getStudentWidgetKey
|
||||
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider.Companion.getTodayLastLessonEndDateTimeWidgetKey
|
||||
import io.github.wulkanowy.utils.getCompatColor
|
||||
import io.github.wulkanowy.utils.getPlural
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import timber.log.Timber
|
||||
@ -35,11 +39,12 @@ class TimetableWidgetFactory(
|
||||
private val studentRepository: StudentRepository,
|
||||
private val semesterRepository: SemesterRepository,
|
||||
private val sharedPref: SharedPrefProvider,
|
||||
private val prefRepository: PreferencesRepository,
|
||||
private val context: Context,
|
||||
private val intent: Intent?
|
||||
) : RemoteViewsService.RemoteViewsFactory {
|
||||
|
||||
private var lessons = emptyList<Timetable>()
|
||||
private var items = emptyList<TimetableWidgetItem>()
|
||||
|
||||
private var timetableCanceledColor: Int? = null
|
||||
|
||||
@ -47,18 +52,13 @@ class TimetableWidgetFactory(
|
||||
|
||||
private var timetableChangeColor: Int? = null
|
||||
|
||||
private var lastSyncInstant: Instant? = null
|
||||
|
||||
override fun getLoadingView() = null
|
||||
|
||||
override fun hasStableIds() = true
|
||||
|
||||
override fun getCount() = when {
|
||||
lessons.isEmpty() -> 0
|
||||
else -> lessons.size + 1
|
||||
}
|
||||
override fun getCount() = items.size
|
||||
|
||||
override fun getViewTypeCount() = 2
|
||||
override fun getViewTypeCount() = 3
|
||||
|
||||
override fun getItemId(position: Int) = position.toLong()
|
||||
|
||||
@ -75,9 +75,10 @@ class TimetableWidgetFactory(
|
||||
runBlocking {
|
||||
val student = getStudent(studentId) ?: return@runBlocking
|
||||
val semester = semesterRepository.getCurrentSemester(student)
|
||||
lessons = getLessons(student, semester, date)
|
||||
lastSyncInstant =
|
||||
timetableRepository.getLastRefreshTimestamp(semester, date, date)
|
||||
items = createItems(
|
||||
lessons = getLessons(student, semester, date),
|
||||
lastSync = timetableRepository.getLastRefreshTimestamp(semester, date, date)
|
||||
)
|
||||
if (date == LocalDate.now()) {
|
||||
updateTodayLastLessonEnd(appWidgetId)
|
||||
}
|
||||
@ -101,8 +102,33 @@ class TimetableWidgetFactory(
|
||||
return lessons.sortedBy { it.number }
|
||||
}
|
||||
|
||||
private fun createItems(
|
||||
lessons: List<Timetable>,
|
||||
lastSync: Instant?,
|
||||
): List<TimetableWidgetItem> {
|
||||
var prevNum = when (prefRepository.showTimetableGaps) {
|
||||
BETWEEN_AND_BEFORE_LESSONS -> 0
|
||||
else -> null
|
||||
}
|
||||
return buildList {
|
||||
lessons.forEach {
|
||||
if (prefRepository.showTimetableGaps != NO_GAPS && prevNum != null && it.number > prevNum!! + 1) {
|
||||
val emptyItem = TimetableWidgetItem.Empty(
|
||||
numFrom = prevNum!! + 1,
|
||||
numTo = it.number - 1
|
||||
)
|
||||
add(emptyItem)
|
||||
}
|
||||
add(TimetableWidgetItem.Normal(it))
|
||||
prevNum = it.number
|
||||
}
|
||||
add(TimetableWidgetItem.Synchronized(lastSync ?: Instant.MIN))
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateTodayLastLessonEnd(appWidgetId: Int) {
|
||||
val todayLastLessonEnd = lessons.maxOfOrNull { it.end } ?: return
|
||||
val todayLastLessonEnd = items.filterIsInstance<TimetableWidgetItem.Normal>()
|
||||
.maxOfOrNull { it.lesson.end } ?: return
|
||||
val key = getTodayLastLessonEndDateTimeWidgetKey(appWidgetId)
|
||||
sharedPref.putLong(key, todayLastLessonEnd.epochSecond, true)
|
||||
}
|
||||
@ -112,44 +138,81 @@ class TimetableWidgetFactory(
|
||||
}
|
||||
|
||||
override fun getViewAt(position: Int): RemoteViews? {
|
||||
if (position == lessons.size) {
|
||||
val synchronizationInstant = lastSyncInstant ?: Instant.MIN
|
||||
val synchronizationText = getSynchronizationInfoText(synchronizationInstant)
|
||||
return RemoteViews(context.packageName, R.layout.item_widget_timetable_footer).apply {
|
||||
setTextViewText(R.id.timetableWidgetSynchronizationTime, synchronizationText)
|
||||
}
|
||||
return when (val item = items.getOrNull(position) ?: return null) {
|
||||
is TimetableWidgetItem.Normal -> getNormalItemRemoteView(item)
|
||||
is TimetableWidgetItem.Empty -> getEmptyItemRemoteView(item)
|
||||
is TimetableWidgetItem.Synchronized -> getSynchronizedItemRemoteView(item)
|
||||
}
|
||||
}
|
||||
|
||||
val lesson = lessons.getOrNull(position) ?: return null
|
||||
private fun getNormalItemRemoteView(item: TimetableWidgetItem.Normal): RemoteViews {
|
||||
val lesson = item.lesson
|
||||
|
||||
val lessonStartTime = lesson.start.toFormattedString(TIME_FORMAT_STYLE)
|
||||
val lessonEndTime = lesson.end.toFormattedString(TIME_FORMAT_STYLE)
|
||||
val roomText = "${context.getString(R.string.timetable_room)} ${lesson.room}"
|
||||
|
||||
val remoteViews = RemoteViews(context.packageName, R.layout.item_widget_timetable).apply {
|
||||
setTextViewText(R.id.timetableWidgetItemNumber, lesson.number.toString())
|
||||
setTextViewText(R.id.timetableWidgetItemTimeStart, lessonStartTime)
|
||||
setTextViewText(R.id.timetableWidgetItemTimeFinish, lessonEndTime)
|
||||
setTextViewText(R.id.timetableWidgetItemSubject, lesson.subject)
|
||||
setTextViewText(R.id.timetableWidgetItemRoom, roomText)
|
||||
|
||||
setTextViewText(R.id.timetableWidgetItemTeacher, lesson.teacher)
|
||||
setTextViewText(R.id.timetableWidgetItemDescription, lesson.info)
|
||||
setOnClickFillInIntent(R.id.timetableWidgetItemContainer, Intent())
|
||||
}
|
||||
|
||||
updateTheme()
|
||||
clearLessonStyles(remoteViews)
|
||||
|
||||
if (lesson.room.isBlank()) {
|
||||
remoteViews.setViewVisibility(R.id.timetableWidgetItemRoom, GONE)
|
||||
} else {
|
||||
remoteViews.setTextViewText(R.id.timetableWidgetItemRoom, lesson.room)
|
||||
}
|
||||
when {
|
||||
lesson.canceled -> applyCancelledLessonStyles(remoteViews)
|
||||
lesson.changes or lesson.info.isNotBlank() -> applyChangedLessonStyles(
|
||||
remoteViews, lesson
|
||||
remoteViews = remoteViews,
|
||||
lesson = lesson,
|
||||
)
|
||||
}
|
||||
|
||||
return remoteViews
|
||||
}
|
||||
|
||||
private fun getEmptyItemRemoteView(item: TimetableWidgetItem.Empty): RemoteViews {
|
||||
return RemoteViews(
|
||||
context.packageName,
|
||||
R.layout.item_widget_timetable_empty
|
||||
).apply {
|
||||
setTextViewText(
|
||||
R.id.timetableWidgetEmptyItemNumber,
|
||||
when (item.numFrom) {
|
||||
item.numTo -> item.numFrom.toString()
|
||||
else -> "${item.numFrom}-${item.numTo}"
|
||||
}
|
||||
)
|
||||
setTextViewText(
|
||||
R.id.timetableWidgetEmptyItemText,
|
||||
context.getPlural(
|
||||
R.plurals.timetable_no_lesson,
|
||||
item.numTo - item.numFrom + 1
|
||||
)
|
||||
)
|
||||
setOnClickFillInIntent(R.id.timetableWidgetEmptyItemContainer, Intent())
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSynchronizedItemRemoteView(item: TimetableWidgetItem.Synchronized): RemoteViews {
|
||||
return RemoteViews(
|
||||
context.packageName,
|
||||
R.layout.item_widget_timetable_footer
|
||||
).apply {
|
||||
setTextViewText(
|
||||
R.id.timetableWidgetSynchronizationTime,
|
||||
getSynchronizationInfoText(item.timestamp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateTheme() {
|
||||
when (context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) {
|
||||
Configuration.UI_MODE_NIGHT_YES -> {
|
||||
|
@ -0,0 +1,26 @@
|
||||
package io.github.wulkanowy.ui.modules.timetablewidget
|
||||
|
||||
import io.github.wulkanowy.data.db.entities.Timetable
|
||||
import java.time.Instant
|
||||
|
||||
sealed class TimetableWidgetItem(val type: TimetableWidgetItemType) {
|
||||
|
||||
data class Normal(
|
||||
val lesson: Timetable,
|
||||
) : TimetableWidgetItem(TimetableWidgetItemType.NORMAL)
|
||||
|
||||
data class Empty(
|
||||
val numFrom: Int,
|
||||
val numTo: Int
|
||||
) : TimetableWidgetItem(TimetableWidgetItemType.EMPTY)
|
||||
|
||||
data class Synchronized(
|
||||
val timestamp: Instant,
|
||||
) : TimetableWidgetItem(TimetableWidgetItemType.SYNCHRONIZED)
|
||||
}
|
||||
|
||||
enum class TimetableWidgetItemType {
|
||||
NORMAL,
|
||||
EMPTY,
|
||||
SYNCHRONIZED,
|
||||
}
|
@ -8,6 +8,7 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
import android.graphics.Bitmap
|
||||
import android.widget.RemoteViews
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.core.graphics.drawable.DrawableCompat
|
||||
@ -76,110 +77,151 @@ class TimetableWidgetProvider : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
GlobalScope.launch {
|
||||
when (intent.action) {
|
||||
ACTION_APPWIDGET_UPDATE -> onUpdate(context, intent)
|
||||
ACTION_APPWIDGET_DELETED -> onDelete(intent)
|
||||
ACTION_APPWIDGET_UPDATE -> onWidgetUpdate(context, intent)
|
||||
ACTION_APPWIDGET_DELETED -> onWidgetDeleted(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun onUpdate(context: Context, intent: Intent) {
|
||||
if (intent.getStringExtra(EXTRA_BUTTON_TYPE) == null) {
|
||||
val isFromConfigure = intent.getBooleanExtra(EXTRA_FROM_CONFIGURE, false)
|
||||
val appWidgetIds = intent.getIntArrayExtra(EXTRA_APPWIDGET_IDS) ?: return
|
||||
private suspend fun onWidgetUpdate(context: Context, intent: Intent) {
|
||||
val pressedButton = intent.getPressedButton()
|
||||
|
||||
appWidgetIds.forEach { appWidgetId ->
|
||||
val student =
|
||||
getStudent(sharedPref.getLong(getStudentWidgetKey(appWidgetId), 0), appWidgetId)
|
||||
val savedDataEpochDay = sharedPref.getLong(getDateWidgetKey(appWidgetId), 0)
|
||||
|
||||
val dateToLoad = if (isFromConfigure && savedDataEpochDay != 0L) {
|
||||
LocalDate.ofEpochDay(savedDataEpochDay)
|
||||
} else {
|
||||
getWidgetDefaultDateToLoad(appWidgetId)
|
||||
}
|
||||
|
||||
updateWidget(context, appWidgetId, dateToLoad, student)
|
||||
}
|
||||
if (pressedButton == null) {
|
||||
val updatedWidgetIds = intent.getWidgetIds() ?: return
|
||||
updatedWidgetIds.forEach { updateWidgetLayout(context, it) }
|
||||
} else {
|
||||
val buttonType = intent.getStringExtra(EXTRA_BUTTON_TYPE)
|
||||
val toggledWidgetId = intent.getIntExtra(EXTRA_TOGGLED_WIDGET_ID, 0)
|
||||
val student = getStudent(
|
||||
sharedPref.getLong(getStudentWidgetKey(toggledWidgetId), 0), toggledWidgetId
|
||||
)
|
||||
val savedDate =
|
||||
LocalDate.ofEpochDay(sharedPref.getLong(getDateWidgetKey(toggledWidgetId), 0))
|
||||
val date = when (buttonType) {
|
||||
BUTTON_RESET -> getWidgetDefaultDateToLoad(toggledWidgetId)
|
||||
BUTTON_NEXT -> savedDate.nextSchoolDay
|
||||
BUTTON_PREV -> savedDate.previousSchoolDay
|
||||
else -> getWidgetDefaultDateToLoad(toggledWidgetId)
|
||||
}
|
||||
if (!buttonType.isNullOrBlank()) {
|
||||
analytics.logEvent(
|
||||
"changed_timetable_widget_day", "button" to buttonType
|
||||
)
|
||||
}
|
||||
updateWidget(context, toggledWidgetId, date, student)
|
||||
val widgetId = intent.getToggledWidgetId() ?: return
|
||||
reportChangedDay(pressedButton)
|
||||
updateSavedWidgetDate(widgetId, pressedButton)
|
||||
updateWidgetLayout(context, widgetId)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onDelete(intent: Intent) {
|
||||
val appWidgetId = intent.getIntExtra(EXTRA_APPWIDGET_ID, 0)
|
||||
private fun Intent.getPressedButton(): String? {
|
||||
return getStringExtra(EXTRA_BUTTON_TYPE)
|
||||
}
|
||||
|
||||
if (appWidgetId != 0) {
|
||||
with(sharedPref) {
|
||||
delete(getStudentWidgetKey(appWidgetId))
|
||||
delete(getDateWidgetKey(appWidgetId))
|
||||
}
|
||||
private fun Intent.getWidgetIds(): IntArray? {
|
||||
return getIntArrayExtra(EXTRA_APPWIDGET_IDS)
|
||||
}
|
||||
|
||||
private fun Intent.getToggledWidgetId(): Int? {
|
||||
val toggledWidgetId = getIntExtra(EXTRA_TOGGLED_WIDGET_ID, INVALID_APPWIDGET_ID)
|
||||
return toggledWidgetId.takeIf { it != INVALID_APPWIDGET_ID }
|
||||
}
|
||||
|
||||
private fun reportChangedDay(buttonType: String) {
|
||||
if (buttonType.isNotBlank()) {
|
||||
analytics.logEvent("changed_timetable_widget_day", "button" to buttonType)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateWidget(
|
||||
context: Context, appWidgetId: Int, date: LocalDate, student: Student?
|
||||
private fun updateSavedWidgetDate(widgetId: Int, buttonType: String) {
|
||||
val savedDate = getSavedWidgetDate(widgetId)
|
||||
val newDate = savedDate?.let { getNewDate(it, widgetId, buttonType) }
|
||||
?: getWidgetDefaultDateToLoad(widgetId)
|
||||
setWidgetDate(widgetId, newDate)
|
||||
}
|
||||
|
||||
private fun getSavedWidgetDate(widgetId: Int): LocalDate? {
|
||||
val epochDay = sharedPref.getLong(getDateWidgetKey(widgetId), 0)
|
||||
return if (epochDay == 0L) null else LocalDate.ofEpochDay(epochDay)
|
||||
}
|
||||
|
||||
private fun getNewDate(
|
||||
currentDate: LocalDate,
|
||||
widgetId: Int,
|
||||
selectedButton: String
|
||||
): LocalDate {
|
||||
return when (selectedButton) {
|
||||
BUTTON_NEXT -> currentDate.nextSchoolDay
|
||||
BUTTON_PREV -> currentDate.previousSchoolDay
|
||||
else -> getWidgetDefaultDateToLoad(widgetId)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setWidgetDate(widgetId: Int, dateToSet: LocalDate) {
|
||||
val widgetDateKey = getDateWidgetKey(widgetId)
|
||||
sharedPref.putLong(widgetDateKey, dateToSet.toEpochDay(), true)
|
||||
}
|
||||
|
||||
private fun getWidgetDefaultDateToLoad(widgetId: Int): LocalDate {
|
||||
val lastLessonEndDateTime = getLastLessonDateTime(widgetId)
|
||||
|
||||
val todayDate = LocalDate.now()
|
||||
val isLastLessonToday = lastLessonEndDateTime.toLocalDate() == todayDate
|
||||
val isEndOfLessons = LocalDateTime.now() > lastLessonEndDateTime
|
||||
|
||||
return if (isLastLessonToday && isEndOfLessons) {
|
||||
todayDate.nextSchoolDay
|
||||
} else {
|
||||
todayDate.nextOrSameSchoolDay
|
||||
}
|
||||
}
|
||||
|
||||
private fun getLastLessonDateTime(widgetId: Int): LocalDateTime {
|
||||
val lastLessonTimestamp = sharedPref
|
||||
.getLong(getTodayLastLessonEndDateTimeWidgetKey(widgetId), 0)
|
||||
return LocalDateTime.ofEpochSecond(lastLessonTimestamp, 0, ZoneOffset.UTC)
|
||||
}
|
||||
|
||||
private suspend fun updateWidgetLayout(
|
||||
context: Context, widgetId: Int
|
||||
) {
|
||||
val nextNavIntent = createNavIntent(context, appWidgetId, appWidgetId, BUTTON_NEXT)
|
||||
val prevNavIntent = createNavIntent(context, -appWidgetId, appWidgetId, BUTTON_PREV)
|
||||
val resetNavIntent =
|
||||
createNavIntent(context, Int.MAX_VALUE - appWidgetId, appWidgetId, BUTTON_RESET)
|
||||
val adapterIntent = Intent(context, TimetableWidgetService::class.java).apply {
|
||||
putExtra(EXTRA_APPWIDGET_ID, appWidgetId)
|
||||
action = appWidgetId.toString() //make Intent unique
|
||||
}
|
||||
val appIntent = PendingIntent.getActivity(
|
||||
context,
|
||||
TIMETABLE_PENDING_INTENT_ID,
|
||||
SplashActivity.getStartIntent(context, Destination.Timetable()),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
|
||||
)
|
||||
val widgetRemoteViews = RemoteViews(context.packageName, R.layout.widget_timetable)
|
||||
|
||||
// Apply the click action intent
|
||||
val appIntent = createPendingAppIntent(context)
|
||||
widgetRemoteViews.setPendingIntentTemplate(R.id.timetableWidgetList, appIntent)
|
||||
|
||||
// Display saved date
|
||||
val date = getSavedWidgetDate(widgetId) ?: getWidgetDefaultDateToLoad(widgetId)
|
||||
val formattedDate = date.toFormattedString("EEE, dd.MM").capitalise()
|
||||
val remoteView = RemoteViews(context.packageName, R.layout.widget_timetable).apply {
|
||||
setEmptyView(R.id.timetableWidgetList, R.id.timetableWidgetEmpty)
|
||||
setTextViewText(R.id.timetableWidgetDate, formattedDate)
|
||||
setRemoteAdapter(R.id.timetableWidgetList, adapterIntent)
|
||||
widgetRemoteViews.setTextViewText(R.id.timetableWidgetDate, formattedDate)
|
||||
|
||||
// Apply intents to the date switcher buttons
|
||||
val nextNavIntent = createNavButtonIntent(context, widgetId, widgetId, BUTTON_NEXT)
|
||||
val prevNavIntent = createNavButtonIntent(context, -widgetId, widgetId, BUTTON_PREV)
|
||||
val resetNavIntent =
|
||||
createNavButtonIntent(context, Int.MAX_VALUE - widgetId, widgetId, BUTTON_RESET)
|
||||
widgetRemoteViews.run {
|
||||
setOnClickPendingIntent(R.id.timetableWidgetNext, nextNavIntent)
|
||||
setOnClickPendingIntent(R.id.timetableWidgetPrev, prevNavIntent)
|
||||
setOnClickPendingIntent(R.id.timetableWidgetDate, resetNavIntent)
|
||||
setPendingIntentTemplate(R.id.timetableWidgetList, appIntent)
|
||||
}
|
||||
|
||||
student?.let {
|
||||
setupAccountView(context, student, remoteView, appWidgetId)
|
||||
// Setup the lesson list adapter
|
||||
val lessonListAdapterIntent = createLessonListAdapterIntent(context, widgetId)
|
||||
// --- Ensure the selected date is stored in the shared preferences,
|
||||
// --- on which the TimetableWidgetFactory relies
|
||||
setWidgetDate(widgetId, date)
|
||||
// ---
|
||||
widgetRemoteViews.apply {
|
||||
setEmptyView(R.id.timetableWidgetList, R.id.timetableWidgetEmpty)
|
||||
setRemoteAdapter(R.id.timetableWidgetList, lessonListAdapterIntent)
|
||||
}
|
||||
|
||||
with(sharedPref) {
|
||||
putLong(getDateWidgetKey(appWidgetId), date.toEpochDay(), true)
|
||||
// Setup profile picture
|
||||
getWidgetStudent(widgetId)?.let { student ->
|
||||
setupAccountView(context, student, widgetRemoteViews, widgetId)
|
||||
}
|
||||
|
||||
// Apply updates
|
||||
with(appWidgetManager) {
|
||||
partiallyUpdateAppWidget(appWidgetId, remoteView)
|
||||
notifyAppWidgetViewDataChanged(appWidgetId, R.id.timetableWidgetList)
|
||||
partiallyUpdateAppWidget(widgetId, widgetRemoteViews)
|
||||
notifyAppWidgetViewDataChanged(widgetId, R.id.timetableWidgetList)
|
||||
}
|
||||
|
||||
Timber.d("TimetableWidgetProvider updated")
|
||||
}
|
||||
|
||||
private fun createNavIntent(
|
||||
private fun createPendingAppIntent(context: Context) = PendingIntent.getActivity(
|
||||
context, TIMETABLE_PENDING_INTENT_ID,
|
||||
SplashActivity.getStartIntent(context, Destination.Timetable()),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
|
||||
)
|
||||
|
||||
private fun createNavButtonIntent(
|
||||
context: Context, code: Int, appWidgetId: Int, buttonType: String
|
||||
) = PendingIntent.getBroadcast(
|
||||
context, code, Intent(context, TimetableWidgetProvider::class.java).apply {
|
||||
@ -189,6 +231,17 @@ class TimetableWidgetProvider : BroadcastReceiver() {
|
||||
}, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
|
||||
)
|
||||
|
||||
private fun createLessonListAdapterIntent(context: Context, widgetId: Int) =
|
||||
Intent(context, TimetableWidgetService::class.java).apply {
|
||||
putExtra(EXTRA_APPWIDGET_ID, widgetId)
|
||||
action = widgetId.toString() //make Intent unique
|
||||
}
|
||||
|
||||
private suspend fun getWidgetStudent(widgetId: Int): Student? {
|
||||
val studentId = sharedPref.getLong(getStudentWidgetKey(widgetId), 0)
|
||||
return getStudent(studentId, widgetId)
|
||||
}
|
||||
|
||||
private suspend fun getStudent(studentId: Long, appWidgetId: Int) = try {
|
||||
val students = studentRepository.getSavedStudents(false)
|
||||
val student = students.singleOrNull { it.student.id == studentId }?.student
|
||||
@ -199,6 +252,7 @@ class TimetableWidgetProvider : BroadcastReceiver() {
|
||||
sharedPref.putLong(getStudentWidgetKey(appWidgetId), it.id)
|
||||
}
|
||||
}
|
||||
|
||||
else -> null
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
@ -208,60 +262,64 @@ class TimetableWidgetProvider : BroadcastReceiver() {
|
||||
null
|
||||
}
|
||||
|
||||
private fun getWidgetDefaultDateToLoad(appWidgetId: Int): LocalDate {
|
||||
val lastLessonEndTimestamp =
|
||||
sharedPref.getLong(getTodayLastLessonEndDateTimeWidgetKey(appWidgetId), 0)
|
||||
val lastLessonEndDateTime =
|
||||
LocalDateTime.ofEpochSecond(lastLessonEndTimestamp, 0, ZoneOffset.UTC)
|
||||
private fun setupAccountView(
|
||||
context: Context, student: Student, remoteViews: RemoteViews, widgetId: Int
|
||||
) {
|
||||
val accountInitials = getAccountInitials(student.nickOrName)
|
||||
val accountPickerPendingIntent = createAccountPickerPendingIntent(context, widgetId)
|
||||
|
||||
val todayDate = LocalDate.now()
|
||||
val isLastLessonEndDateNow = lastLessonEndDateTime.toLocalDate() == todayDate
|
||||
val isLastLessonEndDateAfterNowTime = LocalDateTime.now() > lastLessonEndDateTime
|
||||
getAvatarBackgroundBitmap(context, student.avatarColor)?.let {
|
||||
remoteViews.setImageViewBitmap(R.id.timetableWidgetAccountBackground, it)
|
||||
}
|
||||
|
||||
return if (isLastLessonEndDateNow && isLastLessonEndDateAfterNowTime) {
|
||||
todayDate.nextSchoolDay
|
||||
} else {
|
||||
todayDate.nextOrSameSchoolDay
|
||||
remoteViews.apply {
|
||||
setTextViewText(R.id.timetableWidgetAccountInitials, accountInitials)
|
||||
setOnClickPendingIntent(R.id.timetableWidgetAccount, accountPickerPendingIntent)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupAccountView(
|
||||
context: Context,
|
||||
student: Student,
|
||||
remoteViews: RemoteViews,
|
||||
appWidgetId: Int
|
||||
) {
|
||||
val accountInitials = student.nickOrName
|
||||
.split(" ")
|
||||
.mapNotNull { it.firstOrNull() }.take(2)
|
||||
.joinToString(separator = "").uppercase()
|
||||
private fun getAccountInitials(name: String): String {
|
||||
val firstLetters = name.split(" ").mapNotNull { it.firstOrNull() }
|
||||
return firstLetters.joinToString(separator = "").uppercase()
|
||||
}
|
||||
|
||||
val accountPickerIntent = PendingIntent.getActivity(
|
||||
private fun createAccountPickerPendingIntent(context: Context, widgetId: Int) =
|
||||
PendingIntent.getActivity(
|
||||
context,
|
||||
-Int.MAX_VALUE + appWidgetId,
|
||||
-Int.MAX_VALUE + widgetId,
|
||||
Intent(context, TimetableWidgetConfigureActivity::class.java).apply {
|
||||
addFlags(FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_CLEAR_TASK)
|
||||
putExtra(EXTRA_APPWIDGET_ID, appWidgetId)
|
||||
putExtra(EXTRA_APPWIDGET_ID, widgetId)
|
||||
putExtra(EXTRA_FROM_PROVIDER, true)
|
||||
},
|
||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
|
||||
)
|
||||
|
||||
// Create background bitmap
|
||||
private fun getAvatarBackgroundBitmap(context: Context, avatarColor: Long): Bitmap? {
|
||||
val avatarDrawableResource = R.drawable.background_timetable_widget_avatar
|
||||
AppCompatResources.getDrawable(context, avatarDrawableResource)?.let { drawable ->
|
||||
return AppCompatResources.getDrawable(context, avatarDrawableResource)?.let { drawable ->
|
||||
val screenDensity = context.resources.displayMetrics.density
|
||||
val avatarSize = (48 * screenDensity).toInt()
|
||||
val backgroundBitmap = DrawableCompat.wrap(drawable).run {
|
||||
DrawableCompat.setTint(this, student.avatarColor.toInt())
|
||||
DrawableCompat.wrap(drawable).run {
|
||||
DrawableCompat.setTint(this, avatarColor.toInt())
|
||||
toBitmap(avatarSize, avatarSize)
|
||||
}
|
||||
remoteViews.setImageViewBitmap(R.id.timetableWidgetAccountBackground, backgroundBitmap)
|
||||
}
|
||||
}
|
||||
|
||||
remoteViews.apply {
|
||||
setTextViewText(R.id.timetableWidgetAccountInitials, accountInitials)
|
||||
setOnClickPendingIntent(R.id.timetableWidgetAccount, accountPickerIntent)
|
||||
private fun onWidgetDeleted(intent: Intent) {
|
||||
val deletedWidgetId = intent.getWidgetId()
|
||||
deleteWidgetPreferences(deletedWidgetId)
|
||||
}
|
||||
|
||||
private fun Intent.getWidgetId(): Int {
|
||||
return getIntExtra(EXTRA_APPWIDGET_ID, INVALID_APPWIDGET_ID)
|
||||
}
|
||||
|
||||
private fun deleteWidgetPreferences(widgetId: Int) {
|
||||
with(sharedPref) {
|
||||
delete(getStudentWidgetKey(widgetId))
|
||||
delete(getDateWidgetKey(widgetId))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,27 @@
|
||||
package io.github.wulkanowy.utils
|
||||
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalDate.now
|
||||
import java.time.Month
|
||||
|
||||
inline val Semester.isCurrent: Boolean
|
||||
get() = now() in start..end
|
||||
fun Semester.isCurrent(now: LocalDate = now()): Boolean {
|
||||
val shiftedStart = if (start.month == Month.SEPTEMBER) {
|
||||
start.minusDays(3)
|
||||
} else start
|
||||
|
||||
val shiftedEnd = if (end.month == Month.AUGUST || end.month == Month.SEPTEMBER) {
|
||||
end.minusDays(3)
|
||||
} else end
|
||||
|
||||
return now in shiftedStart..shiftedEnd
|
||||
}
|
||||
|
||||
fun List<Semester>.getCurrentOrLast(): Semester {
|
||||
if (isEmpty()) throw RuntimeException("Empty semester list")
|
||||
|
||||
// when there is only one current semester
|
||||
singleOrNull { it.isCurrent }?.let { return it }
|
||||
singleOrNull { it.isCurrent() }?.let { return it }
|
||||
|
||||
// when there is more than one current semester - find one with higher id
|
||||
singleOrNull { semester -> semester.semesterId == maxByOrNull { it.semesterId }?.semesterId }?.let { return it }
|
||||
|
@ -1,7 +1,8 @@
|
||||
Wersja 2.0.8
|
||||
Wersja 2.1.0
|
||||
|
||||
— poprawiliśmy wyświetlanie kilku rodzajów zmian w planie lekcji
|
||||
— dodaliśmy limit znaków w okienku usprawiedliwiania
|
||||
— naprawiliśmy wyświetlanie frekwencji w szkołach, gdzie działa już system eduOne (ciągle jednak brak opcji usprawiedliwiania)
|
||||
— dodaliśmy tryb incognito w wiadomościach
|
||||
— dodaliśmy wyświetlanie pustych lekcji (okienek) w planie lekcji
|
||||
— poprawiliśmy widżet planu lekcji (będzie teraz trochę bardziej kompaktowy)
|
||||
— zmieniliśmy datę rozpoczęcia roku szkolnego na 3 dni przed 1 września (sorry)
|
||||
|
||||
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases
|
||||
|
@ -2,5 +2,5 @@
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="#FF000000" />
|
||||
<corners android:radius="12dp" />
|
||||
<corners android:radius="14dp" />
|
||||
</shape>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="#FFFFFBFF" />
|
||||
<corners android:radius="12dp" />
|
||||
<corners android:radius="14dp" />
|
||||
</shape>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:width="20dp"
|
||||
android:height="20dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
|
@ -1,6 +1,6 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:width="20dp"
|
||||
android:height="20dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
|
BIN
app/src/main/res/drawable/img_timetable_widget_preview.png
Executable file → Normal file
BIN
app/src/main/res/drawable/img_timetable_widget_preview.png
Executable file → Normal file
Binary file not shown.
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 75 KiB |
@ -5,10 +5,10 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/background_widget_timetable"
|
||||
android:backgroundTint="?attr/colorSurface"
|
||||
android:backgroundTint="?attr/colorSecondaryContainer"
|
||||
android:clipToOutline="true"
|
||||
android:orientation="vertical"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:paddingHorizontal="12dp"
|
||||
android:theme="@style/Wulkanowy.Widget.Theme"
|
||||
tools:context=".ui.modules.timetablewidget.TimetableWidgetProvider">
|
||||
|
||||
@ -16,23 +16,47 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:paddingVertical="16dp">
|
||||
android:paddingTop="12dp"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:importantForAccessibility="no"
|
||||
android:src="@drawable/background_timetable_widget_avatar"
|
||||
android:tint="?attr/colorPrimary"
|
||||
app:tint="?attr/colorPrimary"
|
||||
tools:ignore="UseAppTint" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:text="JK"
|
||||
android:textAppearance="?attr/textAppearanceTitleLarge"
|
||||
android:textColor="?attr/colorOnPrimary"
|
||||
android:textSize="18sp"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginHorizontal="12dp"
|
||||
android:layout_weight="1"
|
||||
android:lines="1"
|
||||
android:text="Pon, 03.10"
|
||||
android:textAppearance="?attr/textAppearanceHeadline5"
|
||||
android:text="Pon, 19.05"
|
||||
android:textSize="18sp"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
<ImageButton
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/all_prev"
|
||||
android:rotation="180"
|
||||
@ -51,46 +75,273 @@
|
||||
app:tint="?attr/colorPrimary"
|
||||
tools:ignore="UseAppTint" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:background="@drawable/background_timetable_widget_avatar"
|
||||
android:backgroundTint="?attr/colorPrimary"
|
||||
android:contentDescription="@string/account_quick_manager"
|
||||
android:gravity="center"
|
||||
android:text="AW"
|
||||
android:textAppearance="?attr/textAppearanceTitleLarge"
|
||||
android:textColor="?attr/colorOnPrimary" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:showDividers="middle">
|
||||
android:paddingBottom="12dp">
|
||||
|
||||
<ImageView
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="56dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:importantForAccessibility="no"
|
||||
android:src="@drawable/background_widget_item_timetable"
|
||||
app:tint="?attr/backgroundColor" />
|
||||
android:background="@drawable/background_widget_item_timetable"
|
||||
android:backgroundTint="?attr/colorSurface"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="48dp"
|
||||
android:orientation="horizontal"
|
||||
android:paddingHorizontal="12dp"
|
||||
android:paddingVertical="8dp">
|
||||
|
||||
<ImageView
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="1"
|
||||
android:textSize="22sp"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="10dp"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="08:00"
|
||||
android:textAppearance="?attr/textAppearanceBodySmall"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="2dp"
|
||||
android:text="09:45"
|
||||
android:textAppearance="?attr/textAppearanceBodySmall"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:lines="1"
|
||||
android:text="Wychowanie fizyczne"
|
||||
android:textSize="14sp"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:text="213"
|
||||
android:textSize="12sp"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:lines="1"
|
||||
android:text="Dorota Nowak"
|
||||
android:textAppearance="?attr/textAppearanceBodySmall"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="56dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:importantForAccessibility="no"
|
||||
android:src="@drawable/background_widget_item_timetable"
|
||||
app:tint="?attr/backgroundColor" />
|
||||
android:background="@drawable/background_widget_item_timetable"
|
||||
android:backgroundTint="?attr/colorSurface"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="48dp"
|
||||
android:orientation="horizontal"
|
||||
android:paddingHorizontal="12dp"
|
||||
android:paddingVertical="8dp">
|
||||
|
||||
<ImageView
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="2"
|
||||
android:textSize="22sp"
|
||||
tools:ignore="HardcodedText"
|
||||
tools:textColor="?attr/colorTimetableChange" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="10dp"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="08:50"
|
||||
android:textAppearance="?attr/textAppearanceBodySmall"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="2dp"
|
||||
android:text="09:35"
|
||||
android:textAppearance="?attr/textAppearanceBodySmall"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:lines="1"
|
||||
android:text="Język polski"
|
||||
android:textColor="?attr/colorTimetableChange"
|
||||
android:textSize="14sp"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:text="125"
|
||||
android:textSize="12sp"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:lines="1"
|
||||
android:text="Karolina Kowalska"
|
||||
android:textAppearance="?attr/textAppearanceBodySmall"
|
||||
android:textColor="?attr/colorTimetableChange"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:contentDescription="@string/timetable_changes"
|
||||
android:tint="?attr/colorTimetableChange"
|
||||
app:tint="?attr/colorTimetableChange"
|
||||
tools:ignore="UseAppTint"
|
||||
tools:src="@drawable/ic_timetable_widget_swap" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="56dp"
|
||||
android:importantForAccessibility="no"
|
||||
android:src="@drawable/background_widget_item_timetable"
|
||||
app:tint="?attr/backgroundColor" />
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/background_widget_item_timetable"
|
||||
android:backgroundTint="?attr/colorSurface"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="48dp"
|
||||
android:orientation="horizontal"
|
||||
android:paddingHorizontal="12dp"
|
||||
android:paddingVertical="8dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="3"
|
||||
android:textSize="22sp"
|
||||
tools:ignore="HardcodedText"
|
||||
tools:textColor="?attr/colorTimetableCanceled" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="10dp"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="09:45"
|
||||
android:textAppearance="?attr/textAppearanceBodySmall"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="2dp"
|
||||
android:text="10:30"
|
||||
android:textAppearance="?attr/textAppearanceBodySmall"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:lines="1"
|
||||
android:text="Wiedza o społeczeństwie"
|
||||
android:textColor="?attr/colorTimetableCanceled"
|
||||
android:textSize="14sp"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Lekcja odwołana: uczniowie zwolnieni do domu"
|
||||
android:textAppearance="?attr/textAppearanceBodySmall"
|
||||
android:textColor="?attr/colorTimetableCanceled"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -105,6 +105,18 @@
|
||||
android:background="?android:attr/listDivider" />
|
||||
</LinearLayout>
|
||||
|
||||
<include
|
||||
android:id="@+id/login_form_message"
|
||||
layout="@layout/item_dashboard_admin_message"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintTop_toBottomOf="@id/loginFormContact"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/loginFormHeader"
|
||||
android:layout_width="match_parent"
|
||||
@ -119,9 +131,8 @@
|
||||
app:layout_constraintBottom_toTopOf="@+id/loginFormUsernameLayout"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/loginFormContact"
|
||||
app:layout_constraintTop_toBottomOf="@+id/login_form_message"
|
||||
app:layout_constraintVertical_bias="0"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
app:layout_goneMarginTop="64dp" />
|
||||
|
||||
<TextView
|
||||
|
43
app/src/main/res/layout/item_timetable_empty.xml
Normal file
43
app/src/main/res/layout/item_timetable_empty.xml
Normal file
@ -0,0 +1,43 @@
|
||||
<androidx.constraintlayout.widget.ConstraintLayout 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"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?selectableItemBackground"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="6dp"
|
||||
android:paddingEnd="12dp"
|
||||
android:paddingBottom="6dp"
|
||||
tools:context=".ui.modules.timetable.TimetableAdapter">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableEmptyItemNumber"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:includeFontPadding="false"
|
||||
android:maxLength="5"
|
||||
android:minWidth="40dp"
|
||||
android:minHeight="40dp"
|
||||
android:textColor="?android:textColorHint"
|
||||
android:textSize="32sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="1-4" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableEmptyItemSubject"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="?android:textColorHint"
|
||||
android:textSize="15sp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/timetableEmptyItemNumber"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/timetableEmptyItemNumber"
|
||||
app:layout_constraintTop_toTopOf="@+id/timetableEmptyItemNumber"
|
||||
tools:text="No lessons" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -6,11 +6,12 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/background_widget_item_timetable"
|
||||
android:backgroundTint="?attr/backgroundColor"
|
||||
android:backgroundTint="?attr/colorSurface"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="48dp"
|
||||
android:orientation="horizontal"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:paddingVertical="12dp"
|
||||
android:paddingHorizontal="12dp"
|
||||
android:paddingVertical="8dp"
|
||||
android:theme="@style/Wulkanowy.Widget.Theme"
|
||||
tools:context=".ui.modules.timetablewidget.TimetableWidgetFactory">
|
||||
|
||||
@ -18,15 +19,14 @@
|
||||
android:id="@+id/timetableWidgetItemNumber"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?attr/textAppearanceHeadline6"
|
||||
android:textSize="24sp"
|
||||
android:textSize="22sp"
|
||||
tools:text="1"
|
||||
tools:textColor="?attr/colorTimetableChange" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="vertical">
|
||||
|
||||
@ -41,7 +41,7 @@
|
||||
android:id="@+id/timetableWidgetItemTimeFinish"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginTop="2dp"
|
||||
android:textAppearance="?attr/textAppearanceBodySmall"
|
||||
tools:text="09:45" />
|
||||
|
||||
@ -60,7 +60,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:lines="1"
|
||||
android:textAppearance="?attr/textAppearanceTitleMedium"
|
||||
android:textSize="14sp"
|
||||
tools:text="Programowanie aplikacji mobilnych i desktopowych" />
|
||||
|
||||
<LinearLayout
|
||||
@ -72,15 +72,15 @@
|
||||
android:id="@+id/timetableWidgetItemRoom"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:textAppearance="?attr/textAppearanceBodySmall"
|
||||
tools:text="Sala 213"
|
||||
tools:text="213"
|
||||
tools:textColor="?attr/colorTimetableChange" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableWidgetItemTeacher"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:ellipsize="end"
|
||||
android:lines="1"
|
||||
android:textAppearance="?attr/textAppearanceBodySmall"
|
||||
|
36
app/src/main/res/layout/item_widget_timetable_empty.xml
Normal file
36
app/src/main/res/layout/item_widget_timetable_empty.xml
Normal file
@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/timetableWidgetEmptyItemContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/background_widget_item_timetable"
|
||||
android:backgroundTint="?attr/colorSurface"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:paddingHorizontal="12dp"
|
||||
android:paddingVertical="8dp"
|
||||
android:theme="@style/Wulkanowy.Widget.Theme"
|
||||
tools:context=".ui.modules.timetablewidget.TimetableWidgetFactory">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableWidgetEmptyItemNumber"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?attr/textAppearanceHeadline6"
|
||||
android:textColor="?android:textColorHint"
|
||||
android:textSize="22sp"
|
||||
tools:text="1-4" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableWidgetEmptyItemText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:ellipsize="end"
|
||||
android:lines="1"
|
||||
android:textAppearance="?attr/textAppearanceTitleMedium"
|
||||
android:textColor="?android:textColorHint"
|
||||
tools:text="No lessons" />
|
||||
|
||||
</LinearLayout>
|
@ -5,35 +5,70 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/background_widget_timetable"
|
||||
android:backgroundTint="?attr/colorSurface"
|
||||
android:backgroundTint="?attr/colorSecondaryContainer"
|
||||
android:clipToOutline="true"
|
||||
android:orientation="vertical"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:paddingHorizontal="12dp"
|
||||
android:theme="@style/Wulkanowy.Widget.Theme"
|
||||
tools:context=".ui.modules.timetablewidget.TimetableWidgetProvider">
|
||||
tools:context=".ui.modules.timetablewidget.TimetableWidgetProvider"
|
||||
tools:targetApi="s">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:paddingVertical="16dp">
|
||||
android:paddingTop="12dp"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/timetableWidgetAccount"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:background="@drawable/background_timetable_widget_avatar"
|
||||
android:backgroundTint="@android:color/transparent"
|
||||
android:clickable="true"
|
||||
android:clipToOutline="true"
|
||||
android:contentDescription="@string/account_quick_manager"
|
||||
android:focusable="true"
|
||||
android:foreground="?attr/selectableItemBackgroundBorderless"
|
||||
android:importantForAccessibility="yes"
|
||||
android:outlineProvider="background"
|
||||
tools:targetApi="s">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/timetableWidgetAccountBackground"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:importantForAccessibility="no"
|
||||
tools:src="@drawable/background_timetable_widget_avatar"
|
||||
tools:tint="?attr/colorPrimary" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableWidgetAccountInitials"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:textAppearance="?attr/textAppearanceTitleLarge"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="18sp"
|
||||
tools:text="JK" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableWidgetDate"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginHorizontal="12dp"
|
||||
android:layout_weight="1"
|
||||
android:lines="1"
|
||||
android:textAppearance="?attr/textAppearanceHeadline5"
|
||||
tools:text="Pon, 12.05" />
|
||||
android:textSize="18sp"
|
||||
tools:text="Friday, 19.05" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/timetableWidgetPrev"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/all_prev"
|
||||
android:rotation="180"
|
||||
@ -53,39 +88,6 @@
|
||||
app:tint="?attr/colorPrimary"
|
||||
tools:ignore="UseAppTint" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/timetableWidgetAccount"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:background="@drawable/background_timetable_widget_avatar"
|
||||
android:backgroundTint="@android:color/transparent"
|
||||
android:clickable="true"
|
||||
android:clipToOutline="true"
|
||||
android:contentDescription="@string/account_quick_manager"
|
||||
android:focusable="true"
|
||||
android:foreground="?attr/selectableItemBackgroundBorderless"
|
||||
android:importantForAccessibility="yes"
|
||||
android:outlineProvider="background">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/timetableWidgetAccountBackground"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:importantForAccessibility="no"
|
||||
tools:src="@drawable/background_timetable_widget_avatar"
|
||||
tools:tint="?attr/colorPrimary" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableWidgetAccountInitials"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:textAppearance="?attr/textAppearanceTitleLarge"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="20sp"
|
||||
tools:text="AW" />
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<FrameLayout
|
||||
@ -99,6 +101,7 @@
|
||||
android:clipToPadding="false"
|
||||
android:divider="@android:color/transparent"
|
||||
android:dividerHeight="4dp"
|
||||
android:listSelector="@android:color/transparent"
|
||||
android:paddingBottom="16dp"
|
||||
tools:listfooter="@layout/item_widget_timetable_footer"
|
||||
tools:listitem="@layout/item_widget_timetable" />
|
||||
@ -111,5 +114,7 @@
|
||||
android:text="@string/widget_timetable_no_items"
|
||||
android:textAppearance="?attr/textAppearanceBody1"
|
||||
android:visibility="gone" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -51,6 +51,11 @@
|
||||
<item>Průměr z průměrů z obou semestrů</item>
|
||||
<item>Průměr známek z celého roku</item>
|
||||
</string-array>
|
||||
<string-array name="timetable_show_gaps_entries">
|
||||
<item>Don\'t show</item>
|
||||
<item>Only between lessons</item>
|
||||
<item>Before and between lessons</item>
|
||||
</string-array>
|
||||
<string-array name="dashboard_tile_entries">
|
||||
<item>Šťastné číslo</item>
|
||||
<item>Nepřečtené zprávy</item>
|
||||
|
@ -37,7 +37,7 @@
|
||||
<string name="login_login_pesel_email_hint">Přihlášení, číslo PESEL nebo e-mail</string>
|
||||
<string name="login_password_hint">Heslo</string>
|
||||
<string name="login_host_hint">Variace deníku UONET+</string>
|
||||
<string name="login_domain_suffix_hint">Custom domain suffix</string>
|
||||
<string name="login_domain_suffix_hint">Vlastní přípona domény</string>
|
||||
<string name="login_type_api">Mobile API</string>
|
||||
<string name="login_type_scrapper">Scraper</string>
|
||||
<string name="login_type_hybrid">Hybridní</string>
|
||||
@ -185,6 +185,12 @@
|
||||
<string name="timetable_notify_change_room">Změna učebny z %1$s na %2$s</string>
|
||||
<string name="timetable_notify_change_teacher">Změna učitele z %1$s na %2$s</string>
|
||||
<string name="timetable_notify_change_subject">Změna předmětu z %1$s na %2$s</string>
|
||||
<plurals name="timetable_no_lesson">
|
||||
<item quantity="one">No lesson</item>
|
||||
<item quantity="few">No lessons</item>
|
||||
<item quantity="many">No lessons</item>
|
||||
<item quantity="other">No lessons</item>
|
||||
</plurals>
|
||||
<plurals name="timetable_notify_new_items_title">
|
||||
<item quantity="one">Změna plánu lekcí</item>
|
||||
<item quantity="few">Změny plánu lekcí</item>
|
||||
@ -352,6 +358,8 @@
|
||||
</plurals>
|
||||
<string name="message_messages_deleted">Zprávy odstraněné</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_description">Díky anonymnímu režimu není odesílatel upozorněn, když si zprávu přečtete</string>
|
||||
<!--Note-->
|
||||
<string name="note_no_items">Žádné informace o poznámkách</string>
|
||||
<string name="note_points">Body</string>
|
||||
@ -698,6 +706,7 @@
|
||||
<string name="pref_view_expand_grade">Rozvíjení známek</string>
|
||||
<string name="pref_view_timetable_show_timers">Označit aktuální lekci</string>
|
||||
<string name="pref_view_timetable_show_groups">Zobrazit skupiny vedle předmětů</string>
|
||||
<string name="pref_view_timetable_show_gaps">Show empty tiles where there\'s no lesson</string>
|
||||
<string name="pref_view_grade_statistics_list">Zobrazit seznam grafů v známkách třídy</string>
|
||||
<string name="pref_view_subjects_without_grades">Zobrazit předměty bez známek</string>
|
||||
<string name="pref_view_grade_color_scheme">Známky barevné schéma</string>
|
||||
@ -738,6 +747,8 @@
|
||||
<string name="pref_other_grade_modifier_minus">Hodnota mínusu</string>
|
||||
<string name="pref_other_fill_message_content">Odpovědět s historií zpráv</string>
|
||||
<string name="pref_other_optional_arithmetic_average">Vypočítat aritmetický průměr, pokud žádná známka nemá váhu</string>
|
||||
<string name="pref_other_incognito_mode">Anonymní režim</string>
|
||||
<string name="pref_other_incognito_mode_summary">Neinformovat o přečtení zprávy</string>
|
||||
<string name="pref_ads_support_category_name">Podpora</string>
|
||||
<string name="pref_ads_privacy_policy">Ochrana osobních údajů</string>
|
||||
<string name="pref_ads_agreements">Souhlasy</string>
|
||||
|
@ -51,6 +51,11 @@
|
||||
<item>Average of averages from both semesters</item>
|
||||
<item>Average of grades from the whole year</item>
|
||||
</string-array>
|
||||
<string-array name="timetable_show_gaps_entries">
|
||||
<item>Don\'t show</item>
|
||||
<item>Only between lessons</item>
|
||||
<item>Before and between lessons</item>
|
||||
</string-array>
|
||||
<string-array name="dashboard_tile_entries">
|
||||
<item>Lucky number</item>
|
||||
<item>Unread messages</item>
|
||||
|
@ -171,6 +171,10 @@
|
||||
<string name="timetable_notify_change_room">Change of room from %1$s to %2$s</string>
|
||||
<string name="timetable_notify_change_teacher">Change of teacher from %1$s to %2$s</string>
|
||||
<string name="timetable_notify_change_subject">Change of subject from %1$s to %2$s</string>
|
||||
<plurals name="timetable_no_lesson">
|
||||
<item quantity="one">No lesson</item>
|
||||
<item quantity="other">No lessons</item>
|
||||
</plurals>
|
||||
<plurals name="timetable_notify_new_items_title">
|
||||
<item quantity="one">Timetable change</item>
|
||||
<item quantity="other">Timetable changes</item>
|
||||
@ -310,6 +314,8 @@
|
||||
</plurals>
|
||||
<string name="message_messages_deleted">Messages deleted</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_description">Thanks to incognito mode sender is not notified when you read the message</string>
|
||||
<!--Note-->
|
||||
<string name="note_no_items">No info about notes</string>
|
||||
<string name="note_points">Points</string>
|
||||
@ -610,6 +616,7 @@
|
||||
<string name="pref_view_expand_grade">Grades expanding</string>
|
||||
<string name="pref_view_timetable_show_timers">Mark current lesson</string>
|
||||
<string name="pref_view_timetable_show_groups">Show groups next to subjects</string>
|
||||
<string name="pref_view_timetable_show_gaps">Show empty tiles where there\'s no lesson</string>
|
||||
<string name="pref_view_grade_statistics_list">Show chart list in class grades</string>
|
||||
<string name="pref_view_subjects_without_grades">Show subjects without grades</string>
|
||||
<string name="pref_view_grade_color_scheme">Grades color scheme</string>
|
||||
@ -650,6 +657,8 @@
|
||||
<string name="pref_other_grade_modifier_minus">Value of the minus</string>
|
||||
<string name="pref_other_fill_message_content">Reply with message history</string>
|
||||
<string name="pref_other_optional_arithmetic_average">Show arithmetic average when no weights provided</string>
|
||||
<string name="pref_other_incognito_mode">Incognito mode</string>
|
||||
<string name="pref_other_incognito_mode_summary">Do not inform about reading the message</string>
|
||||
<string name="pref_ads_support_category_name">Support</string>
|
||||
<string name="pref_ads_privacy_policy">Privacy Policy</string>
|
||||
<string name="pref_ads_agreements">Agreements</string>
|
||||
|
@ -51,6 +51,11 @@
|
||||
<item>Durchschnittswert der Durchschnittswerte beider Semester</item>
|
||||
<item>Durchschnitt der Noten aus dem ganzen Jahr</item>
|
||||
</string-array>
|
||||
<string-array name="timetable_show_gaps_entries">
|
||||
<item>Don\'t show</item>
|
||||
<item>Only between lessons</item>
|
||||
<item>Before and between lessons</item>
|
||||
</string-array>
|
||||
<string-array name="dashboard_tile_entries">
|
||||
<item>Glückszahl</item>
|
||||
<item>Ungelesene Nachrichten</item>
|
||||
|
@ -171,6 +171,10 @@
|
||||
<string name="timetable_notify_change_room">Änderung des Raumes von %1$s zu %2$s</string>
|
||||
<string name="timetable_notify_change_teacher">Wechsel des Lehrers von %1$s zu %2$s</string>
|
||||
<string name="timetable_notify_change_subject">Thema von %1$s zu %2$s wechseln</string>
|
||||
<plurals name="timetable_no_lesson">
|
||||
<item quantity="one">No lesson</item>
|
||||
<item quantity="other">No lessons</item>
|
||||
</plurals>
|
||||
<plurals name="timetable_notify_new_items_title">
|
||||
<item quantity="one">Änderung des Zeitplans</item>
|
||||
<item quantity="other">Änderungen des Zeitplans</item>
|
||||
@ -310,6 +314,8 @@
|
||||
</plurals>
|
||||
<string name="message_messages_deleted">Nachrichten gelöscht</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_description">Thanks to incognito mode sender is not notified when you read the message</string>
|
||||
<!--Note-->
|
||||
<string name="note_no_items">Keine Informationen über Eintragen</string>
|
||||
<string name="note_points">Punkte</string>
|
||||
@ -610,6 +616,7 @@
|
||||
<string name="pref_view_expand_grade">Steigende Sorten</string>
|
||||
<string name="pref_view_timetable_show_timers">Aktuelle Lektion markieren</string>
|
||||
<string name="pref_view_timetable_show_groups">Gruppen neben Schulfächen anzeigen</string>
|
||||
<string name="pref_view_timetable_show_gaps">Show empty tiles where there\'s no lesson</string>
|
||||
<string name="pref_view_grade_statistics_list">Liste der Diagramme in Klassenbewertungen anzeigen</string>
|
||||
<string name="pref_view_subjects_without_grades">Schulfächer ohne Noten anzeigen</string>
|
||||
<string name="pref_view_grade_color_scheme">Farbschema der Noten</string>
|
||||
@ -650,6 +657,8 @@
|
||||
<string name="pref_other_grade_modifier_minus">Wert des Minus</string>
|
||||
<string name="pref_other_fill_message_content">Antwort mit Nachrichtenhistorie</string>
|
||||
<string name="pref_other_optional_arithmetic_average">Arithmetisches Mittel anzeigen, wenn keine Gewichte angegeben sind</string>
|
||||
<string name="pref_other_incognito_mode">Incognito mode</string>
|
||||
<string name="pref_other_incognito_mode_summary">Do not inform about reading the message</string>
|
||||
<string name="pref_ads_support_category_name">Unterstützung</string>
|
||||
<string name="pref_ads_privacy_policy">Datenschutz-Bestimmungen</string>
|
||||
<string name="pref_ads_agreements">Vereinbarungen</string>
|
||||
|
@ -51,6 +51,11 @@
|
||||
<item>Average of averages from both semesters</item>
|
||||
<item>Average of grades from the whole year</item>
|
||||
</string-array>
|
||||
<string-array name="timetable_show_gaps_entries">
|
||||
<item>Don\'t show</item>
|
||||
<item>Only between lessons</item>
|
||||
<item>Before and between lessons</item>
|
||||
</string-array>
|
||||
<string-array name="dashboard_tile_entries">
|
||||
<item>Lucky number</item>
|
||||
<item>Unread messages</item>
|
||||
|
@ -171,6 +171,10 @@
|
||||
<string name="timetable_notify_change_room">Change of room from %1$s to %2$s</string>
|
||||
<string name="timetable_notify_change_teacher">Change of teacher from %1$s to %2$s</string>
|
||||
<string name="timetable_notify_change_subject">Change of subject from %1$s to %2$s</string>
|
||||
<plurals name="timetable_no_lesson">
|
||||
<item quantity="one">No lesson</item>
|
||||
<item quantity="other">No lessons</item>
|
||||
</plurals>
|
||||
<plurals name="timetable_notify_new_items_title">
|
||||
<item quantity="one">Timetable change</item>
|
||||
<item quantity="other">Timetable changes</item>
|
||||
@ -310,6 +314,8 @@
|
||||
</plurals>
|
||||
<string name="message_messages_deleted">Messages deleted</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_description">Thanks to incognito mode sender is not notified when you read the message</string>
|
||||
<!--Note-->
|
||||
<string name="note_no_items">No info about notes</string>
|
||||
<string name="note_points">Points</string>
|
||||
@ -610,6 +616,7 @@
|
||||
<string name="pref_view_expand_grade">Grades expanding</string>
|
||||
<string name="pref_view_timetable_show_timers">Mark current lesson</string>
|
||||
<string name="pref_view_timetable_show_groups">Show groups next to subjects</string>
|
||||
<string name="pref_view_timetable_show_gaps">Show empty tiles where there\'s no lesson</string>
|
||||
<string name="pref_view_grade_statistics_list">Show chart list in class grades</string>
|
||||
<string name="pref_view_subjects_without_grades">Show subjects without grades</string>
|
||||
<string name="pref_view_grade_color_scheme">Grades color scheme</string>
|
||||
@ -650,6 +657,8 @@
|
||||
<string name="pref_other_grade_modifier_minus">Value of the minus</string>
|
||||
<string name="pref_other_fill_message_content">Reply with message history</string>
|
||||
<string name="pref_other_optional_arithmetic_average">Show arithmetic average when no weights provided</string>
|
||||
<string name="pref_other_incognito_mode">Incognito mode</string>
|
||||
<string name="pref_other_incognito_mode_summary">Do not inform about reading the message</string>
|
||||
<string name="pref_ads_support_category_name">Support</string>
|
||||
<string name="pref_ads_privacy_policy">Privacy Policy</string>
|
||||
<string name="pref_ads_agreements">Agreements</string>
|
||||
|
70
app/src/main/res/values-it-rIT/preferences_values.xml
Normal file
70
app/src/main/res/values-it-rIT/preferences_values.xml
Normal file
@ -0,0 +1,70 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<string-array name="app_theme_entries" tools:ignore="InconsistentArrays">
|
||||
<item>Light</item>
|
||||
<item>Dark</item>
|
||||
<item>Black (AMOLED)</item>
|
||||
</string-array>
|
||||
<string-array name="app_language_entries">
|
||||
<item>System language</item>
|
||||
<item>Polski</item>
|
||||
<item>English</item>
|
||||
<item>Pусский</item>
|
||||
<item>Українська</item>
|
||||
<item>Deutsch</item>
|
||||
<item>Čeština</item>
|
||||
<item>Slovenčina</item>
|
||||
</string-array>
|
||||
<string-array name="services_interval_entries">
|
||||
<item>15 minutes</item>
|
||||
<item>30 minutes</item>
|
||||
<item>1 hour</item>
|
||||
<item>2 hours</item>
|
||||
<item>6 hours</item>
|
||||
<item>12 hours</item>
|
||||
<item>24 hours</item>
|
||||
</string-array>
|
||||
<string-array name="grade_modifier_entries">
|
||||
<item>0,00</item>
|
||||
<item>0,25</item>
|
||||
<item>0,33</item>
|
||||
<item>0,5</item>
|
||||
<item>0,75</item>
|
||||
</string-array>
|
||||
<string-array name="grade_sorting_mode_entries">
|
||||
<item>Alphabetically</item>
|
||||
<item>By date</item>
|
||||
<item>By average</item>
|
||||
</string-array>
|
||||
<string-array name="grade_color_scheme_entries">
|
||||
<item>Dzienniczek+</item>
|
||||
<item>Wulkanowy</item>
|
||||
<item>Grade colors in register</item>
|
||||
</string-array>
|
||||
<string-array name="default_expand_grade_entries">
|
||||
<item>Up to 1 at once</item>
|
||||
<item>Always expanded</item>
|
||||
<item>Unlimited expansions</item>
|
||||
</string-array>
|
||||
<string-array name="grade_average_mode_entries">
|
||||
<item>Average of grades only from selected semester</item>
|
||||
<item>Average of averages from both semesters</item>
|
||||
<item>Average of grades from the whole year</item>
|
||||
</string-array>
|
||||
<string-array name="timetable_show_gaps_entries">
|
||||
<item>Don\'t show</item>
|
||||
<item>Only between lessons</item>
|
||||
<item>Before and between lessons</item>
|
||||
</string-array>
|
||||
<string-array name="dashboard_tile_entries">
|
||||
<item>Lucky number</item>
|
||||
<item>Unread messages</item>
|
||||
<item>Attendance</item>
|
||||
<item>Lessons</item>
|
||||
<item>Grades</item>
|
||||
<item>Homework</item>
|
||||
<item>School announcements</item>
|
||||
<item>Exams</item>
|
||||
<item>Conferences</item>
|
||||
</string-array>
|
||||
</resources>
|
756
app/src/main/res/values-it-rIT/strings.xml
Normal file
756
app/src/main/res/values-it-rIT/strings.xml
Normal file
@ -0,0 +1,756 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!--Activity/Fragment title-->
|
||||
<string name="login_title">Login</string>
|
||||
<string name="main_title">Wulkanowy</string>
|
||||
<string name="grade_title">Grades</string>
|
||||
<string name="attendance_title">Attendance</string>
|
||||
<string name="exam_title">Exams</string>
|
||||
<string name="timetable_title">Timetable</string>
|
||||
<string name="settings_title">Settings</string>
|
||||
<string name="more_title">More</string>
|
||||
<string name="about_title">About</string>
|
||||
<string name="logviewer_title">Log viewer</string>
|
||||
<string name="debug_title">Debug</string>
|
||||
<string name="notification_debug_title">Notification debug</string>
|
||||
<string name="contributors_title">Contributors</string>
|
||||
<string name="license_title">Licenses</string>
|
||||
<string name="message_title">Messages</string>
|
||||
<string name="send_message_title">New message</string>
|
||||
<string name="add_homework_title">New homework</string>
|
||||
<string name="note_title">Notes and achievements</string>
|
||||
<string name="homework_title">Homework</string>
|
||||
<string name="account_title">Accounts manager</string>
|
||||
<string name="account_quick_title">Select account</string>
|
||||
<string name="account_details_title">Account details</string>
|
||||
<string name="student_info_title">Student info</string>
|
||||
<string name="dashboard_title">Dashboard</string>
|
||||
<string name="notifications_center_title">Notifications center</string>
|
||||
<string name="menu_order_title">Menu configuartion</string>
|
||||
<!--Subtitles-->
|
||||
<string name="grade_subtitle">Semester %1$d, %2$d/%3$d</string>
|
||||
<!--Login-->
|
||||
<string name="login_header_default">Sign in with the student or parent account</string>
|
||||
<string name="login_header_symbol">Enter the symbol from the register page for account: <b>%1$s</b></string>
|
||||
<string name="login_nickname_hint">Username</string>
|
||||
<string name="login_email_hint">Email</string>
|
||||
<string name="login_login_pesel_email_hint">Login, PESEL or e-mail</string>
|
||||
<string name="login_password_hint">Password</string>
|
||||
<string name="login_host_hint">UONET+ register variant</string>
|
||||
<string name="login_domain_suffix_hint">Custom domain suffix</string>
|
||||
<string name="login_type_api">Mobile API</string>
|
||||
<string name="login_type_scrapper">Scraper</string>
|
||||
<string name="login_type_hybrid">Hybrid</string>
|
||||
<string name="login_token_hint">Token</string>
|
||||
<string name="login_pin_hint">PIN</string>
|
||||
<string name="login_symbol_hint">Symbol</string>
|
||||
<string name="login_sign_in">Sign in</string>
|
||||
<string name="login_invalid_password">Password too short</string>
|
||||
<string name="login_incorrect_password_default">Login details are incorrect</string>
|
||||
<string name="login_incorrect_password">%1$s. Make sure the correct UONET+ register variation is selected below</string>
|
||||
<string name="login_invalid_pin">Invalid PIN</string>
|
||||
<string name="login_invalid_token">Invalid token</string>
|
||||
<string name="login_expired_token">Token expired</string>
|
||||
<string name="login_invalid_email">Invalid email</string>
|
||||
<string name="login_invalid_login">Use the assigned login instead of email</string>
|
||||
<string name="login_invalid_custom_email">Use the assigned login or email in @%1$s</string>
|
||||
<string name="login_invalid_symbol">Invalid symbol</string>
|
||||
<string name="login_incorrect_symbol">Student not found. Validate the symbol and the chosen variation of the UONET+ register</string>
|
||||
<string name="login_duplicate_student">Selected student is already logged in</string>
|
||||
<string name="login_symbol_helper">The symbol can be found on the register page in <b>Uczeń</b> → <b>Dostęp Mobilny</b> → <b>Wygeneruj kod dostępu</b>.\n\nMake sure that you have set the appropriate register variant in the <b>UONET+ register variant</b> field on the first login screen</string>
|
||||
<string name="login_select_student">Select students to log in to the application</string>
|
||||
<string name="login_advanced">Other options</string>
|
||||
<string name="login_advanced_warning_mobile_api">In this mode, a lucky number does not work, a class grade stats, summary of attendance, excuse for absence, completed lessons, school information and preview of the list of registered devices</string>
|
||||
<string name="login_advanced_warning_scraper">This mode displays the same data as it appears on the register website</string>
|
||||
<string name="login_advanced_warning_hybrid">The combination of the best features of the other two modes. It works faster than scraper and provides features not available in the Mobile API mode. It is in the experimental phase</string>
|
||||
<string name="login_privacy_policy">Privacy policy</string>
|
||||
<string name="login_contact_header">Trouble signing in? Contact us!</string>
|
||||
<string name="login_contact_email">Email</string>
|
||||
<string name="login_contact_discord">Discord</string>
|
||||
<string name="login_email_intent_title">Send email</string>
|
||||
<string name="login_recover_warning">Make sure you select the correct UONET+ register variation!</string>
|
||||
<string name="login_recover_button">I forgot my password</string>
|
||||
<string name="login_recover_title">Recover your account</string>
|
||||
<string name="login_recover">Recover</string>
|
||||
<string name="login_signed_in">Student is already signed in</string>
|
||||
<string name="login_host_standard">Standard</string>
|
||||
<string name="login_other_search_locations">Other search locations</string>
|
||||
<string name="login_no_active_student">No active students found</string>
|
||||
<string name="login_symbol_enter">Enter a different symbol</string>
|
||||
<!--Notifications-->
|
||||
<string name="notifications_header_title">Enable notifications</string>
|
||||
<string name="notifications_header_description">Enable notifications so you don\'t miss message from teacher or new grade</string>
|
||||
<string name="notifications_skip">Skip</string>
|
||||
<string name="notifications_enable">Enable</string>
|
||||
<!--Main-->
|
||||
<string name="main_account_picker">Account manager</string>
|
||||
<string name="main_log_in">Log in</string>
|
||||
<string name="main_session_expired">Session expired</string>
|
||||
<string name="main_session_relogin">Session expired, log in again</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_positive">Enable ads</string>
|
||||
<!--Grade-->
|
||||
<string name="grade_header">Grade</string>
|
||||
<string name="grade_semester">Semester %d</string>
|
||||
<string name="grade_switch_semester">Change semester</string>
|
||||
<string name="grade_no_items">No grades</string>
|
||||
<string name="grade_weight">Weight</string>
|
||||
<string name="grade_weight_value">Weight: %s</string>
|
||||
<string name="grade_comment">Comment</string>
|
||||
<string name="grade_number_new_items">Number of new ratings: %1$d</string>
|
||||
<string name="grade_average">Average: %1$.2f</string>
|
||||
<string name="grade_points_sum">Points: %s</string>
|
||||
<string name="grade_no_average">No average</string>
|
||||
<string name="grade_summary_points">Total points</string>
|
||||
<string name="grade_summary_final_grade">Final grade</string>
|
||||
<string name="grade_summary_predicted_grade">Predicted grade</string>
|
||||
<string name="grade_summary_calculated_average">Calculated average</string>
|
||||
<string name="grade_summary_calculated_average_help_dialog_title">How does Calculated Average work?</string>
|
||||
<string name="grade_summary_calculated_average_help_dialog_message">The Calculated Average is the arithmetic average calculated from the subjects averages. It allows you to know the approximate final average. It is calculated in a way selected by the user in the application settings. It is recommended that you choose the appropriate option. This is because the calculation of school averages differs. Additionally, if your school reports the average of the subjects on the Vulcan page, the application downloads them and does not calculate these averages. This can be changed by forcing the calculation of the average in the application settings.\n\n<b>Average of grades only from selected semester</b>:\n1. Calculating the weighted average for each subject in a given semester\n2.Adding calculated averages\n3. Calculation of the arithmetic average of the summed averages\n\n<b>Average of averages from both semesters</b>:\n1.Calculating the weighted average for each subject in semester 1 and 2\n2. Calculating the arithmetic average of the calculated averages for semesters 1 and 2 for each subject.\n3. Adding calculated averages\n4. Calculation of the arithmetic average of the summed averages\n\n<b>Average of grades from the whole year:</b>\n1. Calculating weighted average over the year for each subject. The final average in the 1st semester is irrelevant.\n2. Adding calculated averages\n3. Calculating the arithmetic average of summed averages</string>
|
||||
<string name="grade_summary_final_average_help_dialog_title">How does the Final Average work?</string>
|
||||
<string name="grade_summary_final_average_help_dialog_message">The Final Average is the arithmetic average calculated from all currently available final grades in the given semester.\n\nThe calculation scheme consists of the following steps:\n1. Summing up the final grades given by teachers\n2. Divide by the number of subjects that have already been graded</string>
|
||||
<string name="grade_summary_final_average">Final average</string>
|
||||
<string name="grade_summary_from_subjects">from %1$d of %2$d subjects</string>
|
||||
<string name="grade_menu_summary">Summary</string>
|
||||
<string name="grade_menu_statistics">Class</string>
|
||||
<string name="grade_menu_read">Mark as read</string>
|
||||
<string name="grade_statistics_partial">Partial</string>
|
||||
<string name="grade_statistics_semester">Semester</string>
|
||||
<string name="grade_statistics_points">Points</string>
|
||||
<string name="grade_statistics_legend">Legend</string>
|
||||
<string name="grade_statistics_class_average">Class average: %1$s</string>
|
||||
<string name="grade_statistics_student_average">Your average: %1$s</string>
|
||||
<string name="grade_statistics_student_grade">Your grade: %1$s</string>
|
||||
<string name="grade_statistics_average_class">Class</string>
|
||||
<string name="grade_statistics_average_student">Student</string>
|
||||
<plurals name="grade_number_item">
|
||||
<item quantity="one">%d grade</item>
|
||||
<item quantity="other">%d grades</item>
|
||||
</plurals>
|
||||
<plurals name="grade_new_items">
|
||||
<item quantity="one">New grade</item>
|
||||
<item quantity="other">New grades</item>
|
||||
</plurals>
|
||||
<plurals name="grade_new_items_predicted">
|
||||
<item quantity="one">New predicted grade</item>
|
||||
<item quantity="other">New predicted grades</item>
|
||||
</plurals>
|
||||
<plurals name="grade_new_items_final">
|
||||
<item quantity="one">New final grade</item>
|
||||
<item quantity="other">New final grades</item>
|
||||
</plurals>
|
||||
<plurals name="grade_notify_new_items">
|
||||
<item quantity="one">You received %1$d grade</item>
|
||||
<item quantity="other">You received %1$d grades</item>
|
||||
</plurals>
|
||||
<plurals name="grade_notify_new_items_predicted">
|
||||
<item quantity="one">You received %1$d predicted grade</item>
|
||||
<item quantity="other">You received %1$d predicted grades</item>
|
||||
</plurals>
|
||||
<plurals name="grade_notify_new_items_final">
|
||||
<item quantity="one">You received %1$d final grade</item>
|
||||
<item quantity="other">You received %1$d final grades</item>
|
||||
</plurals>
|
||||
<!--Timetable-->
|
||||
<string name="timetable_lesson">Lesson</string>
|
||||
<string name="timetable_room">Room</string>
|
||||
<string name="timetable_group">Group</string>
|
||||
<string name="timetable_time">Hours</string>
|
||||
<string name="timetable_changes">Changes</string>
|
||||
<string name="timetable_no_items">No lessons this day</string>
|
||||
<string name="timetable_minutes">%s min</string>
|
||||
<string name="timetable_seconds">%s sec</string>
|
||||
<string name="timetable_time_left">%1$s left</string>
|
||||
<string name="timetable_time_until">in %1$s</string>
|
||||
<string name="timetable_finished">Finished</string>
|
||||
<string name="timetable_now">Now: %s</string>
|
||||
<string name="timetable_next">Next: %s</string>
|
||||
<string name="timetable_later">Later: %s</string>
|
||||
<string name="timetable_notify_lesson">%1$s lesson %2$d - %3$s</string>
|
||||
<string name="timetable_notify_change_room">Change of room from %1$s to %2$s</string>
|
||||
<string name="timetable_notify_change_teacher">Change of teacher from %1$s to %2$s</string>
|
||||
<string name="timetable_notify_change_subject">Change of subject from %1$s to %2$s</string>
|
||||
<plurals name="timetable_no_lesson">
|
||||
<item quantity="one">No lesson</item>
|
||||
<item quantity="other">No lessons</item>
|
||||
</plurals>
|
||||
<plurals name="timetable_notify_new_items_title">
|
||||
<item quantity="one">Timetable change</item>
|
||||
<item quantity="other">Timetable changes</item>
|
||||
</plurals>
|
||||
<plurals name="timetable_notify_new_items">
|
||||
<item quantity="one">%1$s - %2$d change in timetable</item>
|
||||
<item quantity="other">%1$s - %2$d changes in timetable</item>
|
||||
</plurals>
|
||||
<plurals name="timetable_notify_new_items_group">
|
||||
<item quantity="one">%1$d change in timetable</item>
|
||||
<item quantity="other">%1$d changes in timetable</item>
|
||||
</plurals>
|
||||
<plurals name="timetable_number_item">
|
||||
<item quantity="one">%d change</item>
|
||||
<item quantity="other">%d changes</item>
|
||||
</plurals>
|
||||
<!--Completed lessons-->
|
||||
<string name="completed_lessons_title">Completed lessons</string>
|
||||
<string name="completed_lessons_button">Show completed lessons</string>
|
||||
<string name="completed_lessons_no_items">No info about completed lessons</string>
|
||||
<string name="completed_lessons_topic">Topic</string>
|
||||
<string name="completed_lessons_absence">Absence</string>
|
||||
<string name="completed_lessons_resources">Resources</string>
|
||||
<!--Additional lessons-->
|
||||
<string name="additional_lessons_title">Additional lessons</string>
|
||||
<string name="additional_lessons_button">Show additional lessons</string>
|
||||
<string name="additional_lessons_no_items">No info about additional lessons</string>
|
||||
<string name="additional_lessons_add">New lesson</string>
|
||||
<string name="additional_lessons_add_title">New additional lesson</string>
|
||||
<string name="additional_lessons_add_success">Additional lesson added successfully</string>
|
||||
<string name="additional_lessons_delete_success">Additional lesson deleted successfully</string>
|
||||
<string name="additional_lessons_repeat">Repeat weekly</string>
|
||||
<string name="additional_lessons_delete_title">Delete additional lesson</string>
|
||||
<string name="additional_lessons_delete_one">Just this lesson</string>
|
||||
<string name="additional_lessons_delete_series">All in the series</string>
|
||||
<string name="additional_lessons_start">Start time</string>
|
||||
<string name="additional_lessons_end">End time</string>
|
||||
<string name="additional_lessons_end_time_error">End time must be greater than start time</string>
|
||||
<!--Attendance-->
|
||||
<string name="attendance_summary_button">Attendance summary</string>
|
||||
<string name="attendance_absence_school">Absent for school reasons</string>
|
||||
<string name="attendance_absence_excused">Excused absence</string>
|
||||
<string name="attendance_absence_unexcused">Unexcused absence</string>
|
||||
<string name="attendance_exemption">Exemption</string>
|
||||
<string name="attendance_excused_lateness">Excused lateness</string>
|
||||
<string name="attendance_unexcused_lateness">Unexcused lateness</string>
|
||||
<string name="attendance_present">Present</string>
|
||||
<string name="attendance_deleted">Deleted</string>
|
||||
<string name="attendance_unknown">Unknown</string>
|
||||
<string name="attendance_number">Number of lesson</string>
|
||||
<string name="attendance_no_items">No entries</string>
|
||||
<string name="attendance_excuse_dialog_reason">Absence reason (optional)</string>
|
||||
<string name="attendance_excuse_dialog_submit">Send</string>
|
||||
<string name="attendance_excuse_success">Absence excuse request sent successfully!</string>
|
||||
<string name="attendance_excuse_no_selection">You must select at least one absence!</string>
|
||||
<string name="attendance_excuse_title">Excuse</string>
|
||||
<plurals name="attendance_notify_new_items_title">
|
||||
<item quantity="one">New attendance</item>
|
||||
<item quantity="other">New attendance</item>
|
||||
</plurals>
|
||||
<plurals name="attendance_notify_new_items">
|
||||
<item quantity="one">%1$d new attendance</item>
|
||||
<item quantity="other">%1$d attendance</item>
|
||||
</plurals>
|
||||
<plurals name="attendance_number_item">
|
||||
<item quantity="one">%d attendance</item>
|
||||
<item quantity="other">%d attendance</item>
|
||||
</plurals>
|
||||
<!--Attendance summary-->
|
||||
<string name="attendance_summary_total">Total</string>
|
||||
<!--Exam-->
|
||||
<string name="exam_no_items">No exams this week</string>
|
||||
<string name="exam_type">Type</string>
|
||||
<string name="exam_entry_date">Entry date</string>
|
||||
<plurals name="exam_notify_new_item_title">
|
||||
<item quantity="one">New exam</item>
|
||||
<item quantity="other">New exams</item>
|
||||
</plurals>
|
||||
<plurals name="exam_notify_new_item_content">
|
||||
<item quantity="one">%d new exam</item>
|
||||
<item quantity="other">%d new exams</item>
|
||||
</plurals>
|
||||
<plurals name="exam_number_item">
|
||||
<item quantity="one">%d exam</item>
|
||||
<item quantity="other">%d exams</item>
|
||||
</plurals>
|
||||
<!--Message-->
|
||||
<string name="message_inbox">Inbox</string>
|
||||
<string name="message_sent">Sent</string>
|
||||
<string name="message_trash">Trash</string>
|
||||
<string name="message_no_subject">(no subject)</string>
|
||||
<string name="message_no_items">No messages</string>
|
||||
<string name="message_from">From:</string>
|
||||
<string name="message_to">To:</string>
|
||||
<string name="message_date">Date: %1$s</string>
|
||||
<string name="message_reply">Reply</string>
|
||||
<string name="message_forward">Forward</string>
|
||||
<string name="message_select_all">Select all</string>
|
||||
<string name="message_unselect_all">Unselect all</string>
|
||||
<string name="message_move_to_trash">Move to trash</string>
|
||||
<string name="message_delete_forever">Delete permanently</string>
|
||||
<string name="message_delete_success">Message deleted successfully</string>
|
||||
<string name="message_mailbox_type_student">student</string>
|
||||
<string name="message_mailbox_type_parent">parent</string>
|
||||
<string name="message_mailbox_type_guardian">guardian</string>
|
||||
<string name="message_mailbox_type_employee">employee</string>
|
||||
<string name="message_share">Share</string>
|
||||
<string name="message_print">Print</string>
|
||||
<string name="message_subject">Subject</string>
|
||||
<string name="message_content">Content</string>
|
||||
<string name="message_send_successful">Message sent successfully</string>
|
||||
<string name="message_not_exists">Message does not exist</string>
|
||||
<string name="message_required_recipients">You need to choose at least 1 recipient</string>
|
||||
<string name="message_content_min_length">The message content must be at least 3 characters</string>
|
||||
<string name="message_chip_all_mailboxes">All mailboxes</string>
|
||||
<string name="message_chip_only_unread">Only unread</string>
|
||||
<string name="message_chip_only_with_attachments">Only with attachments</string>
|
||||
<string name="message_read">Read: %s</string>
|
||||
<string name="message_read_by">Read by: %1$d of %2$d people</string>
|
||||
<plurals name="message_number_item">
|
||||
<item quantity="one">%1$d message</item>
|
||||
<item quantity="other">%1$d messages</item>
|
||||
</plurals>
|
||||
<plurals name="message_new_items">
|
||||
<item quantity="one">New message</item>
|
||||
<item quantity="other">New messages</item>
|
||||
</plurals>
|
||||
<string name="message_restore_dialog">Do you want to restore draft message?</string>
|
||||
<string name="message_restore_dialog_with_recipients">Do you want to restore draft message with recipients: %s?</string>
|
||||
<plurals name="message_notify_new_items">
|
||||
<item quantity="one">You received %1$d message</item>
|
||||
<item quantity="other">You received %1$d messages</item>
|
||||
</plurals>
|
||||
<plurals name="message_selected_messages_count">
|
||||
<item quantity="one">%1$d selected</item>
|
||||
<item quantity="other">%1$d selected</item>
|
||||
</plurals>
|
||||
<string name="message_messages_deleted">Messages deleted</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_description">Thanks to incognito mode sender is not notified when you read the message</string>
|
||||
<!--Note-->
|
||||
<string name="note_no_items">No info about notes</string>
|
||||
<string name="note_points">Points</string>
|
||||
<plurals name="note_number_item">
|
||||
<item quantity="one">%d note</item>
|
||||
<item quantity="other">%d notes</item>
|
||||
</plurals>
|
||||
<plurals name="note_new_items">
|
||||
<item quantity="one">New note</item>
|
||||
<item quantity="other">New notes</item>
|
||||
</plurals>
|
||||
<plurals name="note_notify_new_items">
|
||||
<item quantity="one">You received %1$d note</item>
|
||||
<item quantity="other">You received %1$d notes</item>
|
||||
</plurals>
|
||||
<!--Praise-->
|
||||
<plurals name="praise_number_item">
|
||||
<item quantity="one">%d praise</item>
|
||||
<item quantity="other">%d praises</item>
|
||||
</plurals>
|
||||
<plurals name="praise_new_items">
|
||||
<item quantity="one">New praise</item>
|
||||
<item quantity="other">New praises</item>
|
||||
</plurals>
|
||||
<plurals name="praise_notify_new_items">
|
||||
<item quantity="one">You received %1$d praise</item>
|
||||
<item quantity="other">You received %1$d praises</item>
|
||||
</plurals>
|
||||
<!--Neutral notes-->
|
||||
<plurals name="neutral_note_number_item">
|
||||
<item quantity="one">%d neutral note</item>
|
||||
<item quantity="other">%d neutral notes</item>
|
||||
</plurals>
|
||||
<plurals name="neutral_note_new_items">
|
||||
<item quantity="one">New neutral note</item>
|
||||
<item quantity="other">New neutral notes</item>
|
||||
</plurals>
|
||||
<plurals name="neutral_note_notify_new_items">
|
||||
<item quantity="one">You received %1$d neutral note</item>
|
||||
<item quantity="other">You received %1$d neutral notes</item>
|
||||
</plurals>
|
||||
<!--Homework-->
|
||||
<string name="homework_no_items">No info about homework</string>
|
||||
<string name="homework_mark_as_done">Mark as done</string>
|
||||
<string name="homework_mark_as_undone">Mark as undone</string>
|
||||
<string name="homework_add">Add homework</string>
|
||||
<string name="homework_add_success">Homework added successfully</string>
|
||||
<string name="homework_delete_success">Homework deleted successfully</string>
|
||||
<string name="homework_attachments">Attachments</string>
|
||||
<plurals name="homework_notify_new_item_title">
|
||||
<item quantity="one">New homework</item>
|
||||
<item quantity="other">New homework</item>
|
||||
</plurals>
|
||||
<plurals name="homework_notify_new_item_content">
|
||||
<item quantity="one">You received %d new homework</item>
|
||||
<item quantity="other">You received %d new homework</item>
|
||||
</plurals>
|
||||
<plurals name="homework_number_item">
|
||||
<item quantity="one">%d homework</item>
|
||||
<item quantity="other">%d homework</item>
|
||||
</plurals>
|
||||
<!--Lucky number-->
|
||||
<string name="lucky_number_title">Lucky number</string>
|
||||
<string name="lucky_number_header">Today\'s lucky number is</string>
|
||||
<string name="lucky_number_empty">No info about the lucky number</string>
|
||||
<string name="lucky_number_notify_new_item_title">Lucky number for today</string>
|
||||
<string name="lucky_number_notify_new_item">Today\'s lucky number is: %s</string>
|
||||
<string name="lucky_number_history_button">Show history</string>
|
||||
<!--Lucky number history-->
|
||||
<string name="lucky_number_history_title">Lucky number history</string>
|
||||
<string name="lucky_number_history_empty">No info about lucky numbers</string>
|
||||
<!--Mobile devices-->
|
||||
<string name="mobile_devices_title">Mobile devices</string>
|
||||
<string name="mobile_devices_no_items">No devices</string>
|
||||
<string name="mobile_devices_unregister">Deregister</string>
|
||||
<string name="mobile_device_removed">Device removed</string>
|
||||
<string name="mobile_device_qr">QR code</string>
|
||||
<string name="mobile_device_token">Token</string>
|
||||
<string name="mobile_device_symbol">Symbol</string>
|
||||
<string name="mobile_device_pin">PIN</string>
|
||||
<!--School and teachers-->
|
||||
<string name="schoolandteachers_title">School and teachers</string>
|
||||
<!--School-->
|
||||
<string name="school_title">School</string>
|
||||
<string name="school_no_info">No info about school</string>
|
||||
<string name="school_name">School name</string>
|
||||
<string name="school_address">School address</string>
|
||||
<string name="school_telephone">Telephone</string>
|
||||
<string name="school_headmaster">Name of headmaster</string>
|
||||
<string name="school_pedagogue">Name of pedagogue</string>
|
||||
<string name="school_address_button">Show on map</string>
|
||||
<string name="school_telephone_button">Call</string>
|
||||
<!--Teacher-->
|
||||
<string name="teachers_title">Teachers</string>
|
||||
<string name="teacher_no_items">No info about teachers</string>
|
||||
<string name="teacher_no_subject">No subject</string>
|
||||
<!--Conference-->
|
||||
<string name="conferences_title">Conferences</string>
|
||||
<string name="conference_no_items">No info about conferences</string>
|
||||
<plurals name="conference_number_item">
|
||||
<item quantity="one">%d conference</item>
|
||||
<item quantity="other">%d conferences</item>
|
||||
</plurals>
|
||||
<plurals name="conference_notify_new_item_title">
|
||||
<item quantity="one">New conference</item>
|
||||
<item quantity="other">New conferences</item>
|
||||
</plurals>
|
||||
<plurals name="conference_notify_new_items">
|
||||
<item quantity="one">You have %1$d new conference</item>
|
||||
<item quantity="other">You have %1$d new conferences</item>
|
||||
</plurals>
|
||||
<string name="conferences_present">Present at conference</string>
|
||||
<string name="conference_agenda">Agenda</string>
|
||||
<string name="conference_place">Place</string>
|
||||
<string name="conference_topic">Topic</string>
|
||||
<!--Director information-->
|
||||
<string name="school_announcement_title">School announcements</string>
|
||||
<string name="school_announcement_no_items">No school announcements</string>
|
||||
<plurals name="school_announcement_number_item">
|
||||
<item quantity="one">%d school announcement</item>
|
||||
<item quantity="other">%d school announcements</item>
|
||||
</plurals>
|
||||
<plurals name="school_announcement_notify_new_item_title">
|
||||
<item quantity="one">New school announcement</item>
|
||||
<item quantity="other">New school announcements</item>
|
||||
</plurals>
|
||||
<plurals name="school_announcement_notify_new_items">
|
||||
<item quantity="one">You have %1$d new school announcement</item>
|
||||
<item quantity="other">You have %1$d new school announcements</item>
|
||||
</plurals>
|
||||
<!--Account-->
|
||||
<string name="account_add_new">Add account</string>
|
||||
<string name="account_logout">Logout</string>
|
||||
<string name="account_confirm">Do you want to log out this student?</string>
|
||||
<string name="account_logout_student">Student logout</string>
|
||||
<string name="account_type_student">Student account</string>
|
||||
<string name="account_type_parent">Parent account</string>
|
||||
<string name="account_details_edit">Edit data</string>
|
||||
<string name="account_quick_manager">Accounts manager</string>
|
||||
<string name="account_select_student">Select student</string>
|
||||
<string name="account_family">Family</string>
|
||||
<string name="account_contact">Contact</string>
|
||||
<string name="account_address">Residence details</string>
|
||||
<string name="account_personal_data">Personal information</string>
|
||||
<!--About-->
|
||||
<string name="about_version">App version</string>
|
||||
<string name="about_contributor">Contributors</string>
|
||||
<string name="about_contributor_summary">List of Wulkanowy developers</string>
|
||||
<string name="about_feedback">Report a bug</string>
|
||||
<string name="about_feedback_summary">Send a bug report via e-mail</string>
|
||||
<string name="about_faq">FAQ</string>
|
||||
<string name="about_faq_summary">Read Frequently Asked Questions</string>
|
||||
<string name="about_discord">Discord server</string>
|
||||
<string name="about_discord_summary">Join the Wulkanowy community</string>
|
||||
<string name="about_facebook">Facebook fanpage</string>
|
||||
<string name="about_twitter">Twitter page</string>
|
||||
<string name="about_twitter_summary">Follow us on twitter</string>
|
||||
<string name="about_facebook_summary">Like our facebook fanpage</string>
|
||||
<string name="about_privacy">Privacy policy</string>
|
||||
<string name="about_privacy_summary">Rules for collecting personal data</string>
|
||||
<string name="about_system">System settings</string>
|
||||
<string name="about_system_summary">Open system settings</string>
|
||||
<string name="about_homepage">Homepage</string>
|
||||
<string name="about_homepage_summary">Visit the website and help develop the application</string>
|
||||
<string name="about_licenses">Licenses</string>
|
||||
<string name="about_licenses_summary">Licenses of libraries used in the application</string>
|
||||
<!--Licenses-->
|
||||
<string name="license_dialog_title">License</string>
|
||||
<!--Contributor-->
|
||||
<string name="contributor_avatar_description">Avatar</string>
|
||||
<string name="contributor_see_more">See more on GitHub</string>
|
||||
<!--Student info-->
|
||||
<string name="student_info_empty">No info about student or student family</string>
|
||||
<string name="student_info_first_name">Name</string>
|
||||
<string name="student_info_second_name">Second name</string>
|
||||
<string name="student_info_gender">Gender</string>
|
||||
<string name="student_info_polish_citizenship">Polish citizenship</string>
|
||||
<string name="student_info_family_name">Family name</string>
|
||||
<string name="student_info_parents_name">Mother\'s and father\'s names</string>
|
||||
<string name="student_info_phone">Phone</string>
|
||||
<string name="student_info_cellphone">Cellphone</string>
|
||||
<string name="student_info_email">E-mail</string>
|
||||
<string name="student_info_address">Address of residence</string>
|
||||
<string name="student_info_registered_address">Address of registration</string>
|
||||
<string name="student_info_correspondence_address">Correspondence address</string>
|
||||
<string name="student_info_full_name">Surname and first name</string>
|
||||
<string name="student_info_kinship">Degree of kinship</string>
|
||||
<string name="student_info_guardian_address">Address</string>
|
||||
<string name="student_info_phones">Phones</string>
|
||||
<string name="student_info_male">Male</string>
|
||||
<string name="student_info_female">Female</string>
|
||||
<string name="student_info_last_name">Last name</string>
|
||||
<string name="student_info_guardian">Guardian</string>
|
||||
<!--Account edit-->
|
||||
<string name="account_edit_nick_hint">Nick</string>
|
||||
<string name="account_edit_header">Add nick</string>
|
||||
<string name="account_edit_avatar_title">Choose avatar color</string>
|
||||
<!--Log viewer-->
|
||||
<string name="logviewer_share">Share logs</string>
|
||||
<string name="logviewer_refresh">Refresh</string>
|
||||
<!--Dashboard-->
|
||||
<string name="dashboard_timetable_title">Lessons</string>
|
||||
<string name="dashboard_timetable_title_tomorrow">(Tomorrow)</string>
|
||||
<string name="dashboard_timetable_title_today_and_tomorrow">(Today and tomorrow)</string>
|
||||
<string name="dashboard_timetable_first_lesson_title_moment">In a moment:</string>
|
||||
<string name="dashboard_timetable_first_lesson_title_soon">Soon:</string>
|
||||
<string name="dashboard_timetable_first_lesson_title_first">First:</string>
|
||||
<string name="dashboard_timetable_first_lesson_title_now">Now:</string>
|
||||
<string name="dashboard_timetable_second_lesson_value_end">End of lessons</string>
|
||||
<string name="dashboard_timetable_second_lessons_title">Next:</string>
|
||||
<string name="dashboard_timetable_third_title">Later:</string>
|
||||
<plurals name="dashboard_timetable_third_value">
|
||||
<item quantity="one">%1$d more lesson</item>
|
||||
<item quantity="other">%1$d more lessons</item>
|
||||
</plurals>
|
||||
<string name="dashboard_timetable_third_time">until %1$s</string>
|
||||
<string name="dashboard_timetable_no_lessons">No upcoming lessons</string>
|
||||
<string name="dashboard_timetable_error">An error occurred while loading the lessons</string>
|
||||
<string name="dashboard_homework_title">Homework</string>
|
||||
<string name="dashboard_homework_no_homework">No homework to do</string>
|
||||
<string name="dashboard_homework_error">An error occurred while loading the homework</string>
|
||||
<plurals name="dashboard_homework_more">
|
||||
<item quantity="one">%1$d more homework</item>
|
||||
<item quantity="other">%1$d more homework</item>
|
||||
</plurals>
|
||||
<string name="dashboard_homework_time">due %1$s</string>
|
||||
<string name="dashboard_grade_title">Last grades</string>
|
||||
<string name="dashboard_grade_no_grade">No new grades</string>
|
||||
<string name="dashboard_grade_error">An error occurred while loading the grades</string>
|
||||
<string name="dashboard_announcements_title">School announcements</string>
|
||||
<string name="dashboard_announcements_no_announcements">No current announcements</string>
|
||||
<string name="dashboard_announcements_error">An error occurred while loading the announcements</string>
|
||||
<plurals name="dashboard_announcements_more">
|
||||
<item quantity="one">%1$d more announcement</item>
|
||||
<item quantity="other">%1$d more announcements</item>
|
||||
</plurals>
|
||||
<string name="dashboard_exams_title">Exams</string>
|
||||
<string name="dashboard_exams_no_exams">No upcoming exams</string>
|
||||
<string name="dashboard_exams_error">An error occurred while loading the exams</string>
|
||||
<plurals name="dashboard_exams_more">
|
||||
<item quantity="one">%1$d more exam</item>
|
||||
<item quantity="other">%1$d more exams</item>
|
||||
</plurals>
|
||||
<string name="dashboard_conferences_title">Conferences</string>
|
||||
<string name="dashboard_conferences_no_conferences">No upcoming conferences</string>
|
||||
<string name="dashboard_conferences_error">An error occurred while loading the conferences</string>
|
||||
<plurals name="dashboard_conference_more">
|
||||
<item quantity="one">%1$d more conference</item>
|
||||
<item quantity="other">%1$d more conferences</item>
|
||||
</plurals>
|
||||
<string name="dashboard_horizontal_group_error">An error occurred while loading data</string>
|
||||
<string name="dashboard_horizontal_group_no_data">None</string>
|
||||
<!--Error dialog-->
|
||||
<string name="dialog_error_check_update">Check for updates</string>
|
||||
<string name="dialog_error_check_update_message">Before reporting a bug, check first if an update with the bug fix is available</string>
|
||||
<!--Generic-->
|
||||
<string name="all_content">Content</string>
|
||||
<string name="all_retry">Retry</string>
|
||||
<string name="all_description">Description</string>
|
||||
<string name="all_no_description">No description</string>
|
||||
<string name="all_teacher">Teacher</string>
|
||||
<string name="all_date">Date</string>
|
||||
<string name="all_entry_date">Entry date</string>
|
||||
<string name="all_color">Color</string>
|
||||
<string name="all_details">Details</string>
|
||||
<string name="all_category">Category</string>
|
||||
<string name="all_close">Close</string>
|
||||
<string name="all_no_data">No data</string>
|
||||
<string name="all_subject">Subject</string>
|
||||
<string name="all_prev">Prev</string>
|
||||
<string name="all_next">Next</string>
|
||||
<string name="all_search">Search</string>
|
||||
<string name="all_search_hint">Search…</string>
|
||||
<string name="all_yes">Yes</string>
|
||||
<string name="all_no">No</string>
|
||||
<string name="all_save">Save</string>
|
||||
<string name="all_title">Title</string>
|
||||
<string name="all_add">Add</string>
|
||||
<string name="all_copied">Copied</string>
|
||||
<string name="all_undo">Undo</string>
|
||||
<string name="all_change">Change</string>
|
||||
<string name="all_add_to_calendar">Add to calendar</string>
|
||||
<string name="all_cancel">Cancel</string>
|
||||
<!--Timetable Widget-->
|
||||
<string name="widget_timetable_no_items">No lessons</string>
|
||||
<string name="widget_timetable_last_synchronization">Synchronized on %1$s at %2$s</string>
|
||||
<string name="widget_timetable_theme_title">Choose theme</string>
|
||||
<string name="widget_timetable_theme_light">Light</string>
|
||||
<string name="widget_timetable_theme_dark">Dark</string>
|
||||
<string name="widget_timetable_theme_system">System Theme</string>
|
||||
<!--Preferences-->
|
||||
<string name="pref_view_header">App</string>
|
||||
<string name="pref_view_list">Default view</string>
|
||||
<string name="pref_view_grade_average_mode">Calculated average options</string>
|
||||
<string name="pref_view_grade_average_force_calc">Force average calculation by app</string>
|
||||
<string name="pref_view_present">Show presence</string>
|
||||
<string name="pref_view_app_theme">Theme</string>
|
||||
<string name="pref_view_expand_grade">Grades expanding</string>
|
||||
<string name="pref_view_timetable_show_timers">Mark current lesson</string>
|
||||
<string name="pref_view_timetable_show_groups">Show groups next to subjects</string>
|
||||
<string name="pref_view_timetable_show_gaps">Show empty tiles where there\'s no lesson</string>
|
||||
<string name="pref_view_grade_statistics_list">Show chart list in class grades</string>
|
||||
<string name="pref_view_subjects_without_grades">Show subjects without grades</string>
|
||||
<string name="pref_view_grade_color_scheme">Grades color scheme</string>
|
||||
<string name="pref_view_grade_sorting_mode">Subjects sorting</string>
|
||||
<string name="pref_view_app_language">Language</string>
|
||||
<string name="pref_view_menu_order_title">Menu configuration</string>
|
||||
<string name="pref_view_menu_order_summary">Set the order of functions in the menu</string>
|
||||
<string name="pref_notify_header">Notifications</string>
|
||||
<string name="pref_notify_header_other">Other</string>
|
||||
<string name="pref_notify_switch">Show notifications</string>
|
||||
<string name="pref_notify_upcoming_lessons_switch">Show upcoming lesson notifications</string>
|
||||
<string name="pref_notify_upcoming_lessons_persistent_switch">Make upcoming lesson notification persistent</string>
|
||||
<string name="pref_notify_upcoming_lessons_persistent_summary">Turn off when notification is not showing in your watch/band</string>
|
||||
<string name="pref_notify_open_system_settings">Open system notification settings</string>
|
||||
<string name="pref_notify_fix_sync_issues">Fix synchronization & notifications issues</string>
|
||||
<string name="pref_notify_fix_sync_issues_message">Your device may have data synchronization issues and with notifications.\n\nTo fix them, you need to add Wulkanowy to the autostart and turn off battery optimization/saving in the phone settings.</string>
|
||||
<string name="pref_notify_debug_switch">Show debug notifications</string>
|
||||
<string name="pref_notify_disabled_summary">Synchronization is disabled</string>
|
||||
<string name="pref_notify_notifications_piggyback_header">Official app notifications</string>
|
||||
<string name="pref_notify_notifications_piggyback">Capture official app notifications</string>
|
||||
<string name="pref_notify_notifications_piggyback_cancel_original">Remove official app notifications after capture</string>
|
||||
<string name="pref_notification_piggyback_popup_title">Capture notifications</string>
|
||||
<string name="pref_notification_piggyback_popup_description">With this feature you can gain a substitute of push notifications like in the official app. All you need to do is allow Wulkanowy to receive all notifications in your system settings.\n\nHow it works?\nWhen you get a notification in Dziennik VULCAN, Wulkanowy will be notified (that\'s what these extra permissions are for) and will trigger a sync so that can send its own notification.\n\nFOR ADVANCED USERS ONLY</string>
|
||||
<string name="pref_notification_exact_alarm_popup_title">Upcoming lesson notifications</string>
|
||||
<string name="pref_notification_exact_alarm_popup_descriptions">You must allow the Wulkanowy app to set alarms and reminders in your system settings to use this feature.</string>
|
||||
<string name="pref_notification_go_to_settings">Go to settings</string>
|
||||
<string name="pref_services_header">Synchronization</string>
|
||||
<string name="pref_services_switch">Automatic update</string>
|
||||
<string name="pref_services_suspended">Suspended on holidays</string>
|
||||
<string name="pref_services_interval">Updates interval</string>
|
||||
<string name="pref_services_wifi">Wi-Fi only</string>
|
||||
<string name="pref_services_force_sync">Sync now</string>
|
||||
<string name="pref_services_message_sync_success">Synced!</string>
|
||||
<string name="pref_services_message_sync_failed">Sync failed</string>
|
||||
<string name="pref_services_sync_in_progress">Sync in progress</string>
|
||||
<string name="pref_services_last_full_sync_date">Last full sync: %s</string>
|
||||
<string name="pref_other_grade_modifier_plus">Value of the plus</string>
|
||||
<string name="pref_other_grade_modifier_minus">Value of the minus</string>
|
||||
<string name="pref_other_fill_message_content">Reply with message history</string>
|
||||
<string name="pref_other_optional_arithmetic_average">Show arithmetic average when no weights provided</string>
|
||||
<string name="pref_other_incognito_mode">Incognito mode</string>
|
||||
<string name="pref_other_incognito_mode_summary">Do not inform about reading the message</string>
|
||||
<string name="pref_ads_support_category_name">Support</string>
|
||||
<string name="pref_ads_privacy_policy">Privacy Policy</string>
|
||||
<string name="pref_ads_agreements">Agreements</string>
|
||||
<string name="pref_ads_consent">Consent to processing of data related to ads</string>
|
||||
<string name="pref_ads_show_in_app">Show ads in app</string>
|
||||
<string name="pref_ads_support">Watch single ad to support project</string>
|
||||
<string name="pref_ads_privacy_title">Consent to data processing</string>
|
||||
<string name="pref_ads_privacy_description">To view an advertisement you must agree to the data processing terms of our Privacy Policy</string>
|
||||
<string name="pref_ads_privacy_agree">Agree</string>
|
||||
<string name="pref_ads_privacy_link">Privacy policy</string>
|
||||
<string name="pref_ads_loading">Ad is loading</string>
|
||||
<string name="pref_ads_once_per_visit">Thank you for your support, come back later for more ads</string>
|
||||
<string name="pref_ads_consent_title">Can we use your data to display ads?</string>
|
||||
<string name="pref_ads_consent_description">You can change your choice anytime in the app settings. We may use your data to display ads tailored to you or, using less of your data, display non-personalized ads. Please see our Privacy Policy for details</string>
|
||||
<string name="pref_ads_summary_personalized">Personalized ads</string>
|
||||
<string name="pref_ads_summary_non_personalized">Non-personalized ads</string>
|
||||
<string name="pref_ads_over_18_years_old">I am over 18 years old</string>
|
||||
<string name="pref_ads_option_personalized">Yes, personalized ads</string>
|
||||
<string name="pref_ads_option_non_personalized">Yes, non-personalized ads</string>
|
||||
<string name="pref_settings_advanced_title">Advanced</string>
|
||||
<string name="pref_settings_appearance_title">Appearance & Behavior</string>
|
||||
<string name="pref_settings_notifications_title">Notifications</string>
|
||||
<string name="pref_settings_sync_title">Synchronization</string>
|
||||
<string name="pref_settings_ads_title">Advertisements</string>
|
||||
<string name="pref_grades_appearance_header">Grades</string>
|
||||
<string name="pref_dashboard_appearance_header">Dashboard</string>
|
||||
<string name="pref_dashboard_appearance_tiles_title">Tiles visibility</string>
|
||||
<string name="pref_attendance_appearance_view">Attendance</string>
|
||||
<string name="pref_timetable_appearance_view">Timetable</string>
|
||||
<string name="pref_grades_advanced_header">Grades</string>
|
||||
<string name="pref_counted_average_advanced_header">Calculated average</string>
|
||||
<string name="pref_messages_advanced_header">Messages</string>
|
||||
<string name="pref_appearance_category">Appearance & Behavior</string>
|
||||
<string name="pref_appearance_category_summary">Languages, themes, subjects sorting</string>
|
||||
<string name="pref_notifications_category_summary">App notifications, fix problems</string>
|
||||
<string name="pref_notifications_category">Notifications</string>
|
||||
<string name="pref_sync_category">Synchronization</string>
|
||||
<string name="pref_sync_category_summary">Automatic update, synchronization interval</string>
|
||||
<string name="pref_advanced_category_summary">Plus and minus values, average calculation</string>
|
||||
<string name="pref_advanced_category">Advanced</string>
|
||||
<string name="pref_about_category_summary">App version, contributors, social portals</string>
|
||||
<string name="pref_ads_category_summary">Displaying advertisements, project support</string>
|
||||
<!--Notification Channels-->
|
||||
<string name="channel_new_grades">New grades</string>
|
||||
<string name="channel_new_homework">New homework</string>
|
||||
<string name="channel_new_conference">New conferences</string>
|
||||
<string name="channel_new_exam">New exams</string>
|
||||
<string name="channel_lucky_number">Lucky number</string>
|
||||
<string name="channel_new_message">New messages</string>
|
||||
<string name="channel_new_notes">New notes</string>
|
||||
<string name="channel_new_school_announcement">New school announcements</string>
|
||||
<string name="channel_push">Push notifications</string>
|
||||
<string name="channel_upcoming_lessons">Upcoming lessons</string>
|
||||
<string name="channel_debug">Debug</string>
|
||||
<string name="channel_change_timetable">Timetable change</string>
|
||||
<string name="channel_new_attendance">New attendance</string>
|
||||
<!--Colors-->
|
||||
<string name="all_black">Black</string>
|
||||
<string name="all_red">Red</string>
|
||||
<string name="all_blue">Blue</string>
|
||||
<string name="all_green">Green</string>
|
||||
<string name="all_purple">Purple</string>
|
||||
<string name="all_empty_color">No color</string>
|
||||
<!--Update helper-->
|
||||
<string name="update_download_started">Download of updates has started…</string>
|
||||
<string name="update_download_success">An update has just been downloaded.</string>
|
||||
<string name="update_download_success_button">Restart</string>
|
||||
<string name="update_failed">Update failed! Wulkanowy may not function properly. Consider updating</string>
|
||||
<!--Menu order-->
|
||||
<string name="menu_order_confirm_title">Application restart</string>
|
||||
<string name="menu_order_confirm_content">The application must restart for the changes to be saved</string>
|
||||
<string name="menu_order_confirm_restart">Restart</string>
|
||||
<!--Auth-->
|
||||
<string name="auth_api_error">Authorization has been rejected. The data provided does not match the records in the secretary\'s office.</string>
|
||||
<string name="auth_invalid_error">Invalid PESEL</string>
|
||||
<string name="auth_pesel">PESEL</string>
|
||||
<string name="auth_button">Authorize</string>
|
||||
<string name="auth_success">Authorization completed successfully</string>
|
||||
<string name="auth_title">Authorization</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>
|
||||
<!--Errors-->
|
||||
<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_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_password_change_required">Register password change required</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_app">Unknown application error. Please try again later</string>
|
||||
<string name="error_unknown">An unexpected error occurred</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_field_required">This field is required</string>
|
||||
</resources>
|
@ -51,6 +51,11 @@
|
||||
<item>Średnia ze średnich z obu semestrów</item>
|
||||
<item>Średnia wszystkich ocen z całego roku</item>
|
||||
</string-array>
|
||||
<string-array name="timetable_show_gaps_entries">
|
||||
<item>Nie pokauj</item>
|
||||
<item>Tylko między lekcjami</item>
|
||||
<item>Przed i między lekcjami</item>
|
||||
</string-array>
|
||||
<string-array name="dashboard_tile_entries">
|
||||
<item>Szczęśliwy numerek</item>
|
||||
<item>Nieprzeczytane wiadomości</item>
|
||||
|
@ -185,6 +185,12 @@
|
||||
<string name="timetable_notify_change_room">Zmiana sali z %1$s na %2$s</string>
|
||||
<string name="timetable_notify_change_teacher">Zmiana nauczyciela z %1$s na %2$s</string>
|
||||
<string name="timetable_notify_change_subject">Zmiana przedmiotu z %1$s na %2$s</string>
|
||||
<plurals name="timetable_no_lesson">
|
||||
<item quantity="one">Brak lekcji</item>
|
||||
<item quantity="few">Brak lekcji</item>
|
||||
<item quantity="many">Brak lekcji</item>
|
||||
<item quantity="other">Brak lekcji</item>
|
||||
</plurals>
|
||||
<plurals name="timetable_notify_new_items_title">
|
||||
<item quantity="one">Zmiana planu lekcji</item>
|
||||
<item quantity="few">Zmiany planu lekcji</item>
|
||||
@ -352,6 +358,8 @@
|
||||
</plurals>
|
||||
<string name="message_messages_deleted">Wiadomości zostały usunięte</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_description">Dzięki trybowi incognito nadawca nie zobaczy, że przeczytałeś tę wiadomość</string>
|
||||
<!--Note-->
|
||||
<string name="note_no_items">Brak informacji o uwagach</string>
|
||||
<string name="note_points">Punkty</string>
|
||||
@ -698,6 +706,7 @@
|
||||
<string name="pref_view_expand_grade">Rozwijanie ocen</string>
|
||||
<string name="pref_view_timetable_show_timers">Oznaczaj bieżącą lekcję</string>
|
||||
<string name="pref_view_timetable_show_groups">Pokazuj grupę obok przedmiotu</string>
|
||||
<string name="pref_view_timetable_show_gaps">Pokazuj puste kafelki gdzie nie ma lekcji</string>
|
||||
<string name="pref_view_grade_statistics_list">Pokazuj listę wykresów w ocenach klasy</string>
|
||||
<string name="pref_view_subjects_without_grades">Pokazuj przedmioty bez ocen</string>
|
||||
<string name="pref_view_grade_color_scheme">Schemat kolorów ocen</string>
|
||||
@ -738,6 +747,8 @@
|
||||
<string name="pref_other_grade_modifier_minus">Wartość minusa</string>
|
||||
<string name="pref_other_fill_message_content">Odpowiadaj z historią wiadomości</string>
|
||||
<string name="pref_other_optional_arithmetic_average">Licz średnią arytmetyczną, gdy żadna ocena nie ma wagi</string>
|
||||
<string name="pref_other_incognito_mode">Tryb incognito</string>
|
||||
<string name="pref_other_incognito_mode_summary">Nie informuj o przeczytaniu wiadomości</string>
|
||||
<string name="pref_ads_support_category_name">Wsparcie</string>
|
||||
<string name="pref_ads_privacy_policy">Polityka prywatności</string>
|
||||
<string name="pref_ads_agreements">Zgody</string>
|
||||
|
@ -51,6 +51,11 @@
|
||||
<item>Средняя из средних оценок семестров</item>
|
||||
<item>Средняя из оценок со всего года</item>
|
||||
</string-array>
|
||||
<string-array name="timetable_show_gaps_entries">
|
||||
<item>Don\'t show</item>
|
||||
<item>Only between lessons</item>
|
||||
<item>Before and between lessons</item>
|
||||
</string-array>
|
||||
<string-array name="dashboard_tile_entries">
|
||||
<item>Счастливый номер</item>
|
||||
<item>Непрочитанные письма</item>
|
||||
|
@ -185,6 +185,12 @@
|
||||
<string name="timetable_notify_change_room">Аудитория изменена с %1$s на %2$s</string>
|
||||
<string name="timetable_notify_change_teacher">Учитель изменён с %1$s на %2$s</string>
|
||||
<string name="timetable_notify_change_subject">Тема изменена с %1$s на %2$s</string>
|
||||
<plurals name="timetable_no_lesson">
|
||||
<item quantity="one">No lesson</item>
|
||||
<item quantity="few">No lessons</item>
|
||||
<item quantity="many">No lessons</item>
|
||||
<item quantity="other">No lessons</item>
|
||||
</plurals>
|
||||
<plurals name="timetable_notify_new_items_title">
|
||||
<item quantity="one">Изменение расписания</item>
|
||||
<item quantity="few">Изменения расписания</item>
|
||||
@ -352,6 +358,8 @@
|
||||
</plurals>
|
||||
<string name="message_messages_deleted">Сообщение удалено</string>
|
||||
<string name="message_mailbox_chooser_title">Выбрать почтовый ящик</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>
|
||||
<!--Note-->
|
||||
<string name="note_no_items">Нет записей о замечаниях и свершениях</string>
|
||||
<string name="note_points">Баллы</string>
|
||||
@ -698,6 +706,7 @@
|
||||
<string name="pref_view_expand_grade">Разворачивание оценок</string>
|
||||
<string name="pref_view_timetable_show_timers">Отметить текущий урок</string>
|
||||
<string name="pref_view_timetable_show_groups">Показать группы рядом с темами</string>
|
||||
<string name="pref_view_timetable_show_gaps">Show empty tiles where there\'s no lesson</string>
|
||||
<string name="pref_view_grade_statistics_list">Показывать диаграммы в оценках класса</string>
|
||||
<string name="pref_view_subjects_without_grades">Показать предметы без оценок</string>
|
||||
<string name="pref_view_grade_color_scheme">Цветовая схема оценок</string>
|
||||
@ -738,6 +747,8 @@
|
||||
<string name="pref_other_grade_modifier_minus">Стоимость минуса</string>
|
||||
<string name="pref_other_fill_message_content">Отвечать с историей сообщений</string>
|
||||
<string name="pref_other_optional_arithmetic_average">Показывать среднее арифметическое при отсутствии стоимости</string>
|
||||
<string name="pref_other_incognito_mode">Incognito mode</string>
|
||||
<string name="pref_other_incognito_mode_summary">Do not inform about reading the message</string>
|
||||
<string name="pref_ads_support_category_name">Поддержка</string>
|
||||
<string name="pref_ads_privacy_policy">Политика приватности</string>
|
||||
<string name="pref_ads_agreements">Соглашения</string>
|
||||
|
@ -51,6 +51,11 @@
|
||||
<item>Priemer z priemerov z oboch semestrov</item>
|
||||
<item>Priemer známok z celého roka</item>
|
||||
</string-array>
|
||||
<string-array name="timetable_show_gaps_entries">
|
||||
<item>Don\'t show</item>
|
||||
<item>Only between lessons</item>
|
||||
<item>Before and between lessons</item>
|
||||
</string-array>
|
||||
<string-array name="dashboard_tile_entries">
|
||||
<item>Šťastné číslo</item>
|
||||
<item>Neprečítané správy</item>
|
||||
|
@ -37,7 +37,7 @@
|
||||
<string name="login_login_pesel_email_hint">Prihlásenie, číslo PESEL alebo e-mail</string>
|
||||
<string name="login_password_hint">Heslo</string>
|
||||
<string name="login_host_hint">Variácia denníka UONET+</string>
|
||||
<string name="login_domain_suffix_hint">Custom domain suffix</string>
|
||||
<string name="login_domain_suffix_hint">Vlastná prípona domény</string>
|
||||
<string name="login_type_api">Mobile API</string>
|
||||
<string name="login_type_scrapper">Scraper</string>
|
||||
<string name="login_type_hybrid">Hybridné</string>
|
||||
@ -185,6 +185,12 @@
|
||||
<string name="timetable_notify_change_room">Zmena učebne z %1$s na %2$s</string>
|
||||
<string name="timetable_notify_change_teacher">Zmena učiteľa z %1$s na %2$s</string>
|
||||
<string name="timetable_notify_change_subject">Zmena predmetu z %1$s na %2$s</string>
|
||||
<plurals name="timetable_no_lesson">
|
||||
<item quantity="one">No lesson</item>
|
||||
<item quantity="few">No lessons</item>
|
||||
<item quantity="many">No lessons</item>
|
||||
<item quantity="other">No lessons</item>
|
||||
</plurals>
|
||||
<plurals name="timetable_notify_new_items_title">
|
||||
<item quantity="one">Zmena plánu lekcií</item>
|
||||
<item quantity="few">Zmeny plánu lekcií</item>
|
||||
@ -352,6 +358,8 @@
|
||||
</plurals>
|
||||
<string name="message_messages_deleted">Správy odstránené</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_description">Vďaka inkognito režimu nie je odosielateľ upozornený, keď si správu prečítate</string>
|
||||
<!--Note-->
|
||||
<string name="note_no_items">Žiadne informácie o poznámkach</string>
|
||||
<string name="note_points">Body</string>
|
||||
@ -698,6 +706,7 @@
|
||||
<string name="pref_view_expand_grade">Rozvijanie známok</string>
|
||||
<string name="pref_view_timetable_show_timers">Označiť aktuálne lekciu</string>
|
||||
<string name="pref_view_timetable_show_groups">Zobraziť skupiny vedľa predmetov</string>
|
||||
<string name="pref_view_timetable_show_gaps">Show empty tiles where there\'s no lesson</string>
|
||||
<string name="pref_view_grade_statistics_list">Zobraziť zoznam grafov v známkach triedy</string>
|
||||
<string name="pref_view_subjects_without_grades">Zobraziť predmety bez známok</string>
|
||||
<string name="pref_view_grade_color_scheme">Známky farebnú schému</string>
|
||||
@ -738,6 +747,8 @@
|
||||
<string name="pref_other_grade_modifier_minus">Hodnota mínusu</string>
|
||||
<string name="pref_other_fill_message_content">Odpovedať s históriou správ</string>
|
||||
<string name="pref_other_optional_arithmetic_average">Vypočítať aritmetický priemer, ak žiadna známka nemá váhu</string>
|
||||
<string name="pref_other_incognito_mode">Režim inkognito</string>
|
||||
<string name="pref_other_incognito_mode_summary">Neinformovať o prečítaní správy</string>
|
||||
<string name="pref_ads_support_category_name">Podpora</string>
|
||||
<string name="pref_ads_privacy_policy">Ochrana osobných údajov</string>
|
||||
<string name="pref_ads_agreements">Súhlasy</string>
|
||||
|
@ -51,6 +51,11 @@
|
||||
<item>Середнє значення з обох семестрів</item>
|
||||
<item>Середня оцінка з цілого року</item>
|
||||
</string-array>
|
||||
<string-array name="timetable_show_gaps_entries">
|
||||
<item>Don\'t show</item>
|
||||
<item>Only between lessons</item>
|
||||
<item>Before and between lessons</item>
|
||||
</string-array>
|
||||
<string-array name="dashboard_tile_entries">
|
||||
<item>Щасливий номер</item>
|
||||
<item>Непрочитані листи</item>
|
||||
|
@ -37,7 +37,7 @@
|
||||
<string name="login_login_pesel_email_hint">Логін, PESEL або e-mail</string>
|
||||
<string name="login_password_hint">Пароль</string>
|
||||
<string name="login_host_hint">Тип щоденника UONET+</string>
|
||||
<string name="login_domain_suffix_hint">Custom domain suffix</string>
|
||||
<string name="login_domain_suffix_hint">Користувацький суфікс домену</string>
|
||||
<string name="login_type_api">Мobile API</string>
|
||||
<string name="login_type_scrapper">Scraper</string>
|
||||
<string name="login_type_hybrid">Hybrid</string>
|
||||
@ -185,6 +185,12 @@
|
||||
<string name="timetable_notify_change_room">Зміна аудіторії з %1$s на %2$s</string>
|
||||
<string name="timetable_notify_change_teacher">Зміна вчителя з %1$s на %2$s</string>
|
||||
<string name="timetable_notify_change_subject">Зміна теми з %1$s на %2$s</string>
|
||||
<plurals name="timetable_no_lesson">
|
||||
<item quantity="one">No lesson</item>
|
||||
<item quantity="few">No lessons</item>
|
||||
<item quantity="many">No lessons</item>
|
||||
<item quantity="other">No lessons</item>
|
||||
</plurals>
|
||||
<plurals name="timetable_notify_new_items_title">
|
||||
<item quantity="one">Зміна у розкладі</item>
|
||||
<item quantity="few">Зміни у розкладі</item>
|
||||
@ -352,6 +358,8 @@
|
||||
</plurals>
|
||||
<string name="message_messages_deleted">Листи видалено</string>
|
||||
<string name="message_mailbox_chooser_title">Вибрати поштову скриньку</string>
|
||||
<string name="message_incognito_mode_on">Режим анонімності включено</string>
|
||||
<string name="message_incognito_description">Завдяки режиму анонімності, відправник не буде сповіщений коли ви прочитаєте повідомлення</string>
|
||||
<!--Note-->
|
||||
<string name="note_no_items">Немає інформації о зауваженнях</string>
|
||||
<string name="note_points">Бали</string>
|
||||
@ -698,6 +706,7 @@
|
||||
<string name="pref_view_expand_grade">Розгортання оцінок</string>
|
||||
<string name="pref_view_timetable_show_timers">Позначити поточний урок</string>
|
||||
<string name="pref_view_timetable_show_groups">Показувати групи поруч з темами</string>
|
||||
<string name="pref_view_timetable_show_gaps">Show empty tiles where there\'s no lesson</string>
|
||||
<string name="pref_view_grade_statistics_list">Показувати діаграми в оцінках класу</string>
|
||||
<string name="pref_view_subjects_without_grades">Показати предмети без оцінок</string>
|
||||
<string name="pref_view_grade_color_scheme">Схема кольорів оцінок</string>
|
||||
@ -738,6 +747,8 @@
|
||||
<string name="pref_other_grade_modifier_minus">Вартість мінуса</string>
|
||||
<string name="pref_other_fill_message_content">Відповісти з історією повідомлень</string>
|
||||
<string name="pref_other_optional_arithmetic_average">Вилічити середню аритметичну, якщо оцінка немає вартості</string>
|
||||
<string name="pref_other_incognito_mode">Анонімний режим</string>
|
||||
<string name="pref_other_incognito_mode_summary">Не повідомляти про прочитання повідомлення</string>
|
||||
<string name="pref_ads_support_category_name">Підтримка</string>
|
||||
<string name="pref_ads_privacy_policy">Політика конфіденційності</string>
|
||||
<string name="pref_ads_agreements">Угоди</string>
|
||||
@ -814,8 +825,8 @@
|
||||
<string name="auth_api_error">Авторизацію відхилено. Надані дані не збігаються із записами в кабінеті секретаря.</string>
|
||||
<string name="auth_invalid_error">Неправильний PESEL</string>
|
||||
<string name="auth_pesel">Число PESEL</string>
|
||||
<string name="auth_button">Authorize</string>
|
||||
<string name="auth_success">Authorization completed successfully</string>
|
||||
<string name="auth_button">Авторизовать</string>
|
||||
<string name="auth_success">Авторизація пройшла успішно</string>
|
||||
<string name="auth_title">Авторизувати</string>
|
||||
<string name="auth_description">Для роботи програми нам потрібно підтвердити вашу особу. Будь ласка, введіть число PESEL <b>%1$s</b> студента в поле нижче</string>
|
||||
<string name="auth_button_skip">Поки що пропустити</string>
|
||||
|
@ -23,6 +23,7 @@
|
||||
<string name="pref_default_timetable_show_whole_class">no</string>
|
||||
<string name="pref_default_grade_sorting_mode">alphabetic</string>
|
||||
<bool name="pref_default_timetable_show_timers">false</bool>
|
||||
<string name="pref_default_timetable_show_gaps">between</string>
|
||||
<bool name="pref_default_subjects_without_grades">false</bool>
|
||||
<bool name="pref_default_optional_arithmetic_average">false</bool>
|
||||
<string name="pref_default_last_sync_date">0</string>
|
||||
@ -38,4 +39,5 @@
|
||||
</string-array>
|
||||
<bool name="pref_default_ads_enabled">false</bool>
|
||||
<bool name="pref_default_ads_consent_data_processing">false</bool>
|
||||
<bool name="pref_default_incognito_mode">false</bool>
|
||||
</resources>
|
||||
|
@ -28,6 +28,7 @@
|
||||
<string name="pref_key_timetable_show_whole_class">show_whole_class_plan</string>
|
||||
<string name="pref_key_timetable_show_groups">show_groups_in_plan</string>
|
||||
<string name="pref_key_timetable_show_timers">timetable_show_timers</string>
|
||||
<string name="pref_key_timetable_show_gaps">timetable_show_gaps</string>
|
||||
<string name="pref_key_subjects_without_grades">subjects_without_grades</string>
|
||||
<string name="pref_key_optional_arithmetic_average">optional_arithmetic_average</string>
|
||||
<string name="pref_key_message_draft">message_draft</string>
|
||||
@ -39,5 +40,6 @@
|
||||
<string name="pref_key_ads_privacy_policy">ads_privacy_policy</string>
|
||||
<string name="pref_key_ads_consent_data_processing">ads_consent_data_processing</string>
|
||||
<string name="pref_key_ads_over_eighteen">ads_over_eighteen</string>
|
||||
<string name="pref_key_incognito_moge">incognito_mode</string>
|
||||
<string name="pref_key_menu_order">appearance_menu_order</string>
|
||||
</resources>
|
||||
|
@ -123,6 +123,17 @@
|
||||
<item>all_year</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="timetable_show_gaps_entries">
|
||||
<item>Don\'t show</item>
|
||||
<item>Only between lessons</item>
|
||||
<item>Before and between lessons</item>
|
||||
</string-array>
|
||||
<string-array name="timetable_show_gaps_values" translatable="false">
|
||||
<item>no_gaps</item>
|
||||
<item>between</item>
|
||||
<item>before_and_between</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="dashboard_tile_entries">
|
||||
<item>Lucky number</item>
|
||||
<item>Unread messages</item>
|
||||
|
@ -186,6 +186,10 @@
|
||||
<string name="timetable_notify_change_room">Change of room from %1$s to %2$s</string>
|
||||
<string name="timetable_notify_change_teacher">Change of teacher from %1$s to %2$s</string>
|
||||
<string name="timetable_notify_change_subject">Change of subject from %1$s to %2$s</string>
|
||||
<plurals name="timetable_no_lesson">
|
||||
<item quantity="one">No lesson</item>
|
||||
<item quantity="other">No lessons</item>
|
||||
</plurals>
|
||||
<plurals name="timetable_notify_new_items_title">
|
||||
<item quantity="one">Timetable change</item>
|
||||
<item quantity="other">Timetable changes</item>
|
||||
@ -339,6 +343,8 @@
|
||||
</plurals>
|
||||
<string name="message_messages_deleted">Messages deleted</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_description">Thanks to incognito mode sender is not notified when you read the message</string>
|
||||
|
||||
|
||||
<!--Note-->
|
||||
@ -688,6 +694,7 @@
|
||||
<string name="pref_view_expand_grade">Grades expanding</string>
|
||||
<string name="pref_view_timetable_show_timers">Mark current lesson</string>
|
||||
<string name="pref_view_timetable_show_groups">Show groups next to subjects</string>
|
||||
<string name="pref_view_timetable_show_gaps">Show empty tiles where there\'s no lesson</string>
|
||||
<string name="pref_view_grade_statistics_list">Show chart list in class grades</string>
|
||||
<string name="pref_view_subjects_without_grades">Show subjects without grades</string>
|
||||
<string name="pref_view_grade_color_scheme">Grades color scheme</string>
|
||||
@ -728,6 +735,9 @@
|
||||
<string name="pref_other_grade_modifier_minus">Value of the minus</string>
|
||||
<string name="pref_other_fill_message_content">Reply with message history</string>
|
||||
<string name="pref_other_optional_arithmetic_average">Show arithmetic average when no weights provided</string>
|
||||
<string name="pref_other_incognito_mode">Incognito mode</string>
|
||||
<string name="pref_other_incognito_mode_summary">Do not inform about reading the message</string>
|
||||
|
||||
<string name="pref_ads_support_category_name">Support</string>
|
||||
<string name="pref_ads_privacy_policy">Privacy Policy</string>
|
||||
<string name="pref_ads_agreements">Agreements</string>
|
||||
|
@ -3,15 +3,15 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:configure="io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetConfigureActivity"
|
||||
android:initialLayout="@layout/widget_timetable"
|
||||
android:minWidth="250dp"
|
||||
android:minHeight="110dp"
|
||||
android:minResizeWidth="250dp"
|
||||
android:minResizeHeight="110dp"
|
||||
android:minWidth="245dp"
|
||||
android:minHeight="102dp"
|
||||
android:minResizeWidth="245dp"
|
||||
android:minResizeHeight="102dp"
|
||||
android:previewImage="@drawable/img_timetable_widget_preview"
|
||||
android:previewLayout="@layout/widget_timetable_preview"
|
||||
android:resizeMode="horizontal|vertical"
|
||||
android:targetCellWidth="3"
|
||||
android:targetCellHeight="2"
|
||||
android:targetCellHeight="3"
|
||||
android:updatePeriodMillis="3600000"
|
||||
android:widgetCategory="home_screen"
|
||||
tools:targetApi="s" />
|
||||
|
@ -53,5 +53,12 @@
|
||||
app:key="@string/pref_key_fill_message_content"
|
||||
app:singleLineTitle="false"
|
||||
app:title="@string/pref_other_fill_message_content" />
|
||||
<SwitchPreferenceCompat
|
||||
app:defaultValue="@bool/pref_default_incognito_mode"
|
||||
app:iconSpaceReserved="false"
|
||||
app:key="@string/pref_key_incognito_moge"
|
||||
app:singleLineTitle="false"
|
||||
app:title="@string/pref_other_incognito_mode"
|
||||
app:summary="@string/pref_other_incognito_mode_summary" />
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
|
@ -111,5 +111,13 @@
|
||||
app:title="@string/pref_view_timetable_show_whole_class"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
-->
|
||||
<ListPreference
|
||||
app:defaultValue="@string/pref_default_timetable_show_gaps"
|
||||
app:entries="@array/timetable_show_gaps_entries"
|
||||
app:entryValues="@array/timetable_show_gaps_values"
|
||||
app:iconSpaceReserved="false"
|
||||
app:key="@string/pref_key_timetable_show_gaps"
|
||||
app:title="@string/pref_view_timetable_show_gaps"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
|
@ -2,7 +2,8 @@ package io.github.wulkanowy
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.TestCoroutineDispatcher
|
||||
import kotlinx.coroutines.test.TestDispatcher
|
||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||
import kotlinx.coroutines.test.resetMain
|
||||
import kotlinx.coroutines.test.setMain
|
||||
import org.junit.rules.TestWatcher
|
||||
@ -10,17 +11,14 @@ import org.junit.runner.Description
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
class MainCoroutineRule(
|
||||
private val testDispatcher: TestCoroutineDispatcher = TestCoroutineDispatcher()
|
||||
private val testDispatcher: TestDispatcher = UnconfinedTestDispatcher()
|
||||
) : TestWatcher() {
|
||||
|
||||
override fun starting(description: Description?) {
|
||||
super.starting(description)
|
||||
override fun starting(description: Description) {
|
||||
Dispatchers.setMain(testDispatcher)
|
||||
}
|
||||
|
||||
override fun finished(description: Description?) {
|
||||
super.finished(description)
|
||||
override fun finished(description: Description) {
|
||||
Dispatchers.resetMain()
|
||||
testDispatcher.cleanupTestCoroutines()
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,8 @@ abstract class AbstractMigrationTest {
|
||||
@get:Rule
|
||||
val helper: MigrationTestHelper = MigrationTestHelper(
|
||||
InstrumentationRegistry.getInstrumentation(),
|
||||
AppDatabase::class.java.canonicalName,
|
||||
AppDatabase::class.java,
|
||||
listOf(Migration55()),
|
||||
FrameworkSQLiteOpenHelperFactory()
|
||||
)
|
||||
|
||||
|
@ -22,12 +22,12 @@ class Migration12Test : AbstractMigrationTest() {
|
||||
fun twoNotRelatedStudents() {
|
||||
helper.createDatabase(dbName, 11).apply {
|
||||
// user 1
|
||||
createStudent(this, 1, true)
|
||||
createStudent(this, 1)
|
||||
createSemester(this, 1, false, 5, 1)
|
||||
createSemester(this, 1, true, 5, 2)
|
||||
|
||||
// user 2
|
||||
createStudent(this, 2, true)
|
||||
createStudent(this, 2)
|
||||
createSemester(this, 2, false, 6, 1)
|
||||
createSemester(this, 2, true, 6, 2)
|
||||
close()
|
||||
@ -56,9 +56,9 @@ class Migration12Test : AbstractMigrationTest() {
|
||||
fun removeStudentsWithoutClassId() {
|
||||
helper.createDatabase(dbName, 11).apply {
|
||||
// user 1
|
||||
createStudent(this, 1, true)
|
||||
createStudent(this, 1)
|
||||
createSemester(this, 1, false, 0, 2)
|
||||
createStudent(this, 2, true)
|
||||
createStudent(this, 2)
|
||||
createSemester(this, 2, true, 1, 2)
|
||||
close()
|
||||
}
|
||||
@ -81,11 +81,11 @@ class Migration12Test : AbstractMigrationTest() {
|
||||
fun ensureThereIsOnlyOneCurrentStudent() {
|
||||
helper.createDatabase(dbName, 11).apply {
|
||||
// user 1
|
||||
createStudent(this, 1, true)
|
||||
createStudent(this, 1)
|
||||
createSemester(this, 1, true, 5, 2)
|
||||
createStudent(this, 2, true)
|
||||
createStudent(this, 2)
|
||||
createSemester(this, 2, true, 6, 2)
|
||||
createStudent(this, 3, true)
|
||||
createStudent(this, 3)
|
||||
createSemester(this, 3, false, 7, 2)
|
||||
close()
|
||||
}
|
||||
@ -112,7 +112,7 @@ class Migration12Test : AbstractMigrationTest() {
|
||||
db.close()
|
||||
}
|
||||
|
||||
private fun createStudent(db: SupportSQLiteDatabase, studentId: Int, isCurrent: Boolean) {
|
||||
private fun createStudent(db: SupportSQLiteDatabase, studentId: Int) {
|
||||
db.insert("Students", CONFLICT_FAIL, ContentValues().apply {
|
||||
put("endpoint", "https://fakelog.cf")
|
||||
put("loginType", "STANDARD")
|
||||
@ -123,7 +123,7 @@ class Migration12Test : AbstractMigrationTest() {
|
||||
put("student_name", "Jan Kowalski")
|
||||
put("school_id", "000123")
|
||||
put("school_name", "")
|
||||
put("is_current", isCurrent)
|
||||
put("is_current", true)
|
||||
put("registration_date", "0")
|
||||
})
|
||||
}
|
||||
|
@ -95,22 +95,22 @@ class Migration13Test : AbstractMigrationTest() {
|
||||
fun markAtLeastAndOnlyOneSemesterAtCurrent() {
|
||||
helper.createDatabase(dbName, 12).apply {
|
||||
createStudent(this, 1, "", 5)
|
||||
createSemester(this, 1, 5, 1, 1, false)
|
||||
createSemester(this, 1, 5, 2, 1, false)
|
||||
createSemester(this, 1, 5, 3, 2, false)
|
||||
createSemester(this, 1, 5, 4, 2, false)
|
||||
createSemester(this, 1, 1, 1, false)
|
||||
createSemester(this, 1, 2, 1, false)
|
||||
createSemester(this, 1, 3, 2, false)
|
||||
createSemester(this, 1, 4, 2, false)
|
||||
|
||||
createStudent(this, 2, "", 5)
|
||||
createSemester(this, 2, 5, 5, 5, true)
|
||||
createSemester(this, 2, 5, 6, 5, true)
|
||||
createSemester(this, 2, 5, 7, 55, true)
|
||||
createSemester(this, 2, 5, 8, 55, true)
|
||||
createSemester(this, 2, 5, 5, true)
|
||||
createSemester(this, 2, 6, 5, true)
|
||||
createSemester(this, 2, 7, 55, true)
|
||||
createSemester(this, 2, 8, 55, true)
|
||||
|
||||
createStudent(this, 3, "", 5)
|
||||
createSemester(this, 3, 5, 11, 99, false)
|
||||
createSemester(this, 3, 5, 12, 99, false)
|
||||
createSemester(this, 3, 5, 13, 100, false)
|
||||
createSemester(this, 3, 5, 14, 100, true)
|
||||
createSemester(this, 3, 11, 99, false)
|
||||
createSemester(this, 3, 12, 99, false)
|
||||
createSemester(this, 3, 13, 100, false)
|
||||
createSemester(this, 3, 14, 100, true)
|
||||
close()
|
||||
}
|
||||
|
||||
@ -198,7 +198,13 @@ class Migration13Test : AbstractMigrationTest() {
|
||||
})
|
||||
}
|
||||
|
||||
private fun createSemester(db: SupportSQLiteDatabase, studentId: Int, classId: Int, semesterId: Int, diaryId: Int, isCurrent: Boolean = false) {
|
||||
private fun createSemester(
|
||||
db: SupportSQLiteDatabase,
|
||||
studentId: Int,
|
||||
semesterId: Int,
|
||||
diaryId: Int,
|
||||
isCurrent: Boolean = false
|
||||
) {
|
||||
db.insert("Semesters", SQLiteDatabase.CONFLICT_FAIL, ContentValues().apply {
|
||||
put("student_id", studentId)
|
||||
put("diary_id", diaryId)
|
||||
@ -206,7 +212,7 @@ class Migration13Test : AbstractMigrationTest() {
|
||||
put("semester_id", semesterId)
|
||||
put("semester_name", "1")
|
||||
put("is_current", isCurrent)
|
||||
put("class_id", classId)
|
||||
put("class_id", 5)
|
||||
put("unit_id", "99")
|
||||
})
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ import io.mockk.impl.annotations.MockK
|
||||
import io.mockk.impl.annotations.SpyK
|
||||
import io.mockk.just
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNotEquals
|
||||
import org.junit.Before
|
||||
@ -81,15 +82,15 @@ class SemesterRepositoryTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getSemesters_invalidDiary_scrapper() {
|
||||
fun getSemesters_invalidDiary_scrapper() = runTest {
|
||||
val badSemesters = listOf(
|
||||
getSemesterPojo(0, 1, now().minusMonths(6), now().minusMonths(3)),
|
||||
getSemesterPojo(0, 2, now().minusMonths(3), now())
|
||||
getSemesterPojo(0, 2, now().minusMonths(6), now()),
|
||||
getSemesterPojo(0, 2, now(), now().plusMonths(6)),
|
||||
)
|
||||
|
||||
val goodSemesters = listOf(
|
||||
getSemesterPojo(1, 1, now().minusMonths(6), now().minusMonths(3)),
|
||||
getSemesterPojo(1, 2, now().minusMonths(3), now())
|
||||
getSemesterPojo(1, 2, now().minusMonths(6), now()),
|
||||
getSemesterPojo(2, 3, now(), now().plusMonths(6)),
|
||||
)
|
||||
|
||||
coEvery { semesterDb.loadAll(student.studentId, student.classId) } returnsMany listOf(
|
||||
@ -101,7 +102,9 @@ class SemesterRepositoryTest {
|
||||
coEvery { semesterDb.deleteAll(any()) } just Runs
|
||||
coEvery { semesterDb.insertSemesters(any()) } returns listOf()
|
||||
|
||||
val items = runBlocking { semesterRepository.getSemesters(student.copy(loginMode = Sdk.Mode.SCRAPPER.name)) }
|
||||
val items = semesterRepository.getSemesters(
|
||||
student = student.copy(loginMode = Sdk.Mode.SCRAPPER.name)
|
||||
)
|
||||
assertEquals(2, items.size)
|
||||
assertNotEquals(0, items[0].diaryId)
|
||||
}
|
||||
@ -188,15 +191,15 @@ class SemesterRepositoryTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getSemesters_doubleCurrent_refreshOnNoCurrent() {
|
||||
fun getSemesters_doubleCurrent_refreshOnNoCurrent() = runTest {
|
||||
val semesters = listOf(
|
||||
getSemesterEntity(1, 1, now(), now()),
|
||||
getSemesterEntity(1, 2, now(), now())
|
||||
getSemesterEntity(1, 1, now().minusMonths(1), now().plusMonths(1)),
|
||||
getSemesterEntity(1, 2, now().minusMonths(1), now().plusMonths(1))
|
||||
)
|
||||
|
||||
coEvery { semesterDb.loadAll(student.studentId, student.classId) } returns semesters
|
||||
|
||||
val items = runBlocking { semesterRepository.getSemesters(student, refreshOnNoCurrent = true) }
|
||||
val items = semesterRepository.getSemesters(student, refreshOnNoCurrent = true)
|
||||
assertEquals(2, items.size)
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,9 @@ package io.github.wulkanowy.ui.modules.login.form
|
||||
|
||||
import io.github.wulkanowy.MainCoroutineRule
|
||||
import io.github.wulkanowy.data.pojos.RegisterUser
|
||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.domain.adminmessage.GetAppropriateAdminMessageUseCase
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.sdk.scrapper.Scrapper
|
||||
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
|
||||
@ -40,6 +42,12 @@ class LoginFormPresenterTest {
|
||||
@MockK
|
||||
lateinit var appInfo: AppInfo
|
||||
|
||||
@MockK
|
||||
lateinit var getAppropriateAdminMessageUseCase: GetAppropriateAdminMessageUseCase
|
||||
|
||||
@MockK
|
||||
lateinit var preferencesRepository: PreferencesRepository
|
||||
|
||||
private lateinit var presenter: LoginFormPresenter
|
||||
|
||||
private val registerUser = RegisterUser(
|
||||
@ -72,6 +80,8 @@ class LoginFormPresenterTest {
|
||||
loginErrorHandler = errorHandler,
|
||||
appInfo = appInfo,
|
||||
analytics = analytics,
|
||||
getAppropriateAdminMessageUseCase = getAppropriateAdminMessageUseCase,
|
||||
preferencesRepository = preferencesRepository,
|
||||
)
|
||||
presenter.onAttachView(loginFormView)
|
||||
}
|
||||
|
@ -8,6 +8,40 @@ import kotlin.test.assertEquals
|
||||
|
||||
class SemesterExtensionKtTest {
|
||||
|
||||
@Test
|
||||
fun `check is first semester is current`() {
|
||||
val first = getSemesterEntity(
|
||||
semesterName = 1,
|
||||
start = LocalDate.of(2023, 9, 1),
|
||||
end = LocalDate.of(2024, 1, 31),
|
||||
)
|
||||
|
||||
// first boundary - school-year start
|
||||
assertEquals(false, first.isCurrent(LocalDate.of(2023, 8, 28)))
|
||||
assertEquals(true, first.isCurrent(LocalDate.of(2023, 8, 29)))
|
||||
|
||||
// second boundary
|
||||
assertEquals(true, first.isCurrent(LocalDate.of(2024, 1, 31)))
|
||||
assertEquals(false, first.isCurrent(LocalDate.of(2024, 2, 1)))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `check is second semester is current`() {
|
||||
val second = getSemesterEntity(
|
||||
semesterName = 2,
|
||||
start = LocalDate.of(2024, 2, 1),
|
||||
end = LocalDate.of(2024, 9, 1),
|
||||
)
|
||||
|
||||
// first boundary
|
||||
assertEquals(false, second.isCurrent(LocalDate.of(2024, 1, 31)))
|
||||
assertEquals(true, second.isCurrent(LocalDate.of(2024, 2, 1)))
|
||||
|
||||
// second boundary - school-year end
|
||||
assertEquals(true, second.isCurrent(LocalDate.of(2024, 8, 29)))
|
||||
assertEquals(false, second.isCurrent(LocalDate.of(2024, 8, 30)))
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException::class)
|
||||
fun `get current semester when current is doubled`() {
|
||||
val semesters = listOf(
|
||||
|
19
build.gradle
19
build.gradle
@ -1,8 +1,8 @@
|
||||
buildscript {
|
||||
ext {
|
||||
kotlin_version = '1.8.21'
|
||||
about_libraries = '10.7.0'
|
||||
hilt_version = "2.46.1"
|
||||
kotlin_version = '1.9.0'
|
||||
about_libraries = '10.8.3'
|
||||
hilt_version = "2.47"
|
||||
}
|
||||
repositories {
|
||||
mavenCentral()
|
||||
@ -13,14 +13,15 @@ buildscript {
|
||||
dependencies {
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
|
||||
classpath 'com.android.tools.build:gradle:8.0.2'
|
||||
classpath "com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin:$kotlin_version-1.0.11"
|
||||
classpath 'com.android.tools.build:gradle:8.1.0'
|
||||
classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
|
||||
classpath 'com.google.gms:google-services:4.3.15'
|
||||
classpath 'com.huawei.agconnect:agcp:1.9.0.300'
|
||||
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.5'
|
||||
classpath "com.github.triplet.gradle:play-publisher:3.6.0"
|
||||
classpath 'com.huawei.agconnect:agcp:1.9.1.300'
|
||||
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.8'
|
||||
classpath "com.github.triplet.gradle:play-publisher:3.8.4"
|
||||
classpath "ru.cian:huawei-publish-gradle-plugin:1.4.0"
|
||||
classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:4.1.0.3113"
|
||||
classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:4.3.0.3225"
|
||||
classpath "gradle.plugin.com.star-zero.gradle:githook:1.2.0"
|
||||
classpath "com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin:$about_libraries"
|
||||
}
|
||||
@ -36,6 +37,6 @@ allprojects {
|
||||
}
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
tasks.register('clean', Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-all.zip
|
||||
networkTimeout=10000
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
@ -1,4 +1,4 @@
|
||||
plugins {
|
||||
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.5.0'
|
||||
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.7.0'
|
||||
}
|
||||
include ':app'
|
||||
|
Loading…
x
Reference in New Issue
Block a user