Compare commits
16 Commits
Author | SHA1 | Date | |
---|---|---|---|
3eae3a7667 | |||
b613b84469 | |||
2776d019b9 | |||
729e72cddb | |||
ec101c1f52 | |||
cfec79405f | |||
7d8be1b9fc | |||
c781159e75 | |||
90a5b9e20f | |||
3cf6c295b0 | |||
e757585bd3 | |||
736d16a7ab | |||
6f4a8d5534 | |||
b5e17c4ff7 | |||
cc01525f16 | |||
c2ec05662b |
@ -27,8 +27,8 @@ android {
|
|||||||
testApplicationId "io.github.tests.wulkanowy"
|
testApplicationId "io.github.tests.wulkanowy"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 34
|
targetSdkVersion 34
|
||||||
versionCode 146
|
versionCode 148
|
||||||
versionName "2.4.0"
|
versionName "2.4.2"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
|
||||||
resValue "string", "app_name", "Wulkanowy"
|
resValue "string", "app_name", "Wulkanowy"
|
||||||
@ -164,8 +164,8 @@ play {
|
|||||||
defaultToAppBundles = false
|
defaultToAppBundles = false
|
||||||
track = 'production'
|
track = 'production'
|
||||||
releaseStatus = ReleaseStatus.IN_PROGRESS
|
releaseStatus = ReleaseStatus.IN_PROGRESS
|
||||||
userFraction = 0.50d
|
userFraction = 0.99d
|
||||||
updatePriority = 1
|
updatePriority = 2
|
||||||
enabled.set(false)
|
enabled.set(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,15 +191,15 @@ ext {
|
|||||||
room = "2.6.1"
|
room = "2.6.1"
|
||||||
chucker = "4.0.0"
|
chucker = "4.0.0"
|
||||||
mockk = "1.13.9"
|
mockk = "1.13.9"
|
||||||
coroutines = "1.7.3"
|
coroutines = "1.8.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'io.github.wulkanowy:sdk:2.4.0'
|
implementation 'io.github.wulkanowy:sdk:2.4.1'
|
||||||
|
|
||||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4'
|
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4'
|
||||||
|
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2"
|
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3"
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines"
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines"
|
||||||
|
|
||||||
implementation 'androidx.core:core-ktx:1.12.0'
|
implementation 'androidx.core:core-ktx:1.12.0'
|
||||||
@ -252,7 +252,7 @@ dependencies {
|
|||||||
implementation 'com.fredporciuncula:flow-preferences:1.9.1'
|
implementation 'com.fredporciuncula:flow-preferences:1.9.1'
|
||||||
implementation 'org.apache.commons:commons-text:1.11.0'
|
implementation 'org.apache.commons:commons-text:1.11.0'
|
||||||
|
|
||||||
playImplementation platform('com.google.firebase:firebase-bom:32.7.1')
|
playImplementation platform('com.google.firebase:firebase-bom:32.7.2')
|
||||||
playImplementation 'com.google.firebase:firebase-analytics'
|
playImplementation 'com.google.firebase:firebase-analytics'
|
||||||
playImplementation 'com.google.firebase:firebase-messaging'
|
playImplementation 'com.google.firebase:firebase-messaging'
|
||||||
playImplementation 'com.google.firebase:firebase-crashlytics:'
|
playImplementation 'com.google.firebase:firebase-crashlytics:'
|
||||||
@ -262,7 +262,7 @@ dependencies {
|
|||||||
playImplementation "com.google.android.play:integrity:1.3.0"
|
playImplementation "com.google.android.play:integrity:1.3.0"
|
||||||
playImplementation 'com.google.android.play:app-update-ktx:2.1.0'
|
playImplementation 'com.google.android.play:app-update-ktx:2.1.0'
|
||||||
playImplementation 'com.google.android.play:review-ktx:2.0.1'
|
playImplementation 'com.google.android.play:review-ktx:2.0.1'
|
||||||
playImplementation "com.google.android.ump:user-messaging-platform:2.2.0"
|
playImplementation "com.google.android.ump:user-messaging-platform:2.1.0"
|
||||||
|
|
||||||
hmsImplementation 'com.huawei.hms:hianalytics:6.12.0.301'
|
hmsImplementation 'com.huawei.hms:hianalytics:6.12.0.301'
|
||||||
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.9.1.303'
|
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.9.1.303'
|
||||||
|
@ -30,8 +30,15 @@ val <T> Resource<T>.dataOrNull: T?
|
|||||||
get() = when (this) {
|
get() = when (this) {
|
||||||
is Resource.Success -> this.data
|
is Resource.Success -> this.data
|
||||||
is Resource.Intermediate -> this.data
|
is Resource.Intermediate -> this.data
|
||||||
is Resource.Loading -> null
|
else -> null
|
||||||
is Resource.Error -> null
|
}
|
||||||
|
|
||||||
|
val <T> Resource<T>.dataOrThrow: T
|
||||||
|
get() = when (this) {
|
||||||
|
is Resource.Success -> this.data
|
||||||
|
is Resource.Intermediate -> this.data
|
||||||
|
is Resource.Loading -> throw IllegalStateException("Resource is in loading state")
|
||||||
|
is Resource.Error -> throw this.error
|
||||||
}
|
}
|
||||||
|
|
||||||
val <T> Resource<T>.errorOrNull: Throwable?
|
val <T> Resource<T>.errorOrNull: Throwable?
|
||||||
|
@ -94,6 +94,7 @@ class LoginFormFragment : BaseFragment<FragmentLoginFormBinding>(R.layout.fragme
|
|||||||
loginFormUsername.doOnTextChanged { _, _, _, _ -> presenter.onUsernameTextChanged() }
|
loginFormUsername.doOnTextChanged { _, _, _, _ -> presenter.onUsernameTextChanged() }
|
||||||
loginFormPass.doOnTextChanged { _, _, _, _ -> presenter.onPassTextChanged() }
|
loginFormPass.doOnTextChanged { _, _, _, _ -> presenter.onPassTextChanged() }
|
||||||
loginFormHost.setOnItemClickListener { _, _, _, _ -> presenter.onHostSelected() }
|
loginFormHost.setOnItemClickListener { _, _, _, _ -> presenter.onHostSelected() }
|
||||||
|
loginFormDomainSuffix.doOnTextChanged { _, _, _, _ -> presenter.onDomainSuffixChanged() }
|
||||||
loginFormSignIn.setOnClickListener { presenter.onSignInClick() }
|
loginFormSignIn.setOnClickListener { presenter.onSignInClick() }
|
||||||
loginFormAdvancedButton.setOnClickListener { presenter.onAdvancedLoginClick() }
|
loginFormAdvancedButton.setOnClickListener { presenter.onAdvancedLoginClick() }
|
||||||
loginFormPrivacyLink.setOnClickListener { presenter.onPrivacyLinkClick() }
|
loginFormPrivacyLink.setOnClickListener { presenter.onPrivacyLinkClick() }
|
||||||
@ -188,6 +189,12 @@ class LoginFormFragment : BaseFragment<FragmentLoginFormBinding>(R.layout.fragme
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun setDomainSuffixInvalid() {
|
||||||
|
with(binding.loginFormDomainSuffixLayout) {
|
||||||
|
error = getString(R.string.login_invalid_domain_suffix)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun clearUsernameError() {
|
override fun clearUsernameError() {
|
||||||
binding.loginFormUsernameLayout.error = null
|
binding.loginFormUsernameLayout.error = null
|
||||||
binding.loginFormErrorBox.isVisible = false
|
binding.loginFormErrorBox.isVisible = false
|
||||||
@ -206,6 +213,10 @@ class LoginFormFragment : BaseFragment<FragmentLoginFormBinding>(R.layout.fragme
|
|||||||
binding.loginFormErrorBox.isVisible = false
|
binding.loginFormErrorBox.isVisible = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun clearDomainSuffixError() {
|
||||||
|
binding.loginFormDomainSuffixLayout.error = null
|
||||||
|
}
|
||||||
|
|
||||||
override fun showSoftKeyboard() {
|
override fun showSoftKeyboard() {
|
||||||
activity?.showSoftInput()
|
activity?.showSoftInput()
|
||||||
}
|
}
|
||||||
|
@ -101,6 +101,12 @@ class LoginFormPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onDomainSuffixChanged() {
|
||||||
|
view?.apply {
|
||||||
|
clearDomainSuffixError()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun updateCustomDomainSuffixVisibility() {
|
fun updateCustomDomainSuffixVisibility() {
|
||||||
view?.run {
|
view?.run {
|
||||||
showDomainSuffixInput("customSuffix" in formHostValue)
|
showDomainSuffixInput("customSuffix" in formHostValue)
|
||||||
@ -159,7 +165,7 @@ class LoginFormPresenter @Inject constructor(
|
|||||||
fun onSignInClick() {
|
fun onSignInClick() {
|
||||||
val loginData = getLoginData()
|
val loginData = getLoginData()
|
||||||
|
|
||||||
if (!validateCredentials(loginData.login, loginData.password, loginData.baseUrl)) return
|
if (!validateCredentials(loginData)) return
|
||||||
|
|
||||||
resourceFlow {
|
resourceFlow {
|
||||||
studentRepository.getUserSubjectsFromScrapper(
|
studentRepository.getUserSubjectsFromScrapper(
|
||||||
@ -229,24 +235,29 @@ class LoginFormPresenter @Inject constructor(
|
|||||||
view?.onRecoverClick()
|
view?.onRecoverClick()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun validateCredentials(login: String, password: String, host: String): Boolean {
|
private fun validateCredentials(loginData: LoginData): Boolean {
|
||||||
var isCorrect = true
|
var isCorrect = true
|
||||||
|
|
||||||
if (login.isEmpty()) {
|
if (loginData.login.isEmpty()) {
|
||||||
view?.setErrorUsernameRequired()
|
view?.setErrorUsernameRequired()
|
||||||
isCorrect = false
|
isCorrect = false
|
||||||
} else {
|
} else {
|
||||||
if ("@" in login && "login" in host) {
|
if ("@" in loginData.login && "login" in loginData.baseUrl) {
|
||||||
view?.setErrorLoginRequired()
|
view?.setErrorLoginRequired()
|
||||||
isCorrect = false
|
isCorrect = false
|
||||||
}
|
}
|
||||||
if ("@" !in login && "email" in host) {
|
if ("@" !in loginData.login && "email" in loginData.baseUrl) {
|
||||||
view?.setErrorEmailRequired()
|
view?.setErrorEmailRequired()
|
||||||
isCorrect = false
|
isCorrect = false
|
||||||
}
|
}
|
||||||
if ("@" in login && "||" !in login && "login" !in host && "email" !in host) {
|
|
||||||
val emailHost = login.substringAfter("@")
|
val isEmailLogin = "@" in loginData.login
|
||||||
val emailDomain = URL(host).host
|
val isEmailWithLogin = "||" !in loginData.login
|
||||||
|
val isLoginNotRequired = "login" !in loginData.baseUrl
|
||||||
|
val isEmailNotRequired = "email" !in loginData.baseUrl
|
||||||
|
if (isEmailLogin && isEmailWithLogin && isLoginNotRequired && isEmailNotRequired) {
|
||||||
|
val emailHost = loginData.login.substringAfter("@")
|
||||||
|
val emailDomain = URL(loginData.baseUrl).host
|
||||||
if (!emailHost.equals(emailDomain, true)) {
|
if (!emailHost.equals(emailDomain, true)) {
|
||||||
view?.setErrorEmailInvalid(domain = emailDomain)
|
view?.setErrorEmailInvalid(domain = emailDomain)
|
||||||
isCorrect = false
|
isCorrect = false
|
||||||
@ -254,16 +265,21 @@ class LoginFormPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (password.isEmpty()) {
|
if (loginData.password.isEmpty()) {
|
||||||
view?.setErrorPassRequired(focus = isCorrect)
|
view?.setErrorPassRequired(focus = isCorrect)
|
||||||
isCorrect = false
|
isCorrect = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (password.length < 6 && password.isNotEmpty()) {
|
if (loginData.password.length < 6 && loginData.password.isNotEmpty()) {
|
||||||
view?.setErrorPassInvalid(focus = isCorrect)
|
view?.setErrorPassInvalid(focus = isCorrect)
|
||||||
isCorrect = false
|
isCorrect = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (loginData.domainSuffix !in listOf("", "rc", "kurs")) {
|
||||||
|
view?.setDomainSuffixInvalid()
|
||||||
|
isCorrect = false
|
||||||
|
}
|
||||||
|
|
||||||
return isCorrect
|
return isCorrect
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,12 +46,16 @@ interface LoginFormView : BaseView {
|
|||||||
|
|
||||||
fun setErrorEmailInvalid(domain: String)
|
fun setErrorEmailInvalid(domain: String)
|
||||||
|
|
||||||
|
fun setDomainSuffixInvalid()
|
||||||
|
|
||||||
fun clearUsernameError()
|
fun clearUsernameError()
|
||||||
|
|
||||||
fun clearPassError()
|
fun clearPassError()
|
||||||
|
|
||||||
fun clearHostError()
|
fun clearHostError()
|
||||||
|
|
||||||
|
fun clearDomainSuffixError()
|
||||||
|
|
||||||
fun showSoftKeyboard()
|
fun showSoftKeyboard()
|
||||||
|
|
||||||
fun hideSoftKeyboard()
|
fun hideSoftKeyboard()
|
||||||
|
@ -96,10 +96,7 @@ class LoginSymbolPresenter @Inject constructor(
|
|||||||
?.takeIf { it.symbol == loginData.userEnteredSymbol }
|
?.takeIf { it.symbol == loginData.userEnteredSymbol }
|
||||||
|
|
||||||
if (enteredSymbolDetails?.error is InvalidSymbolException) {
|
if (enteredSymbolDetails?.error is InvalidSymbolException) {
|
||||||
view?.run {
|
showInvalidSymbolError()
|
||||||
setErrorSymbolInvalid()
|
|
||||||
showContact(true)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Timber.i("Login with symbol result: Success")
|
Timber.i("Login with symbol result: Success")
|
||||||
view?.navigateToStudentSelect(loginData, requireNotNull(user.data))
|
view?.navigateToStudentSelect(loginData, requireNotNull(user.data))
|
||||||
@ -128,6 +125,9 @@ class LoginSymbolPresenter @Inject constructor(
|
|||||||
loginErrorHandler.dispatch(user.error)
|
loginErrorHandler.dispatch(user.error)
|
||||||
lastError = user.error
|
lastError = user.error
|
||||||
view?.showContact(true)
|
view?.showContact(true)
|
||||||
|
if (user.error is InvalidSymbolException) {
|
||||||
|
showInvalidSymbolError()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.onResourceNotLoading {
|
}.onResourceNotLoading {
|
||||||
@ -145,6 +145,13 @@ class LoginSymbolPresenter @Inject constructor(
|
|||||||
return normalizedSymbol in definitelyInvalidSymbols
|
return normalizedSymbol in definitelyInvalidSymbols
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun showInvalidSymbolError() {
|
||||||
|
view?.run {
|
||||||
|
setErrorSymbolInvalid()
|
||||||
|
showContact(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun onFaqClick() {
|
fun onFaqClick() {
|
||||||
view?.openFaqPage()
|
view?.openFaqPage()
|
||||||
}
|
}
|
||||||
|
@ -11,10 +11,8 @@ import android.view.View
|
|||||||
import android.widget.RemoteViews
|
import android.widget.RemoteViews
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.Resource
|
import io.github.wulkanowy.data.dataOrThrow
|
||||||
import io.github.wulkanowy.data.dataOrNull
|
|
||||||
import io.github.wulkanowy.data.db.SharedPrefProvider
|
import io.github.wulkanowy.data.db.SharedPrefProvider
|
||||||
import io.github.wulkanowy.data.db.entities.LuckyNumber
|
|
||||||
import io.github.wulkanowy.data.repositories.LuckyNumberRepository
|
import io.github.wulkanowy.data.repositories.LuckyNumberRepository
|
||||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||||
import io.github.wulkanowy.data.toFirstResult
|
import io.github.wulkanowy.data.toFirstResult
|
||||||
@ -69,8 +67,7 @@ class LuckyNumberWidgetProvider : AppWidgetProvider() {
|
|||||||
|
|
||||||
appWidgetIds?.forEach { widgetId ->
|
appWidgetIds?.forEach { widgetId ->
|
||||||
val studentId = sharedPref.getLong(getStudentWidgetKey(widgetId), 0)
|
val studentId = sharedPref.getLong(getStudentWidgetKey(widgetId), 0)
|
||||||
val luckyNumberResource = getLuckyNumber(studentId, widgetId)
|
val luckyNumber = getLuckyNumber(studentId, widgetId)?.luckyNumber?.toString()
|
||||||
val luckyNumber = luckyNumberResource.dataOrNull?.luckyNumber?.toString()
|
|
||||||
val remoteView = RemoteViews(context.packageName, R.layout.widget_luckynumber)
|
val remoteView = RemoteViews(context.packageName, R.layout.widget_luckynumber)
|
||||||
.apply {
|
.apply {
|
||||||
setTextViewText(R.id.luckyNumberWidgetValue, luckyNumber ?: "-")
|
setTextViewText(R.id.luckyNumberWidgetValue, luckyNumber ?: "-")
|
||||||
@ -143,18 +140,18 @@ class LuckyNumberWidgetProvider : AppWidgetProvider() {
|
|||||||
sharedPref.putLong(getStudentWidgetKey(appWidgetId), it.id)
|
sharedPref.putLong(getStudentWidgetKey(appWidgetId), it.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentStudent != null) {
|
if (currentStudent != null) {
|
||||||
luckyNumberRepository.getLuckyNumber(currentStudent, forceRefresh = false)
|
luckyNumberRepository.getLuckyNumber(currentStudent, forceRefresh = false)
|
||||||
.toFirstResult()
|
.toFirstResult()
|
||||||
} else {
|
.dataOrThrow
|
||||||
Resource.Success<LuckyNumber?>(null)
|
} else null
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Timber.e(e, "An error has occurred in lucky number provider")
|
Timber.e(e, "An error has occurred in lucky number provider")
|
||||||
Resource.Error(e)
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ import android.view.View.VISIBLE
|
|||||||
import android.widget.RemoteViews
|
import android.widget.RemoteViews
|
||||||
import android.widget.RemoteViewsService
|
import android.widget.RemoteViewsService
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.dataOrNull
|
import io.github.wulkanowy.data.dataOrThrow
|
||||||
import io.github.wulkanowy.data.db.SharedPrefProvider
|
import io.github.wulkanowy.data.db.SharedPrefProvider
|
||||||
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
|
||||||
@ -27,6 +27,7 @@ import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider.Co
|
|||||||
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider.Companion.getStudentWidgetKey
|
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider.Companion.getStudentWidgetKey
|
||||||
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider.Companion.getTodayLastLessonEndDateTimeWidgetKey
|
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider.Companion.getTodayLastLessonEndDateTimeWidgetKey
|
||||||
import io.github.wulkanowy.utils.getCompatColor
|
import io.github.wulkanowy.utils.getCompatColor
|
||||||
|
import io.github.wulkanowy.utils.getErrorString
|
||||||
import io.github.wulkanowy.utils.getPlural
|
import io.github.wulkanowy.utils.getPlural
|
||||||
import io.github.wulkanowy.utils.toFormattedString
|
import io.github.wulkanowy.utils.toFormattedString
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
@ -67,25 +68,31 @@ class TimetableWidgetFactory(
|
|||||||
override fun onDestroy() {}
|
override fun onDestroy() {}
|
||||||
|
|
||||||
override fun onDataSetChanged() {
|
override fun onDataSetChanged() {
|
||||||
intent?.extras?.getInt(EXTRA_APPWIDGET_ID)?.let { appWidgetId ->
|
val appWidgetId = intent?.extras?.getInt(EXTRA_APPWIDGET_ID) ?: return
|
||||||
val date = LocalDate.ofEpochDay(sharedPref.getLong(getDateWidgetKey(appWidgetId), 0))
|
val date = LocalDate.ofEpochDay(sharedPref.getLong(getDateWidgetKey(appWidgetId), 0))
|
||||||
val studentId = sharedPref.getLong(getStudentWidgetKey(appWidgetId), 0)
|
val studentId = sharedPref.getLong(getStudentWidgetKey(appWidgetId), 0)
|
||||||
|
|
||||||
runCatching {
|
items = emptyList()
|
||||||
|
|
||||||
runBlocking {
|
runBlocking {
|
||||||
|
runCatching {
|
||||||
val student = getStudent(studentId) ?: return@runBlocking
|
val student = getStudent(studentId) ?: return@runBlocking
|
||||||
val semester = semesterRepository.getCurrentSemester(student)
|
val semester = semesterRepository.getCurrentSemester(student)
|
||||||
items = createItems(
|
val lessons = getLessons(student, semester, date)
|
||||||
lessons = getLessons(student, semester, date),
|
val lastSync = timetableRepository.getLastRefreshTimestamp(semester, date, date)
|
||||||
lastSync = timetableRepository.getLastRefreshTimestamp(semester, date, date)
|
|
||||||
)
|
createItems(lessons, lastSync)
|
||||||
|
}
|
||||||
|
.onFailure {
|
||||||
|
items = listOf(TimetableWidgetItem.Error(it))
|
||||||
|
Timber.e(it, "An error has occurred in timetable widget factory")
|
||||||
|
}
|
||||||
|
.onSuccess {
|
||||||
|
items = it
|
||||||
if (date == LocalDate.now()) {
|
if (date == LocalDate.now()) {
|
||||||
updateTodayLastLessonEnd(appWidgetId)
|
updateTodayLastLessonEnd(appWidgetId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.onFailure {
|
|
||||||
Timber.e(it, "An error has occurred in timetable widget factory")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,7 +105,7 @@ class TimetableWidgetFactory(
|
|||||||
student: Student, semester: Semester, date: LocalDate
|
student: Student, semester: Semester, date: LocalDate
|
||||||
): List<Timetable> {
|
): List<Timetable> {
|
||||||
val timetable = timetableRepository.getTimetable(student, semester, date, date, false)
|
val timetable = timetableRepository.getTimetable(student, semester, date, date, false)
|
||||||
val lessons = timetable.toFirstResult().dataOrNull?.lessons.orEmpty()
|
val lessons = timetable.toFirstResult().dataOrThrow.lessons
|
||||||
return lessons.sortedBy { it.number }
|
return lessons.sortedBy { it.number }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,6 +117,7 @@ class TimetableWidgetFactory(
|
|||||||
BETWEEN_AND_BEFORE_LESSONS -> 0
|
BETWEEN_AND_BEFORE_LESSONS -> 0
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
return buildList {
|
return buildList {
|
||||||
lessons.forEach {
|
lessons.forEach {
|
||||||
if (prefRepository.showTimetableGaps != NO_GAPS && prevNum != null && it.number > prevNum!! + 1) {
|
if (prefRepository.showTimetableGaps != NO_GAPS && prevNum != null && it.number > prevNum!! + 1) {
|
||||||
@ -133,15 +141,12 @@ class TimetableWidgetFactory(
|
|||||||
sharedPref.putLong(key, todayLastLessonEnd.epochSecond, true)
|
sharedPref.putLong(key, todayLastLessonEnd.epochSecond, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val TIME_FORMAT_STYLE = "HH:mm"
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getViewAt(position: Int): RemoteViews? {
|
override fun getViewAt(position: Int): RemoteViews? {
|
||||||
return when (val item = items.getOrNull(position) ?: return null) {
|
return when (val item = items.getOrNull(position) ?: return null) {
|
||||||
is TimetableWidgetItem.Normal -> getNormalItemRemoteView(item)
|
is TimetableWidgetItem.Normal -> getNormalItemRemoteView(item)
|
||||||
is TimetableWidgetItem.Empty -> getEmptyItemRemoteView(item)
|
is TimetableWidgetItem.Empty -> getEmptyItemRemoteView(item)
|
||||||
is TimetableWidgetItem.Synchronized -> getSynchronizedItemRemoteView(item)
|
is TimetableWidgetItem.Synchronized -> getSynchronizedItemRemoteView(item)
|
||||||
|
is TimetableWidgetItem.Error -> getErrorItemRemoteView(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,6 +218,18 @@ class TimetableWidgetFactory(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getErrorItemRemoteView(item: TimetableWidgetItem.Error): RemoteViews {
|
||||||
|
return RemoteViews(
|
||||||
|
context.packageName,
|
||||||
|
R.layout.item_widget_timetable_error
|
||||||
|
).apply {
|
||||||
|
setTextViewText(
|
||||||
|
R.id.timetable_widget_item_error_message,
|
||||||
|
context.resources.getErrorString(item.error)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun updateTheme() {
|
private fun updateTheme() {
|
||||||
when (context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) {
|
when (context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) {
|
||||||
Configuration.UI_MODE_NIGHT_YES -> {
|
Configuration.UI_MODE_NIGHT_YES -> {
|
||||||
@ -300,4 +317,8 @@ class TimetableWidgetFactory(
|
|||||||
synchronizationTime,
|
synchronizationTime,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
private const val TIME_FORMAT_STYLE = "HH:mm"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,10 +17,15 @@ sealed class TimetableWidgetItem(val type: TimetableWidgetItemType) {
|
|||||||
data class Synchronized(
|
data class Synchronized(
|
||||||
val timestamp: Instant,
|
val timestamp: Instant,
|
||||||
) : TimetableWidgetItem(TimetableWidgetItemType.SYNCHRONIZED)
|
) : TimetableWidgetItem(TimetableWidgetItemType.SYNCHRONIZED)
|
||||||
|
|
||||||
|
data class Error(
|
||||||
|
val error: Throwable
|
||||||
|
) : TimetableWidgetItem(TimetableWidgetItemType.ERROR)
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class TimetableWidgetItemType {
|
enum class TimetableWidgetItemType {
|
||||||
NORMAL,
|
NORMAL,
|
||||||
EMPTY,
|
EMPTY,
|
||||||
SYNCHRONIZED,
|
SYNCHRONIZED,
|
||||||
|
ERROR,
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package io.github.wulkanowy.utils
|
package io.github.wulkanowy.utils
|
||||||
|
|
||||||
|
import android.util.AndroidRuntimeException
|
||||||
import java.net.CookiePolicy
|
import java.net.CookiePolicy
|
||||||
import java.net.CookieStore
|
import java.net.CookieStore
|
||||||
import java.net.HttpCookie
|
import java.net.HttpCookie
|
||||||
@ -9,7 +10,18 @@ import java.net.CookieManager as JavaCookieManager
|
|||||||
|
|
||||||
class WebkitCookieManagerProxy : JavaCookieManager(null, CookiePolicy.ACCEPT_ALL) {
|
class WebkitCookieManagerProxy : JavaCookieManager(null, CookiePolicy.ACCEPT_ALL) {
|
||||||
|
|
||||||
private val webkitCookieManager: WebkitCookieManager = WebkitCookieManager.getInstance()
|
private val webkitCookieManager: WebkitCookieManager? = getWebkitCookieManager()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see [https://stackoverflow.com/a/70354583/6695449]
|
||||||
|
*/
|
||||||
|
private fun getWebkitCookieManager(): WebkitCookieManager? {
|
||||||
|
return try {
|
||||||
|
WebkitCookieManager.getInstance()
|
||||||
|
} catch (e: AndroidRuntimeException) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun put(uri: URI?, responseHeaders: Map<String?, List<String?>>?) {
|
override fun put(uri: URI?, responseHeaders: Map<String?, List<String?>>?) {
|
||||||
if (uri == null || responseHeaders == null) return
|
if (uri == null || responseHeaders == null) return
|
||||||
@ -23,7 +35,7 @@ class WebkitCookieManagerProxy : JavaCookieManager(null, CookiePolicy.ACCEPT_ALL
|
|||||||
|
|
||||||
// process each of the headers
|
// process each of the headers
|
||||||
for (headerValue in responseHeaders[headerKey].orEmpty()) {
|
for (headerValue in responseHeaders[headerKey].orEmpty()) {
|
||||||
webkitCookieManager.setCookie(url, headerValue)
|
webkitCookieManager?.setCookie(url, headerValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -34,7 +46,7 @@ class WebkitCookieManagerProxy : JavaCookieManager(null, CookiePolicy.ACCEPT_ALL
|
|||||||
): Map<String, List<String>> {
|
): Map<String, List<String>> {
|
||||||
require(!(uri == null || requestHeaders == null)) { "Argument is null" }
|
require(!(uri == null || requestHeaders == null)) { "Argument is null" }
|
||||||
val res = mutableMapOf<String, List<String>>()
|
val res = mutableMapOf<String, List<String>>()
|
||||||
val cookie = webkitCookieManager.getCookie(uri.toString())
|
val cookie = webkitCookieManager?.getCookie(uri.toString())
|
||||||
if (cookie != null) res["Cookie"] = listOf(cookie)
|
if (cookie != null) res["Cookie"] = listOf(cookie)
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
@ -50,7 +62,7 @@ class WebkitCookieManagerProxy : JavaCookieManager(null, CookiePolicy.ACCEPT_ALL
|
|||||||
cookies.remove(uri, cookie)
|
cookies.remove(uri, cookie)
|
||||||
|
|
||||||
override fun removeAll(): Boolean {
|
override fun removeAll(): Boolean {
|
||||||
webkitCookieManager.removeAllCookies(null)
|
webkitCookieManager?.removeAllCookies(null) ?: return false
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
Wersja 2.4.0
|
Wersja 2.4.2
|
||||||
|
|
||||||
— naprawiliśmy logowanie do aplikacji na odmianie standardowej
|
- naprawiliśmy crash przy przełączaniu uczniów, motywów i języków
|
||||||
— naprawiliśmy wyświetlanie lekcji na kolejny dzień w kafelku na ekranie Start
|
- naprawiliśmy crash przy dodawaniu dodatkowych lekcji
|
||||||
— dodaliśmy oceny opisowe
|
- naprawiliśmy obsługę błędów widżetach
|
||||||
— dodaliśmy kolorowe opisy we frekwencji we wpisach innych niż obecność
|
|
||||||
|
|
||||||
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases
|
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:editable="false"
|
android:editable="false"
|
||||||
android:focusable="false"
|
android:focusable="false"
|
||||||
android:inputType="text"
|
android:inputType="none"
|
||||||
tools:ignore="Deprecated" />
|
tools:ignore="Deprecated" />
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
@ -67,7 +67,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:editable="false"
|
android:editable="false"
|
||||||
android:focusable="false"
|
android:focusable="false"
|
||||||
android:inputType="text"
|
android:inputType="none"
|
||||||
tools:ignore="Deprecated" />
|
tools:ignore="Deprecated" />
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
@ -87,7 +87,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:editable="false"
|
android:editable="false"
|
||||||
android:focusable="false"
|
android:focusable="false"
|
||||||
android:inputType="text"
|
android:inputType="none"
|
||||||
tools:ignore="Deprecated" />
|
tools:ignore="Deprecated" />
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
@ -261,6 +261,7 @@
|
|||||||
android:layout_marginEnd="24dp"
|
android:layout_marginEnd="24dp"
|
||||||
android:layout_marginRight="24dp"
|
android:layout_marginRight="24dp"
|
||||||
android:hint="@string/login_domain_suffix_hint"
|
android:hint="@string/login_domain_suffix_hint"
|
||||||
|
app:errorEnabled="true"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/loginFormHostLayout"
|
app:layout_constraintTop_toBottomOf="@+id/loginFormHostLayout"
|
||||||
|
12
app/src/main/res/layout/item_widget_timetable_error.xml
Normal file
12
app/src/main/res/layout/item_widget_timetable_error.xml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/timetable_widget_item_error_message"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:paddingHorizontal="12dp"
|
||||||
|
android:paddingTop="48dp"
|
||||||
|
android:paddingBottom="12dp"
|
||||||
|
android:textSize="16sp"
|
||||||
|
tools:text="@string/error_unknown" />
|
@ -114,7 +114,5 @@
|
|||||||
android:text="@string/widget_timetable_no_items"
|
android:text="@string/widget_timetable_no_items"
|
||||||
android:textAppearance="?attr/textAppearanceBody1"
|
android:textAppearance="?attr/textAppearanceBody1"
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
@ -56,6 +56,7 @@
|
|||||||
<string name="login_invalid_email">Neplatný e-mail</string>
|
<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_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_custom_email">Použijte přiřazené přihlašovací nebo e-mail v @%1$s</string>
|
||||||
|
<string name="login_invalid_domain_suffix">Invalid domain suffix</string>
|
||||||
<string name="login_invalid_symbol">Neplatný symbol. Pokud jej nemůžete najít, kontaktujte školu</string>
|
<string name="login_invalid_symbol">Neplatný symbol. Pokud jej nemůžete najít, kontaktujte školu</string>
|
||||||
<string name="login_invalid_symbol_definitely">Nevymýšlejte si! Pokud symbol nemůžete najít, kontaktujte školu</string>
|
<string name="login_invalid_symbol_definitely">Nevymýšlejte si! Pokud symbol nemůžete najít, kontaktujte školu</string>
|
||||||
<string name="login_incorrect_symbol">Žák nebyl nalezen. Zkontrolujte správnost symbolu a vybrané varianty deníku UONET+</string>
|
<string name="login_incorrect_symbol">Žák nebyl nalezen. Zkontrolujte správnost symbolu a vybrané varianty deníku UONET+</string>
|
||||||
|
@ -56,6 +56,7 @@
|
|||||||
<string name="login_invalid_email">Ungültige email</string>
|
<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_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_custom_email">Benutze den zugewiesenen Login oder E-Mail in @%1$s</string>
|
||||||
|
<string name="login_invalid_domain_suffix">Invalid domain suffix</string>
|
||||||
<string name="login_invalid_symbol">Invalid symbol. If you cannot find it, please contact the school</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_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_incorrect_symbol">Schüler nicht gefunden. Überprüfen Sie das Symbol und die gewählte Variation des UONET+ Registers</string>
|
||||||
|
@ -56,6 +56,7 @@
|
|||||||
<string name="login_invalid_email">Nieprawidłowy adres e-mail</string>
|
<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_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_custom_email">Użyj loginu lub adresu e-mail w @%1$s</string>
|
||||||
|
<string name="login_invalid_domain_suffix">Nieprawidłowy sufiks domeny</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">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_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_incorrect_symbol">Nie znaleziono ucznia. Sprawdź poprawność symbolu i wybranej odmiany dziennika UONET+</string>
|
||||||
|
@ -56,6 +56,7 @@
|
|||||||
<string name="login_invalid_email">Неверный e-mail</string>
|
<string name="login_invalid_email">Неверный e-mail</string>
|
||||||
<string name="login_invalid_login">Используйте назначенный логин вместо 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_custom_email">Используйте назначенный логин или email в @%1$s</string>
|
||||||
|
<string name="login_invalid_domain_suffix">Invalid domain suffix</string>
|
||||||
<string name="login_invalid_symbol">Invalid symbol. If you cannot find it, please contact the school</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_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_incorrect_symbol">Ученик не найден. Проверьте symbol и выбранный тип дненика UONET+</string>
|
||||||
|
@ -56,6 +56,7 @@
|
|||||||
<string name="login_invalid_email">Neplatný e-mail</string>
|
<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_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_custom_email">Použite priradené prihlasovacie alebo e-mail v @%1$s</string>
|
||||||
|
<string name="login_invalid_domain_suffix">Invalid domain suffix</string>
|
||||||
<string name="login_invalid_symbol">Neplatný symbol. Pokiaľ ho nemôžete nájsť, kontaktujte školu</string>
|
<string name="login_invalid_symbol">Neplatný symbol. Pokiaľ ho nemôžete nájsť, kontaktujte školu</string>
|
||||||
<string name="login_invalid_symbol_definitely">Nevymýšľajte si! Pokiaľ symbol nemôžete nájsť, kontaktujte školu</string>
|
<string name="login_invalid_symbol_definitely">Nevymýšľajte si! Pokiaľ symbol nemôžete nájsť, kontaktujte školu</string>
|
||||||
<string name="login_incorrect_symbol">Žiak nebol nájdený. Skontrolujte správnosť symbolu a vybrané varianty denníka UONET+</string>
|
<string name="login_incorrect_symbol">Žiak nebol nájdený. Skontrolujte správnosť symbolu a vybrané varianty denníka UONET+</string>
|
||||||
|
@ -56,6 +56,7 @@
|
|||||||
<string name="login_invalid_email">Недійсна адреса e-mail</string>
|
<string name="login_invalid_email">Недійсна адреса e-mail</string>
|
||||||
<string name="login_invalid_login">Використовуйте призначений логін замість адреси 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_custom_email">Використовуйте призначений логін або адресу e-mail в @%1$s</string>
|
||||||
|
<string name="login_invalid_domain_suffix">Invalid domain suffix</string>
|
||||||
<string name="login_invalid_symbol">Некоректний символ. Якщо ви не можете знайти його, будь ласка, зв\'яжіться зі школою</string>
|
<string name="login_invalid_symbol">Некоректний символ. Якщо ви не можете знайти його, будь ласка, зв\'яжіться зі школою</string>
|
||||||
<string name="login_invalid_symbol_definitely">Не вигадуйте! Якщо ви не можете знайти його, будь ласка, зв\'яжіться зі школою</string>
|
<string name="login_invalid_symbol_definitely">Не вигадуйте! Якщо ви не можете знайти його, будь ласка, зв\'яжіться зі школою</string>
|
||||||
<string name="login_incorrect_symbol">Студента не знайдено. Перевірте symbol та обраний тип щоденника UONET+</string>
|
<string name="login_incorrect_symbol">Студента не знайдено. Перевірте symbol та обраний тип щоденника UONET+</string>
|
||||||
|
@ -61,6 +61,7 @@
|
|||||||
<string name="login_invalid_email">Invalid email</string>
|
<string name="login_invalid_email">Invalid email</string>
|
||||||
<string name="login_invalid_login">Use the assigned login instead of email</string>
|
<string name="login_invalid_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_custom_email">Use the assigned login or email in @%1$s</string>
|
||||||
|
<string name="login_invalid_domain_suffix">Invalid domain suffix</string>
|
||||||
<string name="login_invalid_symbol">Invalid symbol. If you cannot find it, please contact the school</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_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_incorrect_symbol">Student not found. Validate the symbol and the chosen variation of the UONET+ register</string>
|
||||||
|
@ -16,7 +16,7 @@ buildscript {
|
|||||||
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.2'
|
classpath 'com.android.tools.build:gradle:8.2.2'
|
||||||
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.1'
|
||||||
classpath 'com.huawei.agconnect:agcp:1.9.1.303'
|
classpath 'com.huawei.agconnect:agcp:1.9.1.303'
|
||||||
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.9'
|
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.9'
|
||||||
classpath "com.github.triplet.gradle:play-publisher:3.8.4"
|
classpath "com.github.triplet.gradle:play-publisher:3.8.4"
|
||||||
|
Reference in New Issue
Block a user