1
0
mirror of https://github.com/wulkanowy/wulkanowy.git synced 2024-09-20 01:29:09 -05:00

Merge branch 'release/2.2.0'

This commit is contained in:
Mikołaj Pich 2023-09-26 23:13:40 +02:00
commit 1d8378e136
49 changed files with 728 additions and 199 deletions

View File

@ -27,12 +27,11 @@ android {
testApplicationId "io.github.tests.wulkanowy"
minSdkVersion 21
targetSdkVersion 33
versionCode 131
versionName "2.1.0"
versionCode 132
versionName "2.2.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
resValue "string", "app_name", "Wulkanowy"
manifestPlaceholders = [
firebase_enabled: project.hasProperty("enableFirebase"),
admob_project_id: ""
@ -69,6 +68,7 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
buildConfigField "String", "MESSAGES_BASE_URL", "\"https://messages.wulkanowy.net.pl\""
buildConfigField "String", "SCHOOLS_BASE_URL", '"https://schools.wulkanowy.net.pl"'
}
debug {
minifyEnabled false
@ -78,6 +78,7 @@ android {
versionNameSuffix "-dev"
ext.enableCrashlytics = project.hasProperty("enableFirebase")
buildConfigField "String", "MESSAGES_BASE_URL", "\"https://messages.wulkanowy.net.pl\""
buildConfigField "String", "SCHOOLS_BASE_URL", '"https://schools.wulkanowy.net.pl"'
}
}
@ -160,8 +161,8 @@ play {
defaultToAppBundles = false
track = 'production'
releaseStatus = ReleaseStatus.IN_PROGRESS
userFraction = 0.25d
updatePriority = 3
userFraction = 0.01d
updatePriority = 1
enabled.set(false)
}
@ -186,16 +187,16 @@ ext {
android_hilt = "1.0.0"
room = "2.5.2"
chucker = "3.5.2"
mockk = "1.13.7"
mockk = "1.13.8"
coroutines = "1.7.3"
}
dependencies {
implementation 'io.github.wulkanowy:sdk:2.1.0'
implementation 'io.github.wulkanowy:sdk:2.2.0'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.3'
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1"
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines"
implementation "androidx.core:core-ktx:1.10.1"
@ -203,7 +204,7 @@ dependencies {
implementation "androidx.activity:activity-ktx:1.7.2"
implementation "androidx.appcompat:appcompat:1.6.1"
implementation "androidx.fragment:fragment-ktx:1.6.1"
implementation "androidx.annotation:annotation:1.6.0"
implementation "androidx.annotation:annotation:1.7.0"
implementation "androidx.preference:preference-ktx:1.2.1"
implementation "androidx.recyclerview:recyclerview:1.3.1"
@ -219,7 +220,7 @@ dependencies {
implementation "androidx.work:work-runtime-ktx:$work_manager"
playImplementation "androidx.work:work-gcm:$work_manager"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.6.1"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.6.2"
implementation "androidx.room:room-runtime:$room"
implementation "androidx.room:room-ktx:$room"
@ -239,7 +240,7 @@ dependencies {
implementation "com.jakewharton.timber:timber:5.0.1"
implementation "at.favre.lib:slf4j-timber:1.0.1"
implementation 'com.github.bastienpaulfr:Treessence:1.0.5'
implementation 'com.github.bastienpaulfr:Treessence:1.1.2'
implementation "com.mikepenz:aboutlibraries-core:$about_libraries"
implementation "io.coil-kt:coil:2.4.0"
implementation "io.github.wulkanowy:AppKillerManager:3.0.1"
@ -247,17 +248,18 @@ dependencies {
implementation 'com.fredporciuncula:flow-preferences:1.9.1'
implementation 'org.apache.commons:commons-text:1.10.0'
playImplementation platform('com.google.firebase:firebase-bom:32.2.2')
playImplementation platform('com.google.firebase:firebase-bom:32.3.1')
playImplementation 'com.google.firebase:firebase-analytics-ktx'
playImplementation 'com.google.firebase:firebase-messaging:'
playImplementation 'com.google.firebase:firebase-crashlytics:'
playImplementation 'com.google.firebase:firebase-config-ktx'
playImplementation 'com.google.android.play:core:1.10.3'
playImplementation 'com.google.android.play:core-ktx:1.8.1'
playImplementation 'com.google.android.gms:play-services-ads:22.2.0'
playImplementation 'com.google.android.gms:play-services-ads:22.4.0'
playImplementation "com.google.android.play:integrity:1.2.0"
hmsImplementation 'com.huawei.hms:hianalytics:6.10.0.303'
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.9.1.300'
hmsImplementation 'com.huawei.hms:hianalytics:6.12.0.300'
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.9.1.301'
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker"

View File

@ -0,0 +1,11 @@
package io.github.wulkanowy.utils
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class IntegrityHelper @Inject constructor() {
@Suppress("UNUSED_PARAMETER")
fun getIntegrityToken(requestId: String): String? = null
}

View File

@ -2,8 +2,8 @@ package io.github.wulkanowy.utils
import android.util.Log
import com.huawei.agconnect.crash.AGConnectCrash
import fr.bipi.tressence.base.FormatterPriorityTree
import fr.bipi.tressence.common.StackTraceRecorder
import fr.bipi.treessence.base.FormatterPriorityTree
import fr.bipi.treessence.common.StackTraceRecorder
class CrashLogTree : FormatterPriorityTree(Log.VERBOSE) {

View File

@ -0,0 +1,11 @@
package io.github.wulkanowy.utils
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class IntegrityHelper @Inject constructor() {
@Suppress("UNUSED_PARAMETER")
fun getIntegrityToken(requestId: String): String? = null
}

View File

@ -6,7 +6,7 @@ import androidx.hilt.work.HiltWorkerFactory
import androidx.work.Configuration
import com.yariksoffice.lingver.Lingver
import dagger.hilt.android.HiltAndroidApp
import fr.bipi.tressence.file.FileLoggerTree
import fr.bipi.treessence.file.FileLoggerTree
import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.ui.base.ThemeManager
import io.github.wulkanowy.utils.*

View File

@ -14,6 +14,7 @@ import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import io.github.wulkanowy.data.api.AdminMessageService
import io.github.wulkanowy.data.api.SchoolsService
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.SharedPrefProvider
import io.github.wulkanowy.data.repositories.PreferencesRepository
@ -82,19 +83,29 @@ internal class DataModule {
@Singleton
@Provides
fun provideRetrofit(
fun provideAdminMessageService(
okHttpClient: OkHttpClient,
json: Json,
appInfo: AppInfo
): Retrofit = Retrofit.Builder()
): AdminMessageService = Retrofit.Builder()
.baseUrl(appInfo.messagesBaseUrl)
.client(okHttpClient)
.addConverterFactory(json.asConverterFactory("application/json".toMediaType()))
.build()
.create()
@Singleton
@Provides
fun provideAdminMessageService(retrofit: Retrofit): AdminMessageService = retrofit.create()
fun provideSchoolsService(
okHttpClient: OkHttpClient,
json: Json,
appInfo: AppInfo,
): SchoolsService = Retrofit.Builder()
.baseUrl(appInfo.schoolsBaseUrl)
.client(okHttpClient)
.addConverterFactory(json.asConverterFactory("application/json".toMediaType()))
.build()
.create()
@Singleton
@Provides

View File

@ -0,0 +1,14 @@
package io.github.wulkanowy.data.api
import io.github.wulkanowy.data.pojos.IntegrityRequest
import io.github.wulkanowy.data.pojos.LoginEvent
import retrofit2.http.Body
import retrofit2.http.POST
import javax.inject.Singleton
@Singleton
interface SchoolsService {
@POST("/log/loginEvent")
suspend fun logLoginEvent(@Body request: IntegrityRequest<LoginEvent>)
}

View File

@ -0,0 +1,21 @@
package io.github.wulkanowy.data.pojos
import kotlinx.serialization.Serializable
@Serializable
data class LoginEvent(
val uuid: String,
val schoolName: String,
val schoolShort: String,
val schoolAddress: String,
val scraperBaseUrl: String,
val symbol: String,
val schoolId: String,
val loginType: String,
)
@Serializable
data class IntegrityRequest<T>(
val tokenString: String,
val data: T,
)

View File

@ -0,0 +1,68 @@
package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.api.SchoolsService
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
import io.github.wulkanowy.data.pojos.IntegrityRequest
import io.github.wulkanowy.data.pojos.LoginEvent
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.ui.modules.login.LoginData
import io.github.wulkanowy.utils.IntegrityHelper
import io.github.wulkanowy.utils.getCurrentOrLast
import io.github.wulkanowy.utils.init
import kotlinx.coroutines.withTimeout
import timber.log.Timber
import java.util.UUID
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.time.Duration.Companion.seconds
@Singleton
class SchoolsRepository @Inject constructor(
private val integrityHelper: IntegrityHelper,
private val schoolsService: SchoolsService,
private val sdk: Sdk,
) {
suspend fun logSchoolLogin(loginData: LoginData, students: List<StudentWithSemesters>) {
students.forEach {
runCatching {
withTimeout(10.seconds) {
logLogin(loginData, it.student, it.semesters.getCurrentOrLast())
}
}
.onFailure { Timber.e(it) }
}
}
private suspend fun logLogin(loginData: LoginData, student: Student, semester: Semester) {
val requestId = UUID.randomUUID().toString()
val token = integrityHelper.getIntegrityToken(requestId) ?: return
val schoolInfo = sdk
.init(student.copy(password = loginData.password))
.switchDiary(
diaryId = semester.diaryId,
kindergartenDiaryId = semester.kindergartenDiaryId,
schoolYear = semester.schoolYear
)
.getSchool()
schoolsService.logLoginEvent(
IntegrityRequest(
tokenString = token,
data = LoginEvent(
uuid = requestId,
schoolAddress = schoolInfo.address,
schoolName = schoolInfo.name,
schoolShort = student.schoolShortName,
scraperBaseUrl = student.scrapperBaseUrl,
loginType = student.loginType,
symbol = student.symbol,
schoolId = student.schoolSymbol,
)
)
)
}
}

View File

@ -58,7 +58,7 @@ class GradeAverageProvider @Inject constructor(
when (params.gradeAverageMode) {
ONE_SEMESTER -> getGradeSubjects(
student = student,
semester = semesters.single { it.semesterId == semesterId },
semester = semesters.first { it.semesterId == semesterId },
forceRefresh = forceRefresh,
params = params,
)

View File

@ -17,6 +17,8 @@ import io.github.wulkanowy.ui.base.BaseFragment
import io.github.wulkanowy.ui.modules.dashboard.viewholders.AdminMessageViewHolder
import io.github.wulkanowy.ui.modules.login.LoginActivity
import io.github.wulkanowy.ui.modules.login.LoginData
import io.github.wulkanowy.ui.modules.login.support.LoginSupportDialog
import io.github.wulkanowy.ui.modules.login.support.LoginSupportInfo
import io.github.wulkanowy.utils.*
import javax.inject.Inject
@ -184,7 +186,9 @@ class LoginFormFragment : BaseFragment<FragmentLoginFormBinding>(R.layout.fragme
override fun clearPassError() {
binding.loginFormPassLayout.error = null
binding.loginFormPassLayout.setEndIconTintList(null)
binding.loginFormPassLayout.setEndIconTintList(
requireContext().getAttrColorStateList(R.attr.colorOnSurface)
)
binding.loginFormErrorBox.isVisible = false
}
@ -236,8 +240,7 @@ class LoginFormFragment : BaseFragment<FragmentLoginFormBinding>(R.layout.fragme
}
override fun showContact(show: Boolean) {
binding.loginFormContact.visibility = if (show) VISIBLE else GONE
binding.loginFormRecoverLink.visibility = if (show) GONE else VISIBLE
binding.loginFormContact.isVisible = show
}
override fun openPrivacyPolicyPage() {
@ -281,20 +284,7 @@ class LoginFormFragment : BaseFragment<FragmentLoginFormBinding>(R.layout.fragme
presenter.updateCustomDomainSuffixVisibility()
}
override fun openEmail(lastError: String) {
context?.openEmailClient(
chooserTitle = requireContext().getString(R.string.login_email_intent_title),
email = "wulkanowyinc@gmail.com",
subject = requireContext().getString(R.string.login_email_subject),
body = requireContext().getString(
R.string.login_email_text,
"${appInfo.systemManufacturer} ${appInfo.systemModel}",
appInfo.systemVersion.toString(),
"${appInfo.versionName}-${appInfo.buildFlavor}",
"$formHostValue/$formHostSymbol",
preferencesRepository.installationId,
lastError
)
)
override fun openEmail(supportInfo: LoginSupportInfo) {
LoginSupportDialog.newInstance(supportInfo).show(childFragmentManager, "support_dialog")
}
}

View File

@ -17,6 +17,7 @@ import io.github.wulkanowy.domain.adminmessage.GetAppropriateAdminMessageUseCase
import io.github.wulkanowy.ui.base.BasePresenter
import io.github.wulkanowy.ui.modules.login.LoginData
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
import io.github.wulkanowy.ui.modules.login.support.LoginSupportInfo
import io.github.wulkanowy.utils.AnalyticsHelper
import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.ifNullOrBlank
@ -133,7 +134,7 @@ class LoginFormPresenter @Inject constructor(
}
}
fun onSignInClick() {
private fun getLoginData(): LoginData {
val email = view?.formUsernameValue.orEmpty().trim()
val password = view?.formPassValue.orEmpty().trim()
val host = view?.formHostValue.orEmpty().trim()
@ -142,15 +143,27 @@ class LoginFormPresenter @Inject constructor(
}.orEmpty()
val symbol = view?.formHostSymbol.orEmpty().trim()
if (!validateCredentials(email, password, host)) return
return LoginData(
login = email,
password = password,
baseUrl = host,
domainSuffix = domainSuffix,
symbol = symbol
)
}
fun onSignInClick() {
val loginData = getLoginData()
if (!validateCredentials(loginData.login, loginData.password, loginData.baseUrl)) return
resourceFlow {
studentRepository.getUserSubjectsFromScrapper(
email = email,
password = password,
scrapperBaseUrl = host,
domainSuffix = domainSuffix,
symbol = symbol
email = loginData.login,
password = loginData.password,
scrapperBaseUrl = loginData.baseUrl,
domainSuffix = loginData.domainSuffix,
symbol = loginData.symbol.orEmpty(),
)
}
.logResourceStatus("login")
@ -162,7 +175,6 @@ class LoginFormPresenter @Inject constructor(
}
}
.onResourceSuccess {
val loginData = LoginData(email, password, host, domainSuffix, symbol)
when (it.symbols.size) {
0 -> view?.navigateToSymbol(loginData)
else -> view?.navigateToStudentSelect(loginData, it)
@ -170,7 +182,7 @@ class LoginFormPresenter @Inject constructor(
analytics.logEvent(
"registration_form",
"success" to true,
"scrapperBaseUrl" to host,
"scrapperBaseUrl" to loginData.baseUrl,
"error" to "No error"
)
}
@ -187,7 +199,7 @@ class LoginFormPresenter @Inject constructor(
analytics.logEvent(
"registration_form",
"success" to false,
"scrapperBaseUrl" to host,
"scrapperBaseUrl" to loginData.baseUrl,
"error" to it.message.ifNullOrBlank { "No message" }
)
}
@ -199,7 +211,14 @@ class LoginFormPresenter @Inject constructor(
}
fun onEmailClick() {
view?.openEmail(lastError?.message.ifNullOrBlank { "none" })
view?.openEmail(
LoginSupportInfo(
loginData = getLoginData(),
lastErrorMessage = lastError?.message,
registerUser = null,
enteredSymbol = null,
)
)
}
fun onRecoverClick() {

View File

@ -4,6 +4,7 @@ import io.github.wulkanowy.data.db.entities.AdminMessage
import io.github.wulkanowy.data.pojos.RegisterUser
import io.github.wulkanowy.ui.base.BaseView
import io.github.wulkanowy.ui.modules.login.LoginData
import io.github.wulkanowy.ui.modules.login.support.LoginSupportInfo
interface LoginFormView : BaseView {
@ -79,7 +80,7 @@ interface LoginFormView : BaseView {
fun openFaqPage()
fun openEmail(lastError: String)
fun openEmail(supportInfo: LoginSupportInfo)
fun openAdvancedLogin()

View File

@ -46,7 +46,7 @@ class LoginRecoverPresenter @Inject constructor(
fun updateFields() {
view?.run {
setUsernameHint(if ("standard" in recoverHostValue) emailHintString else loginPeselEmailHintString)
setUsernameHint(if ("email" in recoverHostValue) emailHintString else loginPeselEmailHintString)
}
}
@ -92,7 +92,7 @@ class LoginRecoverPresenter @Inject constructor(
isCorrect = false
}
if ("standard" in host && "@" !in username) {
if ("email" in host && "@" !in username) {
view?.setUsernameError(view?.invalidEmailString.orEmpty())
isCorrect = false
}

View File

@ -10,8 +10,11 @@ import io.github.wulkanowy.data.pojos.RegisterUser
import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.databinding.FragmentLoginStudentSelectBinding
import io.github.wulkanowy.ui.base.BaseFragment
import io.github.wulkanowy.ui.modules.auth.AuthDialog
import io.github.wulkanowy.ui.modules.login.LoginActivity
import io.github.wulkanowy.ui.modules.login.LoginData
import io.github.wulkanowy.ui.modules.login.support.LoginSupportDialog
import io.github.wulkanowy.ui.modules.login.support.LoginSupportInfo
import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.openEmailClient
import io.github.wulkanowy.utils.openInternetBrowser
@ -106,21 +109,8 @@ class LoginStudentSelectFragment :
context?.openInternetBrowser("https://discord.gg/vccAQBr", ::showMessage)
}
override fun openEmail(lastError: String) {
context?.openEmailClient(
chooserTitle = requireContext().getString(R.string.login_email_intent_title),
email = "wulkanowyinc@gmail.com",
subject = requireContext().getString(R.string.login_email_subject),
body = requireContext().getString(
R.string.login_email_text,
"${appInfo.systemManufacturer} ${appInfo.systemModel}",
appInfo.systemVersion.toString(),
"${appInfo.versionName}-${appInfo.buildFlavor}",
"Select users to log in",
preferencesRepository.installationId,
lastError
)
)
override fun openEmail(supportInfo: LoginSupportInfo) {
LoginSupportDialog.newInstance(supportInfo).show(childFragmentManager, "support_dialog")
}
override fun onDestroyView() {

View File

@ -9,23 +9,25 @@ import io.github.wulkanowy.data.pojos.RegisterStudent
import io.github.wulkanowy.data.pojos.RegisterSymbol
import io.github.wulkanowy.data.pojos.RegisterUnit
import io.github.wulkanowy.data.pojos.RegisterUser
import io.github.wulkanowy.data.repositories.SchoolsRepository
import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.data.resourceFlow
import io.github.wulkanowy.sdk.scrapper.login.AccountPermissionException
import io.github.wulkanowy.sdk.scrapper.login.InvalidSymbolException
import io.github.wulkanowy.services.sync.SyncManager
import io.github.wulkanowy.ui.base.BasePresenter
import io.github.wulkanowy.ui.modules.login.LoginData
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
import io.github.wulkanowy.ui.modules.login.support.LoginSupportInfo
import io.github.wulkanowy.utils.AnalyticsHelper
import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.ifNullOrBlank
import io.github.wulkanowy.utils.isCurrent
import kotlinx.coroutines.flow.onEach
import timber.log.Timber
import javax.inject.Inject
class LoginStudentSelectPresenter @Inject constructor(
studentRepository: StudentRepository,
private val schoolsRepository: SchoolsRepository,
private val loginErrorHandler: LoginErrorHandler,
private val syncManager: SyncManager,
private val analytics: AnalyticsHelper,
@ -71,7 +73,14 @@ class LoginStudentSelectPresenter @Inject constructor(
students = it.dataOrNull.orEmpty()
when (it) {
is Resource.Loading -> Timber.d("Login student select students load started")
is Resource.Success -> refreshItems()
is Resource.Success -> {
getStudentsWithCurrentlyActiveSemesters()
selectedStudents.clear()
selectedStudents.addAll(getStudentsWithCurrentlyActiveSemesters())
view?.enableSignIn(selectedStudents.isNotEmpty())
refreshItems()
}
is Resource.Error -> {
errorHandler.dispatch(it.error)
lastError = it.error
@ -81,6 +90,21 @@ class LoginStudentSelectPresenter @Inject constructor(
}.launch()
}
private fun getStudentsWithCurrentlyActiveSemesters(): List<LoginStudentSelectItem.Student> {
val students = registerUser.symbols.flatMap { symbol ->
symbol.schools.flatMap { unit ->
unit.students.map {
createStudentItem(it, symbol, unit, students)
}
}
}
return students.filter { student ->
student.student.semesters.any { semester ->
semester.isCurrent()
}
}
}
private fun createItems(): List<LoginStudentSelectItem> = buildList {
val notEmptySymbols = registerUser.symbols.filter { it.schools.isNotEmpty() }
val emptySymbols = registerUser.symbols.filter { it.schools.isEmpty() }
@ -236,8 +260,8 @@ class LoginStudentSelectPresenter @Inject constructor(
}
private fun registerStudents(students: List<LoginStudentSelectItem>) {
val studentsWithSemesters = students
.filterIsInstance<LoginStudentSelectItem.Student>().map { item ->
val filteredStudents = students.filterIsInstance<LoginStudentSelectItem.Student>()
val studentsWithSemesters = filteredStudents.map { item ->
item.student.mapToStudentWithSemesters(
user = registerUser,
symbol = item.symbol,
@ -246,7 +270,10 @@ class LoginStudentSelectPresenter @Inject constructor(
colors = appInfo.defaultColorsForAvatar,
)
}
resourceFlow { studentRepository.saveStudents(studentsWithSemesters) }
resourceFlow {
studentRepository.saveStudents(studentsWithSemesters)
schoolsRepository.logSchoolLogin(loginData, studentsWithSemesters)
}
.logResourceStatus("registration")
.onEach {
when (it) {
@ -254,11 +281,13 @@ class LoginStudentSelectPresenter @Inject constructor(
showProgress(true)
showContent(false)
}
is Resource.Success -> {
syncManager.startOneTimeSyncWorker(quiet = true)
view?.navigateToNext()
logRegisterEvent(studentsWithSemesters)
}
is Resource.Error -> {
view?.apply {
showProgress(false)
@ -281,28 +310,14 @@ class LoginStudentSelectPresenter @Inject constructor(
}
private fun onEmailClick() {
view?.openEmail(lastError?.message.ifNullOrBlank {
loginData.baseUrl + "/" + loginData.symbol + "\n" + registerUser.symbols.filterNot {
(it.error is AccountPermissionException || it.error is InvalidSymbolException) && it.symbol != loginData.symbol
}.joinToString(";\n") { symbol ->
buildString {
append(" -")
append(symbol.symbol)
append("(${symbol.error?.message?.let { it.take(46) + "..." } ?: symbol.schools.size})")
if (symbol.schools.isNotEmpty()) {
append(": ")
}
append(symbol.schools.joinToString(", ") { unit ->
buildString {
append(unit.schoolShortName)
append("(${unit.error?.message?.let { it.take(46) + "..." } ?: unit.students.size})")
}
})
}
} + "\nPozostałe: " + registerUser.symbols.filter {
it.error is AccountPermissionException || it.error is InvalidSymbolException
}.joinToString(", ") { it.symbol }
})
view?.openEmail(
LoginSupportInfo(
loginData = loginData,
registerUser = registerUser,
lastErrorMessage = lastError?.message,
enteredSymbol = loginData.symbol,
)
)
}
private fun logRegisterEvent(

View File

@ -2,6 +2,7 @@ package io.github.wulkanowy.ui.modules.login.studentselect
import io.github.wulkanowy.ui.base.BaseView
import io.github.wulkanowy.ui.modules.login.LoginData
import io.github.wulkanowy.ui.modules.login.support.LoginSupportInfo
interface LoginStudentSelectView : BaseView {
@ -23,5 +24,5 @@ interface LoginStudentSelectView : BaseView {
fun openDiscordInvite()
fun openEmail(lastError: String)
fun openEmail(supportInfo: LoginSupportInfo)
}

View File

@ -0,0 +1,133 @@
package io.github.wulkanowy.ui.modules.login.support
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.os.bundleOf
import androidx.core.widget.doOnTextChanged
import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R
import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.databinding.DialogLoginSupportBinding
import io.github.wulkanowy.sdk.scrapper.login.AccountPermissionException
import io.github.wulkanowy.sdk.scrapper.login.InvalidSymbolException
import io.github.wulkanowy.ui.base.BaseDialogFragment
import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.openEmailClient
import io.github.wulkanowy.utils.serializable
import javax.inject.Inject
@AndroidEntryPoint
class LoginSupportDialog : BaseDialogFragment<DialogLoginSupportBinding>() {
@Inject
lateinit var appInfo: AppInfo
@Inject
lateinit var preferencesRepository: PreferencesRepository
private lateinit var supportInfo: LoginSupportInfo
companion object {
private const val ARGUMENT_KEY = "info"
fun newInstance(info: LoginSupportInfo) = LoginSupportDialog().apply {
arguments = bundleOf(ARGUMENT_KEY to info)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setStyle(STYLE_NO_FRAME, R.style.WulkanowyTheme_NoActionBar)
supportInfo = requireArguments().serializable(ARGUMENT_KEY)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val binding = DialogLoginSupportBinding.inflate(inflater)
.apply { binding = this }
binding.dialogLoginSupportToolbar.setNavigationOnClickListener { dismiss() }
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
with(binding) {
dialogLoginSupportSchoolInput.doOnTextChanged { _, _, _, _ ->
with(dialogLoginSupportSchoolLayout) {
isErrorEnabled = false
error = null
}
}
dialogLoginSupportSubmit.setOnClickListener {
if (dialogLoginSupportSchoolInput.text.isNullOrBlank()) {
with(dialogLoginSupportSchoolLayout) {
isErrorEnabled = true
error = getString(R.string.error_field_required)
}
} else {
onSubmitClick()
dismiss()
}
}
}
}
private fun onSubmitClick() {
with(binding) {
context?.openEmailClient(
chooserTitle = requireContext().getString(R.string.login_email_intent_title),
email = "wulkanowyinc@gmail.com",
subject = requireContext().getString(R.string.login_email_subject),
body = requireContext().getString(
R.string.login_email_text,
"${appInfo.systemManufacturer} ${appInfo.systemModel}",
appInfo.systemVersion.toString(),
"${appInfo.versionName}-${appInfo.buildFlavor}",
supportInfo.loginData.baseUrl + "/" + supportInfo.loginData.symbol,
preferencesRepository.installationId,
getLastErrorFromStudentSelectScreen(),
dialogLoginSupportSchoolInput.text.takeIf { !it.isNullOrBlank() }
?: return@with,
dialogLoginSupportAdditionalInput.text,
)
)
}
}
private fun getLastErrorFromStudentSelectScreen(): String {
if (!supportInfo.lastErrorMessage.isNullOrBlank()) {
return supportInfo.lastErrorMessage!!
}
if (supportInfo.registerUser?.symbols.isNullOrEmpty()) {
return ""
}
return "\n" + supportInfo.registerUser?.symbols?.filterNot {
(it.error is AccountPermissionException || it.error is InvalidSymbolException) &&
it.symbol != supportInfo.enteredSymbol
}?.joinToString(";\n") { symbol ->
buildString {
append(" -")
append(symbol.symbol)
append("(${symbol.error?.message?.let { it.take(46) + "..." } ?: symbol.schools.size})")
if (symbol.schools.isNotEmpty()) {
append(": ")
}
append(symbol.schools.joinToString(", ") { unit ->
buildString {
append(unit.schoolShortName)
append("(${unit.error?.message?.let { it.take(46) + "..." } ?: unit.students.size})")
}
})
}
} + "\nPozostałe: " + supportInfo.registerUser?.symbols?.filter {
it.error is AccountPermissionException || it.error is InvalidSymbolException
}?.joinToString(", ") { it.symbol }
}
}

View File

@ -0,0 +1,12 @@
package io.github.wulkanowy.ui.modules.login.support
import io.github.wulkanowy.data.pojos.RegisterUser
import io.github.wulkanowy.ui.modules.login.LoginData
import java.io.Serializable
data class LoginSupportInfo(
val loginData: LoginData,
val registerUser: RegisterUser?,
val lastErrorMessage: String?,
val enteredSymbol: String?,
) : Serializable

View File

@ -18,7 +18,13 @@ import io.github.wulkanowy.databinding.FragmentLoginSymbolBinding
import io.github.wulkanowy.ui.base.BaseFragment
import io.github.wulkanowy.ui.modules.login.LoginActivity
import io.github.wulkanowy.ui.modules.login.LoginData
import io.github.wulkanowy.utils.*
import io.github.wulkanowy.ui.modules.login.support.LoginSupportDialog
import io.github.wulkanowy.ui.modules.login.support.LoginSupportInfo
import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.hideSoftInput
import io.github.wulkanowy.utils.openInternetBrowser
import io.github.wulkanowy.utils.serializable
import io.github.wulkanowy.utils.showSoftInput
import javax.inject.Inject
@AndroidEntryPoint
@ -100,6 +106,13 @@ class LoginSymbolFragment :
}
}
override fun setErrorSymbolDefinitelyInvalid() {
with(binding.loginSymbolNameLayout) {
requestFocus()
error = getString(R.string.login_invalid_symbol_definitely)
}
}
override fun setErrorSymbolRequire() {
setErrorSymbol(getString(R.string.error_field_required))
}
@ -163,20 +176,7 @@ class LoginSymbolFragment :
)
}
override fun openEmail(host: String, lastError: String) {
context?.openEmailClient(
chooserTitle = requireContext().getString(R.string.login_email_intent_title),
email = "wulkanowyinc@gmail.com",
subject = requireContext().getString(R.string.login_email_subject),
body = requireContext().getString(
R.string.login_email_text,
"${appInfo.systemManufacturer} ${appInfo.systemModel}",
appInfo.systemVersion.toString(),
"${appInfo.versionName}-${appInfo.buildFlavor}",
"$host/${binding.loginSymbolName.text}",
preferencesRepository.installationId,
lastError
)
)
override fun openSupportDialog(supportInfo: LoginSupportInfo) {
LoginSupportDialog.newInstance(supportInfo).show(childFragmentManager, "support_dialog")
}
}

View File

@ -11,6 +11,7 @@ import io.github.wulkanowy.sdk.scrapper.login.InvalidSymbolException
import io.github.wulkanowy.ui.base.BasePresenter
import io.github.wulkanowy.ui.modules.login.LoginData
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
import io.github.wulkanowy.ui.modules.login.support.LoginSupportInfo
import io.github.wulkanowy.utils.AnalyticsHelper
import io.github.wulkanowy.utils.ifNullOrBlank
import kotlinx.coroutines.flow.onEach
@ -53,6 +54,10 @@ class LoginSymbolPresenter @Inject constructor(
view?.setErrorSymbolRequire()
return
}
if (isFormDefinitelyInvalid()) {
view?.setErrorSymbolDefinitelyInvalid()
return
}
loginData = loginData.copy(
symbol = view?.symbolValue?.getNormalizedSymbol(),
@ -74,6 +79,7 @@ class LoginSymbolPresenter @Inject constructor(
showProgress(true)
showContent(false)
}
is Resource.Success -> {
when (user.data.symbols.size) {
0 -> {
@ -83,6 +89,7 @@ class LoginSymbolPresenter @Inject constructor(
showContact(true)
}
}
else -> {
val enteredSymbolDetails = user.data.symbols
.firstOrNull()
@ -107,6 +114,7 @@ class LoginSymbolPresenter @Inject constructor(
"error" to "No error"
)
}
is Resource.Error -> {
Timber.i("Login with symbol result: An exception occurred")
analytics.logEvent(
@ -130,17 +138,25 @@ class LoginSymbolPresenter @Inject constructor(
}.launch("login")
}
private fun isFormDefinitelyInvalid(): Boolean {
val definitelyInvalidSymbols = listOf("vulcan", "uonet", "wulkanowy", "standardowa")
val normalizedSymbol = view?.symbolValue.orEmpty().getNormalizedSymbol()
return normalizedSymbol in definitelyInvalidSymbols
}
fun onFaqClick() {
view?.openFaqPage()
}
fun onEmailClick() {
view?.openEmail(loginData.baseUrl, lastError?.message.ifNullOrBlank {
registerUser?.symbols?.flatMap { symbol ->
symbol.schools.map { it.error?.message } + symbol.error?.message
}?.filterNotNull()?.distinct()?.joinToString(";") {
it.take(46) + "..."
} ?: "blank"
})
view?.openSupportDialog(
LoginSupportInfo(
loginData = loginData,
registerUser = registerUser,
lastErrorMessage = lastError?.message,
enteredSymbol = view?.symbolValue,
)
)
}
}

View File

@ -3,6 +3,7 @@ package io.github.wulkanowy.ui.modules.login.symbol
import io.github.wulkanowy.data.pojos.RegisterUser
import io.github.wulkanowy.ui.base.BaseView
import io.github.wulkanowy.ui.modules.login.LoginData
import io.github.wulkanowy.ui.modules.login.support.LoginSupportInfo
interface LoginSymbolView : BaseView {
@ -18,6 +19,8 @@ interface LoginSymbolView : BaseView {
fun setErrorSymbolInvalid()
fun setErrorSymbolDefinitelyInvalid()
fun setErrorSymbolRequire()
fun setErrorSymbol(message: String)
@ -40,5 +43,5 @@ interface LoginSymbolView : BaseView {
fun openFaqPage()
fun openEmail(host: String, lastError: String)
fun openSupportDialog(supportInfo: LoginSupportInfo)
}

View File

@ -119,7 +119,6 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
//https://developer.android.com/guide/playcore/in-app-updates#status_callback
@Deprecated("Deprecated in Java")
@Suppress("DEPRECATION")
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
updateHelper.onActivityResult(requestCode, resultCode)

View File

@ -25,7 +25,8 @@ open class AppInfo @Inject constructor() {
open val systemModel: String get() = Build.MODEL
open val messagesBaseUrl = BuildConfig.MESSAGES_BASE_URL
open val messagesBaseUrl: String = BuildConfig.MESSAGES_BASE_URL
open val schoolsBaseUrl: String = BuildConfig.SCHOOLS_BASE_URL
@Suppress("DEPRECATION")
open val systemLanguage: String

View File

@ -7,7 +7,7 @@ import android.os.Bundle
import android.view.View
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import fr.bipi.tressence.common.filters.Filter
import fr.bipi.treessence.common.filters.Filter
import io.github.wulkanowy.sdk.exception.FeatureNotAvailableException
import io.github.wulkanowy.sdk.scrapper.exception.FeatureDisabledException
import timber.log.Timber

View File

@ -1,8 +1,5 @@
Wersja 2.1.0
Wersja 2.2.0
— dodaliśmy tryb incognito w wiadomościach
— dodaliśmy wyświetlanie pustych lekcji (okienek) w planie lekcji
— poprawiliśmy widżet planu lekcji (będzie teraz trochę bardziej kompaktowy)
— zmieniliśmy datę rozpoczęcia roku szkolnego na 3 dni przed 1 września (sorry)
Dokonaliśmy drobnych usprawnień w obszarze logowania, które powinny pomóc Wam i nam
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases

View File

@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:tint="#000000" android:viewportHeight="24"
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M11,7L9.6,8.4l2.6,2.6H2v2h10.2l-2.6,2.6L11,17l5,-5L11,7zM20,19h-8v2h8c1.1,0 2,-0.9 2,-2V5c0,-1.1 -0.9,-2 -2,-2h-8v2h8V19z"/>
</vector>

View File

@ -0,0 +1,92 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:windowBackground"
android:orientation="vertical">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/dialog_login_support_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:navigationIcon="?attr/homeAsUpIndicator"
app:navigationIconTint="?attr/colorOnSurfaceVariant"
app:title="@string/login_support_title" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<LinearLayout
android:id="@+id/dialog_login_support_school_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="20dp"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/login_support_school_hint" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/dialog_login_support_school_layout"
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:placeholderText="@string/login_support_school_placeholder"
app:placeholderTextColor="?colorTertiary">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/dialog_login_support_school_input"
style="@style/Widget.Material3.TextInputEditText.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="top" />
<requestFocus />
</com.google.android.material.textfield.TextInputLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/login_support_additional_hint" />
<com.google.android.material.textfield.TextInputLayout
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="top"
app:placeholderText="@string/login_support_additional_placeholder"
app:placeholderTextColor="?colorTertiary">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/dialog_login_support_additional_input"
style="@style/Widget.Material3.TextInputEditText.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="top"
android:minLines="3" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.button.MaterialButton
android:id="@+id/dialog_login_support_submit"
style="@style/Widget.Material3.Button.TextButton.Dialog"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginTop="12dp"
android:insetLeft="0dp"
android:insetTop="0dp"
android:insetRight="0dp"
android:insetBottom="0dp"
android:text="@string/login_support_submit" />
</LinearLayout>
</ScrollView>
</LinearLayout>

View File

@ -26,7 +26,8 @@
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingTop="6dp"
android:paddingBottom="6dp" />
android:paddingBottom="6dp"
tools:listitem="@layout/item_dashboard_grades" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<LinearLayout

View File

@ -56,6 +56,8 @@
android:layout_marginBottom="32dp"
android:enabled="false"
android:text="@string/login_sign_in"
app:icon="@drawable/ic_login"
app:iconGravity="end"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/loginStudentSelectRecycler" />

View File

@ -141,7 +141,9 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/loginSymbolHelper">
app:layout_constraintTop_toBottomOf="@+id/loginSymbolHelper"
app:placeholderText="@string/login_symbol_placeholder"
app:placeholderTextColor="?colorTertiary">
<AutoCompleteTextView
android:id="@+id/loginSymbolName"

View File

@ -52,9 +52,9 @@
<item>Průměr známek z celého roku</item>
</string-array>
<string-array name="timetable_show_gaps_entries">
<item>Don\'t show</item>
<item>Only between lessons</item>
<item>Before and between lessons</item>
<item>Nezobrazovat</item>
<item>Pouze mezi lekcemi</item>
<item>Před a mezi lekcemi</item>
</string-array>
<string-array name="dashboard_tile_entries">
<item>Šťastné číslo</item>

View File

@ -44,6 +44,7 @@
<string name="login_token_hint">Token</string>
<string name="login_pin_hint">PIN</string>
<string name="login_symbol_hint">Symbol</string>
<string name="login_symbol_placeholder">E.g. \"lodz\" or \"powiatjaroslawski\"</string>
<string name="login_sign_in">Přihlásit</string>
<string name="login_invalid_password">Toto heslo je příliš krátké</string>
<string name="login_incorrect_password_default">Přihlašovací údaje jsou nesprávné</string>
@ -54,7 +55,8 @@
<string name="login_invalid_email">Neplatný e-mail</string>
<string name="login_invalid_login">Místo e-mailu použijte přiřazené přihlašovací údaje</string>
<string name="login_invalid_custom_email">Použijte přiřazené přihlašovací nebo e-mail v @%1$s</string>
<string name="login_invalid_symbol">Neplatný symbol</string>
<string name="login_invalid_symbol">Invalid symbol. If you cannot find it, please contact the school</string>
<string name="login_invalid_symbol_definitely">Don\'t make this up! If you cannot find it, please contact the school</string>
<string name="login_incorrect_symbol">Žák nebyl nalezen. Zkontrolujte správnost symbolu a vybrané varianty deníku UONET+</string>
<string name="login_duplicate_student">Vybraný žák je už 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>Wygeneruj kod dostępu</b>.\n\nUjistěte se, že jste nastavili správnou variantu deníku v poli <b>Variace deníku UONET+</b> na první přihlašovací obrazovce</string>
@ -69,7 +71,7 @@
<string name="login_contact_discord">Discord</string>
<string name="login_email_intent_title">Poslat e-mail</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">Reset password</string>
<string name="login_recover_title">Obnovte svůj účet</string>
<string name="login_recover">Obnovit</string>
<string name="login_signed_in">Žák je už přihlášen</string>
@ -77,6 +79,12 @@
<string name="login_other_search_locations">Jiná místa vyhledávání</string>
<string name="login_no_active_student">Nebyli nalezeni žádní aktivní žáci</string>
<string name="login_symbol_enter">Zadejte jiný symbol</string>
<string name="login_support_title">Get help</string>
<string name="login_support_school_hint">Full school name (required)</string>
<string name="login_support_school_placeholder">Np. ZSTiO Jarosław lub SP nr 99 w Łodzi</string>
<string name="login_support_additional_hint">Additional information in Polish (optional)</string>
<string name="login_support_additional_placeholder">Np. \"Ostatnio zmieniłem szkołę i…\" albo \"Jestem rodzicem i nie widzę drugiego dziecka…\"</string>
<string name="login_support_submit">Submit</string>
<!--Notifications-->
<string name="notifications_header_title">Povolit oznámení</string>
<string name="notifications_header_description">Povolit upozornění, abyste nezmeškali zprávu od učitele nebo o nové známce</string>
@ -186,10 +194,10 @@
<string name="timetable_notify_change_teacher">Změna učitele z %1$s na %2$s</string>
<string name="timetable_notify_change_subject">Změna předmětu z %1$s na %2$s</string>
<plurals name="timetable_no_lesson">
<item quantity="one">No lesson</item>
<item quantity="few">No lessons</item>
<item quantity="many">No lessons</item>
<item quantity="other">No lessons</item>
<item quantity="one">Žádné lekce</item>
<item quantity="few">Žádné lekce</item>
<item quantity="many">Žádné lekce</item>
<item quantity="other">Žádné lekce</item>
</plurals>
<plurals name="timetable_notify_new_items_title">
<item quantity="one">Změna plánu lekcí</item>
@ -706,7 +714,7 @@
<string name="pref_view_expand_grade">Rozvíjení známek</string>
<string name="pref_view_timetable_show_timers">Označit aktuální lekci</string>
<string name="pref_view_timetable_show_groups">Zobrazit skupiny vedle předmětů</string>
<string name="pref_view_timetable_show_gaps">Show empty tiles where there\'s no lesson</string>
<string name="pref_view_timetable_show_gaps">Zobrazit prázdné dlaždice, kde není žádná lekce</string>
<string name="pref_view_grade_statistics_list">Zobrazit seznam grafů v známkách třídy</string>
<string name="pref_view_subjects_without_grades">Zobrazit předměty bez známek</string>
<string name="pref_view_grade_color_scheme">Známky barevné schéma</string>

View File

@ -44,6 +44,7 @@
<string name="login_token_hint">Token</string>
<string name="login_pin_hint">PIN</string>
<string name="login_symbol_hint">Symbol</string>
<string name="login_symbol_placeholder">E.g. \"lodz\" or \"powiatjaroslawski\"</string>
<string name="login_sign_in">Sign in</string>
<string name="login_invalid_password">Password too short</string>
<string name="login_incorrect_password_default">Login details are incorrect</string>
@ -54,7 +55,8 @@
<string name="login_invalid_email">Invalid email</string>
<string name="login_invalid_login">Use the assigned login instead of email</string>
<string name="login_invalid_custom_email">Use the assigned login or email in @%1$s</string>
<string name="login_invalid_symbol">Invalid symbol</string>
<string name="login_invalid_symbol">Invalid symbol. If you cannot find it, please contact the school</string>
<string name="login_invalid_symbol_definitely">Don\'t make this up! If you cannot find it, please contact the school</string>
<string name="login_incorrect_symbol">Student not found. Validate the symbol and the chosen variation of the UONET+ register</string>
<string name="login_duplicate_student">Selected student is already logged in</string>
<string name="login_symbol_helper">The symbol can be found on the register page in&#160;<b>Uczeń</b> →&#160;<b>Dostęp Mobilny</b>&#160;<b>Wygeneruj kod dostępu</b>.\n\nMake sure that you have set the appropriate register variant in the <b>UONET+ register variant</b> field on the first login screen</string>
@ -69,7 +71,7 @@
<string name="login_contact_discord">Discord</string>
<string name="login_email_intent_title">Send email</string>
<string name="login_recover_warning">Make sure you select the correct UONET+ register variation!</string>
<string name="login_recover_button">I forgot my password</string>
<string name="login_recover_button">Reset password</string>
<string name="login_recover_title">Recover your account</string>
<string name="login_recover">Recover</string>
<string name="login_signed_in">Student is already signed in</string>
@ -77,6 +79,12 @@
<string name="login_other_search_locations">Other search locations</string>
<string name="login_no_active_student">No active students found</string>
<string name="login_symbol_enter">Enter a different symbol</string>
<string name="login_support_title">Get help</string>
<string name="login_support_school_hint">Full school name (required)</string>
<string name="login_support_school_placeholder">Np. ZSTiO Jarosław lub SP nr 99 w Łodzi</string>
<string name="login_support_additional_hint">Additional information in Polish (optional)</string>
<string name="login_support_additional_placeholder">Np. \"Ostatnio zmieniłem szkołę i…\" albo \"Jestem rodzicem i nie widzę drugiego dziecka…\"</string>
<string name="login_support_submit">Submit</string>
<!--Notifications-->
<string name="notifications_header_title">Enable notifications</string>
<string name="notifications_header_description">Enable notifications so you don\'t miss message from teacher or new grade</string>

View File

@ -44,6 +44,7 @@
<string name="login_token_hint">Token</string>
<string name="login_pin_hint">PIN</string>
<string name="login_symbol_hint">Symbol</string>
<string name="login_symbol_placeholder">E.g. \"lodz\" or \"powiatjaroslawski\"</string>
<string name="login_sign_in">Anmelden</string>
<string name="login_invalid_password">Passwort ist zu kurz</string>
<string name="login_incorrect_password_default">Anmeldedaten sind falsch</string>
@ -54,7 +55,8 @@
<string name="login_invalid_email">Ungültige email</string>
<string name="login_invalid_login">Den zugewiesenen Login anstelle von email verwenden</string>
<string name="login_invalid_custom_email">Benutze den zugewiesenen Login oder E-Mail in @%1$s</string>
<string name="login_invalid_symbol">Ungültige symbol</string>
<string name="login_invalid_symbol">Invalid symbol. If you cannot find it, please contact the school</string>
<string name="login_invalid_symbol_definitely">Don\'t make this up! If you cannot find it, please contact the school</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_duplicate_student">Ausgewählter Student ist bereits angemeldet.</string>
<string name="login_symbol_helper">Das Symbol kann auf der Registerseite in&#160;<b>Student </b>&#160;<b>Tost Möbeln</b>&#160;<b>Registrieren Sie Ihr Mobilgerät</b>gefunden werden.\n\nStellen Sie sicher, dass Sie die entsprechende Registervariante im Feld <b>UONET+ Registervariante</b> auf dem vorherigen Bildschirm festgelegt haben</string>
@ -69,7 +71,7 @@
<string name="login_contact_discord">Discord</string>
<string name="login_email_intent_title">email senden</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">Reset password</string>
<string name="login_recover_title">Ihr Konto wiederherstellen</string>
<string name="login_recover">Wiederherstellen</string>
<string name="login_signed_in">Student ist bereits angemeldet</string>
@ -77,6 +79,12 @@
<string name="login_other_search_locations">Andere Suchorte</string>
<string name="login_no_active_student">Keine aktiven Schüler gefunden</string>
<string name="login_symbol_enter">Geben Sie ein anderes Symbol ein</string>
<string name="login_support_title">Get help</string>
<string name="login_support_school_hint">Full school name (required)</string>
<string name="login_support_school_placeholder">Np. ZSTiO Jarosław lub SP nr 99 w Łodzi</string>
<string name="login_support_additional_hint">Additional information in Polish (optional)</string>
<string name="login_support_additional_placeholder">Np. \"Ostatnio zmieniłem szkołę i…\" albo \"Jestem rodzicem i nie widzę drugiego dziecka…\"</string>
<string name="login_support_submit">Submit</string>
<!--Notifications-->
<string name="notifications_header_title">Benachrichtigungen aktivieren</string>
<string name="notifications_header_description">Aktivieren Sie Benachrichtigungen, damit Sie keine Nachricht vom Lehrer oder eine neue Klasse verpassen</string>

View File

@ -44,6 +44,7 @@
<string name="login_token_hint">Token</string>
<string name="login_pin_hint">PIN</string>
<string name="login_symbol_hint">Symbol</string>
<string name="login_symbol_placeholder">E.g. \"lodz\" or \"powiatjaroslawski\"</string>
<string name="login_sign_in">Sign in</string>
<string name="login_invalid_password">Password too short</string>
<string name="login_incorrect_password_default">Login details are incorrect</string>
@ -54,7 +55,8 @@
<string name="login_invalid_email">Invalid email</string>
<string name="login_invalid_login">Use the assigned login instead of email</string>
<string name="login_invalid_custom_email">Use the assigned login or email in @%1$s</string>
<string name="login_invalid_symbol">Invalid symbol</string>
<string name="login_invalid_symbol">Invalid symbol. If you cannot find it, please contact the school</string>
<string name="login_invalid_symbol_definitely">Don\'t make this up! If you cannot find it, please contact the school</string>
<string name="login_incorrect_symbol">Student not found. Validate the symbol and the chosen variation of the UONET+ register</string>
<string name="login_duplicate_student">Selected student is already logged in</string>
<string name="login_symbol_helper">The symbol can be found on the register page in&#160;<b>Uczeń</b> →&#160;<b>Dostęp Mobilny</b>&#160;<b>Wygeneruj kod dostępu</b>.\n\nMake sure that you have set the appropriate register variant in the <b>UONET+ register variant</b> field on the first login screen</string>
@ -69,7 +71,7 @@
<string name="login_contact_discord">Discord</string>
<string name="login_email_intent_title">Send email</string>
<string name="login_recover_warning">Make sure you select the correct UONET+ register variation!</string>
<string name="login_recover_button">I forgot my password</string>
<string name="login_recover_button">Reset password</string>
<string name="login_recover_title">Recover your account</string>
<string name="login_recover">Recover</string>
<string name="login_signed_in">Student is already signed in</string>
@ -77,6 +79,12 @@
<string name="login_other_search_locations">Other search locations</string>
<string name="login_no_active_student">No active students found</string>
<string name="login_symbol_enter">Enter a different symbol</string>
<string name="login_support_title">Get help</string>
<string name="login_support_school_hint">Full school name (required)</string>
<string name="login_support_school_placeholder">Np. ZSTiO Jarosław lub SP nr 99 w Łodzi</string>
<string name="login_support_additional_hint">Additional information in Polish (optional)</string>
<string name="login_support_additional_placeholder">Np. \"Ostatnio zmieniłem szkołę i…\" albo \"Jestem rodzicem i nie widzę drugiego dziecka…\"</string>
<string name="login_support_submit">Submit</string>
<!--Notifications-->
<string name="notifications_header_title">Enable notifications</string>
<string name="notifications_header_description">Enable notifications so you don\'t miss message from teacher or new grade</string>

View File

@ -44,6 +44,7 @@
<string name="login_token_hint">Token</string>
<string name="login_pin_hint">PIN</string>
<string name="login_symbol_hint">Symbol</string>
<string name="login_symbol_placeholder">E.g. \"lodz\" or \"powiatjaroslawski\"</string>
<string name="login_sign_in">Sign in</string>
<string name="login_invalid_password">Password too short</string>
<string name="login_incorrect_password_default">Login details are incorrect</string>
@ -54,7 +55,8 @@
<string name="login_invalid_email">Invalid email</string>
<string name="login_invalid_login">Use the assigned login instead of email</string>
<string name="login_invalid_custom_email">Use the assigned login or email in @%1$s</string>
<string name="login_invalid_symbol">Invalid symbol</string>
<string name="login_invalid_symbol">Invalid symbol. If you cannot find it, please contact the school</string>
<string name="login_invalid_symbol_definitely">Don\'t make this up! If you cannot find it, please contact the school</string>
<string name="login_incorrect_symbol">Student not found. Validate the symbol and the chosen variation of the UONET+ register</string>
<string name="login_duplicate_student">Selected student is already logged in</string>
<string name="login_symbol_helper">The symbol can be found on the register page in&#160;<b>Uczeń</b> →&#160;<b>Dostęp Mobilny</b>&#160;<b>Wygeneruj kod dostępu</b>.\n\nMake sure that you have set the appropriate register variant in the <b>UONET+ register variant</b> field on the first login screen</string>
@ -69,7 +71,7 @@
<string name="login_contact_discord">Discord</string>
<string name="login_email_intent_title">Send email</string>
<string name="login_recover_warning">Make sure you select the correct UONET+ register variation!</string>
<string name="login_recover_button">I forgot my password</string>
<string name="login_recover_button">Reset password</string>
<string name="login_recover_title">Recover your account</string>
<string name="login_recover">Recover</string>
<string name="login_signed_in">Student is already signed in</string>
@ -77,6 +79,12 @@
<string name="login_other_search_locations">Other search locations</string>
<string name="login_no_active_student">No active students found</string>
<string name="login_symbol_enter">Enter a different symbol</string>
<string name="login_support_title">Get help</string>
<string name="login_support_school_hint">Full school name (required)</string>
<string name="login_support_school_placeholder">Np. ZSTiO Jarosław lub SP nr 99 w Łodzi</string>
<string name="login_support_additional_hint">Additional information in Polish (optional)</string>
<string name="login_support_additional_placeholder">Np. \"Ostatnio zmieniłem szkołę i…\" albo \"Jestem rodzicem i nie widzę drugiego dziecka…\"</string>
<string name="login_support_submit">Submit</string>
<!--Notifications-->
<string name="notifications_header_title">Enable notifications</string>
<string name="notifications_header_description">Enable notifications so you don\'t miss message from teacher or new grade</string>

View File

@ -44,6 +44,7 @@
<string name="login_token_hint">Token</string>
<string name="login_pin_hint">PIN</string>
<string name="login_symbol_hint">Symbol</string>
<string name="login_symbol_placeholder">Np. \"lodz\" czy \"powiatjaroslawski\"</string>
<string name="login_sign_in">Zaloguj</string>
<string name="login_invalid_password">To hasło jest za krótkie</string>
<string name="login_incorrect_password_default">Dane logowania są niepoprawne</string>
@ -54,7 +55,8 @@
<string name="login_invalid_email">Nieprawidłowy adres e-mail</string>
<string name="login_invalid_login">Użyj loginu zamiast adresu e-mail</string>
<string name="login_invalid_custom_email">Użyj loginu lub adresu e-mail w @%1$s</string>
<string name="login_invalid_symbol">Nieprawidłowy symbol</string>
<string name="login_invalid_symbol">Nieprawidłowy symbol. Jeśli nie możesz go znaleźć, skontaktuj się ze szkołą</string>
<string name="login_invalid_symbol_definitely">Nie zmyślaj! Jeśli nie możesz znaleźć symbolu, skontaktuj się ze szkołą</string>
<string name="login_incorrect_symbol">Nie znaleziono ucznia. Sprawdź poprawność symbolu i wybranej odmiany dziennika UONET+</string>
<string name="login_duplicate_student">Wybrany uczeń jest już zalogowany</string>
<string name="login_symbol_helper">Symbol można znaleźć na stronie dziennika w&#160;<b>Uczeń</b>&#160;<b>Dostęp Mobilny</b>&#160;<b>Wygeneruj kod dostępu</b>.\n\nUpewnij się, że ustawiłeś odpowiednią odmianę dziennika w polu <b>Odmiana dziennika UONET+</b> na pierwszym ekranie logowania</string>
@ -69,7 +71,7 @@
<string name="login_contact_discord">Discord</string>
<string name="login_email_intent_title">Wyślij wiadomość e-mail</string>
<string name="login_recover_warning">Upewnij się, że została wybrana odpowiednia odmiana dziennika UONET+!</string>
<string name="login_recover_button">Nie pamiętam hasła</string>
<string name="login_recover_button">Zresetuj hasło</string>
<string name="login_recover_title">Przywróć swoje konto</string>
<string name="login_recover">Przywróć</string>
<string name="login_signed_in">Uczeń jest już zalogowany</string>
@ -77,6 +79,12 @@
<string name="login_other_search_locations">Inne lokalizacje wyszukiwania</string>
<string name="login_no_active_student">Nie znaleziono aktywnych uczniów</string>
<string name="login_symbol_enter">Wprowadź inny symbol</string>
<string name="login_support_title">Uzyskaj pomoc</string>
<string name="login_support_school_hint">Pełna nazwa szkoły (wymagana)</string>
<string name="login_support_school_placeholder">Np. ZSTiO Jarosław lub SP nr 99 w Łodzi</string>
<string name="login_support_additional_hint">Dodatkowe informacje (po polsku) (nieobowiązkowo)</string>
<string name="login_support_additional_placeholder">Np. \"Ostatnio zmieniłem szkołę i…\" albo \"Jestem rodzicem i nie widzę drugiego dziecka…\"</string>
<string name="login_support_submit">Wyślij</string>
<!--Notifications-->
<string name="notifications_header_title">Włącz powiadomienia</string>
<string name="notifications_header_description">Włącz powiadomienia, aby nie przegapić wiadomości od nauczyciela lub nowej oceny</string>

View File

@ -44,6 +44,7 @@
<string name="login_token_hint">Token</string>
<string name="login_pin_hint">PIN</string>
<string name="login_symbol_hint">Symbol</string>
<string name="login_symbol_placeholder">E.g. \"lodz\" or \"powiatjaroslawski\"</string>
<string name="login_sign_in">Войти</string>
<string name="login_invalid_password">Пароль слишком короткий</string>
<string name="login_incorrect_password_default">Данные для входа указаны неверно</string>
@ -54,7 +55,8 @@
<string name="login_invalid_email">Неверный e-mail</string>
<string name="login_invalid_login">Используйте назначенный логин вместо e-mail</string>
<string name="login_invalid_custom_email">Используйте назначенный логин или email в @%1$s</string>
<string name="login_invalid_symbol">Неверный symbol</string>
<string name="login_invalid_symbol">Invalid symbol. If you cannot find it, please contact the school</string>
<string name="login_invalid_symbol_definitely">Don\'t make this up! If you cannot find it, please contact the school</string>
<string name="login_incorrect_symbol">Ученик не найден. Проверьте symbol и выбранный тип дненика UONET+</string>
<string name="login_duplicate_student">Данный ученик уже авторизован</string>
<string name="login_symbol_helper">Symbol можно найти на странице регистрации в &#160;<b>Uczeń</b> →&#160;<b>Dostęp Mobilny</b>&#160;<b>Wygeneruj kod dostępu</b>.\n\nУбедитесь, что вы выбрали соответствующий тип дневника в поле <b>Тип дневника UONET+</b> на первом экране входа</string>
@ -69,7 +71,7 @@
<string name="login_contact_discord">Discord</string>
<string name="login_email_intent_title">Отправить письмо</string>
<string name="login_recover_warning">Убедитесь, что вы выбрали правильный тип дневника UONET+</string>
<string name="login_recover_button">Забыли пароль?</string>
<string name="login_recover_button">Reset password</string>
<string name="login_recover_title">Восстановите свой аккаунт</string>
<string name="login_recover">Восстановить</string>
<string name="login_signed_in">Ученик уже авторизован</string>
@ -77,6 +79,12 @@
<string name="login_other_search_locations">Другие места поиска</string>
<string name="login_no_active_student">Не найдено активных учеников</string>
<string name="login_symbol_enter">Введите другой symbol</string>
<string name="login_support_title">Get help</string>
<string name="login_support_school_hint">Full school name (required)</string>
<string name="login_support_school_placeholder">Np. ZSTiO Jarosław lub SP nr 99 w Łodzi</string>
<string name="login_support_additional_hint">Additional information in Polish (optional)</string>
<string name="login_support_additional_placeholder">Np. \"Ostatnio zmieniłem szkołę i…\" albo \"Jestem rodzicem i nie widzę drugiego dziecka…\"</string>
<string name="login_support_submit">Submit</string>
<!--Notifications-->
<string name="notifications_header_title">Включить уведомления</string>
<string name="notifications_header_description">Включить уведомления, чтобы вы не пропустили сообщение от учителя или новую оценку</string>

View File

@ -52,9 +52,9 @@
<item>Priemer známok z celého roka</item>
</string-array>
<string-array name="timetable_show_gaps_entries">
<item>Don\'t show</item>
<item>Only between lessons</item>
<item>Before and between lessons</item>
<item>Nezobrazovať</item>
<item>Iba medzi lekciami</item>
<item>Pred a medzi lekciami</item>
</string-array>
<string-array name="dashboard_tile_entries">
<item>Šťastné číslo</item>

View File

@ -44,6 +44,7 @@
<string name="login_token_hint">Token</string>
<string name="login_pin_hint">PIN</string>
<string name="login_symbol_hint">Symbol</string>
<string name="login_symbol_placeholder">E.g. \"lodz\" or \"powiatjaroslawski\"</string>
<string name="login_sign_in">Prihlásiť</string>
<string name="login_invalid_password">Toto heslo je príliš krátke</string>
<string name="login_incorrect_password_default">Prihlasovacie údaje sú nesprávne</string>
@ -54,7 +55,8 @@
<string name="login_invalid_email">Neplatný e-mail</string>
<string name="login_invalid_login">Namiesto e-mailu použite priradené prihlasovacie údaje</string>
<string name="login_invalid_custom_email">Použite priradené prihlasovacie alebo e-mail v @%1$s</string>
<string name="login_invalid_symbol">Neplatný symbol</string>
<string name="login_invalid_symbol">Invalid symbol. If you cannot find it, please contact the school</string>
<string name="login_invalid_symbol_definitely">Don\'t make this up! If you cannot find it, please contact the school</string>
<string name="login_incorrect_symbol">Žiak nebol nájdený. Skontrolujte správnosť symbolu a vybrané varianty denníka UONET+</string>
<string name="login_duplicate_student">Vybraný žiak už je prihlásený</string>
<string name="login_symbol_helper">Symbol nájdete na stránke denníka v &#160;<b>Uczeń</b>&#160;<b>Dostęp Mobilny</b>&#160;<b>Wygeneruj kod dostępu</b>.\n\nUistite sa, že ste nastavili správny variant denníka v poli <b>Variácia denníka UONET+</b> na prvej prihlasovacej obrazovke</string>
@ -69,7 +71,7 @@
<string name="login_contact_discord">Discord</string>
<string name="login_email_intent_title">Poslať e-mail</string>
<string name="login_recover_warning">Uistite sa, že ste vybrali správny variant denníka UONET+!</string>
<string name="login_recover_button">Zabudol som heslo</string>
<string name="login_recover_button">Reset password</string>
<string name="login_recover_title">Obnovte svoj účet</string>
<string name="login_recover">Obnoviť</string>
<string name="login_signed_in">Žiak je už prihlásený</string>
@ -77,6 +79,12 @@
<string name="login_other_search_locations">Iné miesta vyhľadávania</string>
<string name="login_no_active_student">Neboli nájdení žiadni aktívni žiaci</string>
<string name="login_symbol_enter">Zadajte iný symbol</string>
<string name="login_support_title">Get help</string>
<string name="login_support_school_hint">Full school name (required)</string>
<string name="login_support_school_placeholder">Np. ZSTiO Jarosław lub SP nr 99 w Łodzi</string>
<string name="login_support_additional_hint">Additional information in Polish (optional)</string>
<string name="login_support_additional_placeholder">Np. \"Ostatnio zmieniłem szkołę i…\" albo \"Jestem rodzicem i nie widzę drugiego dziecka…\"</string>
<string name="login_support_submit">Submit</string>
<!--Notifications-->
<string name="notifications_header_title">Povoliť oznámenia</string>
<string name="notifications_header_description">Povoliť oznámenia, aby ste nezmeškali správu od učiteľa alebo o novej známke</string>
@ -186,10 +194,10 @@
<string name="timetable_notify_change_teacher">Zmena učiteľa z %1$s na %2$s</string>
<string name="timetable_notify_change_subject">Zmena predmetu z %1$s na %2$s</string>
<plurals name="timetable_no_lesson">
<item quantity="one">No lesson</item>
<item quantity="few">No lessons</item>
<item quantity="many">No lessons</item>
<item quantity="other">No lessons</item>
<item quantity="one">Žiadne lekcie</item>
<item quantity="few">Žiadne lekcie</item>
<item quantity="many">Žiadne lekcie</item>
<item quantity="other">Žiadne lekcie</item>
</plurals>
<plurals name="timetable_notify_new_items_title">
<item quantity="one">Zmena plánu lekcií</item>
@ -706,7 +714,7 @@
<string name="pref_view_expand_grade">Rozvijanie známok</string>
<string name="pref_view_timetable_show_timers">Označiť aktuálne lekciu</string>
<string name="pref_view_timetable_show_groups">Zobraziť skupiny vedľa predmetov</string>
<string name="pref_view_timetable_show_gaps">Show empty tiles where there\'s no lesson</string>
<string name="pref_view_timetable_show_gaps">Zobraziť prázdne dlaždice, kde nie je žiadne lekcie</string>
<string name="pref_view_grade_statistics_list">Zobraziť zoznam grafov v známkach triedy</string>
<string name="pref_view_subjects_without_grades">Zobraziť predmety bez známok</string>
<string name="pref_view_grade_color_scheme">Známky farebnú schému</string>

View File

@ -52,9 +52,9 @@
<item>Середня оцінка з цілого року</item>
</string-array>
<string-array name="timetable_show_gaps_entries">
<item>Don\'t show</item>
<item>Only between lessons</item>
<item>Before and between lessons</item>
<item>Не показувати</item>
<item>Тільки між уроками</item>
<item>Перед і між уроками</item>
</string-array>
<string-array name="dashboard_tile_entries">
<item>Щасливий номер</item>

View File

@ -44,6 +44,7 @@
<string name="login_token_hint">Token</string>
<string name="login_pin_hint">PIN</string>
<string name="login_symbol_hint">Symbol</string>
<string name="login_symbol_placeholder">E.g. \"lodz\" or \"powiatjaroslawski\"</string>
<string name="login_sign_in">Увійти</string>
<string name="login_invalid_password">Занадто короткий пароль</string>
<string name="login_incorrect_password_default">Вказані невірні дані</string>
@ -54,8 +55,9 @@
<string name="login_invalid_email">Недійсна адреса e-mail</string>
<string name="login_invalid_login">Використовуйте призначений логін замість адреси e-mail</string>
<string name="login_invalid_custom_email">Використовуйте призначений логін або адресу e-mail в @%1$s</string>
<string name="login_invalid_symbol">Неправильний symbol</string>
<string name="login_incorrect_symbol">Студента не знайдено. Перевірте symbol та обранний тип щоденника UONET+</string>
<string name="login_invalid_symbol">Invalid symbol. If you cannot find it, please contact the school</string>
<string name="login_invalid_symbol_definitely">Don\'t make this up! If you cannot find it, please contact the school</string>
<string name="login_incorrect_symbol">Студента не знайдено. Перевірте symbol та обраний тип щоденника UONET+</string>
<string name="login_duplicate_student">Цього учня вже авторизовано</string>
<string name="login_symbol_helper">Symbol можно знайти на сторінці щоденника у&#160;<b>Uczeń</b> →&#160;<b>Dostęp Mobilny</b>&#160;<b>Wygeneruj kod dostępu</b>.\n\nПереконайтеся, що ви вказали відповідний щоденник у полі <b>Тип щоденника UONET+</b> на першому екрані логування</string>
<string name="login_select_student">Виберіть учнів для авторизації в додатку</string>
@ -69,7 +71,7 @@
<string name="login_contact_discord">Discord</string>
<string name="login_email_intent_title">Надіслати електронний лист</string>
<string name="login_recover_warning">Переконайтеся, що ви вибрали правильний тип щоденника UONET+!</string>
<string name="login_recover_button">Забули пароль?</string>
<string name="login_recover_button">Reset password</string>
<string name="login_recover_title">Відновіть свій обліковий запис</string>
<string name="login_recover">Відновити</string>
<string name="login_signed_in">Учня вже авторизовано</string>
@ -77,6 +79,12 @@
<string name="login_other_search_locations">Інші розташування пошуку</string>
<string name="login_no_active_student">Активних учнів не знайдено</string>
<string name="login_symbol_enter">Введіть інший symbol</string>
<string name="login_support_title">Get help</string>
<string name="login_support_school_hint">Full school name (required)</string>
<string name="login_support_school_placeholder">Np. ZSTiO Jarosław lub SP nr 99 w Łodzi</string>
<string name="login_support_additional_hint">Additional information in Polish (optional)</string>
<string name="login_support_additional_placeholder">Np. \"Ostatnio zmieniłem szkołę i…\" albo \"Jestem rodzicem i nie widzę drugiego dziecka…\"</string>
<string name="login_support_submit">Submit</string>
<!--Notifications-->
<string name="notifications_header_title">Увімкнути сповіщення</string>
<string name="notifications_header_description">Увімкнути сповіщення, щоб не пропустити лист від вчителя або нову оцінку</string>
@ -186,10 +194,10 @@
<string name="timetable_notify_change_teacher">Зміна вчителя з %1$s на %2$s</string>
<string name="timetable_notify_change_subject">Зміна теми з %1$s на %2$s</string>
<plurals name="timetable_no_lesson">
<item quantity="one">No lesson</item>
<item quantity="few">No lessons</item>
<item quantity="many">No lessons</item>
<item quantity="other">No lessons</item>
<item quantity="one">Немає уроку</item>
<item quantity="few">Немає уроків</item>
<item quantity="many">Немає уроків</item>
<item quantity="other">Немає уроків</item>
</plurals>
<plurals name="timetable_notify_new_items_title">
<item quantity="one">Зміна у розкладі</item>
@ -706,7 +714,7 @@
<string name="pref_view_expand_grade">Розгортання оцінок</string>
<string name="pref_view_timetable_show_timers">Позначити поточний урок</string>
<string name="pref_view_timetable_show_groups">Показувати групи поруч з темами</string>
<string name="pref_view_timetable_show_gaps">Show empty tiles where there\'s no lesson</string>
<string name="pref_view_timetable_show_gaps">Показувати порожні плитки там, де немає уроків</string>
<string name="pref_view_grade_statistics_list">Показувати діаграми в оцінках класу</string>
<string name="pref_view_subjects_without_grades">Показати предмети без оцінок</string>
<string name="pref_view_grade_color_scheme">Схема кольорів оцінок</string>

View File

@ -49,6 +49,7 @@
<string name="login_token_hint">Token</string>
<string name="login_pin_hint">PIN</string>
<string name="login_symbol_hint">Symbol</string>
<string name="login_symbol_placeholder">E.g. \"lodz\" or \"powiatjaroslawski\"</string>
<string name="login_sign_in">Sign in</string>
<string name="login_invalid_password">Password too short</string>
<string name="login_incorrect_password_default">Login details are incorrect</string>
@ -59,7 +60,8 @@
<string name="login_invalid_email">Invalid email</string>
<string name="login_invalid_login">Use the assigned login instead of email</string>
<string name="login_invalid_custom_email">Use the assigned login or email in @%1$s</string>
<string name="login_invalid_symbol">Invalid symbol</string>
<string name="login_invalid_symbol">Invalid symbol. If you cannot find it, please contact the school</string>
<string name="login_invalid_symbol_definitely">Don\'t make this up! If you cannot find it, please contact the school</string>
<string name="login_incorrect_symbol">Student not found. Validate the symbol and the chosen variation of the UONET+ register</string>
<string name="login_duplicate_student">Selected student is already logged in</string>
<string name="login_symbol_helper">The symbol can be found on the register page in&#160;<b>Uczeń</b> →&#160;<b>Dostęp Mobilny</b>&#160;<b>Wygeneruj kod dostępu</b>.\n\nMake sure that you have set the appropriate register variant in the <b>UONET+ register variant</b> field on the first login screen</string>
@ -74,9 +76,9 @@
<string name="login_contact_discord">Discord</string>
<string name="login_email_intent_title">Send email</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\nIdentyfikator instalacji: %5$s\nOstatni błąd: %6$s\n\nNazwa szkoły i miejscowość: </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\nIdentyfikator instalacji: %5$s\nOstatni błąd: %6$s\n\nNazwa szkoły i miejscowość: %7$s\nDodatkowe informacje: %8$s</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">Reset password</string>
<string name="login_recover_title">Recover your account</string>
<string name="login_recover">Recover</string>
<string name="login_signed_in">Student is already signed in</string>
@ -84,6 +86,12 @@
<string name="login_other_search_locations">Other search locations</string>
<string name="login_no_active_student">No active students found</string>
<string name="login_symbol_enter">Enter a different symbol</string>
<string name="login_support_title">Get help</string>
<string name="login_support_school_hint">Full school name (required)</string>
<string name="login_support_school_placeholder">Np. ZSTiO Jarosław lub SP nr 99 w Łodzi</string>
<string name="login_support_additional_hint">Additional information in Polish (optional)</string>
<string name="login_support_additional_placeholder">Np. \"Ostatnio zmieniłem szkołę i…\" albo \"Jestem rodzicem i nie widzę drugiego dziecka…\"</string>
<string name="login_support_submit">Submit</string>
<!--Notifications-->

View File

@ -82,7 +82,6 @@
</style>
<style name="FullScreenDialogStyle" parent="WulkanowyTheme">
<item name="android:windowFullscreen">true</item>
<item name="android:windowIsFloating">false</item>
</style>
</resources>

View File

@ -2,8 +2,8 @@ package io.github.wulkanowy.utils
import android.util.Log
import com.google.firebase.crashlytics.FirebaseCrashlytics
import fr.bipi.tressence.base.FormatterPriorityTree
import fr.bipi.tressence.common.StackTraceRecorder
import fr.bipi.treessence.base.FormatterPriorityTree
import fr.bipi.treessence.common.StackTraceRecorder
class CrashLogTree : FormatterPriorityTree(Log.VERBOSE) {

View File

@ -0,0 +1,27 @@
package io.github.wulkanowy.utils
import android.content.Context
import com.google.android.play.core.integrity.IntegrityManagerFactory
import com.google.android.play.core.integrity.IntegrityTokenRequest
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.tasks.await
import java.util.UUID
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class IntegrityHelper @Inject constructor(
@ApplicationContext private val context: Context,
) {
suspend fun getIntegrityToken(nonce: String): String? {
val integrityManager = IntegrityManagerFactory.create(context)
val integrityTokenResponse = integrityManager.requestIntegrityToken(
IntegrityTokenRequest.builder()
.setNonce(nonce)
.build()
)
return integrityTokenResponse.await().token()
}
}

View File

@ -5,6 +5,7 @@ import io.github.wulkanowy.data.pojos.RegisterStudent
import io.github.wulkanowy.data.pojos.RegisterSymbol
import io.github.wulkanowy.data.pojos.RegisterUnit
import io.github.wulkanowy.data.pojos.RegisterUser
import io.github.wulkanowy.data.repositories.SchoolsRepository
import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.sdk.scrapper.Scrapper
@ -40,6 +41,9 @@ class LoginStudentSelectPresenterTest {
@MockK
lateinit var studentRepository: StudentRepository
@MockK
lateinit var schoolsRepository: SchoolsRepository
@MockK(relaxed = true)
lateinit var analytics: AnalyticsHelper
@ -110,6 +114,7 @@ class LoginStudentSelectPresenterTest {
clearMocks(studentRepository, loginStudentSelectView)
coEvery { studentRepository.getSavedStudents(false) } returns emptyList()
coEvery { schoolsRepository.logSchoolLogin(any(), any()) } just Runs
every { loginStudentSelectView.initView() } just Runs
every { loginStudentSelectView.symbols } returns emptyMap()
@ -120,6 +125,7 @@ class LoginStudentSelectPresenterTest {
presenter = LoginStudentSelectPresenter(
studentRepository = studentRepository,
schoolsRepository = schoolsRepository,
loginErrorHandler = errorHandler,
syncManager = syncManager,
analytics = analytics,

View File

@ -1,8 +1,8 @@
buildscript {
ext {
kotlin_version = '1.9.0'
about_libraries = '10.8.3'
hilt_version = "2.47"
kotlin_version = '1.9.10'
about_libraries = '10.9.0'
hilt_version = "2.48"
}
repositories {
mavenCentral()
@ -13,15 +13,15 @@ buildscript {
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
classpath "com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin:$kotlin_version-1.0.11"
classpath 'com.android.tools.build:gradle:8.1.0'
classpath "com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin:$kotlin_version-1.0.13"
classpath 'com.android.tools.build:gradle:8.1.1'
classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
classpath 'com.google.gms:google-services:4.3.15'
classpath 'com.huawei.agconnect:agcp:1.9.1.300'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.8'
classpath 'com.google.gms:google-services:4.4.0'
classpath 'com.huawei.agconnect:agcp:1.9.1.301'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.9'
classpath "com.github.triplet.gradle:play-publisher:3.8.4"
classpath "ru.cian:huawei-publish-gradle-plugin:1.4.0"
classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:4.3.0.3225"
classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:4.3.1.3277"
classpath "gradle.plugin.com.star-zero.gradle:githook:1.2.0"
classpath "com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin:$about_libraries"
}