Merge branch 'release/0.23.0'

This commit is contained in:
Mikołaj Pich 2020-12-06 22:21:36 +01:00
commit afee97a706
69 changed files with 5131 additions and 414 deletions

View File

@ -14,7 +14,7 @@ cache:
branches: branches:
only: only:
- develop - develop
- 0.22.2 - 0.23.0
android: android:
licenses: licenses:

View File

@ -18,8 +18,8 @@ android {
testApplicationId "io.github.tests.wulkanowy" testApplicationId "io.github.tests.wulkanowy"
minSdkVersion 17 minSdkVersion 17
targetSdkVersion 30 targetSdkVersion 30
versionCode 75 versionCode 76
versionName "0.22.2" versionName "0.23.0"
multiDexEnabled true multiDexEnabled true
resValue "string", "app_name", "Wulkanowy" resValue "string", "app_name", "Wulkanowy"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@ -126,14 +126,14 @@ play {
serviceAccountCredentials = file('key.p12') serviceAccountCredentials = file('key.p12')
defaultToAppBundles = false defaultToAppBundles = false
track = 'alpha' track = 'alpha'
updatePriority = 1 updatePriority = 3
} }
ext { ext {
work_manager = "2.4.0" work_manager = "2.4.0"
room = "2.2.5" room = "2.2.5"
chucker = "3.3.0" chucker = "3.4.0"
mockk = "1.10.2" mockk = "1.10.3-jdk8"
moshi = "1.11.0" moshi = "1.11.0"
} }
@ -142,12 +142,12 @@ configurations.all {
} }
dependencies { dependencies {
implementation "io.github.wulkanowy:sdk:0.22.2" implementation "io.github.wulkanowy:sdk:0.23.0"
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.10' coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.1'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.2'
implementation "androidx.core:core-ktx:1.3.2" implementation "androidx.core:core-ktx:1.3.2"
implementation "androidx.activity:activity-ktx:1.1.0" implementation "androidx.activity:activity-ktx:1.1.0"
@ -194,20 +194,20 @@ dependencies {
implementation "fr.bipi.treessence:treessence:0.3.2" implementation "fr.bipi.treessence:treessence:0.3.2"
implementation "com.mikepenz:aboutlibraries-core:$about_libraries" implementation "com.mikepenz:aboutlibraries-core:$about_libraries"
implementation 'com.wdullaer:materialdatetimepicker:4.2.3' implementation 'com.wdullaer:materialdatetimepicker:4.2.3'
implementation "io.coil-kt:coil:1.0.0-rc3" implementation "io.coil-kt:coil:1.1.0"
implementation "io.github.wulkanowy:AppKillerManager:3.0.0" implementation "io.github.wulkanowy:AppKillerManager:3.0.0"
implementation 'me.xdrop:fuzzywuzzy:1.3.1' implementation 'me.xdrop:fuzzywuzzy:1.3.1'
playImplementation 'com.google.firebase:firebase-analytics:17.6.0' playImplementation 'com.google.firebase:firebase-analytics:18.0.0'
playImplementation 'com.google.firebase:firebase-inappmessaging-display-ktx:19.1.1' playImplementation 'com.google.firebase:firebase-inappmessaging-display-ktx:19.1.2'
playImplementation "com.google.firebase:firebase-inappmessaging-ktx:19.1.1" playImplementation "com.google.firebase:firebase-inappmessaging-ktx:19.1.2"
playImplementation 'com.google.firebase:firebase-messaging:20.3.0' playImplementation 'com.google.firebase:firebase-messaging:21.0.0'
playImplementation 'com.google.firebase:firebase-crashlytics:17.2.2' playImplementation 'com.google.firebase:firebase-crashlytics:17.3.0'
playImplementation 'com.google.android.play:core-ktx:1.8.1' playImplementation 'com.google.android.play:core-ktx:1.8.1'
playImplementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava' playImplementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava'
hmsImplementation 'com.huawei.hms:hianalytics:5.0.4.301' hmsImplementation 'com.huawei.hms:hianalytics:5.0.5.301'
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.4.1.300' hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.4.2.301'
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker" releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker"
@ -216,7 +216,7 @@ dependencies {
testImplementation "junit:junit:4.13.1" testImplementation "junit:junit:4.13.1"
testImplementation "io.mockk:mockk:$mockk" testImplementation "io.mockk:mockk:$mockk"
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.9' testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.4.2'
androidTestImplementation "androidx.test:core:1.3.0" androidTestImplementation "androidx.test:core:1.3.0"
androidTestImplementation "androidx.test:runner:1.3.0" androidTestImplementation "androidx.test:runner:1.3.0"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -4,8 +4,8 @@ import androidx.room.Room
import androidx.test.core.app.ApplicationProvider import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import io.github.wulkanowy.data.db.AppDatabase import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.GradePartialStatistics
import io.github.wulkanowy.data.db.entities.GradePointsStatistics import io.github.wulkanowy.data.db.entities.GradePointsStatistics
import io.github.wulkanowy.data.db.entities.GradeStatistics
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
@ -27,7 +27,7 @@ class GradeStatisticsLocalTest {
fun createDb() { fun createDb() {
testDb = Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java) testDb = Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java)
.build() .build()
gradeStatisticsLocal = GradeStatisticsLocal(testDb.gradeStatistics, testDb.gradePointsStatistics) gradeStatisticsLocal = GradeStatisticsLocal(testDb.gradePartialStatisticsDao, testDb.gradePointsStatisticsDao, testDb.gradeSemesterStatisticsDao)
} }
@After @After
@ -41,9 +41,9 @@ class GradeStatisticsLocalTest {
getGradeStatistics("Matematyka", 2, 1), getGradeStatistics("Matematyka", 2, 1),
getGradeStatistics("Fizyka", 1, 2) getGradeStatistics("Fizyka", 1, 2)
) )
runBlocking { gradeStatisticsLocal.saveGradesStatistics(list) } runBlocking { gradeStatisticsLocal.saveGradePartialStatistics(list) }
val stats = runBlocking { gradeStatisticsLocal.getGradesStatistics(getSemester(), false).first() } val stats = runBlocking { gradeStatisticsLocal.getGradePartialStatistics(getSemester()).first() }
assertEquals(1, stats.size) assertEquals(1, stats.size)
assertEquals(stats[0].subject, "Matematyka") assertEquals(stats[0].subject, "Matematyka")
} }
@ -55,12 +55,10 @@ class GradeStatisticsLocalTest {
getGradeStatistics("Chemia", 2, 1), getGradeStatistics("Chemia", 2, 1),
getGradeStatistics("Fizyka", 1, 2) getGradeStatistics("Fizyka", 1, 2)
) )
runBlocking { gradeStatisticsLocal.saveGradesStatistics(list) } runBlocking { gradeStatisticsLocal.saveGradePartialStatistics(list) }
val stats = runBlocking { gradeStatisticsLocal.getGradesStatistics(getSemester(), false).first() } val stats = runBlocking { gradeStatisticsLocal.getGradePartialStatistics(getSemester()).first() }
assertEquals(2, stats.size) assertEquals(2, stats.size)
// assertEquals(3, stats.size)
// assertEquals(stats[0].subject, "Wszystkie") // now in main repo
assertEquals(stats[0].subject, "Matematyka") assertEquals(stats[0].subject, "Matematyka")
assertEquals(stats[1].subject, "Chemia") assertEquals(stats[1].subject, "Chemia")
} }
@ -72,9 +70,9 @@ class GradeStatisticsLocalTest {
getGradePointsStatistics("Chemia", 2, 1), getGradePointsStatistics("Chemia", 2, 1),
getGradePointsStatistics("Fizyka", 1, 2) getGradePointsStatistics("Fizyka", 1, 2)
) )
runBlocking { gradeStatisticsLocal.saveGradesPointsStatistics(list) } runBlocking { gradeStatisticsLocal.saveGradePointsStatistics(list) }
val stats = runBlocking { gradeStatisticsLocal.getGradesPointsStatistics(getSemester()).first() } val stats = runBlocking { gradeStatisticsLocal.getGradePointsStatistics(getSemester()).first() }
with(stats[0]) { with(stats[0]) {
assertEquals(subject, "Matematyka") assertEquals(subject, "Matematyka")
assertEquals(others, 5.0) assertEquals(others, 5.0)
@ -84,17 +82,17 @@ class GradeStatisticsLocalTest {
@Test @Test
fun saveAndRead_subjectEmpty() { fun saveAndRead_subjectEmpty() {
runBlocking { gradeStatisticsLocal.saveGradesPointsStatistics(listOf()) } runBlocking { gradeStatisticsLocal.saveGradePointsStatistics(listOf()) }
val stats = runBlocking { gradeStatisticsLocal.getGradesPointsStatistics(getSemester()).first() } val stats = runBlocking { gradeStatisticsLocal.getGradePointsStatistics(getSemester()).first() }
assertEquals(emptyList(), stats) assertEquals(emptyList(), stats)
} }
@Test @Test
fun saveAndRead_allEmpty() { fun saveAndRead_allEmpty() {
runBlocking { gradeStatisticsLocal.saveGradesPointsStatistics(listOf()) } runBlocking { gradeStatisticsLocal.saveGradePointsStatistics(listOf()) }
val stats = runBlocking { gradeStatisticsLocal.getGradesPointsStatistics(getSemester()).first() } val stats = runBlocking { gradeStatisticsLocal.getGradePointsStatistics(getSemester()).first() }
assertEquals(emptyList(), stats) assertEquals(emptyList(), stats)
} }
@ -102,8 +100,8 @@ class GradeStatisticsLocalTest {
return Semester(2, 2, "", 2019, 1, 2, now(), now(), 1, 1) return Semester(2, 2, "", 2019, 1, 2, now(), now(), 1, 1)
} }
private fun getGradeStatistics(subject: String, studentId: Int, semesterId: Int): GradeStatistics { private fun getGradeStatistics(subject: String, studentId: Int, semesterId: Int): GradePartialStatistics {
return GradeStatistics(studentId, semesterId, subject, 5, 5, false) return GradePartialStatistics(studentId, semesterId, subject, "", "", listOf(5), listOf(5))
} }
private fun getGradePointsStatistics(subject: String, studentId: Int, semesterId: Int): GradePointsStatistics { private fun getGradePointsStatistics(subject: String, studentId: Int, semesterId: Int): GradePointsStatistics {

View File

@ -15,4 +15,8 @@ class AnalyticsHelper @Inject constructor() {
fun setCurrentScreen(activity: Activity, name: String?) { fun setCurrentScreen(activity: Activity, name: String?) {
// do nothing // do nothing
} }
fun popCurrentScreen(name: String?) {
// do nothing
}
} }

View File

@ -30,9 +30,10 @@ class AnalyticsHelper @Inject constructor(
} }
fun setCurrentScreen(activity: Activity, name: String?) { fun setCurrentScreen(activity: Activity, name: String?) {
analytics.onEvent("screen_view", Bundle().apply { analytics.pageStart(name, activity::class.simpleName)
putString("screen_name", name) }
putString("screen_class", activity::class.simpleName)
}) fun popCurrentScreen(name: String?) {
analytics.pageEnd(name)
} }
} }

View File

@ -42,11 +42,11 @@ class CrashLogExceptionTree : FormatterPriorityTree(Log.ERROR) {
connectCrash.setCustomKey("priority", priority) connectCrash.setCustomKey("priority", priority)
connectCrash.setCustomKey("tag", tag.orEmpty()) connectCrash.setCustomKey("tag", tag.orEmpty())
connectCrash.setCustomKey("message", message) connectCrash.setCustomKey("message", message)
connectCrash.log(priority, t?.stackTraceToString())
if (t != null) { if (t != null) {
connectCrash.log(priority, t.stackTraceToString()) connectCrash.recordException(t)
} else { } else {
connectCrash.log(priority, StackTraceRecorder(format(priority, tag, message)).stackTraceToString()) connectCrash.recordException(StackTraceRecorder(format(priority, tag, message)))
} }
} }
} }

View File

@ -33,6 +33,6 @@
}, },
{ {
"displayName": "Mateusz Idziejczak", "displayName": "Mateusz Idziejczak",
"githubUsername": "PanTajemnic" "githubUsername": "Luncenok"
} }
] ]

View File

@ -11,8 +11,8 @@ import com.chuckerteam.chucker.api.RetentionManager
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
import dagger.hilt.android.components.ApplicationComponent
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import io.github.wulkanowy.data.db.AppDatabase import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.SharedPrefProvider import io.github.wulkanowy.data.db.SharedPrefProvider
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
@ -21,7 +21,7 @@ import timber.log.Timber
import javax.inject.Singleton import javax.inject.Singleton
@Module @Module
@InstallIn(ApplicationComponent::class) @InstallIn(SingletonComponent::class)
internal class RepositoryModule { internal class RepositoryModule {
@Singleton @Singleton
@ -85,11 +85,15 @@ internal class RepositoryModule {
@Singleton @Singleton
@Provides @Provides
fun provideGradeStatisticsDao(database: AppDatabase) = database.gradeStatistics fun provideGradePartialStatisticsDao(database: AppDatabase) = database.gradePartialStatisticsDao
@Singleton @Singleton
@Provides @Provides
fun provideGradePointsStatisticsDao(database: AppDatabase) = database.gradePointsStatistics fun provideGradeSemesterStatisticsDao(database: AppDatabase) = database.gradeSemesterStatisticsDao
@Singleton
@Provides
fun provideGradePointsStatisticsDao(database: AppDatabase) = database.gradePointsStatisticsDao
@Singleton @Singleton
@Provides @Provides
@ -154,4 +158,8 @@ internal class RepositoryModule {
@Singleton @Singleton
@Provides @Provides
fun provideSchoolInfoDao(database: AppDatabase) = database.schoolDao fun provideSchoolInfoDao(database: AppDatabase) = database.schoolDao
@Singleton
@Provides
fun provideConferenceDao(database: AppDatabase) = database.conferenceDao
} }

View File

@ -10,10 +10,12 @@ import androidx.room.migration.Migration
import io.github.wulkanowy.data.db.dao.AttendanceDao import io.github.wulkanowy.data.db.dao.AttendanceDao
import io.github.wulkanowy.data.db.dao.AttendanceSummaryDao import io.github.wulkanowy.data.db.dao.AttendanceSummaryDao
import io.github.wulkanowy.data.db.dao.CompletedLessonsDao import io.github.wulkanowy.data.db.dao.CompletedLessonsDao
import io.github.wulkanowy.data.db.dao.ConferenceDao
import io.github.wulkanowy.data.db.dao.ExamDao import io.github.wulkanowy.data.db.dao.ExamDao
import io.github.wulkanowy.data.db.dao.GradeDao import io.github.wulkanowy.data.db.dao.GradeDao
import io.github.wulkanowy.data.db.dao.GradePartialStatisticsDao
import io.github.wulkanowy.data.db.dao.GradePointsStatisticsDao import io.github.wulkanowy.data.db.dao.GradePointsStatisticsDao
import io.github.wulkanowy.data.db.dao.GradeStatisticsDao import io.github.wulkanowy.data.db.dao.GradeSemesterStatisticsDao
import io.github.wulkanowy.data.db.dao.GradeSummaryDao import io.github.wulkanowy.data.db.dao.GradeSummaryDao
import io.github.wulkanowy.data.db.dao.HomeworkDao import io.github.wulkanowy.data.db.dao.HomeworkDao
import io.github.wulkanowy.data.db.dao.LuckyNumberDao import io.github.wulkanowy.data.db.dao.LuckyNumberDao
@ -32,10 +34,12 @@ import io.github.wulkanowy.data.db.dao.TimetableDao
import io.github.wulkanowy.data.db.entities.Attendance import io.github.wulkanowy.data.db.entities.Attendance
import io.github.wulkanowy.data.db.entities.AttendanceSummary import io.github.wulkanowy.data.db.entities.AttendanceSummary
import io.github.wulkanowy.data.db.entities.CompletedLesson import io.github.wulkanowy.data.db.entities.CompletedLesson
import io.github.wulkanowy.data.db.entities.Conference
import io.github.wulkanowy.data.db.entities.Exam import io.github.wulkanowy.data.db.entities.Exam
import io.github.wulkanowy.data.db.entities.Grade import io.github.wulkanowy.data.db.entities.Grade
import io.github.wulkanowy.data.db.entities.GradePartialStatistics
import io.github.wulkanowy.data.db.entities.GradePointsStatistics import io.github.wulkanowy.data.db.entities.GradePointsStatistics
import io.github.wulkanowy.data.db.entities.GradeStatistics import io.github.wulkanowy.data.db.entities.GradeSemesterStatistics
import io.github.wulkanowy.data.db.entities.GradeSummary import io.github.wulkanowy.data.db.entities.GradeSummary
import io.github.wulkanowy.data.db.entities.Homework import io.github.wulkanowy.data.db.entities.Homework
import io.github.wulkanowy.data.db.entities.LuckyNumber import io.github.wulkanowy.data.db.entities.LuckyNumber
@ -70,6 +74,8 @@ import io.github.wulkanowy.data.db.migrations.Migration24
import io.github.wulkanowy.data.db.migrations.Migration25 import io.github.wulkanowy.data.db.migrations.Migration25
import io.github.wulkanowy.data.db.migrations.Migration26 import io.github.wulkanowy.data.db.migrations.Migration26
import io.github.wulkanowy.data.db.migrations.Migration27 import io.github.wulkanowy.data.db.migrations.Migration27
import io.github.wulkanowy.data.db.migrations.Migration28
import io.github.wulkanowy.data.db.migrations.Migration29
import io.github.wulkanowy.data.db.migrations.Migration3 import io.github.wulkanowy.data.db.migrations.Migration3
import io.github.wulkanowy.data.db.migrations.Migration4 import io.github.wulkanowy.data.db.migrations.Migration4
import io.github.wulkanowy.data.db.migrations.Migration5 import io.github.wulkanowy.data.db.migrations.Migration5
@ -90,8 +96,9 @@ import javax.inject.Singleton
AttendanceSummary::class, AttendanceSummary::class,
Grade::class, Grade::class,
GradeSummary::class, GradeSummary::class,
GradeStatistics::class, GradePartialStatistics::class,
GradePointsStatistics::class, GradePointsStatistics::class,
GradeSemesterStatistics::class,
Message::class, Message::class,
MessageAttachment::class, MessageAttachment::class,
Note::class, Note::class,
@ -103,7 +110,8 @@ import javax.inject.Singleton
Recipient::class, Recipient::class,
MobileDevice::class, MobileDevice::class,
Teacher::class, Teacher::class,
School::class School::class,
Conference::class,
], ],
version = AppDatabase.VERSION_SCHEMA, version = AppDatabase.VERSION_SCHEMA,
exportSchema = true exportSchema = true
@ -112,7 +120,7 @@ import javax.inject.Singleton
abstract class AppDatabase : RoomDatabase() { abstract class AppDatabase : RoomDatabase() {
companion object { companion object {
const val VERSION_SCHEMA = 27 const val VERSION_SCHEMA = 29
fun getMigrations(sharedPrefProvider: SharedPrefProvider): Array<Migration> { fun getMigrations(sharedPrefProvider: SharedPrefProvider): Array<Migration> {
return arrayOf( return arrayOf(
@ -142,6 +150,8 @@ abstract class AppDatabase : RoomDatabase() {
Migration25(), Migration25(),
Migration26(), Migration26(),
Migration27(), Migration27(),
Migration28(),
Migration29()
) )
} }
@ -171,9 +181,11 @@ abstract class AppDatabase : RoomDatabase() {
abstract val gradeSummaryDao: GradeSummaryDao abstract val gradeSummaryDao: GradeSummaryDao
abstract val gradeStatistics: GradeStatisticsDao abstract val gradePartialStatisticsDao: GradePartialStatisticsDao
abstract val gradePointsStatistics: GradePointsStatisticsDao abstract val gradePointsStatisticsDao: GradePointsStatisticsDao
abstract val gradeSemesterStatisticsDao: GradeSemesterStatisticsDao
abstract val messagesDao: MessagesDao abstract val messagesDao: MessagesDao
@ -198,4 +210,6 @@ abstract class AppDatabase : RoomDatabase() {
abstract val teacherDao: TeacherDao abstract val teacherDao: TeacherDao
abstract val schoolDao: SchoolDao abstract val schoolDao: SchoolDao
abstract val conferenceDao: ConferenceDao
} }

View File

@ -0,0 +1,15 @@
package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.Conference
import kotlinx.coroutines.flow.Flow
import javax.inject.Singleton
@Dao
@Singleton
interface ConferenceDao : BaseDao<Conference> {
@Query("SELECT * FROM Conferences WHERE diary_id = :diaryId AND student_id = :studentId")
fun loadAll(diaryId: Int, studentId: Int): Flow<List<Conference>>
}

View File

@ -0,0 +1,13 @@
package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.GradePartialStatistics
import kotlinx.coroutines.flow.Flow
@Dao
interface GradePartialStatisticsDao : BaseDao<GradePartialStatistics> {
@Query("SELECT * FROM GradePartialStatistics WHERE student_id = :studentId AND semester_id = :semesterId")
fun loadAll(semesterId: Int, studentId: Int): Flow<List<GradePartialStatistics>>
}

View File

@ -0,0 +1,13 @@
package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.GradeSemesterStatistics
import kotlinx.coroutines.flow.Flow
@Dao
interface GradeSemesterStatisticsDao : BaseDao<GradeSemesterStatistics> {
@Query("SELECT * FROM GradeSemesterStatistics WHERE student_id = :studentId AND semester_id = :semesterId")
fun loadAll(semesterId: Int, studentId: Int): Flow<List<GradeSemesterStatistics>>
}

View File

@ -1,18 +0,0 @@
package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.GradeStatistics
import kotlinx.coroutines.flow.Flow
import javax.inject.Singleton
@Singleton
@Dao
interface GradeStatisticsDao : BaseDao<GradeStatistics> {
@Query("SELECT * FROM GradesStatistics WHERE student_id = :studentId AND semester_id = :semesterId AND subject = :subjectName AND is_semester = :isSemester")
fun loadSubject(semesterId: Int, studentId: Int, subjectName: String, isSemester: Boolean): Flow<List<GradeStatistics>>
@Query("SELECT * FROM GradesStatistics WHERE student_id = :studentId AND semester_id = :semesterId AND is_semester = :isSemester")
fun loadAll(semesterId: Int, studentId: Int, isSemester: Boolean): Flow<List<GradeStatistics>>
}

View File

@ -0,0 +1,35 @@
package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import java.io.Serializable
import java.time.LocalDateTime
@Entity(tableName = "Conferences")
data class Conference(
@ColumnInfo(name = "student_id")
val studentId: Int,
@ColumnInfo(name = "diary_id")
val diaryId: Int,
val title: String,
val subject: String,
val agenda: String,
@ColumnInfo(name = "present_on_conference")
val presentOnConference: String,
@ColumnInfo(name = "conference_id")
val conferenceId: Int,
val date: LocalDateTime
) : Serializable {
@PrimaryKey(autoGenerate = true)
var id: Long = 0
}

View File

@ -0,0 +1,33 @@
package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "GradePartialStatistics")
data class GradePartialStatistics(
@ColumnInfo(name = "student_id")
val studentId: Int,
@ColumnInfo(name = "semester_id")
val semesterId: Int,
val subject: String,
@ColumnInfo(name = "class_average")
val classAverage: String,
@ColumnInfo(name = "student_average")
val studentAverage: String,
@ColumnInfo(name = "class_amounts")
val classAmounts: List<Int>,
@ColumnInfo(name = "student_amounts")
val studentAmounts: List<Int>
) {
@PrimaryKey(autoGenerate = true)
var id: Long = 0
}

View File

@ -4,8 +4,8 @@ import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
@Entity(tableName = "GradesStatistics") @Entity(tableName = "GradeSemesterStatistics")
data class GradeStatistics( data class GradeSemesterStatistics(
@ColumnInfo(name = "student_id") @ColumnInfo(name = "student_id")
val studentId: Int, val studentId: Int,
@ -15,13 +15,14 @@ data class GradeStatistics(
val subject: String, val subject: String,
val grade: Int, val amounts: List<Int>,
val amount: Int, @ColumnInfo(name = "student_grade")
val studentGrade: Int
@ColumnInfo(name = "is_semester")
val semester: Boolean
) { ) {
@PrimaryKey(autoGenerate = true) @PrimaryKey(autoGenerate = true)
var id: Long = 0 var id: Long = 0
@Transient
var average: String = ""
} }

View File

@ -0,0 +1,23 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration28 : Migration(27, 28) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("""
CREATE TABLE IF NOT EXISTS Conferences (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
student_id INTEGER NOT NULL,
diary_id INTEGER NOT NULL,
title TEXT NOT NULL,
subject TEXT NOT NULL,
agenda TEXT NOT NULL,
present_on_conference TEXT NOT NULL,
conference_id INTEGER NOT NULL,
date INTEGER NOT NULL
)
""")
}
}

View File

@ -0,0 +1,33 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration29 : Migration(28, 29) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE IF EXISTS GradesStatistics")
database.execSQL("""
CREATE TABLE IF NOT EXISTS GradeSemesterStatistics (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
student_id INTEGER NOT NULL,
semester_id INTEGER NOT NULL,
subject TEXT NOT NULL,
amounts TEXT NOT NULL,
student_grade INTEGER NOT NULL
)
""")
database.execSQL("""
CREATE TABLE IF NOT EXISTS GradePartialStatistics (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
student_id INTEGER NOT NULL,
semester_id INTEGER NOT NULL,
subject TEXT NOT NULL,
class_average TEXT NOT NULL,
student_average TEXT NOT NULL,
class_amounts TEXT NOT NULL,
student_amounts TEXT NOT NULL
)
""")
}
}

View File

@ -1,14 +1,19 @@
package io.github.wulkanowy.data.pojos package io.github.wulkanowy.data.pojos
import io.github.wulkanowy.data.db.entities.GradePartialStatistics
import io.github.wulkanowy.data.db.entities.GradePointsStatistics import io.github.wulkanowy.data.db.entities.GradePointsStatistics
import io.github.wulkanowy.data.db.entities.GradeStatistics import io.github.wulkanowy.data.db.entities.GradeSemesterStatistics
import io.github.wulkanowy.ui.modules.grade.statistics.ViewType import io.github.wulkanowy.ui.modules.grade.statistics.ViewType
data class GradeStatisticsItem( data class GradeStatisticsItem(
val type: ViewType, val type: ViewType,
val partial: List<GradeStatistics>, val average: String,
val partial: GradePartialStatistics?,
val semester: GradeSemesterStatistics?,
val points: GradePointsStatistics? val points: GradePointsStatistics?
) )

View File

@ -0,0 +1,25 @@
package io.github.wulkanowy.data.repositories.conference
import io.github.wulkanowy.data.db.dao.ConferenceDao
import io.github.wulkanowy.data.db.entities.Conference
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class ConferenceLocal @Inject constructor(private val conferenceDb: ConferenceDao) {
fun getConferences(student: Student, semester: Semester): Flow<List<Conference>> {
return conferenceDb.loadAll(semester.diaryId, student.studentId)
}
suspend fun saveConferences(items: List<Conference>) {
conferenceDb.insertAll(items)
}
suspend fun deleteConferences(items: List<Conference>) {
conferenceDb.deleteAll(items)
}
}

View File

@ -0,0 +1,31 @@
package io.github.wulkanowy.data.repositories.conference
import io.github.wulkanowy.data.db.entities.Conference
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.init
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class ConferenceRemote @Inject constructor(private val sdk: Sdk) {
suspend fun getConferences(student: Student, semester: Semester): List<Conference> {
return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getConferences()
.map {
it.agenda
Conference(
studentId = student.studentId,
diaryId = semester.diaryId,
agenda = it.agenda,
conferenceId = it.id,
date = it.date,
presentOnConference = it.presentOnConference,
subject = it.subject,
title = it.title
)
}
}
}

View File

@ -0,0 +1,25 @@
package io.github.wulkanowy.data.repositories.conference
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.uniqueSubtract
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class ConferenceRepository @Inject constructor(
private val local: ConferenceLocal,
private val remote: ConferenceRemote
) {
fun getConferences(student: Student, semester: Semester, forceRefresh: Boolean) = networkBoundResource(
shouldFetch = { it.isEmpty() || forceRefresh },
query = { local.getConferences(student, semester) },
fetch = { remote.getConferences(student, semester) },
saveFetchResult = { old, new ->
local.deleteConferences(old uniqueSubtract new)
local.saveConferences(new uniqueSubtract old)
}
)
}

View File

@ -1,9 +1,11 @@
package io.github.wulkanowy.data.repositories.gradestatistics package io.github.wulkanowy.data.repositories.gradestatistics
import io.github.wulkanowy.data.db.dao.GradePartialStatisticsDao
import io.github.wulkanowy.data.db.dao.GradePointsStatisticsDao import io.github.wulkanowy.data.db.dao.GradePointsStatisticsDao
import io.github.wulkanowy.data.db.dao.GradeStatisticsDao import io.github.wulkanowy.data.db.dao.GradeSemesterStatisticsDao
import io.github.wulkanowy.data.db.entities.GradePartialStatistics
import io.github.wulkanowy.data.db.entities.GradePointsStatistics import io.github.wulkanowy.data.db.entities.GradePointsStatistics
import io.github.wulkanowy.data.db.entities.GradeStatistics import io.github.wulkanowy.data.db.entities.GradeSemesterStatistics
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import javax.inject.Inject import javax.inject.Inject
@ -11,31 +13,47 @@ import javax.inject.Singleton
@Singleton @Singleton
class GradeStatisticsLocal @Inject constructor( class GradeStatisticsLocal @Inject constructor(
private val gradeStatisticsDb: GradeStatisticsDao, private val gradePartialStatisticsDb: GradePartialStatisticsDao,
private val gradePointsStatisticsDb: GradePointsStatisticsDao private val gradePointsStatisticsDb: GradePointsStatisticsDao,
private val gradeSemesterStatisticsDb: GradeSemesterStatisticsDao
) { ) {
fun getGradesStatistics(semester: Semester, isSemester: Boolean): Flow<List<GradeStatistics>> { // partial
return gradeStatisticsDb.loadAll(semester.semesterId, semester.studentId, isSemester) fun getGradePartialStatistics(semester: Semester): Flow<List<GradePartialStatistics>> {
return gradePartialStatisticsDb.loadAll(semester.semesterId, semester.studentId)
} }
fun getGradesPointsStatistics(semester: Semester): Flow<List<GradePointsStatistics>> { suspend fun saveGradePartialStatistics(items: List<GradePartialStatistics>) {
gradePartialStatisticsDb.insertAll(items)
}
suspend fun deleteGradePartialStatistics(items: List<GradePartialStatistics>) {
gradePartialStatisticsDb.deleteAll(items)
}
// points
fun getGradePointsStatistics(semester: Semester): Flow<List<GradePointsStatistics>> {
return gradePointsStatisticsDb.loadAll(semester.semesterId, semester.studentId) return gradePointsStatisticsDb.loadAll(semester.semesterId, semester.studentId)
} }
suspend fun saveGradesStatistics(gradesStatistics: List<GradeStatistics>) { suspend fun saveGradePointsStatistics(gradePointsStatistics: List<GradePointsStatistics>) {
gradeStatisticsDb.insertAll(gradesStatistics)
}
suspend fun saveGradesPointsStatistics(gradePointsStatistics: List<GradePointsStatistics>) {
gradePointsStatisticsDb.insertAll(gradePointsStatistics) gradePointsStatisticsDb.insertAll(gradePointsStatistics)
} }
suspend fun deleteGradesStatistics(gradesStatistics: List<GradeStatistics>) { suspend fun deleteGradePointsStatistics(gradesPointsStatistics: List<GradePointsStatistics>) {
gradeStatisticsDb.deleteAll(gradesStatistics)
}
suspend fun deleteGradesPointsStatistics(gradesPointsStatistics: List<GradePointsStatistics>) {
gradePointsStatisticsDb.deleteAll(gradesPointsStatistics) gradePointsStatisticsDb.deleteAll(gradesPointsStatistics)
} }
// semester
fun getGradeSemesterStatistics(semester: Semester): Flow<List<GradeSemesterStatistics>> {
return gradeSemesterStatisticsDb.loadAll(semester.semesterId, semester.studentId)
}
suspend fun saveGradeSemesterStatistics(items: List<GradeSemesterStatistics>) {
gradeSemesterStatisticsDb.insertAll(items)
}
suspend fun deleteGradeSemesterStatistics(items: List<GradeSemesterStatistics>) {
gradeSemesterStatisticsDb.deleteAll(items)
}
} }

View File

@ -1,7 +1,8 @@
package io.github.wulkanowy.data.repositories.gradestatistics package io.github.wulkanowy.data.repositories.gradestatistics
import io.github.wulkanowy.data.db.entities.GradePartialStatistics
import io.github.wulkanowy.data.db.entities.GradePointsStatistics import io.github.wulkanowy.data.db.entities.GradePointsStatistics
import io.github.wulkanowy.data.db.entities.GradeStatistics import io.github.wulkanowy.data.db.entities.GradeSemesterStatistics
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
@ -12,18 +13,36 @@ import javax.inject.Singleton
@Singleton @Singleton
class GradeStatisticsRemote @Inject constructor(private val sdk: Sdk) { class GradeStatisticsRemote @Inject constructor(private val sdk: Sdk) {
suspend fun getGradeStatistics(student: Student, semester: Semester, isSemester: Boolean): List<GradeStatistics> { suspend fun getGradePartialStatistics(student: Student, semester: Semester): List<GradePartialStatistics> {
return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear).let { return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
if (isSemester) it.getGradesAnnualStatistics(semester.semesterId) .getGradesPartialStatistics(semester.semesterId)
else it.getGradesPartialStatistics(semester.semesterId) .map {
}.map { GradePartialStatistics(
GradeStatistics( semesterId = semester.semesterId,
studentId = student.studentId,
subject = it.subject,
classAverage = it.classAverage,
studentAverage = it.studentAverage,
classAmounts = it.classItems
.sortedBy { item -> item.grade }
.map { item -> item.amount },
studentAmounts = it.studentItems.map { item -> item.amount }
)
}
}
suspend fun getGradeSemesterStatistics(student: Student, semester: Semester): List<GradeSemesterStatistics> {
return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getGradesSemesterStatistics(semester.semesterId)
.map {
GradeSemesterStatistics(
semesterId = semester.semesterId, semesterId = semester.semesterId,
studentId = semester.studentId, studentId = semester.studentId,
subject = it.subject, subject = it.subject,
grade = it.gradeValue, amounts = it.items
amount = it.amount, .sortedBy { item -> item.grade }
semester = isSemester .map { item -> item.amount },
studentGrade = it.items.singleOrNull { item -> item.isStudentHere }?.grade ?: 0
) )
} }
} }

View File

@ -1,13 +1,15 @@
package io.github.wulkanowy.data.repositories.gradestatistics package io.github.wulkanowy.data.repositories.gradestatistics
import io.github.wulkanowy.data.db.entities.GradePartialStatistics
import io.github.wulkanowy.data.db.entities.GradePointsStatistics import io.github.wulkanowy.data.db.entities.GradePointsStatistics
import io.github.wulkanowy.data.db.entities.GradeStatistics import io.github.wulkanowy.data.db.entities.GradeSemesterStatistics
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.pojos.GradeStatisticsItem import io.github.wulkanowy.data.pojos.GradeStatisticsItem
import io.github.wulkanowy.ui.modules.grade.statistics.ViewType import io.github.wulkanowy.ui.modules.grade.statistics.ViewType
import io.github.wulkanowy.utils.networkBoundResource import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
import java.util.Locale
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -17,55 +19,125 @@ class GradeStatisticsRepository @Inject constructor(
private val remote: GradeStatisticsRemote private val remote: GradeStatisticsRemote
) { ) {
fun getGradesStatistics(student: Student, semester: Semester, subjectName: String, isSemester: Boolean, forceRefresh: Boolean) = networkBoundResource( fun getGradesPartialStatistics(student: Student, semester: Semester, subjectName: String, forceRefresh: Boolean) = networkBoundResource(
shouldFetch = { it.isEmpty() || forceRefresh }, shouldFetch = { it.isEmpty() || forceRefresh },
query = { local.getGradesStatistics(semester, isSemester) }, query = { local.getGradePartialStatistics(semester) },
fetch = { remote.getGradeStatistics(student, semester, isSemester) }, fetch = { remote.getGradePartialStatistics(student, semester) },
saveFetchResult = { old, new -> saveFetchResult = { old, new ->
local.deleteGradesStatistics(old uniqueSubtract new) local.deleteGradePartialStatistics(old uniqueSubtract new)
local.saveGradesStatistics(new uniqueSubtract old) local.saveGradePartialStatistics(new uniqueSubtract old)
}, },
mapResult = { items -> mapResult = { items ->
when (subjectName) { when (subjectName) {
"Wszystkie" -> items.groupBy { it.grade }.map { "Wszystkie" -> {
GradeStatistics(semester.studentId, semester.semesterId, subjectName, it.key, val numerator = items.map {
it.value.fold(0) { acc, e -> acc + e.amount }, false) it.classAverage.replace(",", ".").toDoubleOrNull() ?: .0
} + items }.filterNot { it == .0 }
(items.reversed() + GradePartialStatistics(
studentId = semester.studentId,
semesterId = semester.semesterId,
subject = subjectName,
classAverage = if (numerator.isEmpty()) "" else numerator.average().let {
"%.2f".format(Locale.FRANCE, it)
},
studentAverage = "",
classAmounts = items.map { it.classAmounts }.sumGradeAmounts(),
studentAmounts = items.map { it.studentAmounts }.sumGradeAmounts()
)).reversed()
}
else -> items.filter { it.subject == subjectName } else -> items.filter { it.subject == subjectName }
}.mapToStatisticItems() }.mapPartialToStatisticItems()
}
)
fun getGradesSemesterStatistics(student: Student, semester: Semester, subjectName: String, forceRefresh: Boolean) = networkBoundResource(
shouldFetch = { it.isEmpty() || forceRefresh },
query = { local.getGradeSemesterStatistics(semester) },
fetch = { remote.getGradeSemesterStatistics(student, semester) },
saveFetchResult = { old, new ->
local.deleteGradeSemesterStatistics(old uniqueSubtract new)
local.saveGradeSemesterStatistics(new uniqueSubtract old)
},
mapResult = { items ->
val itemsWithAverage = items.map { item ->
item.copy().apply {
val denominator = item.amounts.sum()
average = if (denominator == 0) "" else (item.amounts.mapIndexed { gradeValue, amount ->
(gradeValue + 1) * amount
}.sum().toDouble() / denominator).let {
"%.2f".format(Locale.FRANCE, it)
}
}
}
when (subjectName) {
"Wszystkie" -> (itemsWithAverage.reversed() + GradeSemesterStatistics(
studentId = semester.studentId,
semesterId = semester.semesterId,
subject = subjectName,
amounts = itemsWithAverage.map { it.amounts }.sumGradeAmounts(),
studentGrade = 0
).apply {
average = itemsWithAverage.mapNotNull { it.average.replace(",", ".").toDoubleOrNull() }.average().let {
"%.2f".format(Locale.FRANCE, it)
}
}).reversed()
else -> itemsWithAverage.filter { it.subject == subjectName }
}.mapSemesterToStatisticItems()
} }
) )
fun getGradesPointsStatistics(student: Student, semester: Semester, subjectName: String, forceRefresh: Boolean) = networkBoundResource( fun getGradesPointsStatistics(student: Student, semester: Semester, subjectName: String, forceRefresh: Boolean) = networkBoundResource(
shouldFetch = { it.isEmpty() || forceRefresh }, shouldFetch = { it.isEmpty() || forceRefresh },
query = { local.getGradesPointsStatistics(semester) }, query = { local.getGradePointsStatistics(semester) },
fetch = { remote.getGradePointsStatistics(student, semester) }, fetch = { remote.getGradePointsStatistics(student, semester) },
saveFetchResult = { old, new -> saveFetchResult = { old, new ->
local.deleteGradesPointsStatistics(old uniqueSubtract new) local.deleteGradePointsStatistics(old uniqueSubtract new)
local.saveGradesPointsStatistics(new uniqueSubtract old) local.saveGradePointsStatistics(new uniqueSubtract old)
}, },
mapResult = { items -> mapResult = { items ->
when (subjectName) { when (subjectName) {
"Wszystkie" -> items "Wszystkie" -> items
else -> items.filter { it.subject == subjectName } else -> items.filter { it.subject == subjectName }
}.mapToStatisticsItem() }.mapPointsToStatisticsItems()
} }
) )
private fun List<GradeStatistics>.mapToStatisticItems() = groupBy { it.subject }.map { private fun List<List<Int>>.sumGradeAmounts(): List<Int> {
val result = mutableListOf(0, 0, 0, 0, 0, 0)
forEach {
it.forEachIndexed { grade, amount ->
result[grade] += amount
}
}
return result
}
private fun List<GradePartialStatistics>.mapPartialToStatisticItems() = filterNot { it.classAmounts.isEmpty() }.map {
GradeStatisticsItem( GradeStatisticsItem(
type = ViewType.PARTIAL, type = ViewType.PARTIAL,
partial = it.value average = it.classAverage,
.sortedByDescending { item -> item.grade } partial = it,
.filter { item -> item.amount != 0 }, points = null,
points = null semester = null
) )
} }
private fun List<GradePointsStatistics>.mapToStatisticsItem() = map { private fun List<GradeSemesterStatistics>.mapSemesterToStatisticItems() = filterNot { it.amounts.isEmpty() }.map {
GradeStatisticsItem(
type = ViewType.SEMESTER,
partial = null,
points = null,
average = "",
semester = it
)
}
private fun List<GradePointsStatistics>.mapPointsToStatisticsItems() = map {
GradeStatisticsItem( GradeStatisticsItem(
type = ViewType.POINTS, type = ViewType.POINTS,
partial = emptyList(), partial = null,
semester = null,
average = "",
points = it points = it
) )
} }

View File

@ -14,7 +14,7 @@ class TimetableRemote @Inject constructor(private val sdk: Sdk) {
suspend fun getTimetable(student: Student, semester: Semester, startDate: LocalDate, endDate: LocalDate): List<Timetable> { suspend fun getTimetable(student: Student, semester: Semester, startDate: LocalDate, endDate: LocalDate): List<Timetable> {
return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear) return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getTimetable(startDate, endDate) .getTimetable(startDate, endDate).first
.map { .map {
Timetable( Timetable(
studentId = semester.studentId, studentId = semester.studentId,

View File

@ -6,13 +6,13 @@ import com.yariksoffice.lingver.Lingver
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
import dagger.hilt.android.components.ApplicationComponent
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import io.github.wulkanowy.utils.DispatchersProvider import io.github.wulkanowy.utils.DispatchersProvider
import javax.inject.Singleton import javax.inject.Singleton
@Module @Module
@InstallIn(ApplicationComponent::class) @InstallIn(SingletonComponent::class)
internal class AppModule { internal class AppModule {
@Singleton @Singleton

View File

@ -9,8 +9,8 @@ import dagger.Binds
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
import dagger.hilt.android.components.ApplicationComponent
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import dagger.multibindings.IntoSet import dagger.multibindings.IntoSet
import io.github.wulkanowy.services.sync.channels.Channel import io.github.wulkanowy.services.sync.channels.Channel
import io.github.wulkanowy.services.sync.channels.DebugChannel import io.github.wulkanowy.services.sync.channels.DebugChannel
@ -38,7 +38,7 @@ import javax.inject.Singleton
@Suppress("unused") @Suppress("unused")
@Module @Module
@InstallIn(ApplicationComponent::class) @InstallIn(SingletonComponent::class)
abstract class ServicesModule { abstract class ServicesModule {
companion object { companion object {

View File

@ -12,8 +12,8 @@ class GradeStatisticsWork @Inject constructor(
override suspend fun doWork(student: Student, semester: Semester) { override suspend fun doWork(student: Student, semester: Semester) {
with(gradeStatisticsRepository) { with(gradeStatisticsRepository) {
getGradesStatistics(student, semester, "Wszystkie", isSemester = true, forceRefresh = true).waitForResult() getGradesPartialStatistics(student, semester, "Wszystkie", forceRefresh = true).waitForResult()
getGradesStatistics(student, semester, "Wszystkie", isSemester = false, forceRefresh = true).waitForResult() getGradesSemesterStatistics(student, semester, "Wszystkie", forceRefresh = true).waitForResult()
getGradesPointsStatistics(student, semester, "Wszystkie", forceRefresh = true).waitForResult() getGradesPointsStatistics(student, semester, "Wszystkie", forceRefresh = true).waitForResult()
} }
} }

View File

@ -3,10 +3,15 @@ package io.github.wulkanowy.ui.base
import android.widget.Toast import android.widget.Toast
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.viewbinding.ViewBinding import androidx.viewbinding.ViewBinding
import io.github.wulkanowy.utils.AnalyticsHelper
import io.github.wulkanowy.utils.lifecycleAwareVariable import io.github.wulkanowy.utils.lifecycleAwareVariable
import javax.inject.Inject
abstract class BaseDialogFragment<VB : ViewBinding> : DialogFragment(), BaseView { abstract class BaseDialogFragment<VB : ViewBinding> : DialogFragment(), BaseView {
@Inject
lateinit var analyticsHelper: AnalyticsHelper
protected var binding: VB by lifecycleAwareVariable() protected var binding: VB by lifecycleAwareVariable()
override fun showError(text: String, error: Throwable) { override fun showError(text: String, error: Throwable) {
@ -28,4 +33,14 @@ abstract class BaseDialogFragment<VB : ViewBinding> : DialogFragment(), BaseView
override fun showErrorDetailsDialog(error: Throwable) { override fun showErrorDetailsDialog(error: Throwable) {
ErrorDialog.newInstance(error).show(childFragmentManager, error.toString()) ErrorDialog.newInstance(error).show(childFragmentManager, error.toString())
} }
override fun onResume() {
super.onResume()
analyticsHelper.setCurrentScreen(requireActivity(), this::class.simpleName)
}
override fun onPause() {
super.onPause()
analyticsHelper.popCurrentScreen(this::class.simpleName)
}
} }

View File

@ -58,6 +58,11 @@ class AboutFragment : BaseFragment<FragmentAboutBinding>(R.layout.fragment_about
Triple(getString(R.string.about_discord), getString(R.string.about_discord_summary), getCompatDrawable(R.drawable.ic_about_discord)) Triple(getString(R.string.about_discord), getString(R.string.about_discord_summary), getCompatDrawable(R.drawable.ic_about_discord))
} }
override val facebookRes: Triple<String, String, Drawable?>?
get() = context?.run {
Triple(getString(R.string.about_facebook), getString(R.string.about_facebook_summary), getCompatDrawable(R.drawable.ic_about_facebook))
}
override val homepageRes: Triple<String, String, Drawable?>? override val homepageRes: Triple<String, String, Drawable?>?
get() = context?.run { get() = context?.run {
Triple(getString(R.string.about_homepage), getString(R.string.about_homepage_summary), getCompatDrawable(R.drawable.ic_about_homepage)) Triple(getString(R.string.about_homepage), getString(R.string.about_homepage_summary), getCompatDrawable(R.drawable.ic_about_homepage))
@ -113,6 +118,10 @@ class AboutFragment : BaseFragment<FragmentAboutBinding>(R.layout.fragment_about
context?.openInternetBrowser("https://discord.gg/vccAQBr", ::showMessage) context?.openInternetBrowser("https://discord.gg/vccAQBr", ::showMessage)
} }
override fun openFacebookPage() {
context?.openInternetBrowser("https://www.facebook.com/wulkanowy", ::showMessage)
}
override fun openHomepage() { override fun openHomepage() {
context?.openInternetBrowser("https://wulkanowy.github.io/", ::showMessage) context?.openInternetBrowser("https://wulkanowy.github.io/", ::showMessage)
} }

View File

@ -3,8 +3,8 @@ package io.github.wulkanowy.ui.modules.about
import io.github.wulkanowy.data.repositories.student.StudentRepository import io.github.wulkanowy.data.repositories.student.StudentRepository
import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.ui.base.BasePresenter
import io.github.wulkanowy.ui.base.ErrorHandler import io.github.wulkanowy.ui.base.ErrorHandler
import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.AnalyticsHelper import io.github.wulkanowy.utils.AnalyticsHelper
import io.github.wulkanowy.utils.AppInfo
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
@ -46,6 +46,11 @@ class AboutPresenter @Inject constructor(
openDiscordInvite() openDiscordInvite()
analytics.logEvent("about_open", "name" to "discord") analytics.logEvent("about_open", "name" to "discord")
} }
facebookRes?.first -> {
Timber.i("Opening facebook")
openFacebookPage()
analytics.logEvent("about_open", "name" to "facebook")
}
homepageRes?.first -> { homepageRes?.first -> {
Timber.i("Opening homepage") Timber.i("Opening homepage")
openHomepage() openHomepage()
@ -78,6 +83,7 @@ class AboutPresenter @Inject constructor(
feedbackRes, feedbackRes,
faqRes, faqRes,
discordRes, discordRes,
facebookRes,
homepageRes, homepageRes,
licensesRes, licensesRes,
privacyRes privacyRes

View File

@ -15,6 +15,8 @@ interface AboutView : BaseView {
val discordRes: Triple<String, String, Drawable?>? val discordRes: Triple<String, String, Drawable?>?
val facebookRes: Triple<String, String, Drawable?>?
val homepageRes: Triple<String, String, Drawable?>? val homepageRes: Triple<String, String, Drawable?>?
val licensesRes: Triple<String, String, Drawable?>? val licensesRes: Triple<String, String, Drawable?>?
@ -31,6 +33,8 @@ interface AboutView : BaseView {
fun openDiscordInvite() fun openDiscordInvite()
fun openFacebookPage()
fun openEmailClient() fun openEmailClient()
fun openFaqPage() fun openFaqPage()

View File

@ -0,0 +1,36 @@
package io.github.wulkanowy.ui.modules.conference
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import io.github.wulkanowy.data.db.entities.Conference
import io.github.wulkanowy.databinding.ItemConferenceBinding
import io.github.wulkanowy.utils.toFormattedString
import javax.inject.Inject
class ConferenceAdapter @Inject constructor() :
RecyclerView.Adapter<ConferenceAdapter.ItemViewHolder>() {
var items = emptyList<Conference>()
override fun getItemCount() = items.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder(
ItemConferenceBinding.inflate(LayoutInflater.from(parent.context), parent, false)
)
override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
val item = items[position]
with(holder.binding) {
conferenceItemDate.text = item.date.toFormattedString("dd.MM.yyyy HH:mm")
conferenceItemName.text = item.presentOnConference
conferenceItemTitle.text = item.title
conferenceItemSubject.text = item.subject
conferenceItemContent.text = item.agenda
conferenceItemContent.visibility = if (item.agenda.isBlank()) View.GONE else View.VISIBLE
}
}
class ItemViewHolder(val binding: ItemConferenceBinding) : RecyclerView.ViewHolder(binding.root)
}

View File

@ -0,0 +1,102 @@
package io.github.wulkanowy.ui.modules.conference
import android.os.Bundle
import android.view.View
import androidx.recyclerview.widget.LinearLayoutManager
import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Conference
import io.github.wulkanowy.databinding.FragmentConferenceBinding
import io.github.wulkanowy.ui.base.BaseFragment
import io.github.wulkanowy.ui.modules.main.MainView
import io.github.wulkanowy.ui.widgets.DividerItemDecoration
import javax.inject.Inject
@AndroidEntryPoint
class ConferenceFragment : BaseFragment<FragmentConferenceBinding>(R.layout.fragment_conference),
ConferenceView, MainView.TitledView {
@Inject
lateinit var presenter: ConferencePresenter
@Inject
lateinit var conferencesAdapter: ConferenceAdapter
companion object {
fun newInstance() = ConferenceFragment()
}
override val isViewEmpty: Boolean
get() = conferencesAdapter.items.isEmpty()
override val titleStringId: Int
get() = R.string.conferences_title
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentConferenceBinding.bind(view)
messageContainer = binding.conferenceRecycler
presenter.onAttachView(this)
}
override fun initView() {
with(binding.conferenceRecycler) {
layoutManager = LinearLayoutManager(context)
adapter = conferencesAdapter
addItemDecoration(DividerItemDecoration(context))
}
with(binding) {
conferenceSwipe.setOnRefreshListener { presenter.onSwipeRefresh() }
conferenceErrorRetry.setOnClickListener { presenter.onRetry() }
conferenceErrorDetails.setOnClickListener { presenter.onDetailsClick() }
}
}
override fun updateData(data: List<Conference>) {
with(conferencesAdapter) {
items = data
notifyDataSetChanged()
}
}
override fun clearData() {
with(conferencesAdapter) {
items = emptyList()
notifyDataSetChanged()
}
}
override fun hideRefresh() {
binding.conferenceSwipe.isRefreshing = false
}
override fun showProgress(show: Boolean) {
binding.conferenceProgress.visibility = if (show) View.VISIBLE else View.GONE
}
override fun showEmpty(show: Boolean) {
binding.conferenceEmpty.visibility = if (show) View.VISIBLE else View.GONE
}
override fun showErrorView(show: Boolean) {
binding.conferenceError.visibility = if (show) View.VISIBLE else View.GONE
}
override fun setErrorDetails(message: String) {
binding.conferenceErrorMessage.text = message
}
override fun enableSwipe(enable: Boolean) {
binding.conferenceSwipe.isEnabled = enable
}
override fun showContent(show: Boolean) {
binding.conferenceRecycler.visibility = if (show) View.VISIBLE else View.GONE
}
override fun onDestroyView() {
presenter.onDetachView()
super.onDestroyView()
}
}

View File

@ -0,0 +1,96 @@
package io.github.wulkanowy.ui.modules.conference
import io.github.wulkanowy.data.Status
import io.github.wulkanowy.data.repositories.conference.ConferenceRepository
import io.github.wulkanowy.data.repositories.semester.SemesterRepository
import io.github.wulkanowy.data.repositories.student.StudentRepository
import io.github.wulkanowy.ui.base.BasePresenter
import io.github.wulkanowy.ui.base.ErrorHandler
import io.github.wulkanowy.utils.AnalyticsHelper
import io.github.wulkanowy.utils.afterLoading
import io.github.wulkanowy.utils.flowWithResourceIn
import kotlinx.coroutines.flow.onEach
import timber.log.Timber
import javax.inject.Inject
class ConferencePresenter @Inject constructor(
errorHandler: ErrorHandler,
studentRepository: StudentRepository,
private val semesterRepository: SemesterRepository,
private val conferenceRepository: ConferenceRepository,
private val analytics: AnalyticsHelper
) : BasePresenter<ConferenceView>(errorHandler, studentRepository) {
private lateinit var lastError: Throwable
override fun onAttachView(view: ConferenceView) {
super.onAttachView(view)
view.initView()
Timber.i("Conferences view was initialized")
errorHandler.showErrorMessage = ::showErrorViewOnError
loadData()
}
fun onSwipeRefresh() {
loadData(true)
}
fun onRetry() {
view?.run {
showErrorView(false)
showProgress(true)
}
loadData(true)
}
fun onDetailsClick() {
view?.showErrorDetailsDialog(lastError)
}
private fun showErrorViewOnError(message: String, error: Throwable) {
view?.run {
if (isViewEmpty) {
lastError = error
setErrorDetails(message)
showErrorView(true)
showEmpty(false)
} else showError(message, error)
}
}
private fun loadData(forceRefresh: Boolean = false) {
flowWithResourceIn {
val student = studentRepository.getCurrentStudent()
val semester = semesterRepository.getCurrentSemester(student)
conferenceRepository.getConferences(student, semester, forceRefresh)
}.onEach {
when (it.status) {
Status.LOADING -> Timber.i("Loading conference data started")
Status.SUCCESS -> {
Timber.i("Loading conference result: Success")
view?.run {
updateData(it.data!!.sortedByDescending { conference -> conference.date })
showContent(it.data.isNotEmpty())
showEmpty(it.data.isEmpty())
showErrorView(false)
}
analytics.logEvent(
"load_data",
"type" to "conferences",
"items" to it.data!!.size
)
}
Status.ERROR -> {
Timber.i("Loading conference result: An exception occurred")
errorHandler.dispatch(it.error!!)
}
}
}.afterLoading {
view?.run {
hideRefresh()
showProgress(false)
enableSwipe(true)
}
}.launch()
}
}

View File

@ -0,0 +1,29 @@
package io.github.wulkanowy.ui.modules.conference
import io.github.wulkanowy.data.db.entities.Conference
import io.github.wulkanowy.ui.base.BaseView
interface ConferenceView : BaseView {
val isViewEmpty: Boolean
fun initView()
fun updateData(data: List<Conference>)
fun clearData()
fun hideRefresh()
fun showEmpty(show: Boolean)
fun showErrorView(show: Boolean)
fun setErrorDetails(message: String)
fun showProgress(show: Boolean)
fun enableSwipe(enable: Boolean)
fun showContent(show: Boolean)
}

View File

@ -17,8 +17,9 @@ import com.github.mikephil.charting.data.PieDataSet
import com.github.mikephil.charting.data.PieEntry import com.github.mikephil.charting.data.PieEntry
import com.github.mikephil.charting.formatter.ValueFormatter import com.github.mikephil.charting.formatter.ValueFormatter
import io.github.wulkanowy.R import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.GradePartialStatistics
import io.github.wulkanowy.data.db.entities.GradePointsStatistics import io.github.wulkanowy.data.db.entities.GradePointsStatistics
import io.github.wulkanowy.data.db.entities.GradeStatistics import io.github.wulkanowy.data.db.entities.GradeSemesterStatistics
import io.github.wulkanowy.data.pojos.GradeStatisticsItem import io.github.wulkanowy.data.pojos.GradeStatisticsItem
import io.github.wulkanowy.databinding.ItemGradeStatisticsBarBinding import io.github.wulkanowy.databinding.ItemGradeStatisticsBarBinding
import io.github.wulkanowy.databinding.ItemGradeStatisticsPieBinding import io.github.wulkanowy.databinding.ItemGradeStatisticsPieBinding
@ -68,22 +69,32 @@ class GradeStatisticsAdapter @Inject constructor() :
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val inflater = LayoutInflater.from(parent.context) val inflater = LayoutInflater.from(parent.context)
return when (viewType) { return when (viewType) {
ViewType.PARTIAL.id, ViewType.SEMESTER.id -> PieViewHolder(ItemGradeStatisticsPieBinding.inflate(inflater, parent, false)) ViewType.PARTIAL.id -> PartialViewHolder(ItemGradeStatisticsPieBinding.inflate(inflater, parent, false))
ViewType.POINTS.id -> BarViewHolder(ItemGradeStatisticsBarBinding.inflate(inflater, parent, false)) ViewType.SEMESTER.id -> SemesterViewHolder(ItemGradeStatisticsPieBinding.inflate(inflater, parent, false))
ViewType.POINTS.id -> PointsViewHolder(ItemGradeStatisticsBarBinding.inflate(inflater, parent, false))
else -> throw IllegalStateException() else -> throw IllegalStateException()
} }
} }
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) { when (holder) {
is PieViewHolder -> bindPieChart(holder, items[position].partial) is PartialViewHolder -> bindPartialChart(holder, items[position].partial!!)
is BarViewHolder -> bindBarChart(holder, items[position].points!!) is SemesterViewHolder -> bindSemesterChart(holder, items[position].semester!!)
is PointsViewHolder -> bindBarChart(holder, items[position].points!!)
} }
} }
private fun bindPieChart(holder: PieViewHolder, partials: List<GradeStatistics>) { private fun bindPartialChart(holder: PartialViewHolder, partials: GradePartialStatistics) {
with(holder.binding.gradeStatisticsPieTitle) { bindPieChart(holder.binding, partials.subject, partials.classAverage, partials.classAmounts)
text = partials.firstOrNull()?.subject }
private fun bindSemesterChart(holder: SemesterViewHolder, semester: GradeSemesterStatistics) {
bindPieChart(holder.binding, semester.subject, semester.average, semester.amounts)
}
private fun bindPieChart(binding: ItemGradeStatisticsPieBinding, subject: String, average: String, amounts: List<Int>) {
with(binding.gradeStatisticsPieTitle) {
text = subject
visibility = if (items.size == 1 || !showAllSubjectsOnList) GONE else VISIBLE visibility = if (items.size == 1 || !showAllSubjectsOnList) GONE else VISIBLE
} }
@ -92,22 +103,23 @@ class GradeStatisticsAdapter @Inject constructor() :
else -> materialGradeColors else -> materialGradeColors
} }
val dataset = PieDataSet(partials.map { val dataset = PieDataSet(amounts.mapIndexed { grade, amount ->
PieEntry(it.amount.toFloat(), it.grade.toString()) PieEntry(amount.toFloat(), (grade + 1).toString())
}, "Legenda") }.reversed().filterNot { it.value == 0f }, "Legenda")
with(dataset) { with(dataset) {
valueTextSize = 12f valueTextSize = 12f
sliceSpace = 1f sliceSpace = 1f
valueTextColor = Color.WHITE valueTextColor = Color.WHITE
setColors(partials.map { val grades = amounts.mapIndexed { grade, amount -> (grade + 1) to amount }.filterNot { it.second == 0 }
gradeColors.single { color -> color.first == it.grade }.second setColors(grades.reversed().map { (grade, _) ->
}.toIntArray(), holder.binding.root.context) gradeColors.single { color -> color.first == grade }.second
}.toIntArray(), binding.root.context)
} }
with(holder.binding.gradeStatisticsPie) { with(binding.gradeStatisticsPie) {
setTouchEnabled(false) setTouchEnabled(false)
if (partials.size == 1) animateXY(1000, 1000) if (amounts.size == 1) animateXY(1000, 1000)
data = PieData(dataset).apply { data = PieData(dataset).apply {
setValueFormatter(object : ValueFormatter() { setValueFormatter(object : ValueFormatter() {
override fun getPieLabel(value: Float, pieEntry: PieEntry): String { override fun getPieLabel(value: Float, pieEntry: PieEntry): String {
@ -128,8 +140,9 @@ class GradeStatisticsAdapter @Inject constructor() :
minAngleForSlices = 25f minAngleForSlices = 25f
description.isEnabled = false description.isEnabled = false
centerText = partials.fold(0) { acc, it -> acc + it.amount } centerText = amounts.fold(0) { acc, it -> acc + it }
.let { resources.getQuantityString(R.plurals.grade_number_item, it, it) } .let { resources.getQuantityString(R.plurals.grade_number_item, it, it) } +
("\n\nŚrednia: $average").takeIf { average.isNotBlank() }.orEmpty()
setHoleColor(context.getThemeAttrColor(android.R.attr.windowBackground)) setHoleColor(context.getThemeAttrColor(android.R.attr.windowBackground))
setCenterTextColor(context.getThemeAttrColor(android.R.attr.textColorPrimary)) setCenterTextColor(context.getThemeAttrColor(android.R.attr.textColorPrimary))
@ -137,7 +150,7 @@ class GradeStatisticsAdapter @Inject constructor() :
} }
} }
private fun bindBarChart(holder: BarViewHolder, points: GradePointsStatistics) { private fun bindBarChart(holder: PointsViewHolder, points: GradePointsStatistics) {
with(holder.binding.gradeStatisticsBarTitle) { with(holder.binding.gradeStatisticsBarTitle) {
text = points.subject text = points.subject
visibility = if (items.size == 1) GONE else VISIBLE visibility = if (items.size == 1) GONE else VISIBLE
@ -200,9 +213,12 @@ class GradeStatisticsAdapter @Inject constructor() :
} }
} }
private class PieViewHolder(val binding: ItemGradeStatisticsPieBinding) : private class PartialViewHolder(val binding: ItemGradeStatisticsPieBinding) :
RecyclerView.ViewHolder(binding.root) RecyclerView.ViewHolder(binding.root)
private class BarViewHolder(val binding: ItemGradeStatisticsBarBinding) : private class SemesterViewHolder(val binding: ItemGradeStatisticsPieBinding) :
RecyclerView.ViewHolder(binding.root)
private class PointsViewHolder(val binding: ItemGradeStatisticsBarBinding) :
RecyclerView.ViewHolder(binding.root) RecyclerView.ViewHolder(binding.root)
} }

View File

@ -153,8 +153,8 @@ class GradeStatisticsPresenter @Inject constructor(
with(gradeStatisticsRepository) { with(gradeStatisticsRepository) {
when (type) { when (type) {
ViewType.SEMESTER -> getGradesStatistics(student, semester, currentSubjectName, true, forceRefresh) ViewType.PARTIAL -> getGradesPartialStatistics(student, semester, currentSubjectName, forceRefresh)
ViewType.PARTIAL -> getGradesStatistics(student, semester, currentSubjectName, false, forceRefresh) ViewType.SEMESTER -> getGradesSemesterStatistics(student, semester, currentSubjectName, forceRefresh)
ViewType.POINTS -> getGradesPointsStatistics(student, semester, currentSubjectName, forceRefresh) ViewType.POINTS -> getGradesPointsStatistics(student, semester, currentSubjectName, forceRefresh)
} }
} }
@ -164,8 +164,15 @@ class GradeStatisticsPresenter @Inject constructor(
Status.SUCCESS -> { Status.SUCCESS -> {
Timber.i("Loading grade stats result: Success") Timber.i("Loading grade stats result: Success")
view?.run { view?.run {
showEmpty(it.data!!.isEmpty() || it.data.first().partial.isEmpty()) val isNoContent = it.data!!.isEmpty() || when (type) {
showContent(it.data.isNotEmpty() && it.data.first().partial.isNotEmpty()) ViewType.SEMESTER -> it.data.firstOrNull()?.semester?.amounts.orEmpty().sum() == 0
ViewType.PARTIAL -> it.data.firstOrNull()?.partial?.classAmounts.orEmpty().sum() == 0
ViewType.POINTS -> it.data.firstOrNull()?.points?.let { points ->
points.student == .0 && points.others == .0
} ?: false
}
showEmpty(isNoContent)
showContent(!isNoContent)
showErrorView(false) showErrorView(false)
updateData(it.data, preferencesRepository.gradeColorTheme, preferencesRepository.showAllSubjectsOnStatisticsList) updateData(it.data, preferencesRepository.gradeColorTheme, preferencesRepository.showAllSubjectsOnStatisticsList)
showSubjects(!preferencesRepository.showAllSubjectsOnStatisticsList) showSubjects(!preferencesRepository.showAllSubjectsOnStatisticsList)

View File

@ -89,6 +89,8 @@ class LoginFormFragment : BaseFragment<FragmentLoginFormBinding>(R.layout.fragme
} }
} }
override fun getHostsValues(): List<String> = hostValues.toList()
override fun setCredentials(username: String, pass: String) { override fun setCredentials(username: String, pass: String) {
with(binding) { with(binding) {
loginFormUsername.setText(username) loginFormUsername.setText(username)
@ -96,6 +98,12 @@ class LoginFormFragment : BaseFragment<FragmentLoginFormBinding>(R.layout.fragme
} }
} }
override fun setHost(host: String) {
binding.loginFormHost.setText(
hostKeys.getOrNull(hostValues.indexOf(host)).orEmpty()
)
}
override fun setUsernameLabel(label: String) { override fun setUsernameLabel(label: String) {
binding.loginFormUsernameLayout.hint = label binding.loginFormUsernameLayout.hint = label
} }

View File

@ -1,5 +1,6 @@
package io.github.wulkanowy.ui.modules.login.form package io.github.wulkanowy.ui.modules.login.form
import androidx.core.net.toUri
import io.github.wulkanowy.data.Status import io.github.wulkanowy.data.Status
import io.github.wulkanowy.data.repositories.student.StudentRepository import io.github.wulkanowy.data.repositories.student.StudentRepository
import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.ui.base.BasePresenter
@ -56,7 +57,7 @@ class LoginFormPresenter @Inject constructor(
fun updateUsernameLabel() { fun updateUsernameLabel() {
view?.run { view?.run {
setUsernameLabel(if ("standard" in formHostValue) emailLabel else nicknameLabel) setUsernameLabel(if ("login" in formHostValue) nicknameLabel else emailLabel)
} }
} }
@ -66,6 +67,16 @@ class LoginFormPresenter @Inject constructor(
fun onUsernameTextChanged() { fun onUsernameTextChanged() {
view?.clearUsernameError() view?.clearUsernameError()
val username = view?.formUsernameValue.orEmpty().trim()
if ("@" in username && "@vulcan" !in username) {
val hosts = view?.getHostsValues().orEmpty().map { it.toUri().host to it }.toMap()
val usernameHost = username.substringAfter("@")
hosts[usernameHost]?.let {
view?.setHost(it)
}
}
} }
fun onSignInClick() { fun onSignInClick() {
@ -135,12 +146,12 @@ class LoginFormPresenter @Inject constructor(
view?.setErrorUsernameRequired() view?.setErrorUsernameRequired()
isCorrect = false isCorrect = false
} else { } else {
if ("@" in login && "standard" !in host) { if ("@" in login && "login" in host) {
view?.setErrorLoginRequired() view?.setErrorLoginRequired()
isCorrect = false isCorrect = false
} }
if ("@" !in login && "standard" in host) { if ("@" !in login && "email" in host) {
view?.setErrorEmailRequired() view?.setErrorEmailRequired()
isCorrect = false isCorrect = false
} }

View File

@ -19,8 +19,12 @@ interface LoginFormView : BaseView {
val emailLabel: String val emailLabel: String
fun getHostsValues(): List<String>
fun setCredentials(username: String, pass: String) fun setCredentials(username: String, pass: String)
fun setHost(host: String)
fun setUsernameLabel(label: String) fun setUsernameLabel(label: String)
fun setErrorUsernameRequired() fun setErrorUsernameRequired()

View File

@ -38,8 +38,8 @@ import io.github.wulkanowy.ui.modules.message.MessageFragment
import io.github.wulkanowy.ui.modules.more.MoreFragment import io.github.wulkanowy.ui.modules.more.MoreFragment
import io.github.wulkanowy.ui.modules.note.NoteFragment import io.github.wulkanowy.ui.modules.note.NoteFragment
import io.github.wulkanowy.ui.modules.timetable.TimetableFragment import io.github.wulkanowy.ui.modules.timetable.TimetableFragment
import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.AnalyticsHelper import io.github.wulkanowy.utils.AnalyticsHelper
import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.UpdateHelper import io.github.wulkanowy.utils.UpdateHelper
import io.github.wulkanowy.utils.dpToPx import io.github.wulkanowy.utils.dpToPx
import io.github.wulkanowy.utils.getThemeAttrColor import io.github.wulkanowy.utils.getThemeAttrColor
@ -182,7 +182,10 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
} }
with(navController) { with(navController) {
setOnViewChangeListener(presenter::onViewChange) setOnViewChangeListener { section, name ->
analytics.setCurrentScreen(this@MainActivity, name)
presenter.onViewChange(section)
}
fragmentHideStrategy = HIDE fragmentHideStrategy = HIDE
rootFragments = listOf( rootFragments = listOf(
GradeFragment.newInstance(), GradeFragment.newInstance(),
@ -194,10 +197,6 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
} }
} }
override fun setCurrentScreen(name: String?) {
analytics.setCurrentScreen(this, name)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
return if (item.itemId == R.id.mainMenuAccount) presenter.onAccountManagerSelected() return if (item.itemId == R.id.mainMenuAccount) presenter.onAccountManagerSelected()
else false else false
@ -208,6 +207,7 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
} }
override fun switchMenuView(position: Int) { override fun switchMenuView(position: Int) {
analytics.popCurrentScreen(navController.currentFrag!!::class.simpleName)
navController.switchTab(position) navController.switchTab(position)
} }
@ -245,10 +245,12 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
} }
fun pushView(fragment: Fragment) { fun pushView(fragment: Fragment) {
analytics.popCurrentScreen(navController.currentFrag!!::class.simpleName)
navController.pushFragment(fragment) navController.pushFragment(fragment)
} }
override fun popView(depth: Int) { override fun popView(depth: Int) {
analytics.popCurrentScreen(navController.currentFrag!!::class.simpleName)
navController.safelyPopFragments(depth) navController.safelyPopFragments(depth)
} }

View File

@ -35,9 +35,8 @@ class MainPresenter @Inject constructor(
analytics.logEvent("app_open", "destination" to initMenu?.name) analytics.logEvent("app_open", "destination" to initMenu?.name)
} }
fun onViewChange(section: MainView.Section?, name: String?) { fun onViewChange(section: MainView.Section?) {
view?.apply { view?.apply {
setCurrentScreen(name)
showActionBarElevation(section != GRADE && section != MESSAGE && section != SCHOOL) showActionBarElevation(section != GRADE && section != MESSAGE && section != SCHOOL)
currentViewTitle?.let { setViewTitle(it) } currentViewTitle?.let { setViewTitle(it) }
currentViewSubtitle?.let { setViewSubTitle(it.ifBlank { null }) } currentViewSubtitle?.let { setViewSubTitle(it.ifBlank { null }) }

View File

@ -24,8 +24,6 @@ interface MainView : BaseView {
fun showAccountPicker() fun showAccountPicker()
fun setCurrentScreen(name: String?)
fun showActionBarElevation(show: Boolean) fun showActionBarElevation(show: Boolean)
fun notifyMenuViewReselected() fun notifyMenuViewReselected()

View File

@ -9,6 +9,7 @@ import io.github.wulkanowy.R
import io.github.wulkanowy.databinding.FragmentMoreBinding import io.github.wulkanowy.databinding.FragmentMoreBinding
import io.github.wulkanowy.ui.base.BaseFragment import io.github.wulkanowy.ui.base.BaseFragment
import io.github.wulkanowy.ui.modules.about.AboutFragment import io.github.wulkanowy.ui.modules.about.AboutFragment
import io.github.wulkanowy.ui.modules.conference.ConferenceFragment
import io.github.wulkanowy.ui.modules.homework.HomeworkFragment import io.github.wulkanowy.ui.modules.homework.HomeworkFragment
import io.github.wulkanowy.ui.modules.luckynumber.LuckyNumberFragment import io.github.wulkanowy.ui.modules.luckynumber.LuckyNumberFragment
import io.github.wulkanowy.ui.modules.main.MainActivity import io.github.wulkanowy.ui.modules.main.MainActivity
@ -53,6 +54,9 @@ class MoreFragment : BaseFragment<FragmentMoreBinding>(R.layout.fragment_more),
override val mobileDevicesRes: Pair<String, Drawable?>? override val mobileDevicesRes: Pair<String, Drawable?>?
get() = context?.run { getString(R.string.mobile_devices_title) to getCompatDrawable(R.drawable.ic_more_mobile_devices) } get() = context?.run { getString(R.string.mobile_devices_title) to getCompatDrawable(R.drawable.ic_more_mobile_devices) }
override val conferencesRes: Pair<String, Drawable?>?
get() = context?.run { getString(R.string.conferences_title) to getCompatDrawable(R.drawable.ic_more_conferences) }
override val schoolAndTeachersRes: Pair<String, Drawable?>? override val schoolAndTeachersRes: Pair<String, Drawable?>?
get() = context?.run { getString(R.string.schoolandteachers_title) to getCompatDrawable((R.drawable.ic_more_schoolandteachers)) } get() = context?.run { getString(R.string.schoolandteachers_title) to getCompatDrawable((R.drawable.ic_more_schoolandteachers)) }
@ -108,6 +112,10 @@ class MoreFragment : BaseFragment<FragmentMoreBinding>(R.layout.fragment_more),
(activity as? MainActivity)?.pushView(MobileDeviceFragment.newInstance()) (activity as? MainActivity)?.pushView(MobileDeviceFragment.newInstance())
} }
override fun openConferencesView() {
(activity as? MainActivity)?.pushView(ConferenceFragment.newInstance())
}
override fun openSchoolAndTeachersView() { override fun openSchoolAndTeachersView() {
(activity as? MainActivity)?.pushView(SchoolAndTeachersFragment.newInstance()) (activity as? MainActivity)?.pushView(SchoolAndTeachersFragment.newInstance())
} }

View File

@ -27,6 +27,7 @@ class MorePresenter @Inject constructor(
noteRes?.first -> openNoteView() noteRes?.first -> openNoteView()
luckyNumberRes?.first -> openLuckyNumberView() luckyNumberRes?.first -> openLuckyNumberView()
mobileDevicesRes?.first -> openMobileDevicesView() mobileDevicesRes?.first -> openMobileDevicesView()
conferencesRes?.first -> openConferencesView()
schoolAndTeachersRes?.first -> openSchoolAndTeachersView() schoolAndTeachersRes?.first -> openSchoolAndTeachersView()
settingsRes?.first -> openSettingsView() settingsRes?.first -> openSettingsView()
aboutRes?.first -> openAboutView() aboutRes?.first -> openAboutView()
@ -48,6 +49,7 @@ class MorePresenter @Inject constructor(
noteRes, noteRes,
luckyNumberRes, luckyNumberRes,
mobileDevicesRes, mobileDevicesRes,
conferencesRes,
schoolAndTeachersRes, schoolAndTeachersRes,
settingsRes, settingsRes,
aboutRes aboutRes

View File

@ -15,6 +15,8 @@ interface MoreView : BaseView {
val mobileDevicesRes: Pair<String, Drawable?>? val mobileDevicesRes: Pair<String, Drawable?>?
val conferencesRes: Pair<String, Drawable?>?
val schoolAndTeachersRes: Pair<String, Drawable?>? val schoolAndTeachersRes: Pair<String, Drawable?>?
val settingsRes: Pair<String, Drawable?>? val settingsRes: Pair<String, Drawable?>?
@ -41,5 +43,7 @@ interface MoreView : BaseView {
fun openMobileDevicesView() fun openMobileDevicesView()
fun openConferencesView()
fun openSchoolAndTeachersView() fun openSchoolAndTeachersView()
} }

View File

@ -1,6 +1,7 @@
Wersja 0.22.2 Wersja 0.23.0
- naprawiliśmy problem z wyświetlaniem pozycji na liście ocen - naprawiliśmy logowanie do dziennika Gdańskiej i Koszalińskiej Platformy Edukacyjnej
- zmieniliśmy komunikaty o błędach, które powinny być teraz czytelniejsze dla większej liczby użytkowników - przy logowaniu odpowiednia odmiana dziennika jest ustawiana automatycznie na podstawie wpisanego adresu email
- zwiększyliśmy maksymalny czas, przez który aplikacja będzie próbowała łączyć się z dziennikiem do 1 minuty - dodaliśmy wyświetlanie średniej w ocenach klasy (jeśli włączone przez szkołę)
- dodaliśmy wyświetlanie zebrań
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFF"
android:fillType="nonZero"
android:pathData="M12,2C6.4883,2 2,6.4883 2,12C2,17.5117 6.4883,22 12,22C17.5117,22 22,17.5117 22,12C22,6.4883 17.5117,2 12,2ZM12,4C16.4297,4 20,7.5703 20,12C20,16.0156 17.0664,19.3125 13.2188,19.8984L13.2188,14.3828L15.5469,14.3828L15.9102,12.0195L13.2188,12.0195L13.2188,10.7266C13.2188,9.7422 13.5391,8.8711 14.457,8.8711L15.9336,8.8711L15.9336,6.8047C15.6758,6.7734 15.125,6.6953 14.0898,6.6953C11.9258,6.6953 10.6523,7.8398 10.6523,10.4453L10.6523,12.0195L8.4258,12.0195L8.4258,14.3828L10.6523,14.3828L10.6523,19.8789C6.8711,19.2422 4,15.9688 4,12C4,7.5703 7.5703,4 12,4ZM12,4" />
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M9,13.75c-2.34,0 -7,1.17 -7,3.5L2,19h14v-1.75c0,-2.33 -4.66,-3.5 -7,-3.5zM4.34,17c0.84,-0.58 2.87,-1.25 4.66,-1.25s3.82,0.67 4.66,1.25L4.34,17zM9,12c1.93,0 3.5,-1.57 3.5,-3.5S10.93,5 9,5 5.5,6.57 5.5,8.5 7.07,12 9,12zM9,7c0.83,0 1.5,0.67 1.5,1.5S9.83,10 9,10s-1.5,-0.67 -1.5,-1.5S8.17,7 9,7zM16.04,13.81c1.16,0.84 1.96,1.96 1.96,3.44L18,19h4v-1.75c0,-2.02 -3.5,-3.17 -5.96,-3.44zM15,12c1.93,0 3.5,-1.57 3.5,-3.5S16.93,5 15,5c-0.54,0 -1.04,0.13 -1.5,0.35 0.63,0.89 1,1.98 1,3.15s-0.37,2.26 -1,3.15c0.46,0.22 0.96,0.35 1.5,0.35z" />
</vector>

View File

@ -0,0 +1,104 @@
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.modules.conference.ConferenceFragment">
<me.zhanghai.android.materialprogressbar.MaterialProgressBar
android:id="@+id/conferenceProgress"
style="@style/Widget.MaterialProgressBar.ProgressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminate="true" />
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/conferenceSwipe"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/conferenceRecycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:listitem="@layout/item_conference" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<LinearLayout
android:id="@+id/conferenceEmpty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:padding="10dp"
android:visibility="gone"
tools:ignore="UseCompoundDrawables">
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
app:srcCompat="@drawable/ic_more_conferences"
app:tint="?colorOnBackground"
tools:ignore="contentDescription" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="center"
android:text="@string/conference_no_items"
android:textSize="20sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/conferenceError"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:visibility="invisible"
tools:ignore="UseCompoundDrawables"
tools:visibility="invisible">
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
app:srcCompat="@drawable/ic_error"
app:tint="?colorOnBackground"
tools:ignore="contentDescription" />
<TextView
android:id="@+id/conferenceErrorMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="center"
android:padding="8dp"
android:text="@string/error_unknown"
android:textSize="20sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:gravity="center"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/conferenceErrorDetails"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:text="@string/all_details" />
<com.google.android.material.button.MaterialButton
android:id="@+id/conferenceErrorRetry"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/all_retry" />
</LinearLayout>
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -0,0 +1,87 @@
<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/conference_item_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?selectableItemBackground"
tools:context=".ui.modules.conference.ConferenceAdapter">
<TextView
android:id="@+id/conferenceItemDate"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_marginTop="10dp"
android:textColor="?android:textColorSecondary"
android:textSize="15sp"
app:layout_constraintRight_toLeftOf="@+id/conferenceItemName"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="@tools:sample/date/ddmmyy" />
<TextView
android:id="@+id/conferenceItemName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:layout_marginEnd="15dp"
android:ellipsize="end"
android:gravity="end"
android:singleLine="true"
android:textSize="13sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/conferenceItemDate"
app:layout_constraintTop_toTopOf="parent"
tools:text="@tools:sample/full_names" />
<TextView
android:id="@+id/conferenceItemTitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:ellipsize="end"
android:maxLines="2"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="@id/conferenceItemName"
app:layout_constraintStart_toStartOf="@id/conferenceItemDate"
app:layout_constraintTop_toBottomOf="@id/conferenceItemDate"
app:layout_goneMarginEnd="0dp"
tools:text="@tools:sample/lorem" />
<TextView
android:id="@+id/conferenceItemSubject"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:ellipsize="end"
android:maxLines="2"
android:textSize="16sp"
app:layout_constraintBottom_toTopOf="@id/conferenceItemContent"
app:layout_constraintEnd_toEndOf="@id/conferenceItemTitle"
app:layout_constraintStart_toStartOf="@id/conferenceItemTitle"
app:layout_constraintTop_toBottomOf="@id/conferenceItemTitle"
app:layout_goneMarginBottom="15dp"
app:layout_goneMarginEnd="0dp"
tools:text="@tools:sample/lorem" />
<TextView
android:id="@+id/conferenceItemContent"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginBottom="15dp"
android:ellipsize="end"
android:lineSpacingMultiplier="1.2"
android:maxLines="2"
android:textSize="14sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@+id/conferenceItemName"
app:layout_constraintStart_toStartOf="@id/conferenceItemDate"
app:layout_constraintTop_toBottomOf="@id/conferenceItemSubject"
tools:text="@tools:sample/lorem/random"
tools:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<!--Activity/Fragment title--> <!--Activity/Fragment title-->
<string name="login_title">Přihlásit se</string> <string name="login_title">Přihlášení</string>
<string name="main_title">Wulkanowy</string> <string name="main_title">Wulkanowy</string>
<string name="grade_title">Známky</string> <string name="grade_title">Známky</string>
<string name="attendance_title">Prezence</string> <string name="attendance_title">Docházka</string>
<string name="exam_title">Zkoušky</string> <string name="exam_title">Zkoušky</string>
<string name="timetable_title">Plán lekce</string> <string name="timetable_title">Plán lekce</string>
<string name="settings_title">Nastavení</string> <string name="settings_title">Nastavení</string>
@ -16,18 +16,18 @@
<string name="message_title">Zprávy</string> <string name="message_title">Zprávy</string>
<string name="send_message_title">Nová zpráva</string> <string name="send_message_title">Nová zpráva</string>
<string name="note_title">Poznámky a úspěchy</string> <string name="note_title">Poznámky a úspěchy</string>
<string name="homework_title">Domácí práce</string> <string name="homework_title">Domácí úkoly</string>
<string name="account_title">Vyberte účet</string> <string name="account_title">Vyberte účet</string>
<!--Subtitles--> <!--Subtitles-->
<string name="grade_subtitle">Semestr %1$d, %2$d/%3$d</string> <string name="grade_subtitle">Semestr %1$d, %2$d/%3$d</string>
<!--Login--> <!--Login-->
<string name="login_header_default">Přihlaste se pomocí studentského nebo nadřazeného účtu</string> <string name="login_header_default">Přihlaste se pomocí studentského nebo rodičovského účtu</string>
<string name="login_header_symbol">Zadejte symbol</string> <string name="login_header_symbol">Zadejte symbol ze stránky deníku</string>
<string name="login_nickname_hint">Uživatelské jméno</string> <string name="login_nickname_hint">Uživatelské jméno</string>
<string name="login_email_hint">Email</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_login_pesel_email_hint">Přihlášení, číslo PESEL nebo e-mail</string>
<string name="login_password_hint">Heslo</string> <string name="login_password_hint">Heslo</string>
<string name="login_host_hint">Deník UONET+</string> <string name="login_host_hint">Variace deníku UONET+</string>
<string name="login_type_api">Mobile API</string> <string name="login_type_api">Mobile API</string>
<string name="login_type_scrapper">Scraper</string> <string name="login_type_scrapper">Scraper</string>
<string name="login_type_hybrid">Hybridní</string> <string name="login_type_hybrid">Hybridní</string>
@ -37,18 +37,18 @@
<string name="login_symbol_hint">Symbol</string> <string name="login_symbol_hint">Symbol</string>
<string name="login_sign_in">Přihlásit</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_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_incorrect_password">Přihlašovací údaje jsou nesprávné. Ujistěte se, že je v poli níže vybrána správná variace deníku UONET+</string>
<string name="login_invalid_pin">Neplatný PIN</string> <string name="login_invalid_pin">Neplatný PIN</string>
<string name="login_invalid_token">Neplatný token</string> <string name="login_invalid_token">Neplatný token</string>
<string name="login_expired_token">Platnost tokenu vypršela</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_email">Neplatný e-mail</string>
<string name="login_invalid_login">Neplatné přihlášení</string> <string name="login_invalid_login">Místo e-mailu použijte přiřazené přihlašovací údaje</string>
<string name="login_invalid_symbol">Neplatný symbol</string> <string name="login_invalid_symbol">Neplatný symbol</string>
<string name="login_incorrect_symbol">Student nebyl nalezen. Zkontrolujte symbol</string> <string name="login_incorrect_symbol">Student nebyl nalezen. Zkontrolujte správnost symbolu a vybrané varianty deníku UONET+</string>
<string name="login_field_required">Toto pole je povinné</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_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_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>.\n\nUjistěte se, že jste na předchozí obrazovce nastavili správnou variantu deníku do pole <b>Variace deníku UONET+</b>. Wulkanowy v tuto chvíli nezjistí předškolní studenty</string>
<string name="login_select_student">Vyberte studenty k přihlášení do aplikace</string> <string name="login_select_student">Vyberte studenty, kteří se mají do aplikace přihlásit</string>
<string name="login_advanced">Jiné možnosti</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_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_scraper">Tento režim zobrazuje stejná data, která se zobrazují na webových stránkách deníka</string>
@ -59,13 +59,13 @@
<string name="login_contact_discord">Discord</string> <string name="login_contact_discord">Discord</string>
<string name="login_email_intent_title">Poslat e-mail</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_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_warning">Ujistěte se, že jste vybrali správnou variantu deníku UONET+!</string>
<string name="login_recover_button">Zapomněl jsem své heslo</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_title">Obnovte svůj účet</string>
<string name="login_recover">Obnovit</string> <string name="login_recover">Obnovit</string>
<string name="login_signed_in">Student je již přihlášen</string> <string name="login_signed_in">Student je již přihlášen</string>
<!--Main--> <!--Main-->
<string name="main_account_picker">Správce účtu</string> <string name="main_account_picker">Manažer účtů</string>
<string name="main_log_in">Přihlásit se</string> <string name="main_log_in">Přihlásit se</string>
<string name="main_session_expired">Platnost relace vypršela</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> <string name="main_session_relogin">Vaše relace vypršela, přihlaste se prosím znovu</string>
@ -79,9 +79,9 @@
<string name="grade_comment">Komentář</string> <string name="grade_comment">Komentář</string>
<string name="grade_no_new_items">Žádné nové známky</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_number_new_items">Počet nových známek: %1$d</string>
<string name="grade_average">Průměr: %1$.2f</string> <string name="grade_average">Průměr: %1$.2f</string>
<string name="grade_points_sum">Body: %s</string> <string name="grade_points_sum">Body: %s</string>
<string name="grade_no_average">Žádný průměr</string> <string name="grade_no_average">Bez průměru</string>
<string name="grade_predicted">Předpovězeno: %1$s</string> <string name="grade_predicted">Předpovězeno: %1$s</string>
<string name="grade_final">Konečná: %1$s</string> <string name="grade_final">Konečná: %1$s</string>
<string name="grade_summary_points">Celkem bodů</string> <string name="grade_summary_points">Celkem bodů</string>
@ -126,10 +126,10 @@
<item quantity="other">Máte %1$d nové známky</item> <item quantity="other">Máte %1$d nové známky</item>
</plurals> </plurals>
<plurals name="grade_notify_new_items_predicted"> <plurals name="grade_notify_new_items_predicted">
<item quantity="one">Máte %1$d novou konečnou známku</item> <item quantity="one">Máte %1$d novou předpokládanou známku</item>
<item quantity="few">Máte %1$d nové konečné známky</item> <item quantity="few">Máte %1$d nové předpokládané známky</item>
<item quantity="many">Máte %1$d nové konečné známky</item> <item quantity="many">Máte %1$d nové předpokládané známky</item>
<item quantity="other">Máte %1$d nové konečné známky</item> <item quantity="other">Máte %1$d nové předpokládané známky</item>
</plurals> </plurals>
<plurals name="grade_notify_new_items_final"> <plurals name="grade_notify_new_items_final">
<item quantity="one">Máte %1$d novou konečnou známku</item> <item quantity="one">Máte %1$d novou konečnou známku</item>
@ -143,7 +143,7 @@
<string name="timetable_group">Skupina</string> <string name="timetable_group">Skupina</string>
<string name="timetable_time">Hodiny</string> <string name="timetable_time">Hodiny</string>
<string name="timetable_changes">Změny</string> <string name="timetable_changes">Změny</string>
<string name="timetable_no_items">Dnes žádné lekce</string> <string name="timetable_no_items">Žádné lekce tento den</string>
<string name="timetable_minutes">%s min</string> <string name="timetable_minutes">%s min</string>
<string name="timetable_seconds">%s sek</string> <string name="timetable_seconds">%s sek</string>
<string name="timetable_time_left">dosud %1$s</string> <string name="timetable_time_left">dosud %1$s</string>
@ -155,32 +155,32 @@
<!--Completed lessons--> <!--Completed lessons-->
<string name="completed_lessons_title">Dokončené lekce</string> <string name="completed_lessons_title">Dokončené lekce</string>
<string name="completed_lessons_button">Zobrazit 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_no_items">Žádné informace o dokončených lekcích</string>
<string name="completed_lessons_topic">Téma</string> <string name="completed_lessons_topic">Téma</string>
<string name="completed_lessons_absence">Absence</string> <string name="completed_lessons_absence">Nepřítomnost</string>
<string name="completed_lessons_resources">Zdroje</string> <string name="completed_lessons_resources">Zdroje</string>
<!--Attendance--> <!--Attendance-->
<string name="attendance_summary_button">Souhrn docházky</string> <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_school">Nepřítomen ze školních důvodů</string>
<string name="attendance_absence_excused">Omluvená absence</string> <string name="attendance_absence_excused">Omluvená nepřítomnost</string>
<string name="attendance_absence_unexcused">Neomluvená absence</string> <string name="attendance_absence_unexcused">Neomluvená absence</string>
<string name="attendance_exemption">Osvobození</string> <string name="attendance_exemption">Osvobození</string>
<string name="attendance_excused_lateness">Oprávněné zpoždění</string> <string name="attendance_excused_lateness">Omluvené zpoždění</string>
<string name="attendance_unexcused_lateness">Neomluvená zpoždění</string> <string name="attendance_unexcused_lateness">Neomluvené zpoždění</string>
<string name="attendance_present">Přítomnost</string> <string name="attendance_present">Přítomnost</string>
<string name="attendance_deleted">Smazáno</string> <string name="attendance_deleted">Smazáno</string>
<string name="attendance_unknown">Neznámý</string> <string name="attendance_unknown">Neznámý</string>
<string name="attendance_number">Číslo lekce</string> <string name="attendance_number">Číslo lekce</string>
<string name="attendance_no_items">Žádné položky</string> <string name="attendance_no_items">Žádné položky</string>
<plurals name="attendance_number_absences"> <plurals name="attendance_number_absences">
<item quantity="one">%1$d absence</item> <item quantity="one">%1$d nepřítomnost</item>
<item quantity="few">%1$d absence</item> <item quantity="few">%1$d nepřítomnosti</item>
<item quantity="many">%1$d absence</item> <item quantity="many">%1$d nepřítomnosti</item>
<item quantity="other">%1$d absence</item> <item quantity="other">%1$d nepřítomnosti</item>
</plurals> </plurals>
<string name="attendance_excuse_dialog_reason">Důvod absence (volitelný)</string> <string name="attendance_excuse_dialog_reason">Důvod nepřítomnosti (volitelný)</string>
<string name="attendance_excuse_dialog_submit">Poslat</string> <string name="attendance_excuse_dialog_submit">Poslat</string>
<string name="attendance_excuse_success">Absence úspěšně omluvena!</string> <string name="attendance_excuse_success">Nepřítomnost úspěšně omluvena!</string>
<string name="attendance_excuse_no_selection">Musíte vybrat alespoň jednu nepřítomnost!</string> <string name="attendance_excuse_no_selection">Musíte vybrat alespoň jednu nepřítomnost!</string>
<string name="attendance_excuse_title">Ospravedlnit</string> <string name="attendance_excuse_title">Ospravedlnit</string>
<!--Attendance summary--> <!--Attendance summary-->
@ -198,7 +198,7 @@
<string name="message_no_items">Žádné zprávy</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_preview_error">Při stahování obsahu zprávy došlo k chybě</string>
<string name="message_from">Od:</string> <string name="message_from">Od:</string>
<string name="message_to">Do:</string> <string name="message_to">Komu:</string>
<string name="message_date">Datum: %s</string> <string name="message_date">Datum: %s</string>
<string name="message_reply">Odpověď</string> <string name="message_reply">Odpověď</string>
<string name="message_forward">Poslat dále</string> <string name="message_forward">Poslat dále</string>
@ -226,10 +226,10 @@
<item quantity="other">Nové zprávy</item> <item quantity="other">Nové zprávy</item>
</plurals> </plurals>
<plurals name="message_notify_new_items"> <plurals name="message_notify_new_items">
<item quantity="one">Obdrželi jste %1$d zprávu</item> <item quantity="one">Máte %1$d novou zprávu</item>
<item quantity="few">Obdrželi jste %1$d zpráv</item> <item quantity="few">Máte %1$d nové zprávy</item>
<item quantity="many">Obdrželi jste %1$d zpráv</item> <item quantity="many">Máte %1$d nové zprávy</item>
<item quantity="other">Obdrželi jste %1$d zpráv</item> <item quantity="other">Máte %1$d nové zprávy</item>
</plurals> </plurals>
<!--Note--> <!--Note-->
<string name="note_no_items">Žádné informace o poznámkách</string> <string name="note_no_items">Žádné informace o poznámkách</string>
@ -286,12 +286,12 @@
</plurals> </plurals>
<plurals name="neutral_note_notify_new_items"> <plurals name="neutral_note_notify_new_items">
<item quantity="one">Máte %1$d novou neutrální pozornost</item> <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="few">Máte %1$d nové neutrální pozornosti</item>
<item quantity="many">Máte %1$d nové neutrální komentáře</item> <item quantity="many">Máte %1$d nové neutrální pozornosti</item>
<item quantity="other">Máte %1$d nové neutrální komentáře</item> <item quantity="other">Máte %1$d nové neutrální pozornosti</item>
</plurals> </plurals>
<!--Homework--> <!--Homework-->
<string name="homework_no_items">Žádný domácí úkol</string> <string name="homework_no_items">Žádné informace o domácím úkolu</string>
<string name="homework_mark_as_done">Označit jako hotové</string> <string name="homework_mark_as_done">Označit jako hotové</string>
<string name="homework_mark_as_undone">Neudělané</string> <string name="homework_mark_as_undone">Neudělané</string>
<string name="homework_attachments">Přílohy</string> <string name="homework_attachments">Přílohy</string>
@ -315,7 +315,7 @@
<!--School--> <!--School-->
<string name="school_title">Škola</string> <string name="school_title">Škola</string>
<string name="school_no_info">Žádné informace o škole</string> <string name="school_no_info">Žádné informace o škole</string>
<string name="school_name">Školní jméno</string> <string name="school_name">Název školy</string>
<string name="school_address">Adresa školy</string> <string name="school_address">Adresa školy</string>
<string name="school_telephone">Telefon</string> <string name="school_telephone">Telefon</string>
<string name="school_headmaster">Jméno ředitele</string> <string name="school_headmaster">Jméno ředitele</string>
@ -326,6 +326,9 @@
<string name="teachers_title">Učitelé</string> <string name="teachers_title">Učitelé</string>
<string name="teacher_no_items">Žádné informace o učitelích</string> <string name="teacher_no_items">Žádné informace o učitelích</string>
<string name="teacher_no_subject">Žádný předmět</string> <string name="teacher_no_subject">Žádný předmět</string>
<!--Conference-->
<string name="conferences_title">Setkání</string>
<string name="conference_no_items">Žádné informace o setkání</string>
<!--Account--> <!--Account-->
<string name="account_add_new">Přidat účet</string> <string name="account_add_new">Přidat účet</string>
<string name="account_logout">Odhlásit se</string> <string name="account_logout">Odhlásit se</string>
@ -333,18 +336,20 @@
<string name="account_logout_student">Odhlášení studentů</string> <string name="account_logout_student">Odhlášení studentů</string>
<string name="account_type_student">Studentský účet</string> <string name="account_type_student">Studentský účet</string>
<string name="account_type_parent">Rodičovský úč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_mobile_api">Režim Mobilního API</string>
<string name="account_login_hybrid">Hybridní režim</string> <string name="account_login_hybrid">Hybridní režim</string>
<!--About--> <!--About-->
<string name="about_version">Verze aplikace</string> <string name="about_version">Verze aplikace</string>
<string name="about_contributor">Tvůrci</string> <string name="about_contributor">Tvůrci</string>
<string name="about_contributor_summary">Seznam vývojářů Wulkanowy</string> <string name="about_contributor_summary">Seznam vývojářů Wulkanowy</string>
<string name="about_feedback">Nahlásit chybu</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_feedback_summary">Odeslat zprávu o chybě e-mailem</string>
<string name="about_faq">FAQ</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_faq_summary">Přečtěte si často kladené otázky</string>
<string name="about_discord">Server Discord</string> <string name="about_discord">Server Discord</string>
<string name="about_discord_summary">Připojte se ke komunitě Wulkanowy</string> <string name="about_discord_summary">Připojte se ke komunitě Wulkanowy</string>
<string name="about_facebook">Facebooková fanpage</string>
<string name="about_facebook_summary">Stejně jako naše facebooková fanpage</string>
<string name="about_privacy">Zásady ochrany osobních údajů</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_privacy_summary">Pravidla pro shromažďování osobních údajů</string>
<string name="about_homepage">Domovská stránka</string> <string name="about_homepage">Domovská stránka</string>
@ -360,8 +365,8 @@
<string name="logviewer_share">Sdílejte protokoly</string> <string name="logviewer_share">Sdílejte protokoly</string>
<string name="logviewer_refresh">Obnovit</string> <string name="logviewer_refresh">Obnovit</string>
<!--Error dialog--> <!--Error dialog-->
<string name="dialog_error_check_update">Kontrola aktualizací</string> <string name="dialog_error_check_update">Zkontrolovat aktualizace</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> <string name="dialog_error_check_update_message">Před hlášením chyby zkontrolujte, zda je k dispozici aktualizace s opravou chyb</string>
<!--Generic--> <!--Generic-->
<string name="all_content">Obsah</string> <string name="all_content">Obsah</string>
<string name="all_retry">Zkuste to znovu</string> <string name="all_retry">Zkuste to znovu</string>
@ -378,21 +383,21 @@
<string name="all_subject">Předmět</string> <string name="all_subject">Předmět</string>
<string name="all_prev">Předchozí</string> <string name="all_prev">Předchozí</string>
<string name="all_next">Další</string> <string name="all_next">Další</string>
<string name="all_search">Vyhledávání</string> <string name="all_search">Hledat</string>
<string name="all_search_hint">Vyhledávání</string> <string name="all_search_hint">Hledat</string>
<!--Timetable Widget--> <!--Timetable Widget-->
<string name="widget_timetable_no_items">Žádné lekce</string> <string name="widget_timetable_no_items">Žádné lekce</string>
<string name="widget_timetable_theme_title">Vyberte téma</string> <string name="widget_timetable_theme_title">Vybrat motiv</string>
<string name="widget_timetable_theme_light">Světlý</string> <string name="widget_timetable_theme_light">Světlý</string>
<string name="widget_timetable_theme_dark">Tmavý</string> <string name="widget_timetable_theme_dark">Tmavý</string>
<string name="widget_timetable_theme_system">Téma systému</string> <string name="widget_timetable_theme_system">Motiv systému</string>
<!--Preferences--> <!--Preferences-->
<string name="pref_view_header">Vzhled</string> <string name="pref_view_header">Vzhled</string>
<string name="pref_view_list">Výchozí zobrazení</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_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_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_present">Zobrazit přítomnost v účasti</string>
<string name="pref_view_app_theme">Téma aplikace</string> <string name="pref_view_app_theme">Motiv aplikace</string>
<string name="pref_view_expand_grade">Rozbalit známky</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_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_timetable_show_groups">Ukázat skupiny vedle předmětů v plánu lekce</string>
@ -407,22 +412,22 @@
<string name="pref_notify_upcoming_lessons_switch">Ukázat nadcházející oznámení o lekci</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">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_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_fix_sync_issues_settings_button">Přejít do nastavení</string>
<string name="pref_notify_debug_switch">Ukázat oznámení o ladění</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_header">Synchronizace</string>
<string name="pref_services_switch">Automatická aktualizace</string> <string name="pref_services_switch">Automatická aktualizace</string>
<string name="pref_services_suspended">Pozastaveno na dovolené</string> <string name="pref_services_suspended">Pozastaveno na dovolené</string>
<string name="pref_services_interval">Interval aktualizací</string> <string name="pref_services_interval">Interval aktualizací</string>
<string name="pref_services_wifi">Pouze Wi-Fi</string> <string name="pref_services_wifi">Pouze Wi-Fi</string>
<string name="pref_services_force_sync">Nyní synchronizovat</string> <string name="pref_services_force_sync">Synchronizovat nyní</string>
<string name="pref_services_message_sync_success">Synchronizováno!</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_message_sync_failed">Synchronizace selhala</string>
<string name="pref_services_sync_in_progress">Probíhá synchronizace</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_title">Synchronizace</string>
<string name="pref_services_dialog_force_sync_summary"> Ruční synchronizace neobnoví zobrazení aplikace. <string name="pref_services_dialog_force_sync_summary"> Ruční synchronizace neobnoví zobrazení aplikace.
\nChcete-li zobrazit synchronizovaná data, restartujte aplikaci po synchronizaci. \nChcete-li zobrazit synchronizovaná data, restartujte aplikaci po synchronizaci.
</string> </string>
<string name="pref_other_header">Jiný</string> <string name="pref_other_header">Jiné</string>
<string name="pref_other_grade_modifier_plus">Hodnota plusu</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_grade_modifier_minus">Hodnota mínusu</string>
<string name="pref_other_fill_message_content">Odpovědět s historií zpráv</string> <string name="pref_other_fill_message_content">Odpovědět s historií zpráv</string>
@ -432,9 +437,9 @@
<string name="channel_lucky_number">Šťastné číslo</string> <string name="channel_lucky_number">Šťastné číslo</string>
<string name="channel_new_message">Nové zprávy</string> <string name="channel_new_message">Nové zprávy</string>
<string name="channel_new_notes">Nové poznámky</string> <string name="channel_new_notes">Nové poznámky</string>
<string name="channel_push">Oznámení push</string> <string name="channel_push">Push oznámení</string>
<string name="channel_upcoming_lessons">Nadcházející lekce</string> <string name="channel_upcoming_lessons">Nadcházející lekce</string>
<string name="channel_debug">Ladění</string> <string name="channel_debug">Debug</string>
<!--Colors--> <!--Colors-->
<string name="all_black">Černý</string> <string name="all_black">Černý</string>
<string name="all_red">Červený</string> <string name="all_red">Červený</string>
@ -452,12 +457,12 @@
<string name="update_failed">Aktualizace selhala! Wulkanowy nemusí fungovat správně. Zvažte aktualizaci</string> <string name="update_failed">Aktualizace selhala! Wulkanowy nemusí fungovat správně. Zvažte aktualizaci</string>
<!--Errors--> <!--Errors-->
<string name="error_no_internet">Žádné internetové připojení</string> <string name="error_no_internet">Žádné internetové připojení</string>
<string name="error_timeout">Vypršel časový limit připojení k denik</string> <string name="error_timeout">Nelze se připojit ke deníku. Servery mohou být přetíženy. Prosím zkuste to znovu později</string>
<string name="error_login_failed">Přihlášení selhalo. Zkus to znovu</string> <string name="error_login_failed">Načítání dat se nezdařilo. Prosím zkuste to znovu později</string>
<string name="error_password_change_required">Je vyžadována změna hesla</string> <string name="error_password_change_required">Je vyžadována změna hesla pro deník</string>
<string name="error_service_unavailable">Probíhá údržba UONET+ deník. Zkuste to později znovu</string> <string name="error_service_unavailable">Probíhá údržba UONET+ deník. Zkuste to později znovu</string>
<string name="error_unknown_uonet">Neznámá chyba denika UONET+. Prosím zkuste to znovu později</string> <string name="error_unknown_uonet">Neznámá chyba denika UONET+. Prosím zkuste to znovu později</string>
<string name="error_unknown_app">Neznámá chyba aplikace</string> <string name="error_unknown_app">Neznámá chyba aplikace. Prosím zkuste to znovu později</string>
<string name="error_unknown">Došlo k neočekávané chybě</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_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> <string name="error_feature_not_available">Funkce není k dispozici. Přihlaste se v jiném režimu než Mobile API</string>

View File

@ -31,8 +31,8 @@
<item>0,75</item> <item>0,75</item>
</string-array> </string-array>
<string-array name="grade_sorting_mode_entries"> <string-array name="grade_sorting_mode_entries">
<item>Alphabetic</item> <item>Alphabetisch</item>
<item>By date</item> <item>Nach Datum</item>
</string-array> </string-array>
<string-array name="grade_color_scheme_entries"> <string-array name="grade_color_scheme_entries">
<item>Dzienniczek+</item> <item>Dzienniczek+</item>

View File

@ -22,12 +22,12 @@
<string name="grade_subtitle">Semester %1$d, %2$d/%3$d</string> <string name="grade_subtitle">Semester %1$d, %2$d/%3$d</string>
<!--Login--> <!--Login-->
<string name="login_header_default">Melden Sie sich mit dem Studenten- oder Elternkonto an</string> <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> <string name="login_header_symbol">Geben Sie das Symbol von der Registerseite ein</string>
<string name="login_nickname_hint">Benutzername</string> <string name="login_nickname_hint">Benutzername</string>
<string name="login_email_hint">Email</string> <string name="login_email_hint">Email</string>
<string name="login_login_pesel_email_hint">Anmeldung, PESEL oder e-mail</string> <string name="login_login_pesel_email_hint">Anmeldung, PESEL oder e-mail</string>
<string name="login_password_hint">Passwort</string> <string name="login_password_hint">Passwort</string>
<string name="login_host_hint">UONET+ Klassenbuch</string> <string name="login_host_hint">UONET+ Registervariante</string>
<string name="login_type_api">Mobile API</string> <string name="login_type_api">Mobile API</string>
<string name="login_type_scrapper">Scraper</string> <string name="login_type_scrapper">Scraper</string>
<string name="login_type_hybrid">Hybride</string> <string name="login_type_hybrid">Hybride</string>
@ -37,17 +37,17 @@
<string name="login_symbol_hint">Symbol</string> <string name="login_symbol_hint">Symbol</string>
<string name="login_sign_in">Anmelden</string> <string name="login_sign_in">Anmelden</string>
<string name="login_invalid_password">Passwort ist zu kurz</string> <string name="login_invalid_password">Passwort ist zu kurz</string>
<string name="login_incorrect_password">Anmeldedaten sind falsch. Stellen Sie sicher, dass das richtige UONET+-Register ausgewählt ist</string> <string name="login_incorrect_password">Anmeldedaten sind falsch. Stellen Sie sicher, dass die richtige UONET+ Registervariation im unteren Feld ausgewählt ist</string>
<string name="login_invalid_pin">Ungültige PIN</string> <string name="login_invalid_pin">Ungültige PIN</string>
<string name="login_invalid_token">Ungültige token</string> <string name="login_invalid_token">Ungültige token</string>
<string name="login_expired_token">Token ist nicht mehr gültig</string> <string name="login_expired_token">Token ist nicht mehr gültig</string>
<string name="login_invalid_email">Ungültige email</string> <string name="login_invalid_email">Ungültige email</string>
<string name="login_invalid_login">Ungültige login</string> <string name="login_invalid_login">Den zugewiesenen Login anstelle von email verwenden</string>
<string name="login_invalid_symbol">Ungültige symbol</string> <string name="login_invalid_symbol">Ungültige symbol</string>
<string name="login_incorrect_symbol">Student nicht gefunden. Überprüfen Sie das Symbol</string> <string name="login_incorrect_symbol">Schüler nicht gefunden. Überprüfen Sie das Symbol und die gewählte Variation des UONET+ Registers</string>
<string name="login_field_required">Dieses Datenfeld ist erforderlich</string> <string name="login_field_required">Dieses Datenfeld ist erforderlich</string>
<string name="login_duplicate_student">Ausgewählter Student ist bereits angemeldet.</string> <string name="login_duplicate_student">Ausgewählter Student ist bereits angemeldet.</string>
<string name="login_symbol_helper">Das Symbol finden Sie auf der Registerseite unter&#160;<b>Uczeń</b> &#160;<b>Dostęp Mobilny</b>&#160;<b>Zarejestruj urządzenie mobilne</b></string> <string name="login_symbol_helper">Das Symbol kann auf der Registerseite in&#160;<b>Uczeń</b>&#160;<b>Dostęp Mobilny</b>&#160;<b>Zarejestruj urządzenie mobilne</b>gefunden werden.\n\nStellen Sie sicher, dass Sie die entsprechende Registervariante im Feld <b>UONET+ Registervariante</b> auf dem vorherigen Bildschirm festgelegt haben. Wulkanowy erkennt zur Zeit keine Vorschulstudenten</string>
<string name="login_select_student">Wählen Sie die Studenten aus, die sich bei der Anwendung anmelden sollen.</string> <string name="login_select_student">Wählen Sie die Studenten aus, die sich bei der Anwendung anmelden sollen.</string>
<string name="login_advanced">Andere Optionen</string> <string name="login_advanced">Andere Optionen</string>
<string name="login_advanced_warning_mobile_api">In diesem Modus funktioniert eine Glücknummer, eine Klassenstatistik, eine Zusammenfassung der Anwesenheit, eine Entschuldigung für die Abwesenheit, abgeschlossene Lektionen, Schulinformationen und eine Vorschau der Liste der registrierten Geräte nicht</string> <string name="login_advanced_warning_mobile_api">In diesem Modus funktioniert eine Glücknummer, eine Klassenstatistik, eine Zusammenfassung der Anwesenheit, eine Entschuldigung für die Abwesenheit, abgeschlossene Lektionen, Schulinformationen und eine Vorschau der Liste der registrierten Geräte nicht</string>
@ -59,7 +59,7 @@
<string name="login_contact_discord">Discord</string> <string name="login_contact_discord">Discord</string>
<string name="login_email_intent_title">email senden</string> <string name="login_email_intent_title">email senden</string>
<string name="login_email_details">Beschreiben Sie die Details des Problems:</string> <string name="login_email_details">Beschreiben Sie die Details des Problems:</string>
<string name="login_recover_warning">Stellen Sie sicher, dass das richtige UONET + Klassenbuch ausgewählt ist!</string> <string name="login_recover_warning">Stellen Sie sicher, dass Sie die richtige UONET+ Registervariation wählen!</string>
<string name="login_recover_button">Ich habe mein Passwort vergessen.</string> <string name="login_recover_button">Ich habe mein Passwort vergessen.</string>
<string name="login_recover_title">Ihr Konto wiederherstellen</string> <string name="login_recover_title">Ihr Konto wiederherstellen</string>
<string name="login_recover">Wiederherstellen</string> <string name="login_recover">Wiederherstellen</string>
@ -154,8 +154,8 @@
<string name="attendance_excused_lateness">Entschuldigte Verspätung</string> <string name="attendance_excused_lateness">Entschuldigte Verspätung</string>
<string name="attendance_unexcused_lateness">Unentschuldigte Verspätung</string> <string name="attendance_unexcused_lateness">Unentschuldigte Verspätung</string>
<string name="attendance_present">Anwesend</string> <string name="attendance_present">Anwesend</string>
<string name="attendance_deleted">Deleted</string> <string name="attendance_deleted">Entfernt</string>
<string name="attendance_unknown">Unknown</string> <string name="attendance_unknown">Unbekannt</string>
<string name="attendance_number">Lektion Nummer</string> <string name="attendance_number">Lektion Nummer</string>
<string name="attendance_no_items">Keine Einträgen</string> <string name="attendance_no_items">Keine Einträgen</string>
<plurals name="attendance_number_absences"> <plurals name="attendance_number_absences">
@ -226,29 +226,29 @@
</plurals> </plurals>
<!--Praise--> <!--Praise-->
<plurals name="praise_number_item"> <plurals name="praise_number_item">
<item quantity="one">%d praise</item> <item quantity="one">%d Lob</item>
<item quantity="other">%d praises</item> <item quantity="other">%d Lob</item>
</plurals> </plurals>
<plurals name="praise_new_items"> <plurals name="praise_new_items">
<item quantity="one">New praise</item> <item quantity="one">Neues Lob</item>
<item quantity="other">New praises</item> <item quantity="other">Neues Lob</item>
</plurals> </plurals>
<plurals name="praise_notify_new_items"> <plurals name="praise_notify_new_items">
<item quantity="one">You received %1$d praise</item> <item quantity="one">Du hast %1$d Lob erhalten</item>
<item quantity="other">You received %1$d praises</item> <item quantity="other">Du hast %1$d Lob erhalten</item>
</plurals> </plurals>
<!--Neutral notes--> <!--Neutral notes-->
<plurals name="neutral_note_number_item"> <plurals name="neutral_note_number_item">
<item quantity="one">%d neutral note</item> <item quantity="one">%d neutrale Notiz</item>
<item quantity="other">%d neutral notes</item> <item quantity="other">%d neutrale Notizen</item>
</plurals> </plurals>
<plurals name="neutral_note_new_items"> <plurals name="neutral_note_new_items">
<item quantity="one">New neutral note</item> <item quantity="one">Neue neutrale Notiz</item>
<item quantity="other">New neutral notes</item> <item quantity="other">Neue neutrale Notizen</item>
</plurals> </plurals>
<plurals name="neutral_note_notify_new_items"> <plurals name="neutral_note_notify_new_items">
<item quantity="one">You received %1$d neutral note</item> <item quantity="one">Du hast %1$d neutrale Notiz erhalten</item>
<item quantity="other">You received %1$d neutral notes</item> <item quantity="other">Du hast %1$d neutrale Notizen erhalten</item>
</plurals> </plurals>
<!--Homework--> <!--Homework-->
<string name="homework_no_items">Keine Informationen über Hausaufgaben</string> <string name="homework_no_items">Keine Informationen über Hausaufgaben</string>
@ -286,6 +286,9 @@
<string name="teachers_title">Lehrerinnen und Lehrer</string> <string name="teachers_title">Lehrerinnen und Lehrer</string>
<string name="teacher_no_items">Keine Informationen über Lehrer</string> <string name="teacher_no_items">Keine Informationen über Lehrer</string>
<string name="teacher_no_subject">Kein Thema</string> <string name="teacher_no_subject">Kein Thema</string>
<!--Conference-->
<string name="conferences_title">Sitzungen</string>
<string name="conference_no_items">Keine Informationen über Sitzungen</string>
<!--Account--> <!--Account-->
<string name="account_add_new">Konto hinzufügen</string> <string name="account_add_new">Konto hinzufügen</string>
<string name="account_logout">Abmelden</string> <string name="account_logout">Abmelden</string>
@ -305,6 +308,8 @@
<string name="about_faq_summary">Lesen Sie Häufig gestellte Fragen</string> <string name="about_faq_summary">Lesen Sie Häufig gestellte Fragen</string>
<string name="about_discord">Discord server</string> <string name="about_discord">Discord server</string>
<string name="about_discord_summary">Treten Sie der Wulkanowy-Gemeinschaft bei</string> <string name="about_discord_summary">Treten Sie der Wulkanowy-Gemeinschaft bei</string>
<string name="about_facebook">Facebook fanpage</string>
<string name="about_facebook_summary">Gefällt unsere Facebook-Fanpage</string>
<string name="about_privacy">Datenschutzerklärung</string> <string name="about_privacy">Datenschutzerklärung</string>
<string name="about_privacy_summary">Regeln für die Sammlung persönlicher Daten</string> <string name="about_privacy_summary">Regeln für die Sammlung persönlicher Daten</string>
<string name="about_homepage">Startseite</string> <string name="about_homepage">Startseite</string>
@ -355,12 +360,12 @@
<string name="pref_view_app_theme">Thema der Anwendung</string> <string name="pref_view_app_theme">Thema der Anwendung</string>
<string name="pref_view_expand_grade">Noten erweitern</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_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_timetable_show_groups">Zeige Gruppen neben Themen im Zeitplan</string>
<string name="pref_view_grade_statistics_list">Liste der Diagramme in Klassenbewertungen anzeigen</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_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_subjects_without_grades">Zeigen Sie Themen ohne Noten in Noten</string>
<string name="pref_view_grade_color_scheme">Farbschema der Noten</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_grade_sorting_mode">Themen sortieren in \"Noten\"</string>
<string name="pref_view_app_language">App Sprache</string> <string name="pref_view_app_language">App Sprache</string>
<string name="pref_notify_header">Benachrichtigungen</string> <string name="pref_notify_header">Benachrichtigungen</string>
<string name="pref_notify_switch">Benachrichtigungen anzeigen</string> <string name="pref_notify_switch">Benachrichtigungen anzeigen</string>
@ -406,18 +411,18 @@
<string name="all_copied">Kopiert</string> <string name="all_copied">Kopiert</string>
<string name="all_undo">lösen</string> <string name="all_undo">lösen</string>
<!--Update helper--> <!--Update helper-->
<string name="update_download_started">Download of updates has started</string> <string name="update_download_started">Download der Updates wurde gestartet</string>
<string name="update_download_success">An update has just been downloaded.</string> <string name="update_download_success">Ein Update wurde gerade heruntergeladen.</string>
<string name="update_download_success_button">Restart</string> <string name="update_download_success_button">Neustart</string>
<string name="update_failed">Update failed! Wulkanowy may not function properly. Consider updating</string> <string name="update_failed">Update fehlgeschlagen! Wulkanowy funktioniert möglicherweise nicht richtig. Überlegen Sie die Aktualisierung</string>
<!--Errors--> <!--Errors-->
<string name="error_no_internet">Keine Internetverbindung</string> <string name="error_no_internet">Keine Internetverbindung</string>
<string name="error_timeout">Das Zeitlimit für die Verbindung zum Klassenbuch ist abgelaufen</string> <string name="error_timeout">Registrierungsverbindung fehlgeschlagen. Server können überlastet sein. Bitte versuchen Sie es später noch einmal</string>
<string name="error_login_failed">Login failed. Try again</string> <string name="error_login_failed">Das Laden der Daten ist fehlgeschlagen. Bitte versuchen Sie es später noch einmal</string>
<string name="error_password_change_required">Passwortänderung erforderlich</string> <string name="error_password_change_required">Passwortänderung für Registrierung erforderlich</string>
<string name="error_service_unavailable">Wartung im Gange UONET + Klassenbuch. Versuchen Sie es später noch einmal</string> <string name="error_service_unavailable">Wartung im Gange UONET + Klassenbuch. Versuchen Sie es später noch einmal</string>
<string name="error_unknown_uonet">Unknown UONET + register error. Try again later</string> <string name="error_unknown_uonet">Unbekannter UONET + Registerfehler. Versuchen Sie es später erneut</string>
<string name="error_unknown_app">Unknown application error</string> <string name="error_unknown_app">Unbekannter Anwendungsfehler. Bitte versuchen Sie es später noch einmal</string>
<string name="error_unknown">Ein unerwarteter Fehler ist aufgetreten</string> <string name="error_unknown">Ein unerwarteter Fehler ist aufgetreten</string>
<string name="error_feature_disabled">Funktion, die von Ihrer Schule deaktiviert wurde</string> <string name="error_feature_disabled">Funktion, die von Ihrer Schule deaktiviert wurde</string>
<string name="error_feature_not_available">Feature in diesem Modus nicht verfügbar</string> <string name="error_feature_not_available">Feature in diesem Modus nicht verfügbar</string>

View File

@ -168,7 +168,7 @@
<string name="attendance_excused_lateness">Spóźnienie usprawiedliwione</string> <string name="attendance_excused_lateness">Spóźnienie usprawiedliwione</string>
<string name="attendance_unexcused_lateness">Spóźnienie nieusprawiedliwione</string> <string name="attendance_unexcused_lateness">Spóźnienie nieusprawiedliwione</string>
<string name="attendance_present">Obecność</string> <string name="attendance_present">Obecność</string>
<string name="attendance_deleted">Usunięty</string> <string name="attendance_deleted">Usunięto</string>
<string name="attendance_unknown">Nieznany</string> <string name="attendance_unknown">Nieznany</string>
<string name="attendance_number">Numer lekcji</string> <string name="attendance_number">Numer lekcji</string>
<string name="attendance_no_items">Brak wpisów</string> <string name="attendance_no_items">Brak wpisów</string>
@ -326,6 +326,9 @@
<string name="teachers_title">Nauczyciele</string> <string name="teachers_title">Nauczyciele</string>
<string name="teacher_no_items">Brak informacji o nauczycielach</string> <string name="teacher_no_items">Brak informacji o nauczycielach</string>
<string name="teacher_no_subject">Brak przedmiotu</string> <string name="teacher_no_subject">Brak przedmiotu</string>
<!--Conference-->
<string name="conferences_title">Zebrania</string>
<string name="conference_no_items">Brak informacji o zebraniach</string>
<!--Account--> <!--Account-->
<string name="account_add_new">Dodaj konto</string> <string name="account_add_new">Dodaj konto</string>
<string name="account_logout">Wyloguj</string> <string name="account_logout">Wyloguj</string>
@ -345,6 +348,8 @@
<string name="about_faq_summary">Zobacz Najczęściej Zadawane Pytania</string> <string name="about_faq_summary">Zobacz Najczęściej Zadawane Pytania</string>
<string name="about_discord">Serwer Discord</string> <string name="about_discord">Serwer Discord</string>
<string name="about_discord_summary">Dołącz do społeczności Wulkanowego</string> <string name="about_discord_summary">Dołącz do społeczności Wulkanowego</string>
<string name="about_facebook">Fanpage na Facebooku</string>
<string name="about_facebook_summary">Polub nasz fanpage na Facebooku</string>
<string name="about_privacy">Polityka prywatności</string> <string name="about_privacy">Polityka prywatności</string>
<string name="about_privacy_summary">Zasady zbierania danych osobowych</string> <string name="about_privacy_summary">Zasady zbierania danych osobowych</string>
<string name="about_homepage">Strona domowa</string> <string name="about_homepage">Strona domowa</string>
@ -398,9 +403,9 @@
<string name="pref_view_timetable_show_groups">Pokazuj grupę obok przedmiotu 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_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_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_subjects_without_grades">Pokazuj przedmioty bez ocen w Ocenach</string>
<string name="pref_view_grade_color_scheme">Schemat kolorów ocen</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_grade_sorting_mode">Sortowanie przedmiotów w Ocenach</string>
<string name="pref_view_app_language">Język aplikacji</string> <string name="pref_view_app_language">Język aplikacji</string>
<string name="pref_notify_header">Powiadomienia</string> <string name="pref_notify_header">Powiadomienia</string>
<string name="pref_notify_switch">Pokazuj powiadomienia</string> <string name="pref_notify_switch">Pokazuj powiadomienia</string>

View File

@ -22,12 +22,12 @@
<string name="grade_subtitle">%1$d семестр, %2$d/%3$d</string> <string name="grade_subtitle">%1$d семестр, %2$d/%3$d</string>
<!--Login--> <!--Login-->
<string name="login_header_default">Авторизируйтесь при помощи аккаунта ученика или родителя</string> <string name="login_header_default">Авторизируйтесь при помощи аккаунта ученика или родителя</string>
<string name="login_header_symbol">Впишите \"symbol\"</string> <string name="login_header_symbol">Введите символ со страницы регистрации</string>
<string name="login_nickname_hint">Имя пользователя</string> <string name="login_nickname_hint">Имя пользователя</string>
<string name="login_email_hint">Электронная почта</string> <string name="login_email_hint">Электронная почта</string>
<string name="login_login_pesel_email_hint">Логин, PESEL или электронная почта</string> <string name="login_login_pesel_email_hint">Логин, PESEL или электронная почта</string>
<string name="login_password_hint">Пароль</string> <string name="login_password_hint">Пароль</string>
<string name="login_host_hint">Дневник UONET+</string> <string name="login_host_hint">Разновидностью бревна UONET+</string>
<string name="login_type_api">Mobile API</string> <string name="login_type_api">Mobile API</string>
<string name="login_type_scrapper">Scraper</string> <string name="login_type_scrapper">Scraper</string>
<string name="login_type_hybrid">Hybrid</string> <string name="login_type_hybrid">Hybrid</string>
@ -37,17 +37,17 @@
<string name="login_symbol_hint">Symbol</string> <string name="login_symbol_hint">Symbol</string>
<string name="login_sign_in">Войти</string> <string name="login_sign_in">Войти</string>
<string name="login_invalid_password">Слишком короткий пароль</string> <string name="login_invalid_password">Слишком короткий пароль</string>
<string name="login_incorrect_password">Указаны неверные данные. Убедитесь, что вы выбрали нужный дневник</string> <string name="login_incorrect_password">Данные для входа неверны. Убедитесь, что в поле ниже выбран правильный вариант регистра UONET+</string>
<string name="login_invalid_pin">Неправильный PIN</string> <string name="login_invalid_pin">Неправильный PIN</string>
<string name="login_invalid_token">Неправильный token</string> <string name="login_invalid_token">Неправильный token</string>
<string name="login_expired_token">Токен просрочен</string> <string name="login_expired_token">Токен просрочен</string>
<string name="login_invalid_email">Неверный адрес электронной почты</string> <string name="login_invalid_email">Неверный адрес электронной почты</string>
<string name="login_invalid_login">Неправильный логин</string> <string name="login_invalid_login">Используйте назначенный логин вместо электронной почты</string>
<string name="login_invalid_symbol">Неправильный symbol</string> <string name="login_invalid_symbol">Неправильный symbol</string>
<string name="login_incorrect_symbol">Не удалось найти ученика. Проверьте \"symbol\"</string> <string name="login_incorrect_symbol">Студент не найден. Подтвердите символ и выбранный вариант регистра UONET+</string>
<string name="login_field_required">Обязательное поле</string> <string name="login_field_required">Обязательное поле</string>
<string name="login_duplicate_student">Данный ученик уже авторизован</string> <string name="login_duplicate_student">Данный ученик уже авторизован</string>
<string name="login_symbol_helper">Вы можете найти \"symbol\" на странице VULCAN по пути <b>Uczeń</b> →&#160;<b>Dostęp Mobilny</b>&#160;<b>Zarejestruj urządzenie mobilne</b></string> <string name="login_symbol_helper">Этот символ можно найти на странице регистрации в &#160;<b>Uczeń</b>&#160;<b>Dostęp Mobilny</b> &#160;<b>Zarejestruj urządzenie mobilne</b>.\n\nУбедитесь, что вы установили соответствующий вариант регистра в поле <b>Разновидностью бревна UONET+</b> на предыдущем экране. Wulkanowy на данный момент не обнаруживает дошкольников</string>
<string name="login_select_student">Выберите учеников для авторизации в приложении</string> <string name="login_select_student">Выберите учеников для авторизации в приложении</string>
<string name="login_advanced">Другие варианты</string> <string name="login_advanced">Другие варианты</string>
<string name="login_advanced_warning_mobile_api">В этом режиме не работают: счастливый номер, статистика класса по оценкам, статистика посещаемости и уроков, информация о школе и список зарегистрированных устройств</string> <string name="login_advanced_warning_mobile_api">В этом режиме не работают: счастливый номер, статистика класса по оценкам, статистика посещаемости и уроков, информация о школе и список зарегистрированных устройств</string>
@ -59,7 +59,7 @@
<string name="login_contact_discord">Discord</string> <string name="login_contact_discord">Discord</string>
<string name="login_email_intent_title">Отправить письмо</string> <string name="login_email_intent_title">Отправить письмо</string>
<string name="login_email_details">Опишите детали проблемы:</string> <string name="login_email_details">Опишите детали проблемы:</string>
<string name="login_recover_warning">Убедитесь, что выбран нужный дневник!</string> <string name="login_recover_warning">Убедитесь, что вы выбрали правильный вариант регистра UONET+!</string>
<string name="login_recover_button">Забыли пароль?</string> <string name="login_recover_button">Забыли пароль?</string>
<string name="login_recover_title">Восстановите свой аккаунт</string> <string name="login_recover_title">Восстановите свой аккаунт</string>
<string name="login_recover">Восстановить</string> <string name="login_recover">Восстановить</string>
@ -326,6 +326,9 @@
<string name="teachers_title">Учителя</string> <string name="teachers_title">Учителя</string>
<string name="teacher_no_items">Нет информации о учителях</string> <string name="teacher_no_items">Нет информации о учителях</string>
<string name="teacher_no_subject">Нет предмета</string> <string name="teacher_no_subject">Нет предмета</string>
<!--Conference-->
<string name="conferences_title">Встречи</string>
<string name="conference_no_items">Нет информации о встречах</string>
<!--Account--> <!--Account-->
<string name="account_add_new">Добавить аккаунт</string> <string name="account_add_new">Добавить аккаунт</string>
<string name="account_logout">Выйти</string> <string name="account_logout">Выйти</string>
@ -345,6 +348,8 @@
<string name="about_faq_summary">Часто задаваемые вопросы</string> <string name="about_faq_summary">Часто задаваемые вопросы</string>
<string name="about_discord">Сервер Discord</string> <string name="about_discord">Сервер Discord</string>
<string name="about_discord_summary">Присоединиться к сообществу приложения</string> <string name="about_discord_summary">Присоединиться к сообществу приложения</string>
<string name="about_facebook">Facebook фан-страница</string>
<string name="about_facebook_summary">Поставьте лайк на нашей странице в Facebook</string>
<string name="about_privacy">Политика приватности</string> <string name="about_privacy">Политика приватности</string>
<string name="about_privacy_summary">Правила хранения личных данных</string> <string name="about_privacy_summary">Правила хранения личных данных</string>
<string name="about_homepage">Домашняя страница</string> <string name="about_homepage">Домашняя страница</string>
@ -446,18 +451,18 @@
<string name="all_copied">Скопировано</string> <string name="all_copied">Скопировано</string>
<string name="all_undo">Отменить</string> <string name="all_undo">Отменить</string>
<!--Update helper--> <!--Update helper-->
<string name="update_download_started">Download of updates has started</string> <string name="update_download_started">Загрузка обновлений началась</string>
<string name="update_download_success">An update has just been downloaded.</string> <string name="update_download_success">Только что было скачано обновление.</string>
<string name="update_download_success_button">Restart</string> <string name="update_download_success_button">Перезапустить</string>
<string name="update_failed">Update failed! Wulkanowy may not function properly. Consider updating</string> <string name="update_failed">Не удалось обновить! Wulkanowy может работать некорректно. Рассмотрите возможность обновления</string>
<!--Errors--> <!--Errors-->
<string name="error_no_internet">Нет интернет-подключения</string> <string name="error_no_internet">Нет интернет-подключения</string>
<string name="error_timeout">Слишком долгое ожидание соединения с дневником</string> <string name="error_timeout">Не удалось подключиться к регистрации. Серверы могут быть перегружены. Пожалуйста, повторите попытку позже</string>
<string name="error_login_failed">Login failed. Try again</string> <string name="error_login_failed">Не удалось загрузить данные. Пожалуйста, повторите попытку позже</string>
<string name="error_password_change_required">Требуется смена пароля</string> <string name="error_password_change_required">Необходимо изменить пароль реестра</string>
<string name="error_service_unavailable">Технический перерыв в журнале UONET + продолжается. Попробуйте позже</string> <string name="error_service_unavailable">Технический перерыв в журнале UONET + продолжается. Попробуйте позже</string>
<string name="error_unknown_uonet">Unknown UONET + register error. Try again later</string> <string name="error_unknown_uonet">Неизвестная ошибка UONET + регистр. Попробуйте позже</string>
<string name="error_unknown_app">Unknown application error</string> <string name="error_unknown_app">Неизвестная ошибка приложения. Пожалуйста, повторите попытку позже</string>
<string name="error_unknown">Произошла неожиданная ошибка</string> <string name="error_unknown">Произошла неожиданная ошибка</string>
<string name="error_feature_disabled">Функция была выключена школой</string> <string name="error_feature_disabled">Функция была выключена школой</string>
<string name="error_feature_not_available">Функция не доступна в этом режиме</string> <string name="error_feature_not_available">Функция не доступна в этом режиме</string>

View File

@ -31,8 +31,8 @@
<item>0,75</item> <item>0,75</item>
</string-array> </string-array>
<string-array name="grade_sorting_mode_entries"> <string-array name="grade_sorting_mode_entries">
<item>Alphabetic</item> <item>За алфавітом</item>
<item>By date</item> <item>За датою</item>
</string-array> </string-array>
<string-array name="grade_color_scheme_entries"> <string-array name="grade_color_scheme_entries">
<item>Dzienniczek+</item> <item>Dzienniczek+</item>
@ -41,8 +41,8 @@
</string-array> </string-array>
<string-array name="grade_average_mode_entries"> <string-array name="grade_average_mode_entries">
<item>Середня оцінка з 2 семестру</item> <item>Середня оцінка з 2 семестру</item>
<item>Average of grades from both semesters</item> <item>Середнє оцінювання за обидва семестри</item>
<item>Average of grades from the whole year</item> <item>Середнє оцінювання за весь рік</item>
</string-array> </string-array>
<string-array name="timetable_show_whole_class_entries"> <string-array name="timetable_show_whole_class_entries">
<item>Не показувати</item> <item>Не показувати</item>

View File

@ -22,12 +22,12 @@
<string name="grade_subtitle">%1$d семестр, %2$d/%3$d</string> <string name="grade_subtitle">%1$d семестр, %2$d/%3$d</string>
<!--Login--> <!--Login-->
<string name="login_header_default">Авторизуйтеся за допомогою аккаунта учня або батька</string> <string name="login_header_default">Авторизуйтеся за допомогою аккаунта учня або батька</string>
<string name="login_header_symbol">Впишіть \"symbol\"</string> <string name="login_header_symbol">Введіть символ зі сторінки реєстру</string>
<string name="login_nickname_hint">Ім\'я користувача</string> <string name="login_nickname_hint">Ім\'я користувача</string>
<string name="login_email_hint">Електронна пошта</string> <string name="login_email_hint">Електронна пошта</string>
<string name="login_login_pesel_email_hint">Логін, PESEL або електронна пошта</string> <string name="login_login_pesel_email_hint">Логін, PESEL або електронна пошта</string>
<string name="login_password_hint">Пароль</string> <string name="login_password_hint">Пароль</string>
<string name="login_host_hint">Щоденник</string> <string name="login_host_hint">UONET + варіант реєстрації</string>
<string name="login_type_api">Мobile API</string> <string name="login_type_api">Мobile API</string>
<string name="login_type_scrapper">Scraper</string> <string name="login_type_scrapper">Scraper</string>
<string name="login_type_hybrid">Hybrid</string> <string name="login_type_hybrid">Hybrid</string>
@ -37,17 +37,17 @@
<string name="login_symbol_hint">Symbol</string> <string name="login_symbol_hint">Symbol</string>
<string name="login_sign_in">Увійти</string> <string name="login_sign_in">Увійти</string>
<string name="login_invalid_password">Занадто короткий пароль</string> <string name="login_invalid_password">Занадто короткий пароль</string>
<string name="login_incorrect_password">Вказані невірні дані. Впевніться, що ви увібрали потрібний щоденник</string> <string name="login_incorrect_password">Дані для входу неправильні. Переконайтеся, що у полі нижче вказано правильний варіант реєстрації UONET+</string>
<string name="login_invalid_pin">Неправильний PIN</string> <string name="login_invalid_pin">Неправильний PIN</string>
<string name="login_invalid_token">Неправильний token</string> <string name="login_invalid_token">Неправильний token</string>
<string name="login_expired_token">Минув термін дії токену</string> <string name="login_expired_token">Минув термін дії токену</string>
<string name="login_invalid_email">Недійсна адреса електронної пошти</string> <string name="login_invalid_email">Недійсна адреса електронної пошти</string>
<string name="login_invalid_login">Неправильний логін</string> <string name="login_invalid_login">Використовуйте призначений логін замість електронної пошти</string>
<string name="login_invalid_symbol">Неправильний symbol</string> <string name="login_invalid_symbol">Неправильний symbol</string>
<string name="login_incorrect_symbol">Не вдалося знайти учня. Будь ласка, перевірте \"symbol\"</string> <string name="login_incorrect_symbol">Студента не знайдено Перевірте символ та обраний варіант реєстру UONET+</string>
<string name="login_field_required">Обов\'язкове поле</string> <string name="login_field_required">Обов\'язкове поле</string>
<string name="login_duplicate_student">Даного учня вже авторизовано</string> <string name="login_duplicate_student">Даного учня вже авторизовано</string>
<string name="login_symbol_helper">Ви можете знайти \"symbol\" на сторінцi VULCAN стежкою <b>Uczeń</b> →&#160;<b>Dostęp Mobilny</b>&#160;<b>Zarejestruj urządzenie mobilne</b></string> <string name="login_symbol_helper">Символ можна знайти на сторінці реєстру в &#160; <b> Uczeń </b>&#160; <b> Dostęp Mobilny </b>&#160; <b> Zarejestruj urządzenie mobilne </b>.\n\nПереконайтесь, що ви встановили відповідний варіант реєстру в полі <b> UONET + варіант реєстрації </b> на попередньому екрані. На даний момент Wulkanowy не виявляє учнів дошкільних закладів</string>
<string name="login_select_student">Виберіть учнів для авторизації в додатку</string> <string name="login_select_student">Виберіть учнів для авторизації в додатку</string>
<string name="login_advanced">Інші варіанти</string> <string name="login_advanced">Інші варіанти</string>
<string name="login_advanced_warning_mobile_api">У цьому режимі не працюють: щасливий номер, статистика класу по оцінкам, статистика відвідуваності і уроків, інформація про школу і список зареєстрованних пристроїв</string> <string name="login_advanced_warning_mobile_api">У цьому режимі не працюють: щасливий номер, статистика класу по оцінкам, статистика відвідуваності і уроків, інформація про школу і список зареєстрованних пристроїв</string>
@ -59,7 +59,7 @@
<string name="login_contact_discord">Discord</string> <string name="login_contact_discord">Discord</string>
<string name="login_email_intent_title">Відправити лист</string> <string name="login_email_intent_title">Відправити лист</string>
<string name="login_email_details">Опишіть деталі помилки:</string> <string name="login_email_details">Опишіть деталі помилки:</string>
<string name="login_recover_warning">Переконайтесь, що обрано потрібний щоденник!</string> <string name="login_recover_warning">Переконайтеся, що ви вибрали правильний варіант реєстрації UONET+!</string>
<string name="login_recover_button">Забули пароль?</string> <string name="login_recover_button">Забули пароль?</string>
<string name="login_recover_title">Відновіть свій аккаунт</string> <string name="login_recover_title">Відновіть свій аккаунт</string>
<string name="login_recover">Відновити</string> <string name="login_recover">Відновити</string>
@ -108,16 +108,16 @@
<item quantity="other">Нові оцінки</item> <item quantity="other">Нові оцінки</item>
</plurals> </plurals>
<plurals name="grade_new_items_predicted"> <plurals name="grade_new_items_predicted">
<item quantity="one">New predicted grade</item> <item quantity="one">Нова прогнозована оцінка</item>
<item quantity="few">New predicted grades</item> <item quantity="few">Нові прогнозовані оцінки</item>
<item quantity="many">New predicted grades</item> <item quantity="many">Нові прогнозовані оцінки</item>
<item quantity="other">New predicted grades</item> <item quantity="other">Нові прогнозовані оцінки</item>
</plurals> </plurals>
<plurals name="grade_new_items_final"> <plurals name="grade_new_items_final">
<item quantity="one">New final grade</item> <item quantity="one">Нова підсумкова оцінка</item>
<item quantity="few">New final grades</item> <item quantity="few">Нові підсумкові оцінки</item>
<item quantity="many">New final grades</item> <item quantity="many">Нові підсумкові оцінки</item>
<item quantity="other">New final grades</item> <item quantity="other">Нові підсумкові оцінки</item>
</plurals> </plurals>
<plurals name="grade_notify_new_items"> <plurals name="grade_notify_new_items">
<item quantity="one">Ви отримали %1$d оцінку</item> <item quantity="one">Ви отримали %1$d оцінку</item>
@ -126,16 +126,16 @@
<item quantity="other">Ви отримали %1$d оцінок</item> <item quantity="other">Ви отримали %1$d оцінок</item>
</plurals> </plurals>
<plurals name="grade_notify_new_items_predicted"> <plurals name="grade_notify_new_items_predicted">
<item quantity="one">You received %1$d predicted grade</item> <item quantity="one">Ви отримали %1$d нову прогнозовану оцінку</item>
<item quantity="few">You received %1$d predicted grades</item> <item quantity="few">Ви отримали %1$d нові прогнозовані оцінки</item>
<item quantity="many">You received %1$d predicted grades</item> <item quantity="many">Ви отримали %1$d нових прогнозованих оцінок</item>
<item quantity="other">You received %1$d predicted grades</item> <item quantity="other">Ви отримали %1$d нових прогнозованих оцінок</item>
</plurals> </plurals>
<plurals name="grade_notify_new_items_final"> <plurals name="grade_notify_new_items_final">
<item quantity="one">You received %1$d final grade</item> <item quantity="one">Ви отримали %1$d нову підсумкову оцінку</item>
<item quantity="few">You received %1$d final grades</item> <item quantity="few">Ви отримали %1$d нові підсумкові оцінки</item>
<item quantity="many">You received %1$d final grades</item> <item quantity="many">Ви отримали %1$d нових підсумкових оцінок</item>
<item quantity="other">You received %1$d final grades</item> <item quantity="other">Ви отримали %1$d нових підсумкових оцінок</item>
</plurals> </plurals>
<!--Timetable--> <!--Timetable-->
<string name="timetable_lesson">Урок</string> <string name="timetable_lesson">Урок</string>
@ -168,8 +168,8 @@
<string name="attendance_excused_lateness">Спізнення з поважних причин</string> <string name="attendance_excused_lateness">Спізнення з поважних причин</string>
<string name="attendance_unexcused_lateness">Спізнення з не поважних причин</string> <string name="attendance_unexcused_lateness">Спізнення з не поважних причин</string>
<string name="attendance_present">Присутність</string> <string name="attendance_present">Присутність</string>
<string name="attendance_deleted">Deleted</string> <string name="attendance_deleted">Вилучено</string>
<string name="attendance_unknown">Unknown</string> <string name="attendance_unknown">Невідомо</string>
<string name="attendance_number">Номер уроку</string> <string name="attendance_number">Номер уроку</string>
<string name="attendance_no_items">Брак записів</string> <string name="attendance_no_items">Брак записів</string>
<plurals name="attendance_number_absences"> <plurals name="attendance_number_absences">
@ -206,8 +206,8 @@
<string name="message_move_to_bin">Перемістити у кошик</string> <string name="message_move_to_bin">Перемістити у кошик</string>
<string name="message_delete_forever">Видалити назавжди</string> <string name="message_delete_forever">Видалити назавжди</string>
<string name="message_delete_success">Повідомлення було успішно видалено</string> <string name="message_delete_success">Повідомлення було успішно видалено</string>
<string name="message_share">Share</string> <string name="message_share">Поділіться</string>
<string name="message_print">Print</string> <string name="message_print">Друк</string>
<string name="message_subject">Тема</string> <string name="message_subject">Тема</string>
<string name="message_content">Зміст</string> <string name="message_content">Зміст</string>
<string name="message_send_successful">Повідомлення було успішно відправлено</string> <string name="message_send_successful">Повідомлення було успішно відправлено</string>
@ -254,41 +254,41 @@
</plurals> </plurals>
<!--Praise--> <!--Praise-->
<plurals name="praise_number_item"> <plurals name="praise_number_item">
<item quantity="one">%d praise</item> <item quantity="one">%d похвалили</item>
<item quantity="few">%d praises</item> <item quantity="few">%d похвали</item>
<item quantity="many">%d praises</item> <item quantity="many">%d похвал</item>
<item quantity="other">%d praises</item> <item quantity="other">%d похвал</item>
</plurals> </plurals>
<plurals name="praise_new_items"> <plurals name="praise_new_items">
<item quantity="one">New praise</item> <item quantity="one">Нова похвала</item>
<item quantity="few">New praises</item> <item quantity="few">Нові похвали</item>
<item quantity="many">New praises</item> <item quantity="many">Нові похвали</item>
<item quantity="other">New praises</item> <item quantity="other">Нові похвали</item>
</plurals> </plurals>
<plurals name="praise_notify_new_items"> <plurals name="praise_notify_new_items">
<item quantity="one">You received %1$d praise</item> <item quantity="one">Ви отримали %1$d нову похвалу</item>
<item quantity="few">You received %1$d praises</item> <item quantity="few">Ви отримали %1$d нові похвали</item>
<item quantity="many">You received %1$d praises</item> <item quantity="many">Ви отримали %1$d нових похвал</item>
<item quantity="other">You received %1$d praises</item> <item quantity="other">Ви отримали %1$d нових похвал</item>
</plurals> </plurals>
<!--Neutral notes--> <!--Neutral notes-->
<plurals name="neutral_note_number_item"> <plurals name="neutral_note_number_item">
<item quantity="one">%d neutral note</item> <item quantity="one">%d нейтральна нота</item>
<item quantity="few">%d neutral notes</item> <item quantity="few">%d нейтральні ноти</item>
<item quantity="many">%d neutral notes</item> <item quantity="many">%d нейтральних нот</item>
<item quantity="other">%d neutral notes</item> <item quantity="other">%d нейтральних нот</item>
</plurals> </plurals>
<plurals name="neutral_note_new_items"> <plurals name="neutral_note_new_items">
<item quantity="one">New neutral note</item> <item quantity="one">Нова нейтральна нота</item>
<item quantity="few">New neutral notes</item> <item quantity="few">Нова нейтральна нота</item>
<item quantity="many">New neutral notes</item> <item quantity="many">Нова нейтральна нота</item>
<item quantity="other">New neutral notes</item> <item quantity="other">Нові нейтральні ноти</item>
</plurals> </plurals>
<plurals name="neutral_note_notify_new_items"> <plurals name="neutral_note_notify_new_items">
<item quantity="one">You received %1$d neutral note</item> <item quantity="one">Ви отримали %1$d нову нейтральну ноту</item>
<item quantity="few">You received %1$d neutral notes</item> <item quantity="few">Ви отримали %1$d нові нейтральні ноти</item>
<item quantity="many">You received %1$d neutral notes</item> <item quantity="many">Ви отримали %1$d нових нейтральних нот</item>
<item quantity="other">You received %1$d neutral notes</item> <item quantity="other">Ви отримали %1$d нових нейтральних нот</item>
</plurals> </plurals>
<!--Homework--> <!--Homework-->
<string name="homework_no_items">Брак домашніх завдань</string> <string name="homework_no_items">Брак домашніх завдань</string>
@ -326,15 +326,18 @@
<string name="teachers_title">Вчителі</string> <string name="teachers_title">Вчителі</string>
<string name="teacher_no_items">Брак інформації про вчителів</string> <string name="teacher_no_items">Брак інформації про вчителів</string>
<string name="teacher_no_subject">Брак предмету</string> <string name="teacher_no_subject">Брак предмету</string>
<!--Conference-->
<string name="conferences_title">Зустрічі</string>
<string name="conference_no_items">Немає інформації про зустрічі</string>
<!--Account--> <!--Account-->
<string name="account_add_new">Додати аккаунт</string> <string name="account_add_new">Додати аккаунт</string>
<string name="account_logout">Вийти</string> <string name="account_logout">Вийти</string>
<string name="account_confirm">Ви впевнені, що хочете вийти з цього аккаунту?</string> <string name="account_confirm">Ви впевнені, що хочете вийти з цього аккаунту?</string>
<string name="account_logout_student">Вийти з аккаунту учня</string> <string name="account_logout_student">Вийти з аккаунту учня</string>
<string name="account_type_student">Student account</string> <string name="account_type_student">Студентський рахунок</string>
<string name="account_type_parent">Parent account</string> <string name="account_type_parent">Головний рахунок</string>
<string name="account_login_mobile_api">Mobile API mode</string> <string name="account_login_mobile_api">Режим мобільного API</string>
<string name="account_login_hybrid">Hybrid mode</string> <string name="account_login_hybrid">Гібридний режим</string>
<!--About--> <!--About-->
<string name="about_version">Версія додатка</string> <string name="about_version">Версія додатка</string>
<string name="about_contributor">Розробники</string> <string name="about_contributor">Розробники</string>
@ -345,6 +348,8 @@
<string name="about_faq_summary">Запитання, які часто задають</string> <string name="about_faq_summary">Запитання, які часто задають</string>
<string name="about_discord">Сервер Discord</string> <string name="about_discord">Сервер Discord</string>
<string name="about_discord_summary">Приєднатися до спільноти додатка</string> <string name="about_discord_summary">Приєднатися до спільноти додатка</string>
<string name="about_facebook">Фен-сторінка Facebook</string>
<string name="about_facebook_summary">Вподобати нашу фансторінку у Facebook</string>
<string name="about_privacy">Політика конфіденційності</string> <string name="about_privacy">Політика конфіденційності</string>
<string name="about_privacy_summary">Правила зберігання особистих даних</string> <string name="about_privacy_summary">Правила зберігання особистих даних</string>
<string name="about_homepage">Домашня сторінка</string> <string name="about_homepage">Домашня сторінка</string>
@ -395,12 +400,12 @@
<string name="pref_view_app_theme">Тема додатку</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_timers">Позначити поточний урок у розкладі</string>
<string name="pref_view_timetable_show_groups">Show groups next to subjects in timetable</string> <string name="pref_view_timetable_show_groups">Покажіть групи поруч із предметами в розкладі</string>
<string name="pref_view_grade_statistics_list">Показувати діаграми в оцінках класу</string> <string name="pref_view_grade_statistics_list">Показувати діаграми в оцінках класу</string>
<string name="pref_view_timetable_show_whole_class">Показати уроки всього класу</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_subjects_without_grades">Показуйте предмети без оцінок у оцінках</string>
<string name="pref_view_grade_color_scheme">Схема кольорів оцінок</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_grade_sorting_mode">Сортування предметів за \"Оцінками\"</string>
<string name="pref_view_app_language">Мова додатку</string> <string name="pref_view_app_language">Мова додатку</string>
<string name="pref_notify_header">Повідомлення</string> <string name="pref_notify_header">Повідомлення</string>
<string name="pref_notify_switch">Показувати повідомлення</string> <string name="pref_notify_switch">Показувати повідомлення</string>
@ -446,18 +451,18 @@
<string name="all_copied">Скопійовано</string> <string name="all_copied">Скопійовано</string>
<string name="all_undo">Відмінити</string> <string name="all_undo">Відмінити</string>
<!--Update helper--> <!--Update helper-->
<string name="update_download_started">Download of updates has started</string> <string name="update_download_started">Завантаження оновлень розпочато</string>
<string name="update_download_success">An update has just been downloaded.</string> <string name="update_download_success">Щойно завантажено оновлення.</string>
<string name="update_download_success_button">Restart</string> <string name="update_download_success_button">Перезапустити</string>
<string name="update_failed">Update failed! Wulkanowy may not function properly. Consider updating</string> <string name="update_failed">Помилка оновлення! Wulkanowy може не працювати належним чином. Подумайте про оновлення</string>
<!--Errors--> <!--Errors-->
<string name="error_no_internet">Брак з\'єднання з інтернетом</string> <string name="error_no_internet">Брак з\'єднання з інтернетом</string>
<string name="error_timeout">Занадто довге очікування з\'єднання з щоденником</string> <string name="error_timeout">Помилка підключення до реєстрації. Сервери можуть бути перевантажені. Будь-ласка спробуйте пізніше</string>
<string name="error_login_failed">Login failed. Try again</string> <string name="error_login_failed">Помилка завантаження даних. Будь-ласка спробуйте пізніше</string>
<string name="error_password_change_required">Потрібно змінити пароль</string> <string name="error_password_change_required">Потрібна реєстрація зміни пароля</string>
<string name="error_service_unavailable">Технічна перерва в журналі UONET + продовжується. Спробуйте пізніше</string> <string name="error_service_unavailable">Технічна перерва в журналі UONET + продовжується. Спробуйте пізніше</string>
<string name="error_unknown_uonet">Unknown UONET + register error. Try again later</string> <string name="error_unknown_uonet">Невідома помилка реєстру UONET+. Спробуйте ще раз пізніше</string>
<string name="error_unknown_app">Unknown application error</string> <string name="error_unknown_app">Невідома помилка програми. Будь-ласка спробуйте пізніше</string>
<string name="error_unknown">Відбулася несподівана помилка</string> <string name="error_unknown">Відбулася несподівана помилка</string>
<string name="error_feature_disabled">Функція вимкнена школою</string> <string name="error_feature_disabled">Функція вимкнена школою</string>
<string name="error_feature_not_available">Функція не доступна в цьому режимі</string> <string name="error_feature_not_available">Функція не доступна в цьому режимі</string>

View File

@ -22,25 +22,25 @@
<item>Fakelog</item> <item>Fakelog</item>
</string-array> </string-array>
<string-array name="hosts_values"> <string-array name="hosts_values">
<item>https://vulcan.net.pl/?standard</item> <item>https://vulcan.net.pl/?email</item>
<item>https://eszkola.opolskie.pl</item> <item>https://eszkola.opolskie.pl</item>
<item>https://edu.gdansk.pl</item> <item>https://edu.gdansk.pl</item>
<item>https://edu.lublin.eu</item> <item>https://edu.lublin.eu</item>
<item>https://umt.tarnow.pl</item> <item>https://umt.tarnow.pl</item>
<item>https://resman.pl</item> <item>https://resman.pl</item>
<item>https://eduportal.koszalin.pl</item> <item>https://eduportal.koszalin.pl</item>
<item>https://vulcan.net.pl/</item> <item>https://vulcan.net.pl/?login</item>
<item>https://vulcan.net.pl/</item> <item>https://vulcan.net.pl/?login</item>
<item>https://vulcan.net.pl/</item> <item>https://vulcan.net.pl/?login</item>
<item>https://vulcan.net.pl/</item> <item>https://vulcan.net.pl/?login</item>
<item>https://vulcan.net.pl/</item> <item>https://vulcan.net.pl/?login</item>
<item>https://vulcan.net.pl/</item> <item>https://vulcan.net.pl/?login</item>
<item>https://vulcan.net.pl/</item> <item>https://vulcan.net.pl/?login</item>
<item>https://vulcan.net.pl/</item> <item>https://vulcan.net.pl/?login</item>
<item>https://vulcan.net.pl/</item> <item>https://vulcan.net.pl/?login</item>
<item>https://vulcan.net.pl/</item> <item>https://vulcan.net.pl/?login</item>
<item>https://vulcan.net.pl/</item> <item>https://vulcan.net.pl/?login</item>
<item>http://fakelog.tk/?standard</item> <item>http://fakelog.cf/?email</item>
</string-array> </string-array>
<string-array name="hosts_symbols"> <string-array name="hosts_symbols">
<item>Default</item> <item>Default</item>

View File

@ -78,7 +78,7 @@
</string-array> </string-array>
<string-array name="grade_sorting_mode_entries"> <string-array name="grade_sorting_mode_entries">
<item>Alphabetic</item> <item>Alphabetically</item>
<item>By date</item> <item>By date</item>
</string-array> </string-array>
<string-array name="grade_sorting_mode_values" translatable="false"> <string-array name="grade_sorting_mode_values" translatable="false">

View File

@ -26,12 +26,12 @@
<!--Login--> <!--Login-->
<string name="login_header_default">Sign in with the student or parent account</string> <string name="login_header_default">Sign in with the student or parent account</string>
<string name="login_header_symbol">Enter the symbol</string> <string name="login_header_symbol">Enter the symbol from the register page</string>
<string name="login_nickname_hint">Username</string> <string name="login_nickname_hint">Username</string>
<string name="login_email_hint">Email</string> <string name="login_email_hint">Email</string>
<string name="login_login_pesel_email_hint">Login, PESEL or e-mail</string> <string name="login_login_pesel_email_hint">Login, PESEL or e-mail</string>
<string name="login_password_hint">Password</string> <string name="login_password_hint">Password</string>
<string name="login_host_hint">UONET+ Register</string> <string name="login_host_hint">UONET+ register variant</string>
<string name="login_type_api">Mobile API</string> <string name="login_type_api">Mobile API</string>
<string name="login_type_scrapper">Scraper</string> <string name="login_type_scrapper">Scraper</string>
<string name="login_type_hybrid">Hybrid</string> <string name="login_type_hybrid">Hybrid</string>
@ -41,17 +41,17 @@
<string name="login_symbol_hint">Symbol</string> <string name="login_symbol_hint">Symbol</string>
<string name="login_sign_in">Sign in</string> <string name="login_sign_in">Sign in</string>
<string name="login_invalid_password">Password too short</string> <string name="login_invalid_password">Password too short</string>
<string name="login_incorrect_password">Login details are incorrect. Make sure the correct UONET+ register is selected</string> <string name="login_incorrect_password">Login details are incorrect. Make sure the correct UONET+ register variation is selected in the field below</string>
<string name="login_invalid_pin">Invalid PIN</string> <string name="login_invalid_pin">Invalid PIN</string>
<string name="login_invalid_token">Invalid token</string> <string name="login_invalid_token">Invalid token</string>
<string name="login_expired_token">Token expired</string> <string name="login_expired_token">Token expired</string>
<string name="login_invalid_email">Invalid email</string> <string name="login_invalid_email">Invalid email</string>
<string name="login_invalid_login">Invalid login</string> <string name="login_invalid_login">Use the assigned login instead of email</string>
<string name="login_invalid_symbol">Invalid symbol</string> <string name="login_invalid_symbol">Invalid symbol</string>
<string name="login_incorrect_symbol">Student not found. Check the symbol</string> <string name="login_incorrect_symbol">Student not found. Validate the symbol and the chosen variation of the UONET+ register</string>
<string name="login_field_required">This field is required</string> <string name="login_field_required">This field is required</string>
<string name="login_duplicate_student">Selected student is already logged in</string> <string name="login_duplicate_student">Selected student is already logged in</string>
<string name="login_symbol_helper">The symbol can be found on the register page in&#160;<b>Uczeń</b> →&#160;<b>Dostęp Mobilny</b>&#160;<b>Zarejestruj urządzenie mobilne</b></string> <string name="login_symbol_helper">The symbol can be found on the register page in&#160;<b>Uczeń</b> →&#160;<b>Dostęp Mobilny</b>&#160;<b>Zarejestruj urządzenie mobilne</b>.\n\nMake sure that you have set the appropriate register variant in the <b>UONET+ register variant</b> field on the previous screen. Wulkanowy does not detect pre-school students at the moment</string>
<string name="login_select_student">Select students to log in to the application</string> <string name="login_select_student">Select students to log in to the application</string>
<string name="login_advanced">Other options</string> <string name="login_advanced">Other options</string>
<string name="login_advanced_warning_mobile_api">In this mode, a lucky number does not work, a class grade stats, summary of attendance, excuse for absence, completed lessons, school information and preview of the list of registered devices</string> <string name="login_advanced_warning_mobile_api">In this mode, a lucky number does not work, a class grade stats, summary of attendance, excuse for absence, completed lessons, school information and preview of the list of registered devices</string>
@ -65,7 +65,7 @@
<string name="login_email_details">Describe details of problem:</string> <string name="login_email_details">Describe details of problem:</string>
<string name="login_email_subject" translatable="false">Zgłoszenie: Problemy z logowaniem</string> <string name="login_email_subject" translatable="false">Zgłoszenie: Problemy z logowaniem</string>
<string name="login_email_text" translatable="false">Informacje o aplikacji:\n\nUrządzenie: %1$s\nWersja SDK: %2$s\nWersja aplikacji: %3$s\nDodatkowe informacje: %4$s\nOstatni błąd: %5$s\n\nOpis problemu: </string> <string name="login_email_text" translatable="false">Informacje o aplikacji:\n\nUrządzenie: %1$s\nWersja SDK: %2$s\nWersja aplikacji: %3$s\nDodatkowe informacje: %4$s\nOstatni błąd: %5$s\n\nOpis problemu: </string>
<string name="login_recover_warning">Make sure the correct UONET+ register is selected!</string> <string name="login_recover_warning">Make sure you select the correct UONET+ register variation!</string>
<string name="login_recover_button">I forgot my password</string> <string name="login_recover_button">I forgot my password</string>
<string name="login_recover_title">Recover your account</string> <string name="login_recover_title">Recover your account</string>
<string name="login_recover">Recover</string> <string name="login_recover">Recover</string>
@ -325,6 +325,11 @@
<string name="teacher_no_subject">No subject</string> <string name="teacher_no_subject">No subject</string>
<!--Conference-->
<string name="conferences_title">Conferences</string>
<string name="conference_no_items">No info about conferences</string>
<!--Account--> <!--Account-->
<string name="account_add_new">Add account</string> <string name="account_add_new">Add account</string>
<string name="account_logout">Logout</string> <string name="account_logout">Logout</string>
@ -346,6 +351,8 @@
<string name="about_faq_summary">Read Frequently Asked Questions</string> <string name="about_faq_summary">Read Frequently Asked Questions</string>
<string name="about_discord">Discord server</string> <string name="about_discord">Discord server</string>
<string name="about_discord_summary">Join the Wulkanowy community</string> <string name="about_discord_summary">Join the Wulkanowy community</string>
<string name="about_facebook">Facebook fanpage</string>
<string name="about_facebook_summary">Like our facebook fanpage</string>
<string name="about_privacy">Privacy policy</string> <string name="about_privacy">Privacy policy</string>
<string name="about_privacy_summary">Rules for collecting personal data</string> <string name="about_privacy_summary">Rules for collecting personal data</string>
<string name="about_homepage">Homepage</string> <string name="about_homepage">Homepage</string>
@ -481,12 +488,12 @@
<!--Errors--> <!--Errors-->
<string name="error_no_internet">No internet connection</string> <string name="error_no_internet">No internet connection</string>
<string name="error_timeout">Connection to the register timed out</string> <string name="error_timeout">Connection to register failed. Servers can be overloaded. Please try again later</string>
<string name="error_login_failed">Login failed. Try again</string> <string name="error_login_failed">Loading data failed. Please try again later</string>
<string name="error_password_change_required">Password change required</string> <string name="error_password_change_required">Register password change required</string>
<string name="error_service_unavailable">Maintenance underway UONET + register. Try again later</string> <string name="error_service_unavailable">Maintenance underway UONET + register. Try again later</string>
<string name="error_unknown_uonet">Unknown UONET + register error. Try again later</string> <string name="error_unknown_uonet">Unknown UONET + register error. Try again later</string>
<string name="error_unknown_app">Unknown application error</string> <string name="error_unknown_app">Unknown application error. Please try again later</string>
<string name="error_unknown">An unexpected error occurred</string> <string name="error_unknown">An unexpected error occurred</string>
<string name="error_feature_disabled">Feature disabled by your school</string> <string name="error_feature_disabled">Feature disabled by your school</string>
<string name="error_feature_not_available">Feature not available. Login in a mode other than Mobile API</string> <string name="error_feature_not_available">Feature not available. Login in a mode other than Mobile API</string>

View File

@ -35,4 +35,8 @@ class AnalyticsHelper @Inject constructor(
putString(FirebaseAnalytics.Param.SCREEN_CLASS, activity::class.simpleName) putString(FirebaseAnalytics.Param.SCREEN_CLASS, activity::class.simpleName)
}) })
} }
@Suppress("UNUSED_PARAMETER")
fun popCurrentScreen(name: String?) {
}
} }

View File

@ -4,7 +4,8 @@ import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.getStudentEntity import io.github.wulkanowy.getStudentEntity
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.sdk.pojo.GradePointsStatistics import io.github.wulkanowy.sdk.pojo.GradePointsStatistics
import io.github.wulkanowy.sdk.pojo.GradeStatistics import io.github.wulkanowy.sdk.pojo.GradeStatisticsItem
import io.github.wulkanowy.sdk.pojo.GradeStatisticsSubject
import io.github.wulkanowy.utils.init import io.github.wulkanowy.utils.init
import io.mockk.MockKAnnotations import io.mockk.MockKAnnotations
import io.mockk.coEvery import io.mockk.coEvery
@ -35,8 +36,8 @@ class GradeStatisticsRemoteTest {
@Test @Test
fun getGradeStatisticsTest() { fun getGradeStatisticsTest() {
coEvery { mockSdk.getGradesPartialStatistics(1) } returns listOf( coEvery { mockSdk.getGradesPartialStatistics(1) } returns listOf(
getGradeStatistics("Fizyka"), getGradeStatisticsPartialSubject("Fizyka"),
getGradeStatistics("Matematyka") getGradeStatisticsPartialSubject("Matematyka")
) )
every { semesterMock.studentId } returns 1 every { semesterMock.studentId } returns 1
@ -45,7 +46,7 @@ class GradeStatisticsRemoteTest {
every { semesterMock.semesterId } returns 1 every { semesterMock.semesterId } returns 1
every { mockSdk.switchDiary(any(), any()) } returns mockSdk every { mockSdk.switchDiary(any(), any()) } returns mockSdk
val stats = runBlocking { GradeStatisticsRemote(mockSdk).getGradeStatistics(student, semesterMock, false) } val stats = runBlocking { GradeStatisticsRemote(mockSdk).getGradePartialStatistics(student, semesterMock) }
assertEquals(2, stats.size) assertEquals(2, stats.size)
} }
@ -66,19 +67,24 @@ class GradeStatisticsRemoteTest {
assertEquals(2, stats.size) assertEquals(2, stats.size)
} }
private fun getGradeStatistics(subjectName: String): GradeStatistics { private fun getGradeStatisticsPartialSubject(subjectName: String): GradeStatisticsSubject {
return GradeStatistics( return GradeStatisticsSubject(
subject = subjectName, subject = subjectName,
gradeValue = 5, studentAverage = "",
amount = 10, classAverage = "",
grade = "", classItems = listOf(
semesterId = 1 GradeStatisticsItem(
subject = subjectName,
grade = 0,
amount = 0
)
),
studentItems = listOf()
) )
} }
private fun getGradePointsStatistics(subjectName: String): GradePointsStatistics { private fun getGradePointsStatistics(subjectName: String): GradePointsStatistics {
return GradePointsStatistics( return GradePointsStatistics(
semesterId = 1,
subject = subjectName, subject = subjectName,
student = 0.80, student = 0.80,
others = 0.40 others = 0.40

View File

@ -39,10 +39,10 @@ class TimetableRemoteTest {
of(2018, 9, 10), of(2018, 9, 10),
of(2018, 9, 15) of(2018, 9, 15)
) )
} returns listOf( } returns (listOf(
getTimetable(of(2018, 9, 10)), getTimetable(of(2018, 9, 10)),
getTimetable(of(2018, 9, 17)) getTimetable(of(2018, 9, 17))
) ) to emptyList())
every { semesterMock.studentId } returns 1 every { semesterMock.studentId } returns 1
every { semesterMock.diaryId } returns 1 every { semesterMock.diaryId } returns 1

View File

@ -1,8 +1,8 @@
buildscript { buildscript {
ext { ext {
kotlin_version = '1.4.10' kotlin_version = '1.4.20'
about_libraries = '8.4.2' about_libraries = '8.6.3'
hilt_version = "2.29.1-alpha" hilt_version = "2.30.1-alpha"
} }
repositories { repositories {
mavenCentral() mavenCentral()
@ -13,11 +13,11 @@ buildscript {
} }
dependencies { dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.android.tools.build:gradle:4.1.0' classpath 'com.android.tools.build:gradle:4.1.1'
classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version" classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
classpath 'com.google.gms:google-services:4.3.4' classpath 'com.google.gms:google-services:4.3.4'
classpath 'com.huawei.agconnect:agcp:1.4.1.300' classpath 'com.huawei.agconnect:agcp:1.4.2.301'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.3.0' classpath 'com.google.firebase:firebase-crashlytics-gradle:2.4.1'
classpath "com.github.triplet.gradle:play-publisher:2.8.0" classpath "com.github.triplet.gradle:play-publisher:2.8.0"
classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.0" classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.0"
classpath "gradle.plugin.com.star-zero.gradle:githook:1.2.0" classpath "gradle.plugin.com.star-zero.gradle:githook:1.2.0"