1
0

Compare commits

..

46 Commits

Author SHA1 Message Date
ddac1d0f98 Merge branch 'release/0.22.0' into master 2020-10-15 17:54:22 +02:00
db6a359bea Version 0.22.0 2020-10-15 17:54:14 +02:00
e7221e6a32 Add Vulcan and Scrapper Exceptions to known exceptions (#994) 2020-10-15 15:55:59 +02:00
db9c2640c7 Add in-app updates support (#914) 2020-10-15 01:00:41 +02:00
ca67e144e4 Add ConnectException and StreamResetException to known exceptions (#992) 2020-10-13 22:32:15 +02:00
da2346ed83 New Crowdin updates (#987) 2020-10-11 21:00:48 +02:00
a87818f3d0 Cancel scheduled lesson notifications which turned into canceled (#991) 2020-10-11 20:51:03 +02:00
5092f8c0bf Reload grade list on mark all as read (#990) 2020-10-11 20:33:18 +02:00
af0787c0b1 Add support for BIG font (#989)
Co-authored-by: Faierbel <RafalBO99@outlook.com>
2020-10-10 02:53:25 +02:00
721b4ac797 Add support for night mode in account switcher dialog (#988) 2020-10-09 21:24:58 +02:00
26a69092cc Add AppGallery badge (#986) 2020-10-07 11:19:34 +02:00
2bd0c75055 Bump about_libraries from 8.3.1 to 8.4.2 (#985) 2020-10-06 21:56:46 +00:00
d6f3c57293 Bump moshi from 1.10.0 to 1.11.0 (#984) 2020-10-06 21:45:38 +00:00
518387e7bb Bump gradle from 4.0.1 to 4.0.2 (#982) 2020-10-06 21:43:56 +00:00
ca6dfbf2d0 Bump core-ktx from 1.3.1 to 1.3.2 (#983) 2020-10-06 21:43:50 +00:00
da6d8a74fd New Crowdin updates (#981) 2020-10-06 23:34:27 +02:00
e35e4ef152 New Crowdin updates (#948) 2020-10-03 13:01:11 +02:00
40fc6ec2e0 Upgrade android sdk to 30 (#966) 2020-10-03 01:08:57 +02:00
b91973aec3 Bump chucker from 3.2.0 to 3.3.0 (#979) 2020-10-01 15:38:29 +00:00
047e70ad46 Bump firebase-crashlytics from 17.2.1 to 17.2.2 (#974) 2020-09-30 20:13:18 +00:00
112c1eb793 Bump moshi from 1.9.3 to 1.10.0 (#972) 2020-09-30 20:13:01 +00:00
c479b31670 Bump coil from 1.0.0-rc2 to 1.0.0-rc3 (#976) 2020-09-30 20:01:45 +00:00
43ed8c8fce Bump firebase-messaging from 20.2.4 to 20.3.0 (#973) 2020-09-30 19:52:02 +00:00
613fa44c27 Bump about_libraries from 8.3.0 to 8.3.1 (#975) 2020-09-30 19:34:53 +00:00
f21216286d Bump mockk from 1.10.0 to 1.10.2 (#977) 2020-09-30 19:34:13 +00:00
7298d0d75a Bump google-services from 4.3.3 to 4.3.4 (#978) 2020-09-30 19:33:22 +00:00
ee0fbcdfd6 Merge tag '0.21.2' into develop
Version 0.21.2
2020-09-29 21:10:17 +02:00
c362ad12c7 Merge branch 'release/0.21.2' into master 2020-09-29 21:10:11 +02:00
8a1a712d6d Version 0.21.2 2020-09-29 21:10:05 +02:00
1f0f6b3e51 Fix string pair list type converter (#971) 2020-09-29 21:02:49 +02:00
11487e77ca Merge tag '0.21.1' into develop
Version 0.21.1
2020-09-29 11:43:58 +02:00
fd0fd4df55 Merge branch 'release/0.21.1' into master 2020-09-29 11:43:54 +02:00
d95a33787b Version 0.21.1 2020-09-29 11:43:49 +02:00
e5661098d9 Fix string pair list type converter (#970) 2020-09-29 11:42:54 +02:00
d020b01794 Merge tag '0.21.0' into develop
Version 0.21.0
2020-09-27 22:12:31 +02:00
d8b1264024 Merge branch 'release/0.21.0' into master 2020-09-27 22:12:27 +02:00
cddd17650b Version 0.21.0 2020-09-27 22:11:55 +02:00
a0f9c70036 Migrate from gson to moshi (#969) 2020-09-27 20:59:27 +02:00
2e05416fb5 Show groups next to subjects in timetable (#953) 2020-09-27 16:33:36 +02:00
d32ebd66de Add subjects sorting in grades (#946) 2020-09-27 16:28:39 +02:00
c6a99f1000 Add remembering the full screen mode in homework (#956)
Co-authored-by: Faierbel <RafalBO99@outlook.com>
2020-09-27 14:49:19 +02:00
bafe52e310 Different notification for notes and praises (#952) 2020-09-25 15:46:08 +02:00
e08abc1fc2 Show subjects without grades in "Grades" (#947) 2020-09-25 15:45:07 +02:00
2a74b11cce Add app shortcuts (#939)
Co-authored-by: Faierbel <RafalBO99@outlook.com>
2020-09-25 15:37:19 +02:00
b0b3ccfd53 Upgrade gradle wrapper to 6.6.1 (#968) 2020-09-20 21:54:59 +02:00
6c68456f7a Merge tag '0.20.5' into develop
Version 0.20.5
2020-09-19 13:03:32 +02:00
97 changed files with 1527 additions and 256 deletions

View File

@ -3,8 +3,8 @@ jdk: oraclejdk8
env:
global:
- ANDROID_API_LEVEL=29
- ANDROID_BUILD_TOOLS_VERSION=29.0.3
- ANDROID_API_LEVEL=30
- ANDROID_BUILD_TOOLS_VERSION=30.0.2
cache:
directories:
@ -14,7 +14,7 @@ cache:
branches:
only:
- develop
- 0.20.5
- 0.22.0
android:
licenses:
@ -28,28 +28,32 @@ android:
- build-tools-$ANDROID_BUILD_TOOLS_VERSION
# The SDK version used to compile your project
- android-$ANDROID_API_LEVEL
# Additional components
# Additional components
- extra-google-google_play_services
- extra-google-m2repository
- extra-android-m2repository
- addon-google_apis-google-$ANDROID_API_LEVEL
# Android emulator
# Android emulator
- android-22
- sys-img-armeabi-v7a-android-22
before_install:
- yes | sdkmanager "platforms;android-30"
- yes | sdkmanager "build-tools;30.0.2"
before_script:
# Launch emulator before the execution
- echo no | android create avd --force -n test -t android-22 --abi armeabi-v7a
- emulator -avd test -no-audio -no-window &
- android-wait-for-emulator
- adb shell input keyevent 82 &
- "curl -H 'Cache-Control: no-cache' https://raw.githubusercontent.com/fossas/fossa-cli/master/install.sh | sudo bash"
# Launch emulator before the execution
- echo no | android create avd --force -n test -t android-22 --abi armeabi-v7a
- emulator -avd test -no-audio -no-window &
- android-wait-for-emulator
- adb shell input keyevent 82 &
- "curl -H 'Cache-Control: no-cache' https://raw.githubusercontent.com/fossas/fossa-cli/master/install.sh | sudo bash"
script:
- ./gradlew dependencies --stacktrace --daemon
- fossa --no-ansi || true
- ./gradlew -Pcoverage testPlayDebugUnitTest --stacktrace --daemon
- ./gradlew -Pcoverage createFdroidDebugCoverageReport --stacktrace --daemon
- ./gradlew -Pcoverage testFdroidDebugUnitTest --stacktrace --daemon
- ./gradlew -Pcoverage connectedFdroidDebugAndroidTest --stacktrace --daemon
- ./gradlew -Pcoverage jacocoTestReport --stacktrace --daemon
- |
if [ $TRAVIS_TAG ]; then

View File

@ -32,14 +32,17 @@ Unofficial android VULCAN UONET+ register client for both students and their par
## Download
You can download the current beta version from the Google Play or the F-Droid store
You can download the current beta version from the Google Play, F-Droid or Huawei AppGallery store
[<img src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png"
alt="Get it on Google Play"
height="80">](https://play.google.com/store/apps/details?id=io.github.wulkanowy)
alt="Get it on Google Play"
height="80">](https://play.google.com/store/apps/details?id=io.github.wulkanowy)
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
alt="Get it on F-Droid"
height="80">](https://f-droid.org/packages/io.github.wulkanowy/)
[<img src="appgallery_badge.png"
alt="Explore it on AppGallery"
height="80">](https://appgallery.cloud.huawei.com/ag/n/app/C101440411?channelId=Badge&id=1b3f7fbb700849a9be0dba6b520b2282&s=EB1D3BF9ED9D1564D869B7B94B18016D3CABFCA5AEFB8E29F675FA04E0DC131D&detailType=0&v=)
You can also download a [development version](https://wulkanowy.github.io/#download) that includes new features being prepared for the next release

View File

@ -32,14 +32,17 @@ Nieoficjalny klient dziennika VULCAN UONET+ dla ucznia i rodzica
## Pobierz
Aktualną wersję beta możesz pobrać ze sklepu Google Play lub F-Droid
Aktualną wersję beta możesz pobrać ze sklepu Google Play, F-Droid lub Huawei AppGallery
[<img src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png"
alt="Pobierz z Google Play"
height="80">](https://play.google.com/store/apps/details?id=io.github.wulkanowy)
alt="Pobierz z Google Play"
height="80">](https://play.google.com/store/apps/details?id=io.github.wulkanowy)
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
alt="Pobierz z F-Droid"
height="80">](https://f-droid.org/packages/io.github.wulkanowy/)
[<img src="appgallery_badge.png"
alt="Odkrywaj w AppGallery"
height="80">](https://appgallery.cloud.huawei.com/ag/n/app/C101440411?channelId=Badge&id=1b3f7fbb700849a9be0dba6b520b2282&s=EB1D3BF9ED9D1564D869B7B94B18016D3CABFCA5AEFB8E29F675FA04E0DC131D&detailType=0&v=)
Możesz także pobrać [wersję rozwojową](https://wulkanowy.github.io/#download), która zawiera nowe funkcje przygotowywane do następnego wydania

View File

@ -10,16 +10,16 @@ apply from: 'sonarqube.gradle'
apply from: 'hooks.gradle'
android {
compileSdkVersion 29
buildToolsVersion '29.0.3'
compileSdkVersion 30
buildToolsVersion '30.0.2'
defaultConfig {
applicationId "io.github.wulkanowy"
testApplicationId "io.github.tests.wulkanowy"
minSdkVersion 17
targetSdkVersion 29
versionCode 69
versionName "0.20.5"
targetSdkVersion 30
versionCode 73
versionName "0.22.0"
multiDexEnabled true
resValue "string", "app_name", "Wulkanowy"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@ -112,13 +112,15 @@ play {
serviceAccountCredentials = file('key.p12')
defaultToAppBundles = false
track = 'alpha'
updatePriority = 0
}
ext {
work_manager = "2.4.0"
room = "2.2.5"
chucker = "3.2.0"
mockk = "1.10.0"
chucker = "3.3.0"
mockk = "1.10.2"
moshi = "1.11.0"
}
configurations.all {
@ -126,14 +128,14 @@ configurations.all {
}
dependencies {
implementation "io.github.wulkanowy:sdk:0.20.5"
implementation "io.github.wulkanowy:sdk:0.22.0"
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.10'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'
implementation "androidx.core:core-ktx:1.3.1"
implementation "androidx.core:core-ktx:1.3.2"
implementation "androidx.activity:activity-ktx:1.1.0"
implementation "androidx.appcompat:appcompat:1.2.0"
implementation "androidx.appcompat:appcompat-resources:1.2.0"
@ -170,21 +172,24 @@ dependencies {
implementation "com.ncapdevi:frag-nav:3.3.0"
implementation "com.github.YarikSOffice:lingver:1.2.2"
implementation "com.google.code.gson:gson:2.8.6"
implementation "com.squareup.moshi:moshi:$moshi"
implementation "com.squareup.moshi:moshi-adapters:$moshi"
kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi"
implementation "com.jakewharton.timber:timber:4.7.1"
implementation "at.favre.lib:slf4j-timber:1.0.1"
implementation "fr.bipi.treessence:treessence:0.3.2"
implementation "com.mikepenz:aboutlibraries-core:$about_libraries"
implementation 'com.wdullaer:materialdatetimepicker:4.2.3'
implementation "io.coil-kt:coil:1.0.0-rc2"
implementation "io.coil-kt:coil:1.0.0-rc3"
implementation "io.github.wulkanowy:AppKillerManager:3.0.0"
implementation 'me.xdrop:fuzzywuzzy:1.3.1'
playImplementation 'com.google.firebase:firebase-analytics:17.5.0'
playImplementation 'com.google.firebase:firebase-analytics:17.6.0'
playImplementation 'com.google.firebase:firebase-inappmessaging-display-ktx:19.1.1'
playImplementation "com.google.firebase:firebase-inappmessaging-ktx:19.1.1"
playImplementation 'com.google.firebase:firebase-messaging:20.2.4'
playImplementation 'com.google.firebase:firebase-crashlytics:17.2.1'
playImplementation 'com.google.firebase:firebase-messaging:20.3.0'
playImplementation 'com.google.firebase:firebase-crashlytics:17.2.2'
playImplementation 'com.google.android.play:core-ktx:1.8.1'
playImplementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava'
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker"

View File

@ -35,13 +35,13 @@ task jacocoTestReport(type: JacocoReport) {
dir: "$buildDir/intermediates/classes/debug",
excludes: excludes
) + fileTree(
dir: "$buildDir/tmp/kotlin-classes/playDebug",
dir: "$buildDir/tmp/kotlin-classes/fdroidDebug",
excludes: excludes
))
sourceDirectories.setFrom(files([
"src/main/java",
"src/play/java"
"src/fdroid/java"
]))
executionData.setFrom(fileTree(
dir: project.projectDir,

View File

@ -0,0 +1,17 @@
package io.github.wulkanowy.utils
import android.app.Activity
import android.view.View
import javax.inject.Inject
@Suppress("UNUSED_PARAMETER")
class UpdateHelper @Inject constructor() {
lateinit var messageContainer: View
fun checkAndInstallUpdates(activity: Activity) {}
fun onActivityResult(requestCode: Int, resultCode: Int) {}
fun onResume(activity: Activity) {}
}

View File

@ -33,7 +33,11 @@ internal class RepositoryModule {
setSimpleHttpLogger { Timber.d(it) }
// for debug only
addInterceptor(ChuckerInterceptor(context, chuckerCollector), true)
addInterceptor(ChuckerInterceptor(
context = context,
collector = chuckerCollector,
alwaysReadResponseBody = true
), true)
}
}

View File

@ -1,8 +1,9 @@
package io.github.wulkanowy.data.db
import androidx.room.TypeConverter
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.squareup.moshi.Moshi
import com.squareup.moshi.Types
import io.github.wulkanowy.data.db.adapters.PairAdapterFactory
import java.time.Instant
import java.time.LocalDate
import java.time.LocalDateTime
@ -12,6 +13,16 @@ import java.util.Date
class Converters {
private val moshi by lazy { Moshi.Builder().add(PairAdapterFactory).build() }
private val integerListAdapter by lazy {
moshi.adapter<List<Int>>(Types.newParameterizedType(List::class.java, Integer::class.java))
}
private val stringListPairAdapter by lazy {
moshi.adapter<List<Pair<String, String>>>(Types.newParameterizedType(List::class.java, Pair::class.java, String::class.java, String::class.java))
}
@TypeConverter
fun timestampToDate(value: Long?): LocalDate? = value?.run {
Date(value).toInstant().atZone(ZoneOffset.UTC).toLocalDate()
@ -39,22 +50,22 @@ class Converters {
fun intToMonth(value: Int?) = value?.let { Month.of(it) }
@TypeConverter
fun intListToGson(list: List<Int>): String {
return Gson().toJson(list)
fun intListToJson(list: List<Int>): String {
return integerListAdapter.toJson(list)
}
@TypeConverter
fun gsonToIntList(value: String): List<Int> {
return Gson().fromJson(value, object : TypeToken<List<Int>>() {}.type)
fun jsonToIntList(value: String): List<Int> {
return integerListAdapter.fromJson(value).orEmpty()
}
@TypeConverter
fun stringPairListToGson(list: List<Pair<String, String>>): String {
return Gson().toJson(list)
fun stringPairListToJson(list: List<Pair<String, String>>): String {
return stringListPairAdapter.toJson(list)
}
@TypeConverter
fun gsonToStringPairList(value: String): List<Pair<String, String>> {
return Gson().fromJson(value, object : TypeToken<List<Pair<String, String>>>() {}.type)
fun jsonToStringPairList(value: String): List<Pair<String, String>> {
return stringListPairAdapter.fromJson(value).orEmpty()
}
}

View File

@ -0,0 +1,68 @@
package io.github.wulkanowy.data.db.adapters
import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.JsonReader
import com.squareup.moshi.JsonWriter
import com.squareup.moshi.Moshi
import com.squareup.moshi.Types
import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type
object PairAdapterFactory : JsonAdapter.Factory {
override fun create(type: Type, annotations: MutableSet<out Annotation>, moshi: Moshi): JsonAdapter<*>? {
if (type !is ParameterizedType || List::class.java != type.rawType) return null
if (type.actualTypeArguments[0] != Pair::class.java) return null
val listType = Types.newParameterizedType(List::class.java, Map::class.java, String::class.java)
val listAdapter = moshi.adapter<List<Map<String, String>>>(listType)
val mapType = Types.newParameterizedType(MutableMap::class.java, String::class.java, String::class.java)
val mapAdapter = moshi.adapter<Map<String, String>>(mapType)
return PairAdapter(listAdapter, mapAdapter)
}
private class PairAdapter(
private val listAdapter: JsonAdapter<List<Map<String, String>>>,
private val mapAdapter: JsonAdapter<Map<String, String>>,
) : JsonAdapter<List<Pair<String, String>>>() {
override fun toJson(writer: JsonWriter, value: List<Pair<String, String>>?) {
writer.beginArray()
value?.forEach {
writer.beginObject()
writer.name("first").value(it.first)
writer.name("second").value(it.second)
writer.endObject()
}
writer.endArray()
}
override fun fromJson(reader: JsonReader): List<Pair<String, String>>? {
return if (reader.peek() == JsonReader.Token.BEGIN_OBJECT) deserializeMoshiMap(reader)
else deserializeGsonPair(reader)
}
// for compatibility with 0.21.0
private fun deserializeMoshiMap(reader: JsonReader): List<Pair<String, String>>? {
val map = mapAdapter.fromJson(reader) ?: return null
return map.entries.map {
it.key to it.value
}
}
private fun deserializeGsonPair(reader: JsonReader): List<Pair<String, String>>? {
val list = listAdapter.fromJson(reader) ?: return null
return list.map {
require(it.size == 2) {
"pair with more or less than two elements: $list"
}
it["first"].orEmpty() to it["second"].orEmpty()
}
}
}
}

View File

@ -1,3 +1,9 @@
package io.github.wulkanowy.data.pojos
class Contributor(val displayName: String, val githubUsername: String)
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
class Contributor(
val displayName: String,
val githubUsername: String
)

View File

@ -1,7 +1,8 @@
package io.github.wulkanowy.data.repositories.appcreator
import android.content.res.AssetManager
import com.google.gson.Gson
import com.squareup.moshi.Moshi
import com.squareup.moshi.Types
import io.github.wulkanowy.data.pojos.Contributor
import io.github.wulkanowy.utils.DispatchersProvider
import kotlinx.coroutines.withContext
@ -15,9 +16,9 @@ class AppCreatorRepository @Inject constructor(
) {
suspend fun getAppCreators() = withContext(dispatchers.backgroundThread) {
Gson().fromJson(
assets.open("contributors.json").bufferedReader().use { it.readText() },
Array<Contributor>::class.java
).toList()
val moshi = Moshi.Builder().build()
val type = Types.newParameterizedType(List::class.java, Contributor::class.java)
val adapter = moshi.adapter<List<Contributor>>(type)
adapter.fromJson(assets.open("contributors.json").bufferedReader().use { it.readText() })
}
}

View File

@ -5,6 +5,7 @@ import android.content.SharedPreferences
import dagger.hilt.android.qualifiers.ApplicationContext
import io.github.wulkanowy.R
import io.github.wulkanowy.ui.modules.grade.GradeAverageMode
import io.github.wulkanowy.ui.modules.grade.GradeSortingMode
import javax.inject.Inject
import javax.inject.Singleton
@ -74,12 +75,25 @@ class PreferencesRepository @Inject constructor(
val fillMessageContent: Boolean
get() = getBoolean(R.string.pref_key_fill_message_content, R.bool.pref_default_fill_message_content)
val showGroupsInPlan: Boolean
get() = getBoolean(R.string.pref_key_timetable_show_groups, R.bool.pref_default_timetable_show_groups)
val showWholeClassPlan: String
get() = getString(R.string.pref_key_timetable_show_whole_class, R.string.pref_default_timetable_show_whole_class)
val gradeSortingMode: GradeSortingMode
get() = GradeSortingMode.getByValue(getString(R.string.pref_key_grade_sorting_mode, R.string.pref_default_grade_sorting_mode))
val showTimetableTimers: Boolean
get() = getBoolean(R.string.pref_key_timetable_show_timers, R.bool.pref_default_timetable_show_timers)
var isHomeworkFullscreen: Boolean
get() = getBoolean(R.string.pref_key_homework_fullscreen, R.bool.pref_default_homework_fullscreen)
set(value) = sharedPref.edit().putBoolean("homework_fullscreen", value).apply()
val showSubjectsWithoutGrades: Boolean
get() = getBoolean(R.string.pref_key_subjects_without_grades, R.bool.pref_default_subjects_without_grades)
private fun getString(id: Int, default: Int) = getString(context.getString(id), default)
private fun getString(id: String, default: Int) = sharedPref.getString(id, context.getString(default)) ?: context.getString(default)

View File

@ -72,18 +72,22 @@ class TimetableNotificationSchedulerHelper @Inject constructor(
withContext(dispatchersProvider.backgroundThread) {
lessons.groupBy { it.date }
.map { it.value.sortedBy { lesson -> lesson.start } }
.map { it.filter { lesson -> !lesson.canceled && lesson.isStudentPlan } }
.map { it.filter { lesson -> lesson.isStudentPlan } }
.map { day ->
day.forEachIndexed { index, lesson ->
val intent = createIntent(student, lesson, day.getOrNull(index + 1))
val canceled = day.filter { it.canceled }
val active = day.filter { !it.canceled }
cancelScheduled(canceled)
active.forEachIndexed { index, lesson ->
val intent = createIntent(student, lesson, active.getOrNull(index + 1))
if (lesson.start > now()) {
scheduleBroadcast(intent, student.studentId, NOTIFICATION_TYPE_UPCOMING, getUpcomingLessonTime(index, day, lesson))
scheduleBroadcast(intent, student.studentId, NOTIFICATION_TYPE_UPCOMING, getUpcomingLessonTime(index, active, lesson))
}
if (lesson.end > now()) {
scheduleBroadcast(intent, student.studentId, NOTIFICATION_TYPE_CURRENT, lesson.start)
if (day.lastIndex == index) {
if (active.lastIndex == index) {
scheduleBroadcast(intent, student.studentId, NOTIFICATION_TYPE_LAST_LESSON_CANCELLATION, lesson.end)
}
}

View File

@ -14,6 +14,9 @@ import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.note.NoteRepository
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
import io.github.wulkanowy.sdk.scrapper.notes.NoteCategory
import io.github.wulkanowy.sdk.scrapper.notes.NoteCategory.NEUTRAL
import io.github.wulkanowy.sdk.scrapper.notes.NoteCategory.POSITIVE
import io.github.wulkanowy.services.sync.channels.NewNotesChannel
import io.github.wulkanowy.ui.modules.main.MainActivity
import io.github.wulkanowy.ui.modules.main.MainView
@ -41,8 +44,20 @@ class NoteWork @Inject constructor(
private fun notify(notes: List<Note>) {
notificationManager.notify(Random.nextInt(Int.MAX_VALUE), NotificationCompat.Builder(context, NewNotesChannel.CHANNEL_ID)
.setContentTitle(context.resources.getQuantityString(R.plurals.note_new_items, notes.size, notes.size))
.setContentText(context.resources.getQuantityString(R.plurals.note_notify_new_items, notes.size, notes.size))
.setContentTitle(
when (NoteCategory.getByValue(notes.first().categoryType)) {
POSITIVE -> context.resources.getQuantityString(R.plurals.praise_new_items, notes.size, notes.size)
NEUTRAL -> context.resources.getQuantityString(R.plurals.neutral_note_new_items, notes.size, notes.size)
else -> context.resources.getQuantityString(R.plurals.note_new_items, notes.size, notes.size)
}
)
.setContentText(
when (NoteCategory.getByValue(notes.first().categoryType)) {
POSITIVE -> context.resources.getQuantityString(R.plurals.praise_notify_new_items, notes.size, notes.size)
NEUTRAL -> context.resources.getQuantityString(R.plurals.neutral_note_notify_new_items, notes.size, notes.size)
else -> context.resources.getQuantityString(R.plurals.note_notify_new_items, notes.size, notes.size)
}
)
.setSmallIcon(R.drawable.ic_stat_note)
.setAutoCancel(true)
.setDefaults(DEFAULT_ALL)
@ -52,7 +67,13 @@ class NoteWork @Inject constructor(
PendingIntent.getActivity(context, MainView.Section.NOTE.id,
MainActivity.getStartIntent(context, MainView.Section.NOTE, true), FLAG_UPDATE_CURRENT))
.setStyle(NotificationCompat.InboxStyle().run {
setSummaryText(context.resources.getQuantityString(R.plurals.note_number_item, notes.size, notes.size))
setSummaryText(
when (NoteCategory.getByValue(notes.first().categoryType)) {
POSITIVE -> context.resources.getQuantityString(R.plurals.praise_number_item, notes.size, notes.size)
NEUTRAL -> context.resources.getQuantityString(R.plurals.neutral_note_number_item, notes.size, notes.size)
else -> context.resources.getQuantityString(R.plurals.note_number_item, notes.size, notes.size)
}
)
notes.forEach { addLine("${it.teacher}: ${it.category}") }
this
})

View File

@ -22,9 +22,11 @@ import io.github.wulkanowy.utils.getString
import io.github.wulkanowy.utils.openAppInMarket
import io.github.wulkanowy.utils.openEmailClient
import io.github.wulkanowy.utils.openInternetBrowser
import okhttp3.internal.http2.StreamResetException
import java.io.InterruptedIOException
import java.io.PrintWriter
import java.io.StringWriter
import java.net.ConnectException
import java.net.SocketTimeoutException
import java.net.UnknownHostException
import javax.inject.Inject
@ -85,6 +87,8 @@ class ErrorDialog : BaseDialogFragment<DialogErrorBinding>() {
errorDialogReport.isEnabled = when (error) {
is UnknownHostException,
is InterruptedIOException,
is ConnectException,
is StreamResetException,
is SocketTimeoutException,
is ServiceUnavailableException,
is FeatureDisabledException,

View File

@ -0,0 +1,10 @@
package io.github.wulkanowy.ui.modules.grade
enum class GradeSortingMode(val value: String) {
ALPHABETIC("alphabetic"),
DATE("date");
companion object {
fun getByValue(value: String) = values().firstOrNull { it.value == value } ?: ALPHABETIC
}
}

View File

@ -1,5 +1,6 @@
package io.github.wulkanowy.ui.modules.grade.details
import android.annotation.SuppressLint
import io.github.wulkanowy.data.Status
import io.github.wulkanowy.data.db.entities.Grade
import io.github.wulkanowy.data.repositories.grade.GradeRepository
@ -10,6 +11,8 @@ import io.github.wulkanowy.ui.base.BasePresenter
import io.github.wulkanowy.ui.base.ErrorHandler
import io.github.wulkanowy.ui.modules.grade.GradeAverageProvider
import io.github.wulkanowy.ui.modules.grade.GradeDetailsWithAverage
import io.github.wulkanowy.ui.modules.grade.GradeSortingMode.ALPHABETIC
import io.github.wulkanowy.ui.modules.grade.GradeSortingMode.DATE
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
import io.github.wulkanowy.utils.afterLoading
import io.github.wulkanowy.utils.flowWithResource
@ -78,7 +81,10 @@ class GradeDetailsPresenter @Inject constructor(
}.onEach {
when (it.status) {
Status.LOADING -> Timber.i("Select mark grades as read")
Status.SUCCESS -> Timber.i("Mark as read result: Success")
Status.SUCCESS -> {
Timber.i("Mark as read result: Success")
loadData(currentSemesterId, false)
}
Status.ERROR -> {
Timber.i("Mark as read result: An exception occurred")
errorHandler.dispatch(it.error!!)
@ -184,10 +190,20 @@ class GradeDetailsPresenter @Inject constructor(
}
}
@SuppressLint("DefaultLocale")
private fun createGradeItems(items: List<GradeDetailsWithAverage>): List<GradeDetailsItem> {
return items
.filter { it.grades.isNotEmpty() }
.sortedBy { it.subject }
.let { gradesWithAverages ->
if (!preferencesRepository.showSubjectsWithoutGrades) {
gradesWithAverages.filter { it.grades.isNotEmpty() }
} else gradesWithAverages
}
.let {
when (preferencesRepository.gradeSortingMode) {
DATE -> it.sortedByDescending { gradeDetailsWithAverage -> gradeDetailsWithAverage.grades.firstOrNull()?.date }
ALPHABETIC -> it.sortedBy { gradeDetailsWithAverage -> gradeDetailsWithAverage.subject.toLowerCase() }
}
}
.map { (subject, average, points, _, grades) ->
val subItems = grades
.sortedByDescending { it.date }

View File

@ -29,6 +29,8 @@ class HomeworkDetailsAdapter @Inject constructor() :
attachments = value?.attachments.orEmpty()
}
var isHomeworkFullscreen = false
var onAttachmentClickListener: (url: String) -> Unit = {}
var onFullScreenClickListener = {}
@ -67,6 +69,8 @@ class HomeworkDetailsAdapter @Inject constructor() :
homeworkDialogSubject.text = homework?.subject
homeworkDialogTeacher.text = homework?.teacher
homeworkDialogContent.text = homework?.content
homeworkDialogFullScreen.visibility = if (isHomeworkFullscreen) GONE else VISIBLE
homeworkDialogFullScreenExit.visibility = if (isHomeworkFullscreen) VISIBLE else GONE
homeworkDialogFullScreen.setOnClickListener {
homeworkDialogFullScreen.visibility = GONE
homeworkDialogFullScreenExit.visibility = VISIBLE

View File

@ -62,12 +62,25 @@ class HomeworkDetailsDialog : BaseDialogFragment<DialogHomeworkBinding>(), Homew
homeworkDialogClose.setOnClickListener { dismiss() }
}
if (presenter.isHomeworkFullscreen) {
dialog?.window?.setLayout(MATCH_PARENT, MATCH_PARENT)
} else {
dialog?.window?.setLayout(WRAP_CONTENT, WRAP_CONTENT)
}
with(binding.homeworkDialogRecycler) {
layoutManager = LinearLayoutManager(context)
adapter = detailsAdapter.apply {
onAttachmentClickListener = { context.openInternetBrowser(it, ::showMessage) }
onFullScreenClickListener = { dialog?.window?.setLayout(MATCH_PARENT, MATCH_PARENT) }
onFullScreenExitClickListener = { dialog?.window?.setLayout(WRAP_CONTENT, WRAP_CONTENT) }
onFullScreenClickListener = {
dialog?.window?.setLayout(MATCH_PARENT, MATCH_PARENT)
presenter.isHomeworkFullscreen = true
}
onFullScreenExitClickListener = {
dialog?.window?.setLayout(WRAP_CONTENT, WRAP_CONTENT)
presenter.isHomeworkFullscreen = false
}
isHomeworkFullscreen = presenter.isHomeworkFullscreen
homework = this@HomeworkDetailsDialog.homework
}
}

View File

@ -3,6 +3,7 @@ package io.github.wulkanowy.ui.modules.homework.details
import io.github.wulkanowy.data.Status
import io.github.wulkanowy.data.db.entities.Homework
import io.github.wulkanowy.data.repositories.homework.HomeworkRepository
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
import io.github.wulkanowy.data.repositories.student.StudentRepository
import io.github.wulkanowy.ui.base.BasePresenter
import io.github.wulkanowy.ui.base.ErrorHandler
@ -16,9 +17,16 @@ class HomeworkDetailsPresenter @Inject constructor(
errorHandler: ErrorHandler,
studentRepository: StudentRepository,
private val homeworkRepository: HomeworkRepository,
private val analytics: FirebaseAnalyticsHelper
private val analytics: FirebaseAnalyticsHelper,
private val preferencesRepository: PreferencesRepository
) : BasePresenter<HomeworkDetailsView>(errorHandler, studentRepository) {
var isHomeworkFullscreen
get() = preferencesRepository.isHomeworkFullscreen
set(value) {
preferencesRepository.isHomeworkFullscreen = value
}
override fun onAttachView(view: HomeworkDetailsView) {
super.onAttachView(view)
view.initView()

View File

@ -14,6 +14,7 @@ import io.github.wulkanowy.ui.modules.login.form.LoginFormFragment
import io.github.wulkanowy.ui.modules.login.recover.LoginRecoverFragment
import io.github.wulkanowy.ui.modules.login.studentselect.LoginStudentSelectFragment
import io.github.wulkanowy.ui.modules.login.symbol.LoginSymbolFragment
import io.github.wulkanowy.utils.UpdateHelper
import io.github.wulkanowy.utils.setOnSelectPageListener
import javax.inject.Inject
@ -25,6 +26,9 @@ class LoginActivity : BaseActivity<LoginPresenter, ActivityLoginBinding>(), Logi
private val loginAdapter = BaseFragmentPagerAdapter(supportFragmentManager)
@Inject
lateinit var updateHelper: UpdateHelper
companion object {
fun getStartIntent(context: Context) = Intent(context, LoginActivity::class.java)
@ -37,8 +41,20 @@ class LoginActivity : BaseActivity<LoginPresenter, ActivityLoginBinding>(), Logi
setContentView(ActivityLoginBinding.inflate(layoutInflater).apply { binding = this }.root)
setSupportActionBar(binding.loginToolbar)
messageContainer = binding.loginContainer
updateHelper.messageContainer = binding.loginContainer
presenter.onAttachView(this)
updateHelper.checkAndInstallUpdates(this)
}
override fun onResume() {
super.onResume()
updateHelper.onResume(this)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
updateHelper.onActivityResult(requestCode, resultCode)
}
override fun initView() {

View File

@ -1,14 +1,21 @@
package io.github.wulkanowy.ui.modules.main
import android.annotation.SuppressLint
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.content.pm.ShortcutInfo
import android.content.pm.ShortcutManager
import android.graphics.drawable.Icon
import android.os.Build
import android.os.Build.VERSION.SDK_INT
import android.os.Build.VERSION_CODES.LOLLIPOP
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import androidx.annotation.RequiresApi
import androidx.core.content.getSystemService
import androidx.core.view.ViewCompat
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.Fragment
@ -31,7 +38,9 @@ import io.github.wulkanowy.ui.modules.message.MessageFragment
import io.github.wulkanowy.ui.modules.more.MoreFragment
import io.github.wulkanowy.ui.modules.note.NoteFragment
import io.github.wulkanowy.ui.modules.timetable.TimetableFragment
import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
import io.github.wulkanowy.utils.UpdateHelper
import io.github.wulkanowy.utils.dpToPx
import io.github.wulkanowy.utils.getThemeAttrColor
import io.github.wulkanowy.utils.safelyPopFragments
@ -48,6 +57,12 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
@Inject
lateinit var analytics: FirebaseAnalyticsHelper
@Inject
lateinit var updateHelper: UpdateHelper
@Inject
lateinit var appInfo: AppInfo
private val overlayProvider by lazy { ElevationOverlayProvider(this) }
private val navController = FragNavController(supportFragmentManager, R.id.mainFragmentContainer)
@ -59,7 +74,7 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
return Intent(context, MainActivity::class.java)
.apply {
if (clear) flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_CLEAR_TASK
startMenu?.let { putExtra(EXTRA_START_MENU, it) }
startMenu?.let { putExtra(EXTRA_START_MENU, it.id) }
}
}
}
@ -83,18 +98,58 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
MainView.Section.LUCKY_NUMBER.id to LuckyNumberFragment.newInstance()
)
@SuppressLint("NewApi")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(ActivityMainBinding.inflate(layoutInflater).apply { binding = this }.root)
setSupportActionBar(binding.mainToolbar)
messageContainer = binding.mainFragmentContainer
updateHelper.messageContainer = binding.mainFragmentContainer
presenter.onAttachView(this, intent.getSerializableExtra(EXTRA_START_MENU) as? MainView.Section)
presenter.onAttachView(this, MainView.Section.values().singleOrNull { it.id == intent.getIntExtra(EXTRA_START_MENU, -1) })
with(navController) {
initialize(startMenuIndex, savedInstanceState)
pushFragment(moreMenuFragments[startMenuMoreIndex])
}
updateHelper.checkAndInstallUpdates(this)
}
override fun onResume() {
super.onResume()
updateHelper.onResume(this)
}
@SuppressLint("NewApi")
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
updateHelper.onActivityResult(requestCode, resultCode)
if (appInfo.systemVersion >= Build.VERSION_CODES.N_MR1) initShortcuts()
}
@RequiresApi(Build.VERSION_CODES.N_MR1)
fun initShortcuts() {
val shortcutsList = mutableListOf<ShortcutInfo>()
listOf(
Triple(getString(R.string.grade_title), R.drawable.ic_shortcut_grade, MainView.Section.GRADE),
Triple(getString(R.string.attendance_title), R.drawable.ic_shortcut_attendance, MainView.Section.ATTENDANCE),
Triple(getString(R.string.exam_title), R.drawable.ic_shortcut_exam, MainView.Section.EXAM),
Triple(getString(R.string.timetable_title), R.drawable.ic_shortcut_timetable, MainView.Section.TIMETABLE),
Triple(getString(R.string.message_title), R.drawable.ic_shortcut_message, MainView.Section.MESSAGE)
).forEach { (title, icon, enum) ->
shortcutsList.add(ShortcutInfo.Builder(applicationContext, title)
.setShortLabel(title)
.setLongLabel(title)
.setIcon(Icon.createWithResource(applicationContext, icon))
.setIntents(arrayOf(
Intent(applicationContext, MainActivity::class.java).setAction(Intent.ACTION_VIEW),
Intent(applicationContext, MainActivity::class.java).putExtra(EXTRA_START_MENU, enum.id)
.setAction(Intent.ACTION_VIEW).addFlags(FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_CLEAR_TASK)))
.build())
}
getSystemService<ShortcutManager>()?.dynamicShortcuts = shortcutsList
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
@ -143,8 +198,8 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
analytics.setCurrentScreen(this, name)
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
return if (item?.itemId == R.id.mainMenuAccount) presenter.onAccountManagerSelected()
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return if (item.itemId == R.id.mainMenuAccount) presenter.onAccountManagerSelected()
else false
}

View File

@ -174,7 +174,7 @@ class MessagePreviewFragment :
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
override fun printDocument(html: String, jobName: String) {
val webView = WebView(activity)
val webView = WebView(requireContext())
webView.webViewClient = object : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest) = false

View File

@ -1,5 +1,6 @@
package io.github.wulkanowy.ui.modules.message.send
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.graphics.Rect
@ -74,6 +75,7 @@ class SendMessageActivity : BaseActivity<SendMessagePresenter, ActivitySendMessa
presenter.onAttachView(this, intent.getSerializableExtra(EXTRA_MESSAGE) as? Message, intent.getSerializableExtra(EXTRA_REPLY) as? Boolean)
}
@SuppressLint("ClickableViewAccessibility")
override fun initView() {
setUpExtendedHitArea()
with(binding) {
@ -87,8 +89,8 @@ class SendMessageActivity : BaseActivity<SendMessagePresenter, ActivitySendMessa
return true
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
return if (item?.itemId == R.id.sendMessageMenuSend) presenter.onSend()
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return if (item.itemId == R.id.sendMessageMenuSend) presenter.onSend()
else false
}

View File

@ -41,6 +41,8 @@ class TimetableAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
var showWholeClassPlan: String = "no"
var showGroupsInPlan: Boolean = false
var showTimers: Boolean = false
private val timers = mutableMapOf<Int, Timer>()
@ -99,6 +101,7 @@ class TimetableAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
with(binding) {
timetableItemNumber.text = lesson.number.toString()
timetableItemSubject.text = lesson.subject
timetableItemGroup.text = lesson.group
timetableItemRoom.text = lesson.room
timetableItemTeacher.text = lesson.teacher
timetableItemTimeStart.text = lesson.start.toFormattedString("HH:mm")
@ -218,6 +221,7 @@ class TimetableAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
timetableItemDescription.text = lesson.info
timetableItemRoom.visibility = GONE
timetableItemGroup.visibility = GONE
timetableItemTeacher.visibility = GONE
timetableItemDescription.setTextColor(root.context.getThemeAttrColor(
@ -227,6 +231,7 @@ class TimetableAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
} else {
timetableItemDescription.visibility = GONE
timetableItemRoom.visibility = VISIBLE
timetableItemGroup.visibility = if (showGroupsInPlan && lesson.group.isNotBlank()) VISIBLE else GONE
timetableItemTeacher.visibility = VISIBLE
}
}

View File

@ -88,11 +88,12 @@ class TimetableFragment : BaseFragment<FragmentTimetableBinding>(R.layout.fragme
else false
}
override fun updateData(data: List<Timetable>, showWholeClassPlanType: String, showTimetableTimers: Boolean) {
override fun updateData(data: List<Timetable>, showWholeClassPlanType: String, showGroupsInPlanType: Boolean, showTimetableTimers: Boolean) {
with(timetableAdapter) {
items = data.toMutableList()
showTimers = showTimetableTimers
showWholeClassPlan = showWholeClassPlanType
showGroupsInPlan = showGroupsInPlanType
notifyDataSetChanged()
}
}

View File

@ -22,7 +22,6 @@ import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.onEach
import timber.log.Timber
import java.lang.NullPointerException
import java.time.LocalDate
import java.time.LocalDate.now
import java.time.LocalDate.of
@ -143,6 +142,7 @@ class TimetablePresenter @Inject constructor(
view?.apply {
updateData(
showWholeClassPlanType = prefRepository.showWholeClassPlan,
showGroupsInPlanType = prefRepository.showGroupsInPlan,
showTimetableTimers = prefRepository.showTimetableTimers,
data = it.data!!
.filter { item -> if (prefRepository.showWholeClassPlan == "no") item.isStudentPlan else true }

View File

@ -12,7 +12,7 @@ interface TimetableView : BaseView {
fun initView()
fun updateData(data: List<Timetable>, showWholeClassPlanType: String, showTimetableTimers: Boolean)
fun updateData(data: List<Timetable>, showWholeClassPlanType: String, showGroupsInPlanType: Boolean, showTimetableTimers: Boolean)
fun updateNavigationDay(date: String)

View File

@ -22,32 +22,32 @@ private fun Bundle?.checkSavedState() = if (this == null) "(STATE IS NULL)" else
class ActivityLifecycleLogger : Application.ActivityLifecycleCallbacks {
override fun onActivityPaused(activity: Activity?) {
activity?.let { Timber.d("${it::class.java.simpleName} PAUSED") }
override fun onActivityPaused(activity: Activity) {
Timber.d("${activity::class.java.simpleName} PAUSED")
}
override fun onActivityResumed(activity: Activity?) {
activity?.let { Timber.d("${it::class.java.simpleName} RESUMED") }
override fun onActivityResumed(activity: Activity) {
Timber.d("${activity::class.java.simpleName} RESUMED")
}
override fun onActivityStarted(activity: Activity?) {
activity?.let { Timber.d("${it::class.java.simpleName} STARTED") }
override fun onActivityStarted(activity: Activity) {
Timber.d("${activity::class.java.simpleName} STARTED")
}
override fun onActivityDestroyed(activity: Activity?) {
activity?.let { Timber.d("${it::class.java.simpleName} DESTROYED") }
override fun onActivityDestroyed(activity: Activity) {
Timber.d("${activity::class.java.simpleName} DESTROYED")
}
override fun onActivitySaveInstanceState(activity: Activity?, outState: Bundle?) {
activity?.let { Timber.d("${it::class.java.simpleName} SAVED INSTANCE STATE") }
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
Timber.d("${activity::class.java.simpleName} SAVED INSTANCE STATE")
}
override fun onActivityStopped(activity: Activity?) {
activity?.let { Timber.d("${it::class.java.simpleName} STOPPED") }
override fun onActivityStopped(activity: Activity) {
Timber.d("${activity::class.java.simpleName} STOPPED")
}
override fun onActivityCreated(activity: Activity?, savedInstanceState: Bundle?) {
activity?.let { Timber.d("${it::class.java.simpleName} CREATED ${savedInstanceState.checkSavedState()}") }
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
Timber.d("${activity::class.java.simpleName} CREATED ${savedInstanceState.checkSavedState()}")
}
}

View File

@ -4,20 +4,26 @@ import android.content.res.Resources
import io.github.wulkanowy.R
import io.github.wulkanowy.sdk.exception.FeatureNotAvailableException
import io.github.wulkanowy.sdk.scrapper.exception.FeatureDisabledException
import io.github.wulkanowy.sdk.scrapper.exception.ScrapperException
import io.github.wulkanowy.sdk.scrapper.exception.ServiceUnavailableException
import io.github.wulkanowy.sdk.scrapper.exception.VulcanException
import io.github.wulkanowy.sdk.scrapper.login.NotLoggedInException
import io.github.wulkanowy.sdk.scrapper.login.PasswordChangeRequiredException
import okhttp3.internal.http2.StreamResetException
import java.io.InterruptedIOException
import java.net.ConnectException
import java.net.SocketTimeoutException
import java.net.UnknownHostException
fun Resources.getString(error: Throwable) = when (error) {
is UnknownHostException -> getString(R.string.error_no_internet)
is SocketTimeoutException, is InterruptedIOException -> getString(R.string.error_timeout)
is SocketTimeoutException, is InterruptedIOException, is ConnectException, is StreamResetException -> getString(R.string.error_timeout)
is NotLoggedInException -> getString(R.string.error_login_failed)
is PasswordChangeRequiredException -> getString(R.string.error_password_change_required)
is ServiceUnavailableException -> getString(R.string.error_service_unavailable)
is FeatureDisabledException -> getString(R.string.error_feature_disabled)
is FeatureNotAvailableException -> getString(R.string.error_feature_not_available)
is VulcanException -> getString(R.string.error_unknown_uonet)
is ScrapperException -> getString(R.string.error_unknown_app)
else -> getString(R.string.error_unknown)
}

View File

@ -1,5 +1,7 @@
Wersja 0.20.5
- naprawiliśmy logowanie do koszalińskiego dziennika
- naprawiliśmy resetowanie hasła na gdańskim dzienniku
Wersja 0.22
- naprawiliśmy krytyczny błąd ze stabilnością przy ładowaniu danych
- naprawiliśmy skalowanie tekstu przy bardzo dużych jego rozmiarach
- naprawiliśmy wyświetlanie powiadomień o odwołanych lekcjach (nie powinny się już pokazywać)
- dodaliśmy informowanie o dostępności aktualizacji w aplikacji
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 902 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 913 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 937 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/mainContainer"
android:layout_width="match_parent"
@ -10,18 +10,19 @@
style="@style/Widget.MaterialComponents.Toolbar.Surface"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:contentInsetStartWithNavigation="0dp" />
app:contentInsetStartWithNavigation="0dp"
app:layout_constraintTop_toTopOf="parent" />
<androidx.fragment.app.FragmentContainerView
android:id="@+id/mainFragmentContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="?actionBarSize"
android:layout_marginBottom="@dimen/bottom_navigation_height" />
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@id/mainBottomNav"
app:layout_constraintTop_toBottomOf="@id/mainToolbar" />
<com.aurelhubert.ahbottomnavigation.AHBottomNavigation
android:id="@+id/mainBottomNav"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -20,17 +21,18 @@
android:id="@+id/creatorRecycler"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
android:layout_weight="1"
tools:listitem="@layout/item_contributor" />
<com.google.android.material.button.MaterialButton
android:id="@+id/creatorSeeMore"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:layout_marginLeft="32dp"
android:layout_marginTop="8dp"
android:layout_marginRight="32dp"
android:layout_marginBottom="8dp"
android:text="@string/contributor_see_more" />
</LinearLayout>
</FrameLayout>

View File

@ -33,7 +33,8 @@
<TextView
android:id="@+id/aboutItemSummary"
android:layout_width="wrap_content"
android:layout_height="20dp"
android:layout_height="wrap_content"
android:minHeight="20dp"
android:layout_below="@id/aboutItemTitle"
android:layout_marginEnd="16dp"
android:layout_toEndOf="@id/aboutItemImage"

View File

@ -1,4 +1,4 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/attendanceItemContainer"
@ -15,10 +15,17 @@
<LinearLayout
android:id="@+id/attendanceItemNumberContainer"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="40dp"
android:minHeight="40dp"
android:gravity="center"
android:orientation="vertical">
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="@+id/attendanceItemDetailsContainer"
app:layout_constraintEnd_toStartOf="@+id/attendanceItemDetailsContainer"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/attendanceItemDetailsContainer">
<TextView
android:id="@+id/attendanceItemNumber"
@ -48,38 +55,52 @@
app:tint="?attr/colorOnSurface" />
</LinearLayout>
<TextView
android:id="@+id/attendanceItemSubject"
android:layout_width="wrap_content"
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/attendanceItemDetailsContainer"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginStart="10dp"
android:layout_marginEnd="40dp"
android:layout_toStartOf="@id/attendanceItemAlert"
android:layout_toEndOf="@+id/attendanceItemNumberContainer"
android:ellipsize="end"
android:maxLines="1"
android:textSize="17sp"
tools:text="Matematyka" />
android:layout_marginEnd="10dp"
app:layout_constraintEnd_toStartOf="@+id/attendanceItemAlert"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/attendanceItemNumberContainer"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/attendanceItemDescription"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignStart="@id/attendanceItemSubject"
android:layout_alignBottom="@+id/attendanceItemNumberContainer"
android:maxLines="1"
android:textColor="?android:textColorSecondary"
android:textSize="12sp"
tools:text="Present" />
<TextView
android:id="@+id/attendanceItemSubject"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:ellipsize="end"
android:maxLines="1"
android:textSize="17sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Matematyka" />
<TextView
android:id="@+id/attendanceItemDescription"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
android:textColor="?android:textColorSecondary"
android:textSize="12sp"
app:layout_constraintBottom_toBottomOf="@id/attendanceItemDetailsContainer"
app:layout_constraintStart_toStartOf="@id/attendanceItemDetailsContainer"
app:layout_constraintTop_toBottomOf="@id/attendanceItemSubject"
tools:text="Present" />
</androidx.constraintlayout.widget.ConstraintLayout>
<ImageView
android:id="@+id/attendanceItemAlert"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_marginTop="10dp"
app:layout_constraintBottom_toBottomOf="@+id/attendanceItemDetailsContainer"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/attendanceItemDetailsContainer"
app:layout_constraintTop_toTopOf="@+id/attendanceItemDetailsContainer"
app:srcCompat="@drawable/ic_all_mark"
app:tint="?colorPrimary"
tools:ignore="contentDescription" />
</RelativeLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -3,7 +3,8 @@
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/attendanceSummaryItemSubject"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_height="wrap_content"
android:minHeight="48dp"
android:gravity="start"
android:maxLines="1"
android:paddingLeft="16dp"

View File

@ -12,8 +12,11 @@
<TextView
android:id="@+id/completedLessonItemNumber"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:minWidth="40dp"
android:minHeight="40dp"
android:layout_centerVertical="true"
android:gravity="center"
android:includeFontPadding="false"
@ -40,9 +43,9 @@
android:id="@+id/completedLessonItemTopic"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/completedLessonItemSubject"
android:layout_alignStart="@id/completedLessonItemSubject"
android:layout_alignEnd="@+id/completedLessonItemAlert"
android:layout_alignBottom="@+id/completedLessonItemNumber"
android:layout_marginEnd="40dp"
android:ellipsize="end"
android:maxLines="1"
@ -56,7 +59,7 @@
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:tint="?colorTimetableChange"
app:srcCompat="@drawable/ic_timetable_swap"
app:tint="?colorTimetableChange"
tools:ignore="contentDescription" />
</RelativeLayout>

View File

@ -15,7 +15,8 @@
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:contentDescription="@string/contributor_avatar_description" />
android:contentDescription="@string/contributor_avatar_description"
tools:src="@tools:sample/avatars" />
<TextView
android:id="@+id/creatorItemName"

View File

@ -18,62 +18,82 @@
<TextView
android:id="@+id/gradeItemValue"
android:layout_width="45dp"
android:layout_height="40dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/grade_material_default"
android:gravity="center"
android:maxLength="5"
android:minWidth="45dp"
android:minHeight="40dp"
android:textColor="@android:color/white"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintBottom_toBottomOf="@+id/gradeDetailsContainer"
app:layout_constraintEnd_toStartOf="@+id/gradeDetailsContainer"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintTop_toTopOf="@+id/gradeDetailsContainer"
tools:text="6" />
<TextView
android:id="@+id/gradeItemDescription"
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/gradeDetailsContainer"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginEnd="20dp"
android:ellipsize="end"
android:maxLines="1"
android:textSize="14sp"
app:layout_constraintEnd_toStartOf="@id/gradeItemNote"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/gradeItemNote"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/gradeItemValue"
app:layout_constraintTop_toTopOf="parent"
tools:text="@tools:sample/lorem" />
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/gradeItemDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
android:textSize="12sp"
app:layout_constraintBottom_toBottomOf="@+id/gradeItemValue"
app:layout_constraintStart_toStartOf="@+id/gradeItemDescription"
tools:text="@tools:sample/date/ddmmyy" />
<TextView
android:id="@+id/gradeItemDescription"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginEnd="20dp"
android:ellipsize="end"
android:maxLines="1"
android:textSize="14sp"
app:layout_constraintEnd_toEndOf="@id/gradeDetailsContainer"
app:layout_constraintStart_toStartOf="@id/gradeDetailsContainer"
app:layout_constraintTop_toTopOf="parent"
tools:text="@tools:sample/lorem" />
<TextView
android:id="@+id/gradeItemWeight"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginEnd="20dp"
android:maxLines="1"
android:textSize="12sp"
app:layout_constraintBottom_toBottomOf="@+id/gradeItemValue"
app:layout_constraintEnd_toStartOf="@id/gradeItemNote"
app:layout_constraintStart_toEndOf="@+id/gradeItemDate"
tools:text="@tools:sample/lorem" />
<TextView
android:id="@+id/gradeItemDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
android:textSize="12sp"
app:layout_constraintBottom_toBottomOf="@+id/gradeDetailsContainer"
app:layout_constraintStart_toStartOf="@+id/gradeItemDescription"
app:layout_constraintTop_toBottomOf="@+id/gradeItemDescription"
tools:text="@tools:sample/date/ddmmyy" />
<TextView
android:id="@+id/gradeItemWeight"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginEnd="20dp"
android:maxLines="1"
android:textSize="12sp"
app:layout_constraintBottom_toBottomOf="@+id/gradeDetailsContainer"
app:layout_constraintEnd_toEndOf="@id/gradeDetailsContainer"
app:layout_constraintStart_toEndOf="@+id/gradeItemDate"
app:layout_constraintTop_toBottomOf="@+id/gradeItemDescription"
tools:text="@tools:sample/lorem" />
</androidx.constraintlayout.widget.ConstraintLayout>
<ImageView
android:id="@+id/gradeItemNote"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
app:layout_constraintBottom_toBottomOf="@+id/gradeDetailsContainer"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/gradeDetailsContainer"
app:layout_constraintTop_toTopOf="@+id/gradeDetailsContainer"
app:srcCompat="@drawable/ic_all_round_mark"
app:tint="?colorPrimary"
tools:ignore="contentDescription" />

View File

@ -2,7 +2,8 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="64dp"
android:layout_height="wrap_content"
android:minHeight="64dp"
android:background="?selectableItemBackground"
android:orientation="vertical"
android:paddingStart="16dp"
@ -14,7 +15,8 @@
<TextView
android:id="@+id/licenseItemName"
android:layout_width="match_parent"
android:layout_height="28dp"
android:layout_height="wrap_content"
android:minHeight="28dp"
android:ellipsize="end"
android:gravity="bottom"
android:singleLine="true"
@ -24,7 +26,8 @@
<TextView
android:id="@+id/licenseItemSummary"
android:layout_width="match_parent"
android:layout_height="20dp"
android:layout_height="wrap_content"
android:minHeight="20dp"
android:gravity="bottom"
android:textColor="?android:textColorSecondary"
android:textSize="14sp"

View File

@ -48,7 +48,8 @@
<TextView
android:id="@+id/loginItemSignedIn"
android:layout_width="wrap_content"
android:layout_height="20dp"
android:layout_height="wrap_content"
android:minHeight="20dp"
android:layout_below="@id/loginItemSchool"
android:layout_marginEnd="16dp"
android:layout_toEndOf="@id/loginItemCheck"

View File

@ -3,25 +3,30 @@
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/mobileDevice_subitem_container"
android:layout_width="match_parent"
android:layout_height="64dp"
android:layout_height="wrap_content"
android:minHeight="64dp"
tools:context=".ui.modules.mobiledevice.MobileDeviceAdapter">
<TextView
android:id="@+id/mobileDeviceItemName"
android:layout_width="match_parent"
android:layout_height="32dp"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginStart="16dp"
android:layout_marginTop="0dp"
android:layout_toStartOf="@id/mobileDeviceItemUnregister"
android:ellipsize="end"
android:gravity="bottom"
android:maxLines="1"
android:minHeight="32dp"
android:textSize="16sp"
tools:text="@tools:sample/lorem/random" />
<TextView
android:id="@+id/mobileDeviceItemDate"
android:layout_width="match_parent"
android:layout_height="20dp"
android:layout_height="wrap_content"
android:minHeight="20dp"
android:layout_below="@id/mobileDeviceItemName"
android:layout_marginStart="16dp"
android:layout_toStartOf="@id/mobileDeviceItemUnregister"

View File

@ -13,8 +13,10 @@
<TextView
android:id="@+id/timetableItemNumber"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="40dp"
android:minHeight="40dp"
android:gravity="center"
android:includeFontPadding="false"
android:maxLength="2"
@ -74,7 +76,22 @@
app:layout_constraintBottom_toBottomOf="@+id/timetableItemNumber"
app:layout_constraintStart_toEndOf="@+id/timetableItemTimeStart"
tools:text="22"
tools:visibility="gone" />
tools:visibility="visible" />
<TextView
android:id="@+id/timetableItemGroup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="0dp"
android:layout_marginEnd="5dp"
android:textColor="?android:textColorSecondary"
android:textSize="13sp"
app:layout_constraintEnd_toStartOf="@+id/timetableItemTeacher"
app:layout_constraintStart_toEndOf="@+id/timetableItemRoom"
app:layout_constraintTop_toTopOf="@+id/timetableItemTimeFinish"
tools:text="(2/2)"
tools:visibility="visible" />
<TextView
android:id="@+id/timetableItemTeacher"
@ -87,9 +104,9 @@
android:textColor="?android:textColorSecondary"
android:textSize="13sp"
app:layout_constraintBottom_toBottomOf="@+id/timetableItemNumber"
app:layout_constraintStart_toEndOf="@id/timetableItemRoom"
app:layout_constraintStart_toEndOf="@id/timetableItemGroup"
tools:text="Agata Kowalska - Błaszczyk"
tools:visibility="gone" />
tools:visibility="visible" />
<TextView
android:id="@+id/timetableItemDescription"
@ -101,7 +118,7 @@
android:textColor="?colorTimetableChange"
android:textSize="13sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/timetableItemTimeStart"
app:layout_constraintStart_toEndOf="@+id/timetableItemTeacher"
app:layout_constraintTop_toTopOf="@+id/timetableItemTimeFinish"
tools:text="Lekcja odwołana: uczniowie zwolnieni do domu"
tools:visibility="visible" />

View File

@ -7,7 +7,8 @@
<TextView
android:id="@+id/timetableSmallItemNumber"
android:layout_width="40dp"
android:layout_width="wrap_content"
android:minWidth="40dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:gravity="center"

View File

@ -19,8 +19,10 @@
<TextView
android:id="@+id/timetableWidgetItemNumber"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="40dp"
android:minHeight="40dp"
android:gravity="center"
android:includeFontPadding="false"
android:maxLength="2"

View File

@ -16,7 +16,8 @@
<TextView
android:id="@+id/timetableWidgetItemNumber"
android:layout_width="40dp"
android:layout_width="wrap_content"
android:minWidth="40dp"
android:layout_height="wrap_content"
android:gravity="center"
android:maxLength="2"

View File

@ -16,7 +16,8 @@
<TextView
android:id="@+id/timetableWidgetItemNumber"
android:layout_width="40dp"
android:layout_width="wrap_content"
android:minWidth="40dp"
android:layout_height="wrap_content"
android:gravity="center"
android:maxLength="2"
@ -29,7 +30,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="6dp"
android:layout_marginLeft="6dp"
android:maxLines="1"
android:textColor="@android:color/white"
android:textSize="13sp"
@ -46,7 +46,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginLeft="10dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="@android:color/white"
@ -58,7 +57,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginLeft="10dp"
android:maxLines="1"
android:textColor="@android:color/white"
android:textSize="15sp"
@ -69,7 +67,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginLeft="10dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="@android:color/white"

View File

@ -3,7 +3,8 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="104dp"
android:layout_height="wrap_content"
android:minHeight="104dp"
android:orientation="vertical"
tools:context=".ui.modules.about.AboutAdapter">

View File

@ -0,0 +1,52 @@
<?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>Světlý</item>
<item>Tmavý</item>
<item>Černý (AMOLED)</item>
</string-array>
<string-array name="app_language_entries">
<item>Jazyk systému</item>
<item>Polski</item>
<item>English</item>
<item>Pусский</item>
<item>Українська</item>
<item>Deutsch</item>
<item>Čeština</item>
</string-array>
<string-array name="services_interval_entries">
<item>15 minut</item>
<item>30 minut</item>
<item>1 hodina</item>
<item>2 hodiny</item>
<item>6 hodin</item>
<item>12 hodin</item>
<item>24 hodin</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>Abecedně</item>
<item>Podle data</item>
</string-array>
<string-array name="grade_color_scheme_entries">
<item>Dzienniczek+</item>
<item>Wulkanowy</item>
<item>Barvy známek v deníku</item>
</string-array>
<string-array name="grade_average_mode_entries">
<item>Průměrná známka od druhého semestru</item>
<item>Průměr známek z obou semestrů</item>
<item>Průměr známek z celého roku</item>
</string-array>
<string-array name="timetable_show_whole_class_entries">
<item>Neukaž</item>
<item>Ukázat vše</item>
<item>Ukázat menší</item>
</string-array>
</resources>

View File

@ -0,0 +1,457 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--Activity/Fragment title-->
<string name="login_title">Přihlásit se</string>
<string name="main_title">Wulkanowy</string>
<string name="grade_title">Známky</string>
<string name="attendance_title">Prezence</string>
<string name="exam_title">Zkoušky</string>
<string name="timetable_title">Plán lekce</string>
<string name="settings_title">Nastavení</string>
<string name="more_title">Více</string>
<string name="about_title">O aplikaci</string>
<string name="logviewer_title">Prohlížeč protokolů</string>
<string name="contributors_title">Tvůrci</string>
<string name="license_title">Licence</string>
<string name="message_title">Zprávy</string>
<string name="send_message_title">Nová zpráva</string>
<string name="note_title">Poznámky a úspěchy</string>
<string name="homework_title">Domácí práce</string>
<string name="account_title">Vyberte účet</string>
<!--Subtitles-->
<string name="grade_subtitle">Semestr %1$d, %2$d/%3$d</string>
<!--Login-->
<string name="login_header_default">Přihlaste se pomocí studentského nebo nadřazeného účtu</string>
<string name="login_header_symbol">Zadejte symbol</string>
<string name="login_nickname_hint">Uživatelské jméno</string>
<string name="login_email_hint">Email</string>
<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">Deník UONET+</string>
<string name="login_type_api">Mobile API</string>
<string name="login_type_scrapper">Scraper</string>
<string name="login_type_hybrid">Hybridní</string>
<string name="login_token_hint">Token</string>
<string name="login_pin_hint">PIN</string>
<string name="login_api_key_hint">Klíč API</string>
<string name="login_symbol_hint">Symbol</string>
<string name="login_sign_in">Přihlásit</string>
<string name="login_invalid_password">Toto heslo je příliš krátké</string>
<string name="login_incorrect_password">Přihlašovací údaje jsou nesprávné. Zkontrolujte, zda je v poli níže vybrán správný deník UONET+</string>
<string name="login_invalid_pin">Neplatný PIN</string>
<string name="login_invalid_token">Neplatný token</string>
<string name="login_expired_token">Platnost tokenu vypršela</string>
<string name="login_invalid_email">Nesprávná e-mailová adresa</string>
<string name="login_invalid_login">Neplatné přihlášení</string>
<string name="login_invalid_symbol">Neplatný symbol</string>
<string name="login_incorrect_symbol">Student nebyl nalezen. Zkontrolujte symbol</string>
<string name="login_field_required">Toto pole je povinné</string>
<string name="login_duplicate_student">Vybraný student je již přihlášen</string>
<string name="login_symbol_helper">Symbol najdete na stránce deníku v&#160;<b>Uczeń</b>&#160;<b>Dostęp Mobilny</b>&#160;<b>Zarejestruj urządzenie mobilne</b></string>
<string name="login_select_student">Vyberte studenty k přihlášení do aplikace</string>
<string name="login_advanced">Jiné možnosti</string>
<string name="login_advanced_warning_mobile_api">V tomto režimu nefungují následující: šťastné číslo, statistiky třídy, shrnutí docházky, ospravedlnění nepřítomnosti, absolvované lekce, informace o škole a prohlížení seznamu registrovaných zařízení</string>
<string name="login_advanced_warning_scraper">Tento režim zobrazuje stejná data, která se zobrazují na webových stránkách deníka</string>
<string name="login_advanced_warning_hybrid">Kombinace nejlepších vlastností ostatních dvou režimů. Funguje rychleji než scraper a poskytuje funkce, které nejsou k dispozici v režimu Mobile API. Je to v experimentální fázi</string>
<string name="login_privacy_policy">Zásady ochrany osobních údajů</string>
<string name="login_contact_header">Problémy s přihlášením? Napište nám!</string>
<string name="login_contact_email">Email</string>
<string name="login_contact_discord">Discord</string>
<string name="login_email_intent_title">Poslat e-mail</string>
<string name="login_email_details">Popište podrobnosti problému:</string>
<string name="login_recover_warning">Ujistěte se, že je vybrán správný UONET+ deník!</string>
<string name="login_recover_button">Zapomněl jsem své heslo</string>
<string name="login_recover_title">Obnovte svůj účet</string>
<string name="login_recover">Obnovit</string>
<string name="login_signed_in">Student je již přihlášen</string>
<!--Main-->
<string name="main_account_picker">Správce účtu</string>
<string name="main_log_in">Přihlásit se</string>
<string name="main_session_expired">Platnost relace vypršela</string>
<string name="main_session_relogin">Vaše relace vypršela, přihlaste se prosím znovu</string>
<!--Grade-->
<string name="grade_header">Známka</string>
<string name="grade_semester">Semestr %d</string>
<string name="grade_switch_semester">Změnit semestr</string>
<string name="grade_no_items">Žádné známky</string>
<string name="grade_weight">Váha</string>
<string name="grade_weight_value">Váha: %s</string>
<string name="grade_comment">Komentář</string>
<string name="grade_no_new_items">Žádné nové známky</string>
<string name="grade_number_new_items">Počet nových známek: %1$d</string>
<string name="grade_average">Průměrný: %1$.2f</string>
<string name="grade_points_sum">Body: %s</string>
<string name="grade_no_average">Žádný průměr</string>
<string name="grade_predicted">Předpovězeno: %1$s</string>
<string name="grade_final">Konečná: %1$s</string>
<string name="grade_summary_points">Celkem bodů</string>
<string name="grade_summary_final_grade">Konečná známka</string>
<string name="grade_summary_predicted_grade">Předpokládaná známka</string>
<string name="grade_summary_calculated_average">Vypočítaný průměr</string>
<string name="grade_summary_final_average">Konečný průměr</string>
<string name="grade_menu_summary">Souhrn</string>
<string name="grade_menu_statistics">Třída</string>
<string name="grade_menu_read">Označit jako přečtené</string>
<string name="grade_statistics_partial">Částečně</string>
<string name="grade_statistics_semester">Semestr</string>
<string name="grade_statistics_points">Body</string>
<plurals name="grade_number_item">
<item quantity="one">%d známka</item>
<item quantity="few">%d známky</item>
<item quantity="many">%d známky</item>
<item quantity="other">%d známky</item>
</plurals>
<plurals name="grade_new_items">
<item quantity="one">Nová známka</item>
<item quantity="few">Nové známky</item>
<item quantity="many">Nové známky</item>
<item quantity="other">Nové známky</item>
</plurals>
<plurals name="grade_new_items_predicted">
<item quantity="one">Nová předpokládaná známka</item>
<item quantity="few">Nové předpovídané známky</item>
<item quantity="many">Nové předpovídané známky</item>
<item quantity="other">Nové předpovídané známky</item>
</plurals>
<plurals name="grade_new_items_final">
<item quantity="one">Nová konečná známka</item>
<item quantity="few">Nové konečné známky</item>
<item quantity="many">Nové konečné známky</item>
<item quantity="other">Nové konečné známky</item>
</plurals>
<plurals name="grade_notify_new_items">
<item quantity="one">Máte %1$d novou známku</item>
<item quantity="few">Máte %1$d nové známky</item>
<item quantity="many">Máte %1$d nové známky</item>
<item quantity="other">Máte %1$d nové známky</item>
</plurals>
<plurals name="grade_notify_new_items_predicted">
<item quantity="one">Máte %1$d novou konečnou známku</item>
<item quantity="few">Máte %1$d nové konečné známky</item>
<item quantity="many">Máte %1$d nové konečné známky</item>
<item quantity="other">Máte %1$d nové konečné známky</item>
</plurals>
<plurals name="grade_notify_new_items_final">
<item quantity="one">Máte %1$d novou konečnou známku</item>
<item quantity="few">Máte %1$d nové konečné známky</item>
<item quantity="many">Máte %1$d nové konečné známky</item>
<item quantity="other">Máte %1$d nové konečné známky</item>
</plurals>
<!--Timetable-->
<string name="timetable_lesson">Lekce</string>
<string name="timetable_room">Pokoj</string>
<string name="timetable_group">Skupina</string>
<string name="timetable_time">Hodiny</string>
<string name="timetable_changes">Změny</string>
<string name="timetable_no_items">Dnes žádné lekce</string>
<string name="timetable_minutes">%s min</string>
<string name="timetable_seconds">%s sek</string>
<string name="timetable_time_left">dosud %1$s</string>
<string name="timetable_time_until">za %1$s</string>
<string name="timetable_finished">Lekce skončila</string>
<string name="timetable_now">Nyní: %s</string>
<string name="timetable_next">Okamžik: %s</string>
<string name="timetable_later">Později: %s</string>
<!--Completed lessons-->
<string name="completed_lessons_title">Dokončené lekce</string>
<string name="completed_lessons_button">Zobrazit dokončené lekce</string>
<string name="completed_lessons_no_items">Žádné informace o absolvovaných lekcích</string>
<string name="completed_lessons_topic">Téma</string>
<string name="completed_lessons_absence">Absence</string>
<string name="completed_lessons_resources">Zdroje</string>
<!--Attendance-->
<string name="attendance_summary_button">Souhrn docházky</string>
<string name="attendance_absence_school">Nepřítomen ze školních důvodů</string>
<string name="attendance_absence_excused">Omluvená absence</string>
<string name="attendance_absence_unexcused">Neomluvená absence</string>
<string name="attendance_exemption">Osvobození</string>
<string name="attendance_excused_lateness">Oprávněné zpoždění</string>
<string name="attendance_unexcused_lateness">Neomluvená zpoždění</string>
<string name="attendance_present">Přítomnost</string>
<string name="attendance_deleted">Smazáno</string>
<string name="attendance_unknown">Neznámý</string>
<string name="attendance_number">Číslo lekce</string>
<string name="attendance_no_items">Žádné položky</string>
<plurals name="attendance_number_absences">
<item quantity="one">%1$d absence</item>
<item quantity="few">%1$d absence</item>
<item quantity="many">%1$d absence</item>
<item quantity="other">%1$d absence</item>
</plurals>
<string name="attendance_excuse_dialog_reason">Důvod absence (volitelný)</string>
<string name="attendance_excuse_dialog_submit">Poslat</string>
<string name="attendance_excuse_success">Absence úspěšně omluvena!</string>
<string name="attendance_excuse_no_selection">Musíte vybrat alespoň jednu nepřítomnost!</string>
<string name="attendance_excuse_title">Ospravedlnit</string>
<!--Attendance summary-->
<string name="attendance_summary_final">Účast</string>
<string name="attendance_summary_total">Celkový</string>
<!--Exam-->
<string name="exam_no_items">Tento týden žádné testy</string>
<string name="exam_type">Typ</string>
<string name="exam_entry_date">Datum vstupu</string>
<!--Message-->
<string name="message_inbox">Doručená pošta</string>
<string name="message_sent">Odesláno</string>
<string name="message_trash">Koš</string>
<string name="message_no_subject">(žádné téma)</string>
<string name="message_no_items">Žádné zprávy</string>
<string name="message_preview_error">Při stahování obsahu zprávy došlo k chybě</string>
<string name="message_from">Od:</string>
<string name="message_to">Do:</string>
<string name="message_date">Datum: %s</string>
<string name="message_reply">Odpověď</string>
<string name="message_forward">Poslat dále</string>
<string name="message_delete">Vymazat</string>
<string name="message_move_to_bin">Přesunout do koše</string>
<string name="message_delete_forever">Trvale smazat</string>
<string name="message_delete_success">Zpráva byla úspěšně smazána</string>
<string name="message_share">Podíl</string>
<string name="message_print">Vytisknout</string>
<string name="message_subject">Téma</string>
<string name="message_content">Obsah</string>
<string name="message_send_successful">Zpráva úspěšně odeslána</string>
<string name="message_required_recipients">Musíte vybrat alespoň 1 příjemce</string>
<string name="message_content_min_length">Obsah zprávy musí mít alespoň 3 znaky</string>
<plurals name="message_number_item">
<item quantity="one">%d zpráva</item>
<item quantity="few">%d zprávy</item>
<item quantity="many">%d zprávy</item>
<item quantity="other">%d zprávy</item>
</plurals>
<plurals name="message_new_items">
<item quantity="one">Nová zpráva</item>
<item quantity="few">Nové zprávy</item>
<item quantity="many">Nové zprávy</item>
<item quantity="other">Nové zprávy</item>
</plurals>
<plurals name="message_notify_new_items">
<item quantity="one">Obdrželi jste %1$d zprávu</item>
<item quantity="few">Obdrželi jste %1$d zpráv</item>
<item quantity="many">Obdrželi jste %1$d zpráv</item>
<item quantity="other">Obdrželi jste %1$d zpráv</item>
</plurals>
<!--Note-->
<string name="note_no_items">Žádné informace o poznámkách</string>
<string name="note_points">Body</string>
<plurals name="note_number_item">
<item quantity="one">%d poznámka</item>
<item quantity="few">%d poznámky</item>
<item quantity="many">%d poznámky</item>
<item quantity="other">%d poznámky</item>
</plurals>
<plurals name="note_new_items">
<item quantity="one">Nová poznámka</item>
<item quantity="few">Nové poznámky</item>
<item quantity="many">Nové poznámky</item>
<item quantity="other">Nové poznámky</item>
</plurals>
<plurals name="note_notify_new_items">
<item quantity="one">Máte %1$d novou poznámku</item>
<item quantity="few">Máte %1$d nové poznámky</item>
<item quantity="many">Máte %1$d nové poznámky</item>
<item quantity="other">Máte %1$d nové poznámky</item>
</plurals>
<!--Praise-->
<plurals name="praise_number_item">
<item quantity="one">%d chvála</item>
<item quantity="few">%d chvály</item>
<item quantity="many">%d chvály</item>
<item quantity="other">%d chvály</item>
</plurals>
<plurals name="praise_new_items">
<item quantity="one">Nová chvála</item>
<item quantity="few">Nové chvály</item>
<item quantity="many">Nové chvály</item>
<item quantity="other">Nové chvály</item>
</plurals>
<plurals name="praise_notify_new_items">
<item quantity="one">Máte %1$d novou chválu</item>
<item quantity="few">Máte %1$d nové chvály</item>
<item quantity="many">Máte %1$d nové chvály</item>
<item quantity="other">Máte %1$d nové chvály</item>
</plurals>
<!--Neutral notes-->
<plurals name="neutral_note_number_item">
<item quantity="one">%d neutrální poznámka</item>
<item quantity="few">%d neutrální poznámky</item>
<item quantity="many">%d neutrální poznámky</item>
<item quantity="other">%d neutrální poznámky</item>
</plurals>
<plurals name="neutral_note_new_items">
<item quantity="one">Nová neutrální poznámka</item>
<item quantity="few">Nové neutrální poznámky</item>
<item quantity="many">Nové neutrální poznámky</item>
<item quantity="other">Nové neutrální poznámky</item>
</plurals>
<plurals name="neutral_note_notify_new_items">
<item quantity="one">Máte %1$d novou neutrální pozornost</item>
<item quantity="few">Máte %1$d nové neutrální komentáře</item>
<item quantity="many">Máte %1$d nové neutrální komentáře</item>
<item quantity="other">Máte %1$d nové neutrální komentáře</item>
</plurals>
<!--Homework-->
<string name="homework_no_items">Žádný domácí úkol</string>
<string name="homework_mark_as_done">Označit jako hotové</string>
<string name="homework_mark_as_undone">Neudělané</string>
<string name="homework_attachments">Přílohy</string>
<!--Lucky number-->
<string name="lucky_number_title">Šťastné číslo</string>
<string name="lucky_number_header">Dnešní šťastné číslo je</string>
<string name="lucky_number_empty">Žádné informace o šťastném čísle</string>
<string name="lucky_number_notify_new_item_title">Šťastné číslo pro dnešek</string>
<string name="lucky_number_notify_new_item">Dnes je šťastným číslem: %d</string>
<!--Mobile devices-->
<string name="mobile_devices_title">Mobilní přístup</string>
<string name="mobile_devices_no_items">Žádná zařízení</string>
<string name="mobile_devices_unregister">Zrušit registraci</string>
<string name="mobile_device_removed">Zařízení odstraněno</string>
<string name="mobile_device_qr">QR kód</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">Škola a učitelé</string>
<!--School-->
<string name="school_title">Škola</string>
<string name="school_no_info">Žádné informace o škole</string>
<string name="school_name">Školní jméno</string>
<string name="school_address">Adresa školy</string>
<string name="school_telephone">Telefon</string>
<string name="school_headmaster">Jméno ředitele</string>
<string name="school_pedagogue">Jméno pedagoga</string>
<string name="school_address_button">Zobrazit na mapě</string>
<string name="school_telephone_button">Volání</string>
<!--Teacher-->
<string name="teachers_title">Učitelé</string>
<string name="teacher_no_items">Žádné informace o učitelích</string>
<string name="teacher_no_subject">Žádný předmět</string>
<!--Account-->
<string name="account_add_new">Přidat účet</string>
<string name="account_logout">Odhlásit se</string>
<string name="account_confirm">Chcete se odhlásit z aktivního studenta?</string>
<string name="account_logout_student">Odhlášení studentů</string>
<string name="account_type_student">Studentský účet</string>
<string name="account_type_parent">Rodičovský účet</string>
<string name="account_login_mobile_api">Režimu Mobíle API</string>
<string name="account_login_hybrid">Hybridní režim</string>
<!--About-->
<string name="about_version">Verze aplikace</string>
<string name="about_contributor">Tvůrci</string>
<string name="about_contributor_summary">Seznam vývojářů Wulkanowy</string>
<string name="about_feedback">Nahlásit chybu</string>
<string name="about_feedback_summary">Pošlete hlášení o chybě e-mailem</string>
<string name="about_faq">FAQ</string>
<string name="about_faq_summary">Přečtěte si často kladené otázky</string>
<string name="about_discord">Server Discord</string>
<string name="about_discord_summary">Připojte se ke komunitě Wulkanowy</string>
<string name="about_privacy">Zásady ochrany osobních údajů</string>
<string name="about_privacy_summary">Pravidla pro shromažďování osobních údajů</string>
<string name="about_homepage">Domovská stránka</string>
<string name="about_homepage_summary">Navštivte web a pomozte s vývojem aplikace</string>
<string name="about_licenses">Licence</string>
<string name="about_licenses_summary">Licence knihoven použitých v aplikaci</string>
<!--Licenses-->
<string name="license_dialog_title">Licence</string>
<!--Contributor-->
<string name="contributor_avatar_description">Avatar</string>
<string name="contributor_see_more">Zobrazit více na GitHub</string>
<!--Log viewer-->
<string name="logviewer_share">Sdílejte protokoly</string>
<string name="logviewer_refresh">Obnovit</string>
<!--Error dialog-->
<string name="dialog_error_check_update">Kontrola aktualizací</string>
<string name="dialog_error_check_update_message">Před nahlášením chyby nejprve zkontrolujte, zda je k dispozici aktualizace s opravou chyby</string>
<!--Generic-->
<string name="all_content">Obsah</string>
<string name="all_retry">Zkuste to znovu</string>
<string name="all_description">Popis</string>
<string name="all_no_description">Bez popisu</string>
<string name="all_teacher">Učitel</string>
<string name="all_date">Datum</string>
<string name="all_entry_date">Datum vstupu</string>
<string name="all_color">Barva</string>
<string name="all_details">Detaily</string>
<string name="all_category">Kategorie</string>
<string name="all_close">Zavřít</string>
<string name="all_no_data">Žádná data</string>
<string name="all_subject">Předmět</string>
<string name="all_prev">Předchozí</string>
<string name="all_next">Další</string>
<string name="all_search">Vyhledávání</string>
<string name="all_search_hint">Vyhledávání…</string>
<!--Timetable Widget-->
<string name="widget_timetable_no_items">Žádné lekce</string>
<string name="widget_timetable_theme_title">Vyberte téma</string>
<string name="widget_timetable_theme_light">Světlý</string>
<string name="widget_timetable_theme_dark">Tmavý</string>
<string name="widget_timetable_theme_system">Téma systému</string>
<!--Preferences-->
<string name="pref_view_header">Vzhled</string>
<string name="pref_view_list">Výchozí zobrazení</string>
<string name="pref_view_grade_average_mode">Výpočet koncoročního průměru</string>
<string name="pref_view_grade_average_force_calc">Vynutit průměrný výpočet podle aplikace</string>
<string name="pref_view_present">Zobrazit přítomnost v účasti</string>
<string name="pref_view_app_theme">Téma aplikace</string>
<string name="pref_view_expand_grade">Rozbalit známky</string>
<string name="pref_view_timetable_show_timers">Označte aktuální lekci v plánu lekce</string>
<string name="pref_view_timetable_show_groups">Ukázat skupiny vedle předmětů v plánu lekce</string>
<string name="pref_view_grade_statistics_list">Ukázat seznam grafů ve třídních známkách</string>
<string name="pref_view_timetable_show_whole_class">Ukázat lekce pro celou třídu</string>
<string name="pref_view_subjects_without_grades">Ukázat předměty bez známek v \"Známky\"</string>
<string name="pref_view_grade_color_scheme">Známky barevné schéma</string>
<string name="pref_view_grade_sorting_mode">Předměty seřazené v \"Známky\"</string>
<string name="pref_view_app_language">Jazyk aplikace</string>
<string name="pref_notify_header">Oznámení</string>
<string name="pref_notify_switch">Ukázat notifikace</string>
<string name="pref_notify_upcoming_lessons_switch">Ukázat nadcházející oznámení o lekci</string>
<string name="pref_notify_fix_sync_issues">Opravte problémy se synchronizací a upozorněním</string>
<string name="pref_notify_fix_sync_issues_message">Ve vašem zařízení mohou nastat problémy se synchronizací dat a oznámenímii.\n\nChcete-li je opravit, přidejte Wulkanowy do funkce Autostart a vypněte optimalizaci/úsporu baterie v nastavení systému telefonu.</string>
<string name="pref_notify_fix_sync_issues_settings_button">Jdi do nastavení</string>
<string name="pref_notify_debug_switch">Ukázat oznámení o ladění</string>
<string name="pref_services_header">Synchronizace</string>
<string name="pref_services_switch">Automatická aktualizace</string>
<string name="pref_services_suspended">Pozastaveno na dovolené</string>
<string name="pref_services_interval">Interval aktualizací</string>
<string name="pref_services_wifi">Pouze Wi-Fi</string>
<string name="pref_services_force_sync">Nyní synchronizovat</string>
<string name="pref_services_message_sync_success">Synchronizováno!</string>
<string name="pref_services_message_sync_failed">Synchronizace se nezdařila</string>
<string name="pref_services_sync_in_progress">Probíhá synchronizace</string>
<string name="pref_services_dialog_force_sync_title">Synchronizace</string>
<string name="pref_services_dialog_force_sync_summary"> Ruční synchronizace neobnoví zobrazení aplikace.
\nChcete-li zobrazit synchronizovaná data, restartujte aplikaci po synchronizaci.
</string>
<string name="pref_other_header">Jiný</string>
<string name="pref_other_grade_modifier_plus">Hodnota plusu</string>
<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>
<!--Notification Channels-->
<string name="channel_new_entries">Nové položky v deník</string>
<string name="channel_new_grades">Nové známky</string>
<string name="channel_lucky_number">Šťastné číslo</string>
<string name="channel_new_message">Nové zprávy</string>
<string name="channel_new_notes">Nové poznámky</string>
<string name="channel_push">Oznámení push</string>
<string name="channel_upcoming_lessons">Nadcházející lekce</string>
<string name="channel_debug">Ladění</string>
<!--Colors-->
<string name="all_black">Černý</string>
<string name="all_red">Červený</string>
<string name="all_blue">Modrý</string>
<string name="all_green">Zelený</string>
<string name="all_purple">Nachový</string>
<string name="all_empty_color">Žádná barva</string>
<!--Others-->
<string name="all_copied">Zkopírováno</string>
<string name="all_undo">Vrátit</string>
<!--Errors-->
<string name="error_no_internet">Žádné internetové připojení</string>
<string name="error_timeout">Vypršel časový limit připojení k denik</string>
<string name="error_login_failed">Přihlášení selhalo. Zkuste to znovu nebo restartujte aplikaci</string>
<string name="error_password_change_required">Je vyžadována změna hesla</string>
<string name="error_service_unavailable">Probíhá údržba UONET+ deník. Zkuste to později znovu</string>
<string name="error_unknown">Došlo k neočekávané chybě</string>
<string name="error_feature_disabled">Funkce deaktivována vaší školou</string>
<string name="error_feature_not_available">Funkce není k dispozici. Přihlaste se v jiném režimu než Mobile API</string>
</resources>

View File

@ -12,6 +12,7 @@
<item>Pусский</item>
<item>Українська</item>
<item>Deutsch</item>
<item>Čeština</item>
</string-array>
<string-array name="services_interval_entries">
<item>15 Minuten</item>
@ -29,6 +30,10 @@
<item>0,5</item>
<item>0,75</item>
</string-array>
<string-array name="grade_sorting_mode_entries">
<item>Alphabetic</item>
<item>By date</item>
</string-array>
<string-array name="grade_color_scheme_entries">
<item>Dzienniczek+</item>
<item>Wulkanowy</item>

View File

@ -19,7 +19,7 @@
<string name="homework_title">Hausaufgaben</string>
<string name="account_title">Wählen Sie ein Konto</string>
<!--Subtitles-->
<string name="grade_subtitle">Semester %d, %d/%d</string>
<string name="grade_subtitle">Semester %1$d, %2$d/%3$d</string>
<!--Login-->
<string name="login_header_default">Melden Sie sich mit dem Studenten- oder Elternkonto an</string>
<string name="login_header_symbol">Geben Sie das Symbol</string>
@ -154,6 +154,8 @@
<string name="attendance_excused_lateness">Entschuldigte Verspätung</string>
<string name="attendance_unexcused_lateness">Unentschuldigte Verspätung</string>
<string name="attendance_present">Anwesend</string>
<string name="attendance_deleted">Deleted</string>
<string name="attendance_unknown">Unknown</string>
<string name="attendance_number">Lektion Nummer</string>
<string name="attendance_no_items">Keine Einträgen</string>
<plurals name="attendance_number_absences">
@ -222,6 +224,32 @@
<item quantity="one">Du hast %1$d Eintrag bekommen</item>
<item quantity="other">Du hast %1$d Eintragen bekommen</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">Keine Informationen über Hausaufgaben</string>
<string name="homework_mark_as_done">Gemacht</string>
@ -327,9 +355,12 @@
<string name="pref_view_app_theme">Thema der Anwendung</string>
<string name="pref_view_expand_grade">Noten erweitern</string>
<string name="pref_view_timetable_show_timers">Aktuelle Lektion im Stundenplan markieren</string>
<string name="pref_view_timetable_show_groups">Show groups next to subjects in timetable</string>
<string name="pref_view_grade_statistics_list">Liste der Diagramme in Klassenbewertungen anzeigen</string>
<string name="pref_view_timetable_show_whole_class">Unterricht der ganzen Klasse anzeigen</string>
<string name="pref_view_subjects_without_grades">Show subjects without grades in Grades</string>
<string name="pref_view_grade_color_scheme">Farbschema der Noten</string>
<string name="pref_view_grade_sorting_mode">Subjects sorting in \"Grades\"</string>
<string name="pref_view_app_language">App Sprache</string>
<string name="pref_notify_header">Benachrichtigungen</string>
<string name="pref_notify_switch">Benachrichtigungen anzeigen</string>

View File

@ -12,6 +12,7 @@
<item>Pусский</item>
<item>Українська</item>
<item>Deutsch</item>
<item>Čeština</item>
</string-array>
<string-array name="services_interval_entries">
<item>15 minut</item>
@ -29,6 +30,10 @@
<item>0,5</item>
<item>0,75</item>
</string-array>
<string-array name="grade_sorting_mode_entries">
<item>Alfabetycznie</item>
<item>Według daty</item>
</string-array>
<string-array name="grade_color_scheme_entries">
<item>Dzienniczek+</item>
<item>Wulkanowy</item>

View File

@ -19,7 +19,7 @@
<string name="homework_title">Zadania domowe</string>
<string name="account_title">Wybierz konto</string>
<!--Subtitles-->
<string name="grade_subtitle">Semestr %d, %d/%d</string>
<string name="grade_subtitle">Semestr %1$d, %2$d/%3$d</string>
<!--Login-->
<string name="login_header_default">Zaloguj się za pomocą konta ucznia lub rodzica</string>
<string name="login_header_symbol">Podaj symbol</string>
@ -252,6 +252,44 @@
<item quantity="many">Masz %1$d nowych uwag</item>
<item quantity="other">Masz %1$d nowych uwag</item>
</plurals>
<!--Praise-->
<plurals name="praise_number_item">
<item quantity="one">%d pochwała</item>
<item quantity="few">%d pochwały</item>
<item quantity="many">%d pochwał</item>
<item quantity="other">%d pochwał</item>
</plurals>
<plurals name="praise_new_items">
<item quantity="one">Nowa pochwała</item>
<item quantity="few">Nowe pochwały</item>
<item quantity="many">Nowe pochwały</item>
<item quantity="other">Nowe pochwały</item>
</plurals>
<plurals name="praise_notify_new_items">
<item quantity="one">Masz %1$d nową pochwałę</item>
<item quantity="few">Masz %1$d nowe pochwały</item>
<item quantity="many">Masz %1$d nowych pochwał</item>
<item quantity="other">Masz %1$d nowych pochwał</item>
</plurals>
<!--Neutral notes-->
<plurals name="neutral_note_number_item">
<item quantity="one">%d neutralna uwaga</item>
<item quantity="few">%d neutralne uwagi</item>
<item quantity="many">%d neutralnych uwag</item>
<item quantity="other">%d neutralnych uwag</item>
</plurals>
<plurals name="neutral_note_new_items">
<item quantity="one">Nowa neutralna uwaga</item>
<item quantity="few">Nowe neutralne uwagi</item>
<item quantity="many">Nowe neutralne uwagi</item>
<item quantity="other">Nowe neutralne uwagi</item>
</plurals>
<plurals name="neutral_note_notify_new_items">
<item quantity="one">Masz %1$d nową neutralną uwagę</item>
<item quantity="few">Masz %1$d nowe neutralne uwagi</item>
<item quantity="many">Masz %1$d nowych neutralnych uwag</item>
<item quantity="other">Masz %1$d nowych neutralnych uwag</item>
</plurals>
<!--Homework-->
<string name="homework_no_items">Brak zadań domowych</string>
<string name="homework_mark_as_done">Wykonane</string>
@ -357,9 +395,12 @@
<string name="pref_view_app_theme">Motyw aplikacji</string>
<string name="pref_view_expand_grade">Rozwiń oceny</string>
<string name="pref_view_timetable_show_timers">Oznaczaj bieżącą lekcję na planie</string>
<string name="pref_view_timetable_show_groups">Pokazuj grupę obok przedmiotu na planie</string>
<string name="pref_view_grade_statistics_list">Pokazuj listę wykresów w ocenach klasy</string>
<string name="pref_view_timetable_show_whole_class">Pokazuj lekcje całej klasy</string>
<string name="pref_view_subjects_without_grades">Pokazuj przedmioty bez ocen w Oceny</string>
<string name="pref_view_grade_color_scheme">Schemat kolorów ocen</string>
<string name="pref_view_grade_sorting_mode">Sortowanie przedmiotów w \"Oceny\"</string>
<string name="pref_view_app_language">Język aplikacji</string>
<string name="pref_notify_header">Powiadomienia</string>
<string name="pref_notify_switch">Pokazuj powiadomienia</string>
@ -407,9 +448,11 @@
<!--Errors-->
<string name="error_no_internet">Brak połączenia z internetem</string>
<string name="error_timeout">Upłynął limit czasu na połączenie z dziennikiem</string>
<string name="error_login_failed">Logowanie nie powiodło się. Spróbuj ponownie lub zrestartuj aplikację</string>
<string name="error_login_failed">Logowanie nie powiodło się. Spróbuj ponownie</string>
<string name="error_password_change_required">Wymagana zmiana hasła</string>
<string name="error_service_unavailable">Trwa przerwa techniczna dziennika UONET+. Spróbuj ponownie później</string>
<string name="error_unknown_uonet">Wystąpił nieznany błąd dziennika UONET+. Spróbuj ponownie później</string>
<string name="error_unknown_app">Wystąpił nieznany błąd aplikacji</string>
<string name="error_unknown">Wystąpił nieoczekiwany błąd</string>
<string name="error_feature_disabled">Funkcja wyłączona przez szkołę</string>
<string name="error_feature_not_available">Funkcja niedostępna. Zaloguj się w trybie innym niż Mobilne API</string>

View File

@ -12,6 +12,7 @@
<item>Pусский</item>
<item>Українська</item>
<item>Deutsch</item>
<item>Čeština</item>
</string-array>
<string-array name="services_interval_entries">
<item>15 минут</item>
@ -29,6 +30,10 @@
<item>0,5</item>
<item>0,75</item>
</string-array>
<string-array name="grade_sorting_mode_entries">
<item>Алфавитный</item>
<item>По дате</item>
</string-array>
<string-array name="grade_color_scheme_entries">
<item>Dzienniczek+</item>
<item>Wulkanowy</item>
@ -36,8 +41,8 @@
</string-array>
<string-array name="grade_average_mode_entries">
<item>Средняя оценка со 2 семестра</item>
<item>Average of grades from both semesters</item>
<item>Average of grades from the whole year</item>
<item>Средняя оценка с двух семестров</item>
<item>Средняя оценок со всего года</item>
</string-array>
<string-array name="timetable_show_whole_class_entries">
<item>Не показывать</item>

View File

@ -19,7 +19,7 @@
<string name="homework_title">Домашние задания</string>
<string name="account_title">Выберите аккаунт</string>
<!--Subtitles-->
<string name="grade_subtitle">%d семестр, %d/%d</string>
<string name="grade_subtitle">%1$d семестр, %2$d/%3$d</string>
<!--Login-->
<string name="login_header_default">Авторизируйтесь при помощи аккаунта ученика или родителя</string>
<string name="login_header_symbol">Впишите \"symbol\"</string>
@ -108,16 +108,16 @@
<item quantity="other">Новые оценки</item>
</plurals>
<plurals name="grade_new_items_predicted">
<item quantity="one">New predicted grade</item>
<item quantity="few">New predicted grades</item>
<item quantity="many">New predicted grades</item>
<item quantity="other">New predicted grades</item>
<item quantity="one">Новая ожидаемая оценка</item>
<item quantity="few">Новые ожидаемые оценки</item>
<item quantity="many">Новые ожидаемые оценки</item>
<item quantity="other">Новые ожидаемые оценки</item>
</plurals>
<plurals name="grade_new_items_final">
<item quantity="one">New final grade</item>
<item quantity="few">New final grades</item>
<item quantity="many">New final grades</item>
<item quantity="other">New final grades</item>
<item quantity="one">Новая итоговая оценка</item>
<item quantity="few">Новые итоговые оценки</item>
<item quantity="many">Новые итоговые оценки</item>
<item quantity="other">Новые итоговые оценки</item>
</plurals>
<plurals name="grade_notify_new_items">
<item quantity="one">Вы получили %1$d оценку</item>
@ -126,16 +126,16 @@
<item quantity="other">Вы получили %1$d оценок</item>
</plurals>
<plurals name="grade_notify_new_items_predicted">
<item quantity="one">You received %1$d predicted grade</item>
<item quantity="few">You received %1$d predicted grades</item>
<item quantity="many">You received %1$d predicted grades</item>
<item quantity="other">You received %1$d predicted grades</item>
<item quantity="one">Вы получили %1$d ожидаемую оценку</item>
<item quantity="few">Вы получили %1$d ожидаемые оценки</item>
<item quantity="many">Вы получили %1$d ожидаемых оценок</item>
<item quantity="other">Вы получили %1$d ожидаемых оценок</item>
</plurals>
<plurals name="grade_notify_new_items_final">
<item quantity="one">You received %1$d final grade</item>
<item quantity="few">You received %1$d final grades</item>
<item quantity="many">You received %1$d final grades</item>
<item quantity="other">You received %1$d final grades</item>
<item quantity="one">Вы получили %1$d финальную оценку</item>
<item quantity="few">Вы получили %1$d итоговых оценки</item>
<item quantity="many">Вы получили %1$d итоговых оценок</item>
<item quantity="other">Вы получили %1$d финальные оценки</item>
</plurals>
<!--Timetable-->
<string name="timetable_lesson">Урок</string>
@ -168,6 +168,8 @@
<string name="attendance_excused_lateness">Опоздание по уважительным причинам</string>
<string name="attendance_unexcused_lateness">Опоздание по неуважительным причинам</string>
<string name="attendance_present">Присутствие</string>
<string name="attendance_deleted">Удалено</string>
<string name="attendance_unknown">Неизвестно</string>
<string name="attendance_number">Урок №</string>
<string name="attendance_no_items">Данные не найдены</string>
<plurals name="attendance_number_absences">
@ -204,8 +206,8 @@
<string name="message_move_to_bin">Перенести в корзину</string>
<string name="message_delete_forever">Удалить навсегда</string>
<string name="message_delete_success">Сообщение успешно удалено</string>
<string name="message_share">Share</string>
<string name="message_print">Print</string>
<string name="message_share">Поделиться</string>
<string name="message_print">Печать</string>
<string name="message_subject">Тема</string>
<string name="message_content">Текст</string>
<string name="message_send_successful">Сообщение успешно отправлено</string>
@ -250,6 +252,44 @@
<item quantity="many">Вы получили %1$d предупреждений</item>
<item quantity="other">Вы получили %1$d предупреждений</item>
</plurals>
<!--Praise-->
<plurals name="praise_number_item">
<item quantity="one">%d похвала</item>
<item quantity="few">%d похвала</item>
<item quantity="many">%d похвала</item>
<item quantity="other">%d похвала</item>
</plurals>
<plurals name="praise_new_items">
<item quantity="one">Новая похвала</item>
<item quantity="few">Новые похвалы</item>
<item quantity="many">Новые свершения</item>
<item quantity="other">Новые похвалы</item>
</plurals>
<plurals name="praise_notify_new_items">
<item quantity="one">Вы получили %1$d похвалу</item>
<item quantity="few">Вы получили %1$d похвалы</item>
<item quantity="many">Вы получили %1$d похвалы</item>
<item quantity="other">Вы получили %1$d похвалы</item>
</plurals>
<!--Neutral notes-->
<plurals name="neutral_note_number_item">
<item quantity="one">%d нейтральное замечание</item>
<item quantity="few">%d нейтральных замечания</item>
<item quantity="many">%d нейтральных замечаний</item>
<item quantity="other">%d нейтральных замечаний</item>
</plurals>
<plurals name="neutral_note_new_items">
<item quantity="one">Новое нейтральное замечание</item>
<item quantity="few">Новые нейтральные замечания</item>
<item quantity="many">Новые нейтральные замечания</item>
<item quantity="other">Новые нейтральные замечания</item>
</plurals>
<plurals name="neutral_note_notify_new_items">
<item quantity="one">Вы получили %1$d нейтральное замечание</item>
<item quantity="few">Вы получили %1$d нейтральных замечания</item>
<item quantity="many">Вы получили %1$d нейтральных замечаний</item>
<item quantity="other">Вы получили %1$d нейтральных замечаний</item>
</plurals>
<!--Homework-->
<string name="homework_no_items">Нет домашних заданий</string>
<string name="homework_mark_as_done">сделанный</string>
@ -291,10 +331,10 @@
<string name="account_logout">Выйти</string>
<string name="account_confirm">Вы точно хотите выйти из данного аккаунта?</string>
<string name="account_logout_student">Выйти</string>
<string name="account_type_student">Student account</string>
<string name="account_type_parent">Parent account</string>
<string name="account_login_mobile_api">Mobile API mode</string>
<string name="account_login_hybrid">Hybrid mode</string>
<string name="account_type_student">Профиль ученика</string>
<string name="account_type_parent">Профиль родителя</string>
<string name="account_login_mobile_api">Режим Mobile API</string>
<string name="account_login_hybrid">Гибридный режим</string>
<!--About-->
<string name="about_version">Версия приложения</string>
<string name="about_contributor">Разработчики</string>
@ -353,11 +393,14 @@
<string name="pref_view_grade_average_force_calc">Принудительно высчитать среднюю оценку через приложение</string>
<string name="pref_view_present">Показывать присутствия в посещаемости</string>
<string name="pref_view_app_theme">Тема приложения</string>
<string name="pref_view_expand_grade">Больше оценок</string>
<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_grade_statistics_list">Показывать диаграммы в оценках класса</string>
<string name="pref_view_timetable_show_whole_class">Показать уроки всего класса</string>
<string name="pref_view_subjects_without_grades">Показывать предметы без оценок в \"Оценках\"</string>
<string name="pref_view_grade_color_scheme">Схема цветов оценок</string>
<string name="pref_view_grade_sorting_mode">Сортировка предметов в \"Оценках\"</string>
<string name="pref_view_app_language">Язык приложения</string>
<string name="pref_notify_header">Уведомления</string>
<string name="pref_notify_switch">Показывать уведомления</string>

View File

@ -12,6 +12,7 @@
<item>Pусский</item>
<item>Українська</item>
<item>Deutsch</item>
<item>Čeština</item>
</string-array>
<string-array name="services_interval_entries">
<item>15 хвилин</item>
@ -29,6 +30,10 @@
<item>0,5</item>
<item>0,75</item>
</string-array>
<string-array name="grade_sorting_mode_entries">
<item>Alphabetic</item>
<item>By date</item>
</string-array>
<string-array name="grade_color_scheme_entries">
<item>Dzienniczek+</item>
<item>Wulkanowy</item>

View File

@ -19,7 +19,7 @@
<string name="homework_title">Домашні завдання</string>
<string name="account_title">Оберіть аккаунт</string>
<!--Subtitles-->
<string name="grade_subtitle">%d семестр, %d/%d</string>
<string name="grade_subtitle">%1$d семестр, %2$d/%3$d</string>
<!--Login-->
<string name="login_header_default">Авторизуйтеся за допомогою аккаунта учня або батька</string>
<string name="login_header_symbol">Впишіть \"symbol\"</string>
@ -168,6 +168,8 @@
<string name="attendance_excused_lateness">Спізнення з поважних причин</string>
<string name="attendance_unexcused_lateness">Спізнення з не поважних причин</string>
<string name="attendance_present">Присутність</string>
<string name="attendance_deleted">Deleted</string>
<string name="attendance_unknown">Unknown</string>
<string name="attendance_number">Номер уроку</string>
<string name="attendance_no_items">Брак записів</string>
<plurals name="attendance_number_absences">
@ -250,6 +252,44 @@
<item quantity="many">%1$d нових зауважень</item>
<item quantity="other">%1$d нових зауважень</item>
</plurals>
<!--Praise-->
<plurals name="praise_number_item">
<item quantity="one">%d praise</item>
<item quantity="few">%d praises</item>
<item quantity="many">%d praises</item>
<item quantity="other">%d praises</item>
</plurals>
<plurals name="praise_new_items">
<item quantity="one">New praise</item>
<item quantity="few">New praises</item>
<item quantity="many">New praises</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="few">You received %1$d praises</item>
<item quantity="many">You received %1$d praises</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="few">%d neutral notes</item>
<item quantity="many">%d neutral notes</item>
<item quantity="other">%d neutral notes</item>
</plurals>
<plurals name="neutral_note_new_items">
<item quantity="one">New neutral note</item>
<item quantity="few">New neutral notes</item>
<item quantity="many">New neutral notes</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="few">You received %1$d neutral notes</item>
<item quantity="many">You received %1$d neutral notes</item>
<item quantity="other">You received %1$d neutral notes</item>
</plurals>
<!--Homework-->
<string name="homework_no_items">Брак домашніх завдань</string>
<string name="homework_mark_as_done">Позначити як зроблене</string>
@ -355,9 +395,12 @@
<string name="pref_view_app_theme">Тема додатку</string>
<string name="pref_view_expand_grade">Більше оцінок</string>
<string name="pref_view_timetable_show_timers">Позначити поточний урок у розкладі</string>
<string name="pref_view_timetable_show_groups">Show groups next to subjects in timetable</string>
<string name="pref_view_grade_statistics_list">Показувати діаграми в оцінках класу</string>
<string name="pref_view_timetable_show_whole_class">Показати уроки всього класу</string>
<string name="pref_view_subjects_without_grades">Show subjects without grades in Grades</string>
<string name="pref_view_grade_color_scheme">Схема кольорів оцінок</string>
<string name="pref_view_grade_sorting_mode">Subjects sorting in \"Grades\"</string>
<string name="pref_view_app_language">Мова додатку</string>
<string name="pref_notify_header">Повідомлення</string>
<string name="pref_notify_switch">Показувати повідомлення</string>

View File

@ -18,6 +18,10 @@
<string name="pref_default_grade_modifier_plus">0.33</string>
<string name="pref_default_grade_modifier_minus">0.33</string>
<bool name="pref_default_fill_message_content">true</bool>
<bool name="pref_default_timetable_show_groups">false</bool>
<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>
<bool name="pref_default_homework_fullscreen">false</bool>
<bool name="pref_default_subjects_without_grades">false</bool>
</resources>

View File

@ -20,6 +20,10 @@
<string name="pref_key_grade_modifier_plus">grade_modifier_plus</string>
<string name="pref_key_grade_modifier_minus">grade_modifier_minus</string>
<string name="pref_key_fill_message_content">fill_message_content</string>
<string name="pref_key_grade_sorting_mode">grade_sorting_mode</string>
<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_homework_fullscreen">homework_fullscreen</string>
<string name="pref_key_subjects_without_grades">subjects_without_grades</string>
</resources>

View File

@ -31,6 +31,7 @@
<item>Pусский</item>
<item>Українська</item>
<item>Deutsch</item>
<item>Čeština</item>
</string-array>
<string-array name="app_language_values" translatable="false">
<item>system</item>
@ -39,6 +40,7 @@
<item>ru</item>
<item>uk</item>
<item>de</item>
<item>cs</item>
</string-array>
<string-array name="services_interval_entries">
@ -75,6 +77,15 @@
<item>0.75</item>
</string-array>
<string-array name="grade_sorting_mode_entries">
<item>Alphabetic</item>
<item>By date</item>
</string-array>
<string-array name="grade_sorting_mode_values" translatable="false">
<item>alphabetic</item>
<item>date</item>
</string-array>
<string-array name="grade_color_scheme_entries">
<item>Dzienniczek+</item>
<item>Wulkanowy</item>

View File

@ -21,7 +21,7 @@
<!--Subtitles-->
<string name="grade_subtitle">Semester %d, %d/%d</string>
<string name="grade_subtitle">Semester %1$d, %2$d/%3$d</string>
<!--Login-->
@ -249,6 +249,34 @@
<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>
@ -383,9 +411,12 @@
<string name="pref_view_app_theme">Application theme</string>
<string name="pref_view_expand_grade">Expand grades</string>
<string name="pref_view_timetable_show_timers">Mark current lesson in timetable</string>
<string name="pref_view_timetable_show_groups">Show groups next to subjects in timetable</string>
<string name="pref_view_grade_statistics_list">Show chart list in class grades</string>
<string name="pref_view_timetable_show_whole_class">Show whole class lessons</string>
<string name="pref_view_subjects_without_grades">Show subjects without grades in Grades</string>
<string name="pref_view_grade_color_scheme">Grades color scheme</string>
<string name="pref_view_grade_sorting_mode">Subjects sorting in "Grades"</string>
<string name="pref_view_app_language">App language</string>
<string name="pref_notify_header">Notifications</string>
@ -441,13 +472,21 @@
<string name="all_copied">Copied</string>
<string name="all_undo">Undo</string>
<!--Update helper-->
<string name="update_download_started">Start downloading update…</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>
<!--Errors-->
<string name="error_no_internet">No internet connection</string>
<string name="error_timeout">Connection to the register timed out</string>
<string name="error_login_failed">Login failed. Try again or restart the app</string>
<string name="error_login_failed">Login failed. Try again</string>
<string name="error_password_change_required">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</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>

View File

@ -23,7 +23,7 @@
<item name="android:windowBackground">@drawable/layer_splash_background</item>
</style>
<style name="WulkanowyTheme.WidgetAccountSwitcher" parent="Theme.MaterialComponents.Light.Dialog">
<style name="WulkanowyTheme.WidgetAccountSwitcher" parent="Theme.MaterialComponents.DayNight.Dialog">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorSecondary">@color/colorPrimary</item>
<item name="windowActionBar">false</item>

View File

@ -40,6 +40,18 @@
app:key="@string/pref_key_grade_statistics_list"
app:singleLineTitle="false"
app:title="@string/pref_view_grade_statistics_list" />
<SwitchPreferenceCompat
app:defaultValue="@bool/pref_default_timetable_show_groups"
app:iconSpaceReserved="false"
app:key="@string/pref_key_timetable_show_groups"
app:singleLineTitle="false"
app:title="@string/pref_view_timetable_show_groups" />
<SwitchPreferenceCompat
app:defaultValue="@bool/pref_default_subjects_without_grades"
app:iconSpaceReserved="false"
app:key="@string/pref_key_subjects_without_grades"
app:singleLineTitle="false"
app:title="@string/pref_view_subjects_without_grades" />
<ListPreference
app:defaultValue="@string/pref_default_timetable_show_whole_class"
app:entries="@array/timetable_show_whole_class_entries"
@ -56,6 +68,14 @@
app:key="@string/pref_key_grade_color_scheme"
app:title="@string/pref_view_grade_color_scheme"
app:useSimpleSummaryProvider="true" />
<ListPreference
app:defaultValue="@string/pref_default_grade_sorting_mode"
app:entries="@array/grade_sorting_mode_entries"
app:entryValues="@array/grade_sorting_mode_values"
app:iconSpaceReserved="false"
app:key="@string/pref_key_grade_sorting_mode"
app:title="@string/pref_view_grade_sorting_mode"
app:useSimpleSummaryProvider="true" />
<ListPreference
app:defaultValue="@string/pref_default_app_language"
app:entries="@array/app_language_entries"

View File

@ -0,0 +1,105 @@
package io.github.wulkanowy.utils
import android.app.Activity
import android.app.Activity.RESULT_OK
import android.content.Context
import android.view.View
import android.widget.Toast
import com.google.android.material.snackbar.Snackbar
import com.google.android.play.core.appupdate.AppUpdateInfo
import com.google.android.play.core.appupdate.AppUpdateManagerFactory
import com.google.android.play.core.install.InstallStateUpdatedListener
import com.google.android.play.core.install.model.AppUpdateType.FLEXIBLE
import com.google.android.play.core.install.model.AppUpdateType.IMMEDIATE
import com.google.android.play.core.install.model.InstallStatus.DOWNLOADED
import com.google.android.play.core.install.model.InstallStatus.PENDING
import com.google.android.play.core.install.model.UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS
import com.google.android.play.core.install.model.UpdateAvailability.UPDATE_AVAILABLE
import com.google.android.play.core.ktx.isFlexibleUpdateAllowed
import com.google.android.play.core.ktx.isImmediateUpdateAllowed
import dagger.hilt.android.qualifiers.ApplicationContext
import io.github.wulkanowy.R
import timber.log.Timber
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class UpdateHelper @Inject constructor(@ApplicationContext private val context: Context) {
lateinit var messageContainer: View
companion object {
const val IN_APP_UPDATE_REQUEST_CODE = 1721
const val DAYS_FOR_FLEXIBLE_UPDATE = 7
const val HIGH_PRIORITY_UPDATE = 4
}
private val appUpdateManager by lazy { AppUpdateManagerFactory.create(context) }
private val flexibleUpdateListener = InstallStateUpdatedListener { state ->
when (state.installStatus()) {
PENDING -> Toast.makeText(context, R.string.update_download_started, Toast.LENGTH_SHORT).show()
DOWNLOADED -> popupSnackBarForCompleteUpdate()
else -> Timber.d("Update state: ${state.installStatus()}")
}
}
private inline val AppUpdateInfo.isImmediateUpdateAvailable: Boolean
get() = updateAvailability() == UPDATE_AVAILABLE && isImmediateUpdateAllowed &&
updatePriority() >= HIGH_PRIORITY_UPDATE
private inline val AppUpdateInfo.isFlexibleUpdateAvailable: Boolean
get() = updateAvailability() == UPDATE_AVAILABLE && isFlexibleUpdateAllowed &&
clientVersionStalenessDays() ?: 0 >= DAYS_FOR_FLEXIBLE_UPDATE
fun checkAndInstallUpdates(activity: Activity) {
Timber.d("Checking for updates...")
appUpdateManager.appUpdateInfo.addOnSuccessListener { appUpdateInfo ->
when {
appUpdateInfo.isImmediateUpdateAvailable -> startUpdate(activity, appUpdateInfo, IMMEDIATE)
appUpdateInfo.isFlexibleUpdateAvailable -> {
appUpdateManager.registerListener(flexibleUpdateListener)
startUpdate(activity, appUpdateInfo, FLEXIBLE)
}
else -> Timber.d("No update available")
}
}
}
private fun startUpdate(activity: Activity, appUpdateInfo: AppUpdateInfo, updateType: Int) {
appUpdateManager.startUpdateFlowForResult(
appUpdateInfo, updateType, activity, IN_APP_UPDATE_REQUEST_CODE
)
}
fun onActivityResult(requestCode: Int, resultCode: Int) {
if (requestCode == IN_APP_UPDATE_REQUEST_CODE && resultCode != RESULT_OK) {
Timber.e("Update failed! Result code: $resultCode")
Toast.makeText(context, R.string.update_failed, Toast.LENGTH_LONG).show()
}
}
fun onResume(activity: Activity) {
appUpdateManager.appUpdateInfo.addOnSuccessListener { info ->
Timber.d("InAppUpdate.onResume() listener: $info")
when {
DOWNLOADED == info.installStatus() -> popupSnackBarForCompleteUpdate()
DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS == info.updateAvailability() -> {
startUpdate(activity, info, if (info.isImmediateUpdateAvailable) IMMEDIATE else FLEXIBLE)
}
}
}
}
private fun popupSnackBarForCompleteUpdate() {
Snackbar.make(messageContainer, R.string.update_download_success, Snackbar.LENGTH_INDEFINITE).apply {
setAction(R.string.update_download_success_button) {
appUpdateManager.completeUpdate()
appUpdateManager.unregisterListener(flexibleUpdateListener)
}
show()
}
}
}

View File

@ -0,0 +1,30 @@
package io.github.wulkanowy.data.db
import org.junit.Assert.assertEquals
import org.junit.Test
class ConvertersTest {
@Test
fun stringPairListToJson() {
assertEquals(Converters().stringPairListToJson(listOf("aaa" to "bbb", "ccc" to "ddd", "eee" to "fff")), "[{\"first\":\"aaa\",\"second\":\"bbb\"},{\"first\":\"ccc\",\"second\":\"ddd\"},{\"first\":\"eee\",\"second\":\"fff\"}]")
assertEquals(Converters().stringPairListToJson(listOf("aaa" to "bbb", "ccc" to "ddd")), "[{\"first\":\"aaa\",\"second\":\"bbb\"},{\"first\":\"ccc\",\"second\":\"ddd\"}]")
assertEquals(Converters().stringPairListToJson(listOf("aaa" to "bbb")), "[{\"first\":\"aaa\",\"second\":\"bbb\"}]")
assertEquals(Converters().stringPairListToJson(listOf()), "[]")
}
@Test
fun jsonToStringPairList() {
assertEquals(Converters().jsonToStringPairList("[{\"first\":\"aaa\",\"second\":\"bbb\"},{\"first\":\"ccc\",\"second\":\"ddd\"},{\"first\":\"eee\",\"second\":\"fff\"}]"), listOf("aaa" to "bbb", "ccc" to "ddd", "eee" to "fff"))
assertEquals(Converters().jsonToStringPairList("[{\"first\":\"aaa\",\"second\":\"bbb\"},{\"first\":\"ccc\",\"second\":\"ddd\"}]"), listOf("aaa" to "bbb", "ccc" to "ddd"))
assertEquals(Converters().jsonToStringPairList("[{\"first\":\"aaa\",\"second\":\"bbb\"}]"), listOf("aaa" to "bbb"))
assertEquals(Converters().jsonToStringPairList("[]"), listOf<Pair<String, String>>())
}
@Test
fun jsonToStringPairList_0210() {
assertEquals(Converters().jsonToStringPairList("{\"aaa\":\"bbb\",\"ccc\":\"ddd\"}"), listOf("aaa" to "bbb", "ccc" to "ddd"))
assertEquals(Converters().jsonToStringPairList("{\"aaa\":\"bbb\"}"), listOf("aaa" to "bbb"))
assertEquals(Converters().jsonToStringPairList("{}"), listOf<Pair<String, String>>())
}
}

BIN
appgallery_badge.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

View File

@ -1,7 +1,7 @@
buildscript {
ext {
kotlin_version = '1.4.10'
about_libraries = '8.3.0'
about_libraries = '8.4.2'
hilt_version = "2.29.1-alpha"
}
repositories {
@ -12,11 +12,11 @@ buildscript {
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.android.tools.build:gradle:4.0.1'
classpath 'com.android.tools.build:gradle:4.0.2'
classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
classpath 'com.google.gms:google-services:4.3.3'
classpath 'com.google.gms:google-services:4.3.4'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.3.0'
classpath "com.github.triplet.gradle:play-publisher:2.7.5"
classpath "com.github.triplet.gradle:play-publisher:2.8.0"
classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.0"
classpath "gradle.plugin.com.star-zero.gradle:githook:1.2.0"
classpath "com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin:$about_libraries"

Binary file not shown.

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

2
gradlew vendored
View File

@ -82,6 +82,7 @@ esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
@ -129,6 +130,7 @@ fi
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath

22
gradlew.bat vendored
View File

@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@ -54,7 +54,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@ -64,28 +64,14 @@ echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell