mirror of
https://github.com/wulkanowy/wulkanowy.git
synced 2025-02-07 21:44:37 +01:00
Merge branch 'release/2.3.2'
This commit is contained in:
commit
f893170dec
@ -27,8 +27,8 @@ android {
|
|||||||
testApplicationId "io.github.tests.wulkanowy"
|
testApplicationId "io.github.tests.wulkanowy"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 34
|
targetSdkVersion 34
|
||||||
versionCode 141
|
versionCode 142
|
||||||
versionName "2.3.1"
|
versionName "2.3.2"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
|
||||||
resValue "string", "app_name", "Wulkanowy"
|
resValue "string", "app_name", "Wulkanowy"
|
||||||
@ -188,12 +188,12 @@ ext {
|
|||||||
android_hilt = "1.1.0"
|
android_hilt = "1.1.0"
|
||||||
room = "2.6.1"
|
room = "2.6.1"
|
||||||
chucker = "4.0.0"
|
chucker = "4.0.0"
|
||||||
mockk = "1.13.8"
|
mockk = "1.13.9"
|
||||||
coroutines = "1.7.3"
|
coroutines = "1.7.3"
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'com.github.wulkanowy:sdk:2.3.3'
|
implementation 'io.github.wulkanowy:sdk:2.3.4'
|
||||||
|
|
||||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4'
|
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4'
|
||||||
|
|
||||||
@ -240,7 +240,7 @@ dependencies {
|
|||||||
implementation "com.squareup.okhttp3:logging-interceptor:4.12.0"
|
implementation "com.squareup.okhttp3:logging-interceptor:4.12.0"
|
||||||
|
|
||||||
implementation "com.jakewharton.timber:timber:5.0.1"
|
implementation "com.jakewharton.timber:timber:5.0.1"
|
||||||
implementation "at.favre.lib:slf4j-timber:1.0.1"
|
implementation 'com.github.Faierbel:slf4j-timber:2.0'
|
||||||
implementation 'com.github.bastienpaulfr:Treessence:1.1.2'
|
implementation 'com.github.bastienpaulfr:Treessence:1.1.2'
|
||||||
implementation "com.mikepenz:aboutlibraries-core:$about_libraries"
|
implementation "com.mikepenz:aboutlibraries-core:$about_libraries"
|
||||||
implementation 'io.coil-kt:coil:2.5.0'
|
implementation 'io.coil-kt:coil:2.5.0'
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
package io.github.wulkanowy.data.db.dao
|
package io.github.wulkanowy.data.db.dao
|
||||||
|
|
||||||
import androidx.room.*
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Delete
|
||||||
|
import androidx.room.Insert
|
||||||
|
import androidx.room.OnConflictStrategy
|
||||||
|
import androidx.room.Query
|
||||||
|
import androidx.room.Transaction
|
||||||
|
import androidx.room.Update
|
||||||
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.db.entities.StudentName
|
import io.github.wulkanowy.data.db.entities.StudentName
|
||||||
import io.github.wulkanowy.data.db.entities.StudentNickAndAvatar
|
import io.github.wulkanowy.data.db.entities.StudentNickAndAvatar
|
||||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@ -47,6 +52,9 @@ abstract class StudentDao {
|
|||||||
@Query("UPDATE Students SET is_current = 0")
|
@Query("UPDATE Students SET is_current = 0")
|
||||||
abstract suspend fun resetCurrent()
|
abstract suspend fun resetCurrent()
|
||||||
|
|
||||||
|
@Query("DELETE FROM Students WHERE email = :email AND user_name = :userName")
|
||||||
|
abstract suspend fun deleteByEmailAndUserName(email: String, userName: String)
|
||||||
|
|
||||||
@Transaction
|
@Transaction
|
||||||
open suspend fun switchCurrent(id: Long) {
|
open suspend fun switchCurrent(id: Long) {
|
||||||
resetCurrent()
|
resetCurrent()
|
||||||
|
@ -35,12 +35,15 @@ class LuckyNumberRepository @Inject constructor(
|
|||||||
fetch = {
|
fetch = {
|
||||||
sdk.init(student).getLuckyNumber(student.schoolShortName)?.mapToEntity(student)
|
sdk.init(student).getLuckyNumber(student.schoolShortName)?.mapToEntity(student)
|
||||||
},
|
},
|
||||||
saveFetchResult = { old, new ->
|
saveFetchResult = { oldLuckyNumber, newLuckyNumber ->
|
||||||
if (new != old) {
|
newLuckyNumber ?: return@networkBoundResource
|
||||||
old?.let { luckyNumberDb.deleteAll(listOfNotNull(it)) }
|
|
||||||
luckyNumberDb.insertAll(listOfNotNull((new?.apply {
|
if (newLuckyNumber != oldLuckyNumber) {
|
||||||
if (notify) isNotified = false
|
val updatedLuckNumberList =
|
||||||
})))
|
listOf(newLuckyNumber.apply { if (notify) isNotified = false })
|
||||||
|
|
||||||
|
oldLuckyNumber?.let { luckyNumberDb.deleteAll(listOfNotNull(it)) }
|
||||||
|
luckyNumberDb.insertAll(updatedLuckNumberList)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
package io.github.wulkanowy.data.repositories
|
package io.github.wulkanowy.data.repositories
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import androidx.room.withTransaction
|
import androidx.room.withTransaction
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
|
||||||
import io.github.wulkanowy.data.db.AppDatabase
|
import io.github.wulkanowy.data.db.AppDatabase
|
||||||
import io.github.wulkanowy.data.db.dao.SemesterDao
|
import io.github.wulkanowy.data.db.dao.SemesterDao
|
||||||
import io.github.wulkanowy.data.db.dao.StudentDao
|
import io.github.wulkanowy.data.db.dao.StudentDao
|
||||||
@ -17,20 +15,19 @@ import io.github.wulkanowy.data.pojos.RegisterUser
|
|||||||
import io.github.wulkanowy.sdk.Sdk
|
import io.github.wulkanowy.sdk.Sdk
|
||||||
import io.github.wulkanowy.utils.DispatchersProvider
|
import io.github.wulkanowy.utils.DispatchersProvider
|
||||||
import io.github.wulkanowy.utils.init
|
import io.github.wulkanowy.utils.init
|
||||||
import io.github.wulkanowy.utils.security.decrypt
|
import io.github.wulkanowy.utils.security.Scrambler
|
||||||
import io.github.wulkanowy.utils.security.encrypt
|
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class StudentRepository @Inject constructor(
|
class StudentRepository @Inject constructor(
|
||||||
@ApplicationContext private val context: Context,
|
|
||||||
private val dispatchers: DispatchersProvider,
|
private val dispatchers: DispatchersProvider,
|
||||||
private val studentDb: StudentDao,
|
private val studentDb: StudentDao,
|
||||||
private val semesterDb: SemesterDao,
|
private val semesterDb: SemesterDao,
|
||||||
private val sdk: Sdk,
|
private val sdk: Sdk,
|
||||||
private val appDatabase: AppDatabase
|
private val appDatabase: AppDatabase,
|
||||||
|
private val scrambler: Scrambler,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
suspend fun isCurrentStudentSet() = studentDb.loadCurrent()?.isCurrent ?: false
|
suspend fun isCurrentStudentSet() = studentDb.loadCurrent()?.isCurrent ?: false
|
||||||
@ -68,7 +65,7 @@ class StudentRepository @Inject constructor(
|
|||||||
student = student.apply {
|
student = student.apply {
|
||||||
if (decryptPass && Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.HEBE) {
|
if (decryptPass && Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.HEBE) {
|
||||||
student.password = withContext(dispatchers.io) {
|
student.password = withContext(dispatchers.io) {
|
||||||
decrypt(student.password)
|
scrambler.decrypt(student.password)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -86,7 +83,7 @@ class StudentRepository @Inject constructor(
|
|||||||
}.apply {
|
}.apply {
|
||||||
if (decryptPass && Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.HEBE) {
|
if (decryptPass && Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.HEBE) {
|
||||||
student.password = withContext(dispatchers.io) {
|
student.password = withContext(dispatchers.io) {
|
||||||
decrypt(student.password)
|
scrambler.decrypt(student.password)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -96,7 +93,7 @@ class StudentRepository @Inject constructor(
|
|||||||
|
|
||||||
if (decryptPass && Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.HEBE) {
|
if (decryptPass && Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.HEBE) {
|
||||||
student.password = withContext(dispatchers.io) {
|
student.password = withContext(dispatchers.io) {
|
||||||
decrypt(student.password)
|
scrambler.decrypt(student.password)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return student
|
return student
|
||||||
@ -107,7 +104,7 @@ class StudentRepository @Inject constructor(
|
|||||||
|
|
||||||
if (decryptPass && Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.HEBE) {
|
if (decryptPass && Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.HEBE) {
|
||||||
student.password = withContext(dispatchers.io) {
|
student.password = withContext(dispatchers.io) {
|
||||||
decrypt(student.password)
|
scrambler.decrypt(student.password)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return student
|
return student
|
||||||
@ -120,7 +117,7 @@ class StudentRepository @Inject constructor(
|
|||||||
it.apply {
|
it.apply {
|
||||||
if (Sdk.Mode.valueOf(it.loginMode) != Sdk.Mode.HEBE) {
|
if (Sdk.Mode.valueOf(it.loginMode) != Sdk.Mode.HEBE) {
|
||||||
password = withContext(dispatchers.io) {
|
password = withContext(dispatchers.io) {
|
||||||
encrypt(password, context)
|
scrambler.encrypt(password)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -166,4 +163,15 @@ class StudentRepository @Inject constructor(
|
|||||||
|
|
||||||
studentDb.update(studentName)
|
studentDb.update(studentName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun deleteStudentsAssociatedWithAccount(student: Student) {
|
||||||
|
studentDb.deleteByEmailAndUserName(student.email, student.userName)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun clearAll() {
|
||||||
|
withContext(dispatchers.io) {
|
||||||
|
scrambler.clearKeyPair()
|
||||||
|
appDatabase.clearAllTables()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,11 +68,20 @@ abstract class BaseActivity<T : BasePresenter<out BaseView>, VB : ViewBinding> :
|
|||||||
} else Toast.makeText(this, text, Toast.LENGTH_LONG).show()
|
} else Toast.makeText(this, text, Toast.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showExpiredDialog() {
|
override fun showExpiredCredentialsDialog() {
|
||||||
|
MaterialAlertDialogBuilder(this)
|
||||||
|
.setTitle(R.string.main_expired_credentials_title)
|
||||||
|
.setMessage(R.string.main_expired_credentials_description)
|
||||||
|
.setPositiveButton(R.string.main_log_in) { _, _ -> presenter.onConfirmExpiredCredentialsSelected() }
|
||||||
|
.setNegativeButton(android.R.string.cancel) { _, _ -> }
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showDecryptionFailedDialog() {
|
||||||
MaterialAlertDialogBuilder(this)
|
MaterialAlertDialogBuilder(this)
|
||||||
.setTitle(R.string.main_session_expired)
|
.setTitle(R.string.main_session_expired)
|
||||||
.setMessage(R.string.main_session_relogin)
|
.setMessage(R.string.main_session_relogin)
|
||||||
.setPositiveButton(R.string.main_log_in) { _, _ -> presenter.onExpiredLoginSelected() }
|
.setPositiveButton(R.string.main_log_in) { _, _ -> presenter.onConfirmDecryptionFailedSelected() }
|
||||||
.setNegativeButton(android.R.string.cancel) { _, _ -> }
|
.setNegativeButton(android.R.string.cancel) { _, _ -> }
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
|
@ -28,8 +28,12 @@ abstract class BaseDialogFragment<VB : ViewBinding> : DialogFragment(), BaseView
|
|||||||
Toast.makeText(context, text, Toast.LENGTH_LONG).show()
|
Toast.makeText(context, text, Toast.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showExpiredDialog() {
|
override fun showExpiredCredentialsDialog() {
|
||||||
(activity as? BaseActivity<*, *>)?.showExpiredDialog()
|
(activity as? BaseActivity<*, *>)?.showExpiredCredentialsDialog()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showDecryptionFailedDialog() {
|
||||||
|
(activity as? BaseActivity<*, *>)?.showDecryptionFailedDialog()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun openClearLoginView() {
|
override fun openClearLoginView() {
|
||||||
|
@ -39,8 +39,12 @@ abstract class BaseFragment<VB : ViewBinding>(@LayoutRes layoutId: Int) : Fragme
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showExpiredDialog() {
|
override fun showExpiredCredentialsDialog() {
|
||||||
(activity as? BaseActivity<*, *>)?.showExpiredDialog()
|
(activity as? BaseActivity<*, *>)?.showExpiredCredentialsDialog()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showDecryptionFailedDialog() {
|
||||||
|
(activity as? BaseActivity<*, *>)?.showDecryptionFailedDialog()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showAuthDialog() {
|
override fun showAuthDialog() {
|
||||||
|
@ -28,20 +28,37 @@ open class BasePresenter<T : BaseView>(
|
|||||||
this.view = view
|
this.view = view
|
||||||
errorHandler.apply {
|
errorHandler.apply {
|
||||||
showErrorMessage = view::showError
|
showErrorMessage = view::showError
|
||||||
onSessionExpired = view::showExpiredDialog
|
onExpiredCredentials = view::showExpiredCredentialsDialog
|
||||||
|
onDecryptionFailed = view::showDecryptionFailedDialog
|
||||||
onNoCurrentStudent = view::openClearLoginView
|
onNoCurrentStudent = view::openClearLoginView
|
||||||
onPasswordChangeRequired = view::showChangePasswordSnackbar
|
onPasswordChangeRequired = view::showChangePasswordSnackbar
|
||||||
onAuthorizationRequired = view::showAuthDialog
|
onAuthorizationRequired = view::showAuthDialog
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onExpiredLoginSelected() {
|
fun onConfirmDecryptionFailedSelected() {
|
||||||
Timber.i("Attempt to switch the student after the session expires")
|
Timber.i("Attempt to clear all data")
|
||||||
|
|
||||||
|
presenterScope.launch {
|
||||||
|
runCatching { studentRepository.clearAll() }
|
||||||
|
.onFailure {
|
||||||
|
Timber.i("Clear data result: An exception occurred")
|
||||||
|
errorHandler.dispatch(it)
|
||||||
|
}
|
||||||
|
.onSuccess {
|
||||||
|
Timber.i("Clear data result: Open login view")
|
||||||
|
view?.openClearLoginView()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onConfirmExpiredCredentialsSelected() {
|
||||||
|
Timber.i("Attempt to delete students associated with the account and switch to new student")
|
||||||
|
|
||||||
presenterScope.launch {
|
presenterScope.launch {
|
||||||
runCatching {
|
runCatching {
|
||||||
val student = studentRepository.getCurrentStudent(false)
|
val student = studentRepository.getCurrentStudent(false)
|
||||||
studentRepository.logoutStudent(student)
|
studentRepository.deleteStudentsAssociatedWithAccount(student)
|
||||||
|
|
||||||
val students = studentRepository.getSavedStudents(false)
|
val students = studentRepository.getSavedStudents(false)
|
||||||
if (students.isNotEmpty()) {
|
if (students.isNotEmpty()) {
|
||||||
@ -50,11 +67,11 @@ open class BasePresenter<T : BaseView>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onFailure {
|
.onFailure {
|
||||||
Timber.i("Switch student result: An exception occurred")
|
Timber.i("Delete students result: An exception occurred")
|
||||||
errorHandler.dispatch(it)
|
errorHandler.dispatch(it)
|
||||||
}
|
}
|
||||||
.onSuccess {
|
.onSuccess {
|
||||||
Timber.i("Switch student result: Open login view")
|
Timber.i("Delete students result: Open login view")
|
||||||
view?.openClearLoginView()
|
view?.openClearLoginView()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,9 @@ interface BaseView {
|
|||||||
|
|
||||||
fun showMessage(text: String)
|
fun showMessage(text: String)
|
||||||
|
|
||||||
fun showExpiredDialog()
|
fun showExpiredCredentialsDialog()
|
||||||
|
|
||||||
|
fun showDecryptionFailedDialog()
|
||||||
|
|
||||||
fun showAuthDialog()
|
fun showAuthDialog()
|
||||||
|
|
||||||
|
@ -15,7 +15,9 @@ open class ErrorHandler @Inject constructor(@ApplicationContext protected val co
|
|||||||
|
|
||||||
var showErrorMessage: (String, Throwable) -> Unit = { _, _ -> }
|
var showErrorMessage: (String, Throwable) -> Unit = { _, _ -> }
|
||||||
|
|
||||||
var onSessionExpired: () -> Unit = {}
|
var onExpiredCredentials: () -> Unit = {}
|
||||||
|
|
||||||
|
var onDecryptionFailed: () -> Unit = {}
|
||||||
|
|
||||||
var onNoCurrentStudent: () -> Unit = {}
|
var onNoCurrentStudent: () -> Unit = {}
|
||||||
|
|
||||||
@ -32,7 +34,8 @@ open class ErrorHandler @Inject constructor(@ApplicationContext protected val co
|
|||||||
showErrorMessage(context.resources.getErrorString(error), error)
|
showErrorMessage(context.resources.getErrorString(error), error)
|
||||||
when (error) {
|
when (error) {
|
||||||
is PasswordChangeRequiredException -> onPasswordChangeRequired(error.redirectUrl)
|
is PasswordChangeRequiredException -> onPasswordChangeRequired(error.redirectUrl)
|
||||||
is ScramblerException, is BadCredentialsException -> onSessionExpired()
|
is ScramblerException -> onDecryptionFailed()
|
||||||
|
is BadCredentialsException -> onExpiredCredentials()
|
||||||
is NoCurrentStudentException -> onNoCurrentStudent()
|
is NoCurrentStudentException -> onNoCurrentStudent()
|
||||||
is AuthorizationRequiredException -> onAuthorizationRequired()
|
is AuthorizationRequiredException -> onAuthorizationRequired()
|
||||||
}
|
}
|
||||||
@ -40,7 +43,8 @@ open class ErrorHandler @Inject constructor(@ApplicationContext protected val co
|
|||||||
|
|
||||||
open fun clear() {
|
open fun clear() {
|
||||||
showErrorMessage = { _, _ -> }
|
showErrorMessage = { _, _ -> }
|
||||||
onSessionExpired = {}
|
onExpiredCredentials = {}
|
||||||
|
onDecryptionFailed = {}
|
||||||
onNoCurrentStudent = {}
|
onNoCurrentStudent = {}
|
||||||
onPasswordChangeRequired = {}
|
onPasswordChangeRequired = {}
|
||||||
onAuthorizationRequired = {}
|
onAuthorizationRequired = {}
|
||||||
|
@ -30,7 +30,12 @@ import io.github.wulkanowy.ui.modules.message.MessageFragment
|
|||||||
import io.github.wulkanowy.ui.modules.notificationscenter.NotificationsCenterFragment
|
import io.github.wulkanowy.ui.modules.notificationscenter.NotificationsCenterFragment
|
||||||
import io.github.wulkanowy.ui.modules.schoolannouncement.SchoolAnnouncementFragment
|
import io.github.wulkanowy.ui.modules.schoolannouncement.SchoolAnnouncementFragment
|
||||||
import io.github.wulkanowy.ui.modules.timetable.TimetableFragment
|
import io.github.wulkanowy.ui.modules.timetable.TimetableFragment
|
||||||
import io.github.wulkanowy.utils.*
|
import io.github.wulkanowy.utils.capitalise
|
||||||
|
import io.github.wulkanowy.utils.dpToPx
|
||||||
|
import io.github.wulkanowy.utils.getErrorString
|
||||||
|
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||||
|
import io.github.wulkanowy.utils.openInternetBrowser
|
||||||
|
import io.github.wulkanowy.utils.toFormattedString
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@ -24,7 +24,9 @@ class SettingsFragment : PreferenceFragmentCompat(), MainView.TitledView, Settin
|
|||||||
|
|
||||||
override fun showMessage(text: String) {}
|
override fun showMessage(text: String) {}
|
||||||
|
|
||||||
override fun showExpiredDialog() {}
|
override fun showExpiredCredentialsDialog() {}
|
||||||
|
|
||||||
|
override fun showDecryptionFailedDialog() {}
|
||||||
|
|
||||||
override fun openClearLoginView() {}
|
override fun openClearLoginView() {}
|
||||||
|
|
||||||
|
@ -47,8 +47,12 @@ class AdvancedFragment : PreferenceFragmentCompat(),
|
|||||||
(activity as? BaseActivity<*, *>)?.showMessage(text)
|
(activity as? BaseActivity<*, *>)?.showMessage(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showExpiredDialog() {
|
override fun showExpiredCredentialsDialog() {
|
||||||
(activity as? BaseActivity<*, *>)?.showExpiredDialog()
|
(activity as? BaseActivity<*, *>)?.showExpiredCredentialsDialog()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showDecryptionFailedDialog() {
|
||||||
|
(activity as? BaseActivity<*, *>)?.showDecryptionFailedDialog()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showChangePasswordSnackbar(redirectUrl: String) {
|
override fun showChangePasswordSnackbar(redirectUrl: String) {
|
||||||
|
@ -63,8 +63,12 @@ class AppearanceFragment : PreferenceFragmentCompat(),
|
|||||||
(activity as? BaseActivity<*, *>)?.showMessage(text)
|
(activity as? BaseActivity<*, *>)?.showMessage(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showExpiredDialog() {
|
override fun showExpiredCredentialsDialog() {
|
||||||
(activity as? BaseActivity<*, *>)?.showExpiredDialog()
|
(activity as? BaseActivity<*, *>)?.showExpiredCredentialsDialog()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showDecryptionFailedDialog() {
|
||||||
|
(activity as? BaseActivity<*, *>)?.showDecryptionFailedDialog()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showChangePasswordSnackbar(redirectUrl: String) {
|
override fun showChangePasswordSnackbar(redirectUrl: String) {
|
||||||
|
@ -133,8 +133,12 @@ class NotificationsFragment : PreferenceFragmentCompat(),
|
|||||||
(activity as? BaseActivity<*, *>)?.showMessage(text)
|
(activity as? BaseActivity<*, *>)?.showMessage(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showExpiredDialog() {
|
override fun showExpiredCredentialsDialog() {
|
||||||
(activity as? BaseActivity<*, *>)?.showExpiredDialog()
|
(activity as? BaseActivity<*, *>)?.showExpiredCredentialsDialog()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showDecryptionFailedDialog() {
|
||||||
|
(activity as? BaseActivity<*, *>)?.showDecryptionFailedDialog()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showChangePasswordSnackbar(redirectUrl: String) {
|
override fun showChangePasswordSnackbar(redirectUrl: String) {
|
||||||
|
@ -84,8 +84,12 @@ class SyncFragment : PreferenceFragmentCompat(),
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showExpiredDialog() {
|
override fun showExpiredCredentialsDialog() {
|
||||||
(activity as? BaseActivity<*, *>)?.showExpiredDialog()
|
(activity as? BaseActivity<*, *>)?.showExpiredCredentialsDialog()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showDecryptionFailedDialog() {
|
||||||
|
(activity as? BaseActivity<*, *>)?.showDecryptionFailedDialog()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showChangePasswordSnackbar(redirectUrl: String) {
|
override fun showChangePasswordSnackbar(redirectUrl: String) {
|
||||||
|
@ -11,6 +11,7 @@ fun Sdk.init(student: Student): Sdk {
|
|||||||
schoolSymbol = student.schoolSymbol
|
schoolSymbol = student.schoolSymbol
|
||||||
studentId = student.studentId
|
studentId = student.studentId
|
||||||
classId = student.classId
|
classId = student.classId
|
||||||
|
emptyCookieJarInterceptor = true
|
||||||
|
|
||||||
if (Sdk.Mode.valueOf(student.loginMode) == Sdk.Mode.HEBE) {
|
if (Sdk.Mode.valueOf(student.loginMode) == Sdk.Mode.HEBE) {
|
||||||
mobileBaseUrl = student.mobileBaseUrl
|
mobileBaseUrl = student.mobileBaseUrl
|
||||||
|
@ -16,6 +16,7 @@ import android.util.Base64.DEFAULT
|
|||||||
import android.util.Base64.decode
|
import android.util.Base64.decode
|
||||||
import android.util.Base64.encode
|
import android.util.Base64.encode
|
||||||
import android.util.Base64.encodeToString
|
import android.util.Base64.encodeToString
|
||||||
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
@ -33,21 +34,23 @@ import javax.crypto.CipherInputStream
|
|||||||
import javax.crypto.CipherOutputStream
|
import javax.crypto.CipherOutputStream
|
||||||
import javax.crypto.spec.OAEPParameterSpec
|
import javax.crypto.spec.OAEPParameterSpec
|
||||||
import javax.crypto.spec.PSource.PSpecified
|
import javax.crypto.spec.PSource.PSpecified
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
import javax.security.auth.x500.X500Principal
|
import javax.security.auth.x500.X500Principal
|
||||||
|
|
||||||
private const val KEYSTORE_NAME = "AndroidKeyStore"
|
@Singleton
|
||||||
|
class Scrambler @Inject constructor(
|
||||||
|
@ApplicationContext private val context: Context,
|
||||||
|
) {
|
||||||
|
private val keyCharset = Charset.forName("UTF-8")
|
||||||
|
|
||||||
private const val KEY_ALIAS = "wulkanowy_password"
|
private val isKeyPairExists: Boolean
|
||||||
|
|
||||||
private val KEY_CHARSET = Charset.forName("UTF-8")
|
|
||||||
|
|
||||||
private val isKeyPairExists: Boolean
|
|
||||||
get() = keyStore.getKey(KEY_ALIAS, null) != null
|
get() = keyStore.getKey(KEY_ALIAS, null) != null
|
||||||
|
|
||||||
private val keyStore: KeyStore
|
private val keyStore: KeyStore
|
||||||
get() = KeyStore.getInstance(KEYSTORE_NAME).apply { load(null) }
|
get() = KeyStore.getInstance(KEYSTORE_NAME).apply { load(null) }
|
||||||
|
|
||||||
private val cipher: Cipher
|
private val cipher: Cipher
|
||||||
get() {
|
get() {
|
||||||
return if (SDK_INT >= M) Cipher.getInstance(
|
return if (SDK_INT >= M) Cipher.getInstance(
|
||||||
"RSA/ECB/OAEPWithSHA-256AndMGF1Padding",
|
"RSA/ECB/OAEPWithSHA-256AndMGF1Padding",
|
||||||
@ -56,11 +59,11 @@ private val cipher: Cipher
|
|||||||
else Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidOpenSSL")
|
else Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidOpenSSL")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun encrypt(plainText: String, context: Context): String {
|
fun encrypt(plainText: String): String {
|
||||||
if (plainText.isEmpty()) throw ScramblerException("Text to be encrypted is empty")
|
if (plainText.isEmpty()) throw ScramblerException("Text to be encrypted is empty")
|
||||||
|
|
||||||
return try {
|
return try {
|
||||||
if (!isKeyPairExists) generateKeyPair(context)
|
if (!isKeyPairExists) generateKeyPair()
|
||||||
|
|
||||||
cipher.let {
|
cipher.let {
|
||||||
if (SDK_INT >= M) {
|
if (SDK_INT >= M) {
|
||||||
@ -71,7 +74,7 @@ fun encrypt(plainText: String, context: Context): String {
|
|||||||
|
|
||||||
ByteArrayOutputStream().let { output ->
|
ByteArrayOutputStream().let { output ->
|
||||||
CipherOutputStream(output, it).apply {
|
CipherOutputStream(output, it).apply {
|
||||||
write(plainText.toByteArray(KEY_CHARSET))
|
write(plainText.toByteArray(keyCharset))
|
||||||
close()
|
close()
|
||||||
}
|
}
|
||||||
encodeToString(output.toByteArray(), DEFAULT)
|
encodeToString(output.toByteArray(), DEFAULT)
|
||||||
@ -79,11 +82,11 @@ fun encrypt(plainText: String, context: Context): String {
|
|||||||
}
|
}
|
||||||
} catch (exception: Exception) {
|
} catch (exception: Exception) {
|
||||||
Timber.e(exception, "An error occurred while encrypting text")
|
Timber.e(exception, "An error occurred while encrypting text")
|
||||||
String(encode(plainText.toByteArray(KEY_CHARSET), DEFAULT), KEY_CHARSET)
|
String(encode(plainText.toByteArray(keyCharset), DEFAULT), keyCharset)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fun decrypt(cipherText: String): String {
|
fun decrypt(cipherText: String): String {
|
||||||
if (cipherText.isEmpty()) throw ScramblerException("Text to be encrypted is empty")
|
if (cipherText.isEmpty()) throw ScramblerException("Text to be encrypted is empty")
|
||||||
|
|
||||||
return try {
|
return try {
|
||||||
@ -96,7 +99,10 @@ fun decrypt(cipherText: String): String {
|
|||||||
}
|
}
|
||||||
} else it.init(DECRYPT_MODE, keyStore.getKey(KEY_ALIAS, null))
|
} else it.init(DECRYPT_MODE, keyStore.getKey(KEY_ALIAS, null))
|
||||||
|
|
||||||
CipherInputStream(ByteArrayInputStream(decode(cipherText, DEFAULT)), it).let { input ->
|
CipherInputStream(
|
||||||
|
ByteArrayInputStream(decode(cipherText, DEFAULT)),
|
||||||
|
it
|
||||||
|
).let { input ->
|
||||||
val values = ArrayList<Byte>()
|
val values = ArrayList<Byte>()
|
||||||
var nextByte: Int
|
var nextByte: Int
|
||||||
while (run { nextByte = input.read(); nextByte } != -1) {
|
while (run { nextByte = input.read(); nextByte } != -1) {
|
||||||
@ -106,15 +112,15 @@ fun decrypt(cipherText: String): String {
|
|||||||
for (i in bytes.indices) {
|
for (i in bytes.indices) {
|
||||||
bytes[i] = values[i]
|
bytes[i] = values[i]
|
||||||
}
|
}
|
||||||
String(bytes, 0, bytes.size, KEY_CHARSET)
|
String(bytes, 0, bytes.size, keyCharset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
throw ScramblerException("An error occurred while decrypting text", e)
|
throw ScramblerException("An error occurred while decrypting text", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateKeyPair(context: Context) {
|
private fun generateKeyPair() {
|
||||||
(if (SDK_INT >= M) {
|
(if (SDK_INT >= M) {
|
||||||
KeyGenParameterSpec.Builder(KEY_ALIAS, PURPOSE_DECRYPT or PURPOSE_ENCRYPT)
|
KeyGenParameterSpec.Builder(KEY_ALIAS, PURPOSE_DECRYPT or PURPOSE_ENCRYPT)
|
||||||
.setDigests(DIGEST_SHA256, DIGEST_SHA512)
|
.setDigests(DIGEST_SHA256, DIGEST_SHA512)
|
||||||
@ -137,4 +143,15 @@ private fun generateKeyPair(context: Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Timber.i("A new KeyPair has been generated")
|
Timber.i("A new KeyPair has been generated")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clearKeyPair() {
|
||||||
|
keyStore.deleteEntry(KEY_ALIAS)
|
||||||
|
Timber.i("KeyPair has been cleared")
|
||||||
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
private const val KEYSTORE_NAME = "AndroidKeyStore"
|
||||||
|
private const val KEY_ALIAS = "wulkanowy_password"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
Wersja 2.3.1
|
Wersja 2.3.2
|
||||||
|
|
||||||
— poprawiliśmy kilka usterek przy odświeżaniu danych (ale pewnie nie wszystkie)
|
— poprawiliśmy kolejne usterki przy odświeżaniu danych (teraz to powinno działać już dużo lepiej)
|
||||||
|
|
||||||
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases
|
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases
|
||||||
|
@ -96,6 +96,8 @@
|
|||||||
<string name="main_log_in">Přihlásit se</string>
|
<string name="main_log_in">Přihlásit se</string>
|
||||||
<string name="main_session_expired">Relace vypršela</string>
|
<string name="main_session_expired">Relace vypršela</string>
|
||||||
<string name="main_session_relogin">Relace vypršela. Přihlaste se prosím znovu</string>
|
<string name="main_session_relogin">Relace vypršela. Přihlaste se prosím znovu</string>
|
||||||
|
<string name="main_expired_credentials_description">Heslo k vašemu účtu bylo změněno. Musíte se znovu přihlásit do Wulkanového</string>
|
||||||
|
<string name="main_expired_credentials_title">Heslo bylo změněno</string>
|
||||||
<string name="main_support_title">Podpora aplikace</string>
|
<string name="main_support_title">Podpora aplikace</string>
|
||||||
<string name="main_support_description">Líbí se Vám tato aplikace? Podpořte její vývoj tím, že povolíte neinvazivní reklamy, které můžete kdykoliv vypnout</string>
|
<string name="main_support_description">Líbí se Vám tato aplikace? Podpořte její vývoj tím, že povolíte neinvazivní reklamy, které můžete kdykoliv vypnout</string>
|
||||||
<string name="main_support_positive">Zapnout reklamy</string>
|
<string name="main_support_positive">Zapnout reklamy</string>
|
||||||
@ -760,7 +762,7 @@
|
|||||||
<string name="pref_ads_support_category_name">Podpora</string>
|
<string name="pref_ads_support_category_name">Podpora</string>
|
||||||
<string name="pref_ads_privacy_policy">Ochrana osobních údajů</string>
|
<string name="pref_ads_privacy_policy">Ochrana osobních údajů</string>
|
||||||
<string name="pref_ads_agreements">Souhlasy</string>
|
<string name="pref_ads_agreements">Souhlasy</string>
|
||||||
<string name="pref_ads_consent">Show consent to data processing</string>
|
<string name="pref_ads_consent">Zobrazit souhlas se zpracováním údajů</string>
|
||||||
<string name="pref_ads_show_in_app">Zobrazit reklamy v aplikaci</string>
|
<string name="pref_ads_show_in_app">Zobrazit reklamy v aplikaci</string>
|
||||||
<string name="pref_ads_support">Podívejte se na jednu reklamu pro podporu projektu</string>
|
<string name="pref_ads_support">Podívejte se na jednu reklamu pro podporu projektu</string>
|
||||||
<string name="pref_ads_privacy_title">Souhlas se zpracováním dat</string>
|
<string name="pref_ads_privacy_title">Souhlas se zpracováním dat</string>
|
||||||
|
@ -96,6 +96,8 @@
|
|||||||
<string name="main_log_in">Log in</string>
|
<string name="main_log_in">Log in</string>
|
||||||
<string name="main_session_expired">Session expired</string>
|
<string name="main_session_expired">Session expired</string>
|
||||||
<string name="main_session_relogin">Session expired, log in again</string>
|
<string name="main_session_relogin">Session expired, log in again</string>
|
||||||
|
<string name="main_expired_credentials_description">Your account password has been changed. You need to log in to Wulkanowy again</string>
|
||||||
|
<string name="main_expired_credentials_title">Password changed</string>
|
||||||
<string name="main_support_title">Application support</string>
|
<string name="main_support_title">Application support</string>
|
||||||
<string name="main_support_description">Do you like this app? Support its development by enabling non-invasive ads that you can disable at any time</string>
|
<string name="main_support_description">Do you like this app? Support its development by enabling non-invasive ads that you can disable at any time</string>
|
||||||
<string name="main_support_positive">Enable ads</string>
|
<string name="main_support_positive">Enable ads</string>
|
||||||
|
@ -96,6 +96,8 @@
|
|||||||
<string name="main_log_in">Anmelden</string>
|
<string name="main_log_in">Anmelden</string>
|
||||||
<string name="main_session_expired">Die Sitzung ist abgelaufen</string>
|
<string name="main_session_expired">Die Sitzung ist abgelaufen</string>
|
||||||
<string name="main_session_relogin">Die Sitzung ist abgelaufen, bitte loggen Sie sich erneut ein</string>
|
<string name="main_session_relogin">Die Sitzung ist abgelaufen, bitte loggen Sie sich erneut ein</string>
|
||||||
|
<string name="main_expired_credentials_description">Your account password has been changed. You need to log in to Wulkanowy again</string>
|
||||||
|
<string name="main_expired_credentials_title">Password changed</string>
|
||||||
<string name="main_support_title">Anwendungsunterstützung</string>
|
<string name="main_support_title">Anwendungsunterstützung</string>
|
||||||
<string name="main_support_description">Gefällt Ihnen diese App? Unterstützen Sie ihre Entwicklung, indem Sie nicht-invasive Werbung aktivieren, die Sie jederzeit deaktivieren können</string>
|
<string name="main_support_description">Gefällt Ihnen diese App? Unterstützen Sie ihre Entwicklung, indem Sie nicht-invasive Werbung aktivieren, die Sie jederzeit deaktivieren können</string>
|
||||||
<string name="main_support_positive">Werbung aktivieren</string>
|
<string name="main_support_positive">Werbung aktivieren</string>
|
||||||
|
@ -96,6 +96,8 @@
|
|||||||
<string name="main_log_in">Log in</string>
|
<string name="main_log_in">Log in</string>
|
||||||
<string name="main_session_expired">Session expired</string>
|
<string name="main_session_expired">Session expired</string>
|
||||||
<string name="main_session_relogin">Session expired, log in again</string>
|
<string name="main_session_relogin">Session expired, log in again</string>
|
||||||
|
<string name="main_expired_credentials_description">Your account password has been changed. You need to log in to Wulkanowy again</string>
|
||||||
|
<string name="main_expired_credentials_title">Password changed</string>
|
||||||
<string name="main_support_title">Application support</string>
|
<string name="main_support_title">Application support</string>
|
||||||
<string name="main_support_description">Do you like this app? Support its development by enabling non-invasive ads that you can disable at any time</string>
|
<string name="main_support_description">Do you like this app? Support its development by enabling non-invasive ads that you can disable at any time</string>
|
||||||
<string name="main_support_positive">Enable ads</string>
|
<string name="main_support_positive">Enable ads</string>
|
||||||
|
@ -96,6 +96,8 @@
|
|||||||
<string name="main_log_in">Log in</string>
|
<string name="main_log_in">Log in</string>
|
||||||
<string name="main_session_expired">Session expired</string>
|
<string name="main_session_expired">Session expired</string>
|
||||||
<string name="main_session_relogin">Session expired, log in again</string>
|
<string name="main_session_relogin">Session expired, log in again</string>
|
||||||
|
<string name="main_expired_credentials_description">Your account password has been changed. You need to log in to Wulkanowy again</string>
|
||||||
|
<string name="main_expired_credentials_title">Password changed</string>
|
||||||
<string name="main_support_title">Application support</string>
|
<string name="main_support_title">Application support</string>
|
||||||
<string name="main_support_description">Do you like this app? Support its development by enabling non-invasive ads that you can disable at any time</string>
|
<string name="main_support_description">Do you like this app? Support its development by enabling non-invasive ads that you can disable at any time</string>
|
||||||
<string name="main_support_positive">Enable ads</string>
|
<string name="main_support_positive">Enable ads</string>
|
||||||
|
@ -96,6 +96,8 @@
|
|||||||
<string name="main_log_in">Zaloguj się</string>
|
<string name="main_log_in">Zaloguj się</string>
|
||||||
<string name="main_session_expired">Sesja wygasła</string>
|
<string name="main_session_expired">Sesja wygasła</string>
|
||||||
<string name="main_session_relogin">Sesja wygasła, zaloguj się ponownie</string>
|
<string name="main_session_relogin">Sesja wygasła, zaloguj się ponownie</string>
|
||||||
|
<string name="main_expired_credentials_description">Hasło do Twojego konta zostało zmienione. Musisz zalogować się ponownie do Wulkanowego</string>
|
||||||
|
<string name="main_expired_credentials_title">Hasło zostało zmienione</string>
|
||||||
<string name="main_support_title">Wparcie aplikacji</string>
|
<string name="main_support_title">Wparcie aplikacji</string>
|
||||||
<string name="main_support_description">Podoba Ci się ta aplikacja? Wspieraj jej rozwój poprzez włączenie nieinwazyjnych reklam, które możesz wyłączyć w dowolnym momencie</string>
|
<string name="main_support_description">Podoba Ci się ta aplikacja? Wspieraj jej rozwój poprzez włączenie nieinwazyjnych reklam, które możesz wyłączyć w dowolnym momencie</string>
|
||||||
<string name="main_support_positive">Włącz reklamy</string>
|
<string name="main_support_positive">Włącz reklamy</string>
|
||||||
|
@ -96,6 +96,8 @@
|
|||||||
<string name="main_log_in">Войти</string>
|
<string name="main_log_in">Войти</string>
|
||||||
<string name="main_session_expired">Сеанс истёк</string>
|
<string name="main_session_expired">Сеанс истёк</string>
|
||||||
<string name="main_session_relogin">Сеанс истёк, авторизуйтесь снова</string>
|
<string name="main_session_relogin">Сеанс истёк, авторизуйтесь снова</string>
|
||||||
|
<string name="main_expired_credentials_description">Your account password has been changed. You need to log in to Wulkanowy again</string>
|
||||||
|
<string name="main_expired_credentials_title">Password changed</string>
|
||||||
<string name="main_support_title">Поддержка приложения</string>
|
<string name="main_support_title">Поддержка приложения</string>
|
||||||
<string name="main_support_description">Вам нравится это приложение? Поддержите его разработку, включив неинвазивную рекламу, которую можно отключить в любое время</string>
|
<string name="main_support_description">Вам нравится это приложение? Поддержите его разработку, включив неинвазивную рекламу, которую можно отключить в любое время</string>
|
||||||
<string name="main_support_positive">Включить рекламу</string>
|
<string name="main_support_positive">Включить рекламу</string>
|
||||||
|
@ -96,6 +96,8 @@
|
|||||||
<string name="main_log_in">Prihlásiť sa</string>
|
<string name="main_log_in">Prihlásiť sa</string>
|
||||||
<string name="main_session_expired">Relácia vypršala</string>
|
<string name="main_session_expired">Relácia vypršala</string>
|
||||||
<string name="main_session_relogin">Relácia vypršala. Prihláste sa prosím znovu</string>
|
<string name="main_session_relogin">Relácia vypršala. Prihláste sa prosím znovu</string>
|
||||||
|
<string name="main_expired_credentials_description">Heslo k vášmu účtu bolo zmenené. Musíte sa znovu prihlásiť do Wulkanového</string>
|
||||||
|
<string name="main_expired_credentials_title">Heslo bolo zmenené</string>
|
||||||
<string name="main_support_title">Podpora aplikácie</string>
|
<string name="main_support_title">Podpora aplikácie</string>
|
||||||
<string name="main_support_description">Páči sa Vám táto aplikácia? Podporte jej vývoj tým, že povolíte neinvazívne reklamy, ktoré môžete kedykoľvek vypnúť</string>
|
<string name="main_support_description">Páči sa Vám táto aplikácia? Podporte jej vývoj tým, že povolíte neinvazívne reklamy, ktoré môžete kedykoľvek vypnúť</string>
|
||||||
<string name="main_support_positive">Zapnúť reklamy</string>
|
<string name="main_support_positive">Zapnúť reklamy</string>
|
||||||
@ -760,7 +762,7 @@
|
|||||||
<string name="pref_ads_support_category_name">Podpora</string>
|
<string name="pref_ads_support_category_name">Podpora</string>
|
||||||
<string name="pref_ads_privacy_policy">Ochrana osobných údajov</string>
|
<string name="pref_ads_privacy_policy">Ochrana osobných údajov</string>
|
||||||
<string name="pref_ads_agreements">Súhlasy</string>
|
<string name="pref_ads_agreements">Súhlasy</string>
|
||||||
<string name="pref_ads_consent">Show consent to data processing</string>
|
<string name="pref_ads_consent">Zobraziť súhlas so spracovaním údajov</string>
|
||||||
<string name="pref_ads_show_in_app">Zobraziť reklamy v aplikácii</string>
|
<string name="pref_ads_show_in_app">Zobraziť reklamy v aplikácii</string>
|
||||||
<string name="pref_ads_support">Pozrite sa na jednu reklamu pre podporu projektu</string>
|
<string name="pref_ads_support">Pozrite sa na jednu reklamu pre podporu projektu</string>
|
||||||
<string name="pref_ads_privacy_title">Súhlas so spracovaním dát</string>
|
<string name="pref_ads_privacy_title">Súhlas so spracovaním dát</string>
|
||||||
|
@ -96,6 +96,8 @@
|
|||||||
<string name="main_log_in">Увійти</string>
|
<string name="main_log_in">Увійти</string>
|
||||||
<string name="main_session_expired">Минув термін дії сесії</string>
|
<string name="main_session_expired">Минув термін дії сесії</string>
|
||||||
<string name="main_session_relogin">Минув термін дії сесії, авторизуйтеся знову</string>
|
<string name="main_session_relogin">Минув термін дії сесії, авторизуйтеся знову</string>
|
||||||
|
<string name="main_expired_credentials_description">Your account password has been changed. You need to log in to Wulkanowy again</string>
|
||||||
|
<string name="main_expired_credentials_title">Password changed</string>
|
||||||
<string name="main_support_title">Підтримка додатку</string>
|
<string name="main_support_title">Підтримка додатку</string>
|
||||||
<string name="main_support_description">Вам подобається цей додаток? Підтримайте його розвиток, увімкнувши неінвазивну рекламу, яку ви можете відключити в будь-який час</string>
|
<string name="main_support_description">Вам подобається цей додаток? Підтримайте його розвиток, увімкнувши неінвазивну рекламу, яку ви можете відключити в будь-який час</string>
|
||||||
<string name="main_support_positive">Увімкнути рекламу</string>
|
<string name="main_support_positive">Увімкнути рекламу</string>
|
||||||
|
@ -107,6 +107,8 @@
|
|||||||
<string name="main_log_in">Log in</string>
|
<string name="main_log_in">Log in</string>
|
||||||
<string name="main_session_expired">Session expired</string>
|
<string name="main_session_expired">Session expired</string>
|
||||||
<string name="main_session_relogin">Session expired, log in again</string>
|
<string name="main_session_relogin">Session expired, log in again</string>
|
||||||
|
<string name="main_expired_credentials_description">Your account password has been changed. You need to log in to Wulkanowy again</string>
|
||||||
|
<string name="main_expired_credentials_title">Password changed</string>
|
||||||
<string name="main_support_title">Application support</string>
|
<string name="main_support_title">Application support</string>
|
||||||
<string name="main_support_description">Do you like this app? Support its development by enabling non-invasive ads that you can disable at any time</string>
|
<string name="main_support_description">Do you like this app? Support its development by enabling non-invasive ads that you can disable at any time</string>
|
||||||
<string name="main_support_positive">Enable ads</string>
|
<string name="main_support_positive">Enable ads</string>
|
||||||
|
@ -101,8 +101,12 @@ class AdsFragment : PreferenceFragmentCompat(), MainView.TitledView, AdsView {
|
|||||||
(activity as? BaseActivity<*, *>)?.showMessage(text)
|
(activity as? BaseActivity<*, *>)?.showMessage(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showExpiredDialog() {
|
override fun showExpiredCredentialsDialog() {
|
||||||
(activity as? BaseActivity<*, *>)?.showExpiredDialog()
|
(activity as? BaseActivity<*, *>)?.showExpiredCredentialsDialog()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showDecryptionFailedDialog() {
|
||||||
|
(activity as? BaseActivity<*, *>)?.showDecryptionFailedDialog()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showChangePasswordSnackbar(redirectUrl: String) {
|
override fun showChangePasswordSnackbar(redirectUrl: String) {
|
||||||
|
@ -14,7 +14,7 @@ buildscript {
|
|||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
classpath "org.jetbrains.kotlin:kotlin-serialization:$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.16"
|
classpath "com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin:$kotlin_version-1.0.16"
|
||||||
classpath 'com.android.tools.build:gradle:8.2.0'
|
classpath 'com.android.tools.build:gradle:8.2.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.4.0'
|
classpath 'com.google.gms:google-services:4.4.0'
|
||||||
classpath 'com.huawei.agconnect:agcp:1.9.1.303'
|
classpath 'com.huawei.agconnect:agcp:1.9.1.303'
|
||||||
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,6 +1,6 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-all.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
17
gradlew
vendored
17
gradlew
vendored
@ -83,7 +83,8 @@ done
|
|||||||
# This is normally unused
|
# This is normally unused
|
||||||
# shellcheck disable=SC2034
|
# shellcheck disable=SC2034
|
||||||
APP_BASE_NAME=${0##*/}
|
APP_BASE_NAME=${0##*/}
|
||||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||||
|
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
MAX_FD=maximum
|
MAX_FD=maximum
|
||||||
@ -144,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
|||||||
case $MAX_FD in #(
|
case $MAX_FD in #(
|
||||||
max*)
|
max*)
|
||||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||||
# shellcheck disable=SC3045
|
# shellcheck disable=SC2039,SC3045
|
||||||
MAX_FD=$( ulimit -H -n ) ||
|
MAX_FD=$( ulimit -H -n ) ||
|
||||||
warn "Could not query maximum file descriptor limit"
|
warn "Could not query maximum file descriptor limit"
|
||||||
esac
|
esac
|
||||||
@ -152,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
|||||||
'' | soft) :;; #(
|
'' | soft) :;; #(
|
||||||
*)
|
*)
|
||||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||||
# shellcheck disable=SC3045
|
# shellcheck disable=SC2039,SC3045
|
||||||
ulimit -n "$MAX_FD" ||
|
ulimit -n "$MAX_FD" ||
|
||||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||||
esac
|
esac
|
||||||
@ -201,11 +202,11 @@ fi
|
|||||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
# Collect all arguments for the java command;
|
# Collect all arguments for the java command:
|
||||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||||
# shell script including quotes and variable substitutions, so put them in
|
# and any embedded shellness will be escaped.
|
||||||
# double quotes to make sure that they get re-expanded; and
|
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||||
# * put everything else in single quotes, so that it's not re-expanded.
|
# treated as '${Hostname}' itself on the command line.
|
||||||
|
|
||||||
set -- \
|
set -- \
|
||||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
|
Loading…
x
Reference in New Issue
Block a user