diff --git a/app/build.gradle b/app/build.gradle index b09078a9..ec3ee4f3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -27,12 +27,11 @@ android { testApplicationId "io.github.tests.wulkanowy" minSdkVersion 21 targetSdkVersion 33 - versionCode 131 - versionName "2.1.0" + versionCode 132 + versionName "2.2.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" resValue "string", "app_name", "Wulkanowy" - manifestPlaceholders = [ firebase_enabled: project.hasProperty("enableFirebase"), admob_project_id: "" @@ -69,6 +68,7 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' signingConfig signingConfigs.release buildConfigField "String", "MESSAGES_BASE_URL", "\"https://messages.wulkanowy.net.pl\"" + buildConfigField "String", "SCHOOLS_BASE_URL", '"https://schools.wulkanowy.net.pl"' } debug { minifyEnabled false @@ -78,6 +78,7 @@ android { versionNameSuffix "-dev" ext.enableCrashlytics = project.hasProperty("enableFirebase") buildConfigField "String", "MESSAGES_BASE_URL", "\"https://messages.wulkanowy.net.pl\"" + buildConfigField "String", "SCHOOLS_BASE_URL", '"https://schools.wulkanowy.net.pl"' } } @@ -160,8 +161,8 @@ play { defaultToAppBundles = false track = 'production' releaseStatus = ReleaseStatus.IN_PROGRESS - userFraction = 0.25d - updatePriority = 3 + userFraction = 0.01d + updatePriority = 1 enabled.set(false) } @@ -186,16 +187,16 @@ ext { android_hilt = "1.0.0" room = "2.5.2" chucker = "3.5.2" - mockk = "1.13.7" + mockk = "1.13.8" coroutines = "1.7.3" } dependencies { - implementation 'io.github.wulkanowy:sdk:2.1.0' + implementation 'io.github.wulkanowy:sdk:2.2.0' coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.3' - implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1" + implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines" implementation "androidx.core:core-ktx:1.10.1" @@ -203,7 +204,7 @@ dependencies { implementation "androidx.activity:activity-ktx:1.7.2" implementation "androidx.appcompat:appcompat:1.6.1" implementation "androidx.fragment:fragment-ktx:1.6.1" - implementation "androidx.annotation:annotation:1.6.0" + implementation "androidx.annotation:annotation:1.7.0" implementation "androidx.preference:preference-ktx:1.2.1" implementation "androidx.recyclerview:recyclerview:1.3.1" @@ -219,7 +220,7 @@ dependencies { implementation "androidx.work:work-runtime-ktx:$work_manager" playImplementation "androidx.work:work-gcm:$work_manager" - implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.6.1" + implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.6.2" implementation "androidx.room:room-runtime:$room" implementation "androidx.room:room-ktx:$room" @@ -239,7 +240,7 @@ dependencies { implementation "com.jakewharton.timber:timber:5.0.1" implementation "at.favre.lib:slf4j-timber:1.0.1" - implementation 'com.github.bastienpaulfr:Treessence:1.0.5' + implementation 'com.github.bastienpaulfr:Treessence:1.1.2' implementation "com.mikepenz:aboutlibraries-core:$about_libraries" implementation "io.coil-kt:coil:2.4.0" implementation "io.github.wulkanowy:AppKillerManager:3.0.1" @@ -247,17 +248,18 @@ dependencies { implementation 'com.fredporciuncula:flow-preferences:1.9.1' implementation 'org.apache.commons:commons-text:1.10.0' - playImplementation platform('com.google.firebase:firebase-bom:32.2.2') + playImplementation platform('com.google.firebase:firebase-bom:32.3.1') playImplementation 'com.google.firebase:firebase-analytics-ktx' playImplementation 'com.google.firebase:firebase-messaging:' playImplementation 'com.google.firebase:firebase-crashlytics:' playImplementation 'com.google.firebase:firebase-config-ktx' playImplementation 'com.google.android.play:core:1.10.3' playImplementation 'com.google.android.play:core-ktx:1.8.1' - playImplementation 'com.google.android.gms:play-services-ads:22.2.0' + playImplementation 'com.google.android.gms:play-services-ads:22.4.0' + playImplementation "com.google.android.play:integrity:1.2.0" - hmsImplementation 'com.huawei.hms:hianalytics:6.10.0.303' - hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.9.1.300' + hmsImplementation 'com.huawei.hms:hianalytics:6.12.0.300' + hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.9.1.301' releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker" diff --git a/app/src/fdroid/java/io/github/wulkanowy/utils/IntegrityHelper.kt b/app/src/fdroid/java/io/github/wulkanowy/utils/IntegrityHelper.kt new file mode 100644 index 00000000..7af68058 --- /dev/null +++ b/app/src/fdroid/java/io/github/wulkanowy/utils/IntegrityHelper.kt @@ -0,0 +1,11 @@ +package io.github.wulkanowy.utils + +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class IntegrityHelper @Inject constructor() { + + @Suppress("UNUSED_PARAMETER") + fun getIntegrityToken(requestId: String): String? = null +} diff --git a/app/src/hms/java/io/github/wulkanowy/utils/CrashLogUtils.kt b/app/src/hms/java/io/github/wulkanowy/utils/CrashLogUtils.kt index 377e8366..2b1f1d30 100644 --- a/app/src/hms/java/io/github/wulkanowy/utils/CrashLogUtils.kt +++ b/app/src/hms/java/io/github/wulkanowy/utils/CrashLogUtils.kt @@ -2,8 +2,8 @@ package io.github.wulkanowy.utils import android.util.Log import com.huawei.agconnect.crash.AGConnectCrash -import fr.bipi.tressence.base.FormatterPriorityTree -import fr.bipi.tressence.common.StackTraceRecorder +import fr.bipi.treessence.base.FormatterPriorityTree +import fr.bipi.treessence.common.StackTraceRecorder class CrashLogTree : FormatterPriorityTree(Log.VERBOSE) { diff --git a/app/src/hms/java/io/github/wulkanowy/utils/IntegrityHelper.kt b/app/src/hms/java/io/github/wulkanowy/utils/IntegrityHelper.kt new file mode 100644 index 00000000..7af68058 --- /dev/null +++ b/app/src/hms/java/io/github/wulkanowy/utils/IntegrityHelper.kt @@ -0,0 +1,11 @@ +package io.github.wulkanowy.utils + +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class IntegrityHelper @Inject constructor() { + + @Suppress("UNUSED_PARAMETER") + fun getIntegrityToken(requestId: String): String? = null +} diff --git a/app/src/main/java/io/github/wulkanowy/WulkanowyApp.kt b/app/src/main/java/io/github/wulkanowy/WulkanowyApp.kt index a39a3874..dc106101 100644 --- a/app/src/main/java/io/github/wulkanowy/WulkanowyApp.kt +++ b/app/src/main/java/io/github/wulkanowy/WulkanowyApp.kt @@ -6,7 +6,7 @@ import androidx.hilt.work.HiltWorkerFactory import androidx.work.Configuration import com.yariksoffice.lingver.Lingver import dagger.hilt.android.HiltAndroidApp -import fr.bipi.tressence.file.FileLoggerTree +import fr.bipi.treessence.file.FileLoggerTree import io.github.wulkanowy.data.repositories.PreferencesRepository import io.github.wulkanowy.ui.base.ThemeManager import io.github.wulkanowy.utils.* diff --git a/app/src/main/java/io/github/wulkanowy/data/DataModule.kt b/app/src/main/java/io/github/wulkanowy/data/DataModule.kt index c9e4990f..bea3f706 100644 --- a/app/src/main/java/io/github/wulkanowy/data/DataModule.kt +++ b/app/src/main/java/io/github/wulkanowy/data/DataModule.kt @@ -14,6 +14,7 @@ import dagger.hilt.InstallIn import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent import io.github.wulkanowy.data.api.AdminMessageService +import io.github.wulkanowy.data.api.SchoolsService import io.github.wulkanowy.data.db.AppDatabase import io.github.wulkanowy.data.db.SharedPrefProvider import io.github.wulkanowy.data.repositories.PreferencesRepository @@ -82,19 +83,29 @@ internal class DataModule { @Singleton @Provides - fun provideRetrofit( + fun provideAdminMessageService( okHttpClient: OkHttpClient, json: Json, appInfo: AppInfo - ): Retrofit = Retrofit.Builder() + ): AdminMessageService = Retrofit.Builder() .baseUrl(appInfo.messagesBaseUrl) .client(okHttpClient) .addConverterFactory(json.asConverterFactory("application/json".toMediaType())) .build() + .create() @Singleton @Provides - fun provideAdminMessageService(retrofit: Retrofit): AdminMessageService = retrofit.create() + fun provideSchoolsService( + okHttpClient: OkHttpClient, + json: Json, + appInfo: AppInfo, + ): SchoolsService = Retrofit.Builder() + .baseUrl(appInfo.schoolsBaseUrl) + .client(okHttpClient) + .addConverterFactory(json.asConverterFactory("application/json".toMediaType())) + .build() + .create() @Singleton @Provides diff --git a/app/src/main/java/io/github/wulkanowy/data/api/SchoolsService.kt b/app/src/main/java/io/github/wulkanowy/data/api/SchoolsService.kt new file mode 100644 index 00000000..a7da9b63 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/api/SchoolsService.kt @@ -0,0 +1,14 @@ +package io.github.wulkanowy.data.api + +import io.github.wulkanowy.data.pojos.IntegrityRequest +import io.github.wulkanowy.data.pojos.LoginEvent +import retrofit2.http.Body +import retrofit2.http.POST +import javax.inject.Singleton + +@Singleton +interface SchoolsService { + + @POST("/log/loginEvent") + suspend fun logLoginEvent(@Body request: IntegrityRequest) +} diff --git a/app/src/main/java/io/github/wulkanowy/data/pojos/LoginEvent.kt b/app/src/main/java/io/github/wulkanowy/data/pojos/LoginEvent.kt new file mode 100644 index 00000000..c2b4d2de --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/pojos/LoginEvent.kt @@ -0,0 +1,21 @@ +package io.github.wulkanowy.data.pojos + +import kotlinx.serialization.Serializable + +@Serializable +data class LoginEvent( + val uuid: String, + val schoolName: String, + val schoolShort: String, + val schoolAddress: String, + val scraperBaseUrl: String, + val symbol: String, + val schoolId: String, + val loginType: String, +) + +@Serializable +data class IntegrityRequest( + val tokenString: String, + val data: T, +) diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/SchoolsRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/SchoolsRepository.kt new file mode 100644 index 00000000..9c642934 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/SchoolsRepository.kt @@ -0,0 +1,68 @@ +package io.github.wulkanowy.data.repositories + +import io.github.wulkanowy.data.api.SchoolsService +import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.db.entities.Student +import io.github.wulkanowy.data.db.entities.StudentWithSemesters +import io.github.wulkanowy.data.pojos.IntegrityRequest +import io.github.wulkanowy.data.pojos.LoginEvent +import io.github.wulkanowy.sdk.Sdk +import io.github.wulkanowy.ui.modules.login.LoginData +import io.github.wulkanowy.utils.IntegrityHelper +import io.github.wulkanowy.utils.getCurrentOrLast +import io.github.wulkanowy.utils.init +import kotlinx.coroutines.withTimeout +import timber.log.Timber +import java.util.UUID +import javax.inject.Inject +import javax.inject.Singleton +import kotlin.time.Duration.Companion.seconds + +@Singleton +class SchoolsRepository @Inject constructor( + private val integrityHelper: IntegrityHelper, + private val schoolsService: SchoolsService, + private val sdk: Sdk, +) { + + suspend fun logSchoolLogin(loginData: LoginData, students: List) { + students.forEach { + runCatching { + withTimeout(10.seconds) { + logLogin(loginData, it.student, it.semesters.getCurrentOrLast()) + } + } + .onFailure { Timber.e(it) } + } + } + + private suspend fun logLogin(loginData: LoginData, student: Student, semester: Semester) { + val requestId = UUID.randomUUID().toString() + val token = integrityHelper.getIntegrityToken(requestId) ?: return + + val schoolInfo = sdk + .init(student.copy(password = loginData.password)) + .switchDiary( + diaryId = semester.diaryId, + kindergartenDiaryId = semester.kindergartenDiaryId, + schoolYear = semester.schoolYear + ) + .getSchool() + + schoolsService.logLoginEvent( + IntegrityRequest( + tokenString = token, + data = LoginEvent( + uuid = requestId, + schoolAddress = schoolInfo.address, + schoolName = schoolInfo.name, + schoolShort = student.schoolShortName, + scraperBaseUrl = student.scrapperBaseUrl, + loginType = student.loginType, + symbol = student.symbol, + schoolId = student.schoolSymbol, + ) + ) + ) + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProvider.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProvider.kt index 2d63aae4..ec4bd8e8 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProvider.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProvider.kt @@ -58,7 +58,7 @@ class GradeAverageProvider @Inject constructor( when (params.gradeAverageMode) { ONE_SEMESTER -> getGradeSubjects( student = student, - semester = semesters.single { it.semesterId == semesterId }, + semester = semesters.first { it.semesterId == semesterId }, forceRefresh = forceRefresh, params = params, ) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormFragment.kt index ff7fd864..8e9b86fa 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormFragment.kt @@ -17,6 +17,8 @@ import io.github.wulkanowy.ui.base.BaseFragment import io.github.wulkanowy.ui.modules.dashboard.viewholders.AdminMessageViewHolder import io.github.wulkanowy.ui.modules.login.LoginActivity import io.github.wulkanowy.ui.modules.login.LoginData +import io.github.wulkanowy.ui.modules.login.support.LoginSupportDialog +import io.github.wulkanowy.ui.modules.login.support.LoginSupportInfo import io.github.wulkanowy.utils.* import javax.inject.Inject @@ -184,7 +186,9 @@ class LoginFormFragment : BaseFragment(R.layout.fragme override fun clearPassError() { binding.loginFormPassLayout.error = null - binding.loginFormPassLayout.setEndIconTintList(null) + binding.loginFormPassLayout.setEndIconTintList( + requireContext().getAttrColorStateList(R.attr.colorOnSurface) + ) binding.loginFormErrorBox.isVisible = false } @@ -236,8 +240,7 @@ class LoginFormFragment : BaseFragment(R.layout.fragme } override fun showContact(show: Boolean) { - binding.loginFormContact.visibility = if (show) VISIBLE else GONE - binding.loginFormRecoverLink.visibility = if (show) GONE else VISIBLE + binding.loginFormContact.isVisible = show } override fun openPrivacyPolicyPage() { @@ -281,20 +284,7 @@ class LoginFormFragment : BaseFragment(R.layout.fragme presenter.updateCustomDomainSuffixVisibility() } - override fun openEmail(lastError: String) { - context?.openEmailClient( - chooserTitle = requireContext().getString(R.string.login_email_intent_title), - email = "wulkanowyinc@gmail.com", - subject = requireContext().getString(R.string.login_email_subject), - body = requireContext().getString( - R.string.login_email_text, - "${appInfo.systemManufacturer} ${appInfo.systemModel}", - appInfo.systemVersion.toString(), - "${appInfo.versionName}-${appInfo.buildFlavor}", - "$formHostValue/$formHostSymbol", - preferencesRepository.installationId, - lastError - ) - ) + override fun openEmail(supportInfo: LoginSupportInfo) { + LoginSupportDialog.newInstance(supportInfo).show(childFragmentManager, "support_dialog") } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt index 4e0404d9..ad535c38 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt @@ -17,6 +17,7 @@ import io.github.wulkanowy.domain.adminmessage.GetAppropriateAdminMessageUseCase import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.ui.modules.login.LoginData import io.github.wulkanowy.ui.modules.login.LoginErrorHandler +import io.github.wulkanowy.ui.modules.login.support.LoginSupportInfo import io.github.wulkanowy.utils.AnalyticsHelper import io.github.wulkanowy.utils.AppInfo import io.github.wulkanowy.utils.ifNullOrBlank @@ -133,7 +134,7 @@ class LoginFormPresenter @Inject constructor( } } - fun onSignInClick() { + private fun getLoginData(): LoginData { val email = view?.formUsernameValue.orEmpty().trim() val password = view?.formPassValue.orEmpty().trim() val host = view?.formHostValue.orEmpty().trim() @@ -142,15 +143,27 @@ class LoginFormPresenter @Inject constructor( }.orEmpty() val symbol = view?.formHostSymbol.orEmpty().trim() - if (!validateCredentials(email, password, host)) return + return LoginData( + login = email, + password = password, + baseUrl = host, + domainSuffix = domainSuffix, + symbol = symbol + ) + } + + fun onSignInClick() { + val loginData = getLoginData() + + if (!validateCredentials(loginData.login, loginData.password, loginData.baseUrl)) return resourceFlow { studentRepository.getUserSubjectsFromScrapper( - email = email, - password = password, - scrapperBaseUrl = host, - domainSuffix = domainSuffix, - symbol = symbol + email = loginData.login, + password = loginData.password, + scrapperBaseUrl = loginData.baseUrl, + domainSuffix = loginData.domainSuffix, + symbol = loginData.symbol.orEmpty(), ) } .logResourceStatus("login") @@ -162,7 +175,6 @@ class LoginFormPresenter @Inject constructor( } } .onResourceSuccess { - val loginData = LoginData(email, password, host, domainSuffix, symbol) when (it.symbols.size) { 0 -> view?.navigateToSymbol(loginData) else -> view?.navigateToStudentSelect(loginData, it) @@ -170,7 +182,7 @@ class LoginFormPresenter @Inject constructor( analytics.logEvent( "registration_form", "success" to true, - "scrapperBaseUrl" to host, + "scrapperBaseUrl" to loginData.baseUrl, "error" to "No error" ) } @@ -187,7 +199,7 @@ class LoginFormPresenter @Inject constructor( analytics.logEvent( "registration_form", "success" to false, - "scrapperBaseUrl" to host, + "scrapperBaseUrl" to loginData.baseUrl, "error" to it.message.ifNullOrBlank { "No message" } ) } @@ -199,7 +211,14 @@ class LoginFormPresenter @Inject constructor( } fun onEmailClick() { - view?.openEmail(lastError?.message.ifNullOrBlank { "none" }) + view?.openEmail( + LoginSupportInfo( + loginData = getLoginData(), + lastErrorMessage = lastError?.message, + registerUser = null, + enteredSymbol = null, + ) + ) } fun onRecoverClick() { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormView.kt index 5b4dcadf..f2b7b100 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormView.kt @@ -4,6 +4,7 @@ import io.github.wulkanowy.data.db.entities.AdminMessage import io.github.wulkanowy.data.pojos.RegisterUser import io.github.wulkanowy.ui.base.BaseView import io.github.wulkanowy.ui.modules.login.LoginData +import io.github.wulkanowy.ui.modules.login.support.LoginSupportInfo interface LoginFormView : BaseView { @@ -79,7 +80,7 @@ interface LoginFormView : BaseView { fun openFaqPage() - fun openEmail(lastError: String) + fun openEmail(supportInfo: LoginSupportInfo) fun openAdvancedLogin() diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/recover/LoginRecoverPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/recover/LoginRecoverPresenter.kt index 3d049301..a424df40 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/recover/LoginRecoverPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/recover/LoginRecoverPresenter.kt @@ -46,7 +46,7 @@ class LoginRecoverPresenter @Inject constructor( fun updateFields() { view?.run { - setUsernameHint(if ("standard" in recoverHostValue) emailHintString else loginPeselEmailHintString) + setUsernameHint(if ("email" in recoverHostValue) emailHintString else loginPeselEmailHintString) } } @@ -92,7 +92,7 @@ class LoginRecoverPresenter @Inject constructor( isCorrect = false } - if ("standard" in host && "@" !in username) { + if ("email" in host && "@" !in username) { view?.setUsernameError(view?.invalidEmailString.orEmpty()) isCorrect = false } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectFragment.kt index c33d12fa..06efd8d9 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectFragment.kt @@ -10,8 +10,11 @@ import io.github.wulkanowy.data.pojos.RegisterUser import io.github.wulkanowy.data.repositories.PreferencesRepository import io.github.wulkanowy.databinding.FragmentLoginStudentSelectBinding import io.github.wulkanowy.ui.base.BaseFragment +import io.github.wulkanowy.ui.modules.auth.AuthDialog import io.github.wulkanowy.ui.modules.login.LoginActivity import io.github.wulkanowy.ui.modules.login.LoginData +import io.github.wulkanowy.ui.modules.login.support.LoginSupportDialog +import io.github.wulkanowy.ui.modules.login.support.LoginSupportInfo import io.github.wulkanowy.utils.AppInfo import io.github.wulkanowy.utils.openEmailClient import io.github.wulkanowy.utils.openInternetBrowser @@ -106,21 +109,8 @@ class LoginStudentSelectFragment : context?.openInternetBrowser("https://discord.gg/vccAQBr", ::showMessage) } - override fun openEmail(lastError: String) { - context?.openEmailClient( - chooserTitle = requireContext().getString(R.string.login_email_intent_title), - email = "wulkanowyinc@gmail.com", - subject = requireContext().getString(R.string.login_email_subject), - body = requireContext().getString( - R.string.login_email_text, - "${appInfo.systemManufacturer} ${appInfo.systemModel}", - appInfo.systemVersion.toString(), - "${appInfo.versionName}-${appInfo.buildFlavor}", - "Select users to log in", - preferencesRepository.installationId, - lastError - ) - ) + override fun openEmail(supportInfo: LoginSupportInfo) { + LoginSupportDialog.newInstance(supportInfo).show(childFragmentManager, "support_dialog") } override fun onDestroyView() { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenter.kt index 70862e82..cc9e422e 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenter.kt @@ -9,23 +9,25 @@ import io.github.wulkanowy.data.pojos.RegisterStudent import io.github.wulkanowy.data.pojos.RegisterSymbol import io.github.wulkanowy.data.pojos.RegisterUnit import io.github.wulkanowy.data.pojos.RegisterUser +import io.github.wulkanowy.data.repositories.SchoolsRepository import io.github.wulkanowy.data.repositories.StudentRepository import io.github.wulkanowy.data.resourceFlow -import io.github.wulkanowy.sdk.scrapper.login.AccountPermissionException import io.github.wulkanowy.sdk.scrapper.login.InvalidSymbolException import io.github.wulkanowy.services.sync.SyncManager import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.ui.modules.login.LoginData import io.github.wulkanowy.ui.modules.login.LoginErrorHandler +import io.github.wulkanowy.ui.modules.login.support.LoginSupportInfo import io.github.wulkanowy.utils.AnalyticsHelper import io.github.wulkanowy.utils.AppInfo -import io.github.wulkanowy.utils.ifNullOrBlank +import io.github.wulkanowy.utils.isCurrent import kotlinx.coroutines.flow.onEach import timber.log.Timber import javax.inject.Inject class LoginStudentSelectPresenter @Inject constructor( studentRepository: StudentRepository, + private val schoolsRepository: SchoolsRepository, private val loginErrorHandler: LoginErrorHandler, private val syncManager: SyncManager, private val analytics: AnalyticsHelper, @@ -71,7 +73,14 @@ class LoginStudentSelectPresenter @Inject constructor( students = it.dataOrNull.orEmpty() when (it) { is Resource.Loading -> Timber.d("Login student select students load started") - is Resource.Success -> refreshItems() + is Resource.Success -> { + getStudentsWithCurrentlyActiveSemesters() + selectedStudents.clear() + selectedStudents.addAll(getStudentsWithCurrentlyActiveSemesters()) + view?.enableSignIn(selectedStudents.isNotEmpty()) + refreshItems() + } + is Resource.Error -> { errorHandler.dispatch(it.error) lastError = it.error @@ -81,6 +90,21 @@ class LoginStudentSelectPresenter @Inject constructor( }.launch() } + private fun getStudentsWithCurrentlyActiveSemesters(): List { + val students = registerUser.symbols.flatMap { symbol -> + symbol.schools.flatMap { unit -> + unit.students.map { + createStudentItem(it, symbol, unit, students) + } + } + } + return students.filter { student -> + student.student.semesters.any { semester -> + semester.isCurrent() + } + } + } + private fun createItems(): List = buildList { val notEmptySymbols = registerUser.symbols.filter { it.schools.isNotEmpty() } val emptySymbols = registerUser.symbols.filter { it.schools.isEmpty() } @@ -236,17 +260,20 @@ class LoginStudentSelectPresenter @Inject constructor( } private fun registerStudents(students: List) { - val studentsWithSemesters = students - .filterIsInstance().map { item -> - item.student.mapToStudentWithSemesters( - user = registerUser, - symbol = item.symbol, - scrapperDomainSuffix = loginData.domainSuffix, - unit = item.unit, - colors = appInfo.defaultColorsForAvatar, - ) - } - resourceFlow { studentRepository.saveStudents(studentsWithSemesters) } + val filteredStudents = students.filterIsInstance() + val studentsWithSemesters = filteredStudents.map { item -> + item.student.mapToStudentWithSemesters( + user = registerUser, + symbol = item.symbol, + scrapperDomainSuffix = loginData.domainSuffix, + unit = item.unit, + colors = appInfo.defaultColorsForAvatar, + ) + } + resourceFlow { + studentRepository.saveStudents(studentsWithSemesters) + schoolsRepository.logSchoolLogin(loginData, studentsWithSemesters) + } .logResourceStatus("registration") .onEach { when (it) { @@ -254,11 +281,13 @@ class LoginStudentSelectPresenter @Inject constructor( showProgress(true) showContent(false) } + is Resource.Success -> { syncManager.startOneTimeSyncWorker(quiet = true) view?.navigateToNext() logRegisterEvent(studentsWithSemesters) } + is Resource.Error -> { view?.apply { showProgress(false) @@ -281,28 +310,14 @@ class LoginStudentSelectPresenter @Inject constructor( } private fun onEmailClick() { - view?.openEmail(lastError?.message.ifNullOrBlank { - loginData.baseUrl + "/" + loginData.symbol + "\n" + registerUser.symbols.filterNot { - (it.error is AccountPermissionException || it.error is InvalidSymbolException) && it.symbol != loginData.symbol - }.joinToString(";\n") { symbol -> - buildString { - append(" -") - append(symbol.symbol) - append("(${symbol.error?.message?.let { it.take(46) + "..." } ?: symbol.schools.size})") - if (symbol.schools.isNotEmpty()) { - append(": ") - } - append(symbol.schools.joinToString(", ") { unit -> - buildString { - append(unit.schoolShortName) - append("(${unit.error?.message?.let { it.take(46) + "..." } ?: unit.students.size})") - } - }) - } - } + "\nPozostałe: " + registerUser.symbols.filter { - it.error is AccountPermissionException || it.error is InvalidSymbolException - }.joinToString(", ") { it.symbol } - }) + view?.openEmail( + LoginSupportInfo( + loginData = loginData, + registerUser = registerUser, + lastErrorMessage = lastError?.message, + enteredSymbol = loginData.symbol, + ) + ) } private fun logRegisterEvent( diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectView.kt index 39f312bf..b69700f1 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectView.kt @@ -2,6 +2,7 @@ package io.github.wulkanowy.ui.modules.login.studentselect import io.github.wulkanowy.ui.base.BaseView import io.github.wulkanowy.ui.modules.login.LoginData +import io.github.wulkanowy.ui.modules.login.support.LoginSupportInfo interface LoginStudentSelectView : BaseView { @@ -23,5 +24,5 @@ interface LoginStudentSelectView : BaseView { fun openDiscordInvite() - fun openEmail(lastError: String) + fun openEmail(supportInfo: LoginSupportInfo) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/support/LoginSupportDialog.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/support/LoginSupportDialog.kt new file mode 100644 index 00000000..d2b1d2ce --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/support/LoginSupportDialog.kt @@ -0,0 +1,133 @@ +package io.github.wulkanowy.ui.modules.login.support + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.core.os.bundleOf +import androidx.core.widget.doOnTextChanged +import dagger.hilt.android.AndroidEntryPoint +import io.github.wulkanowy.R +import io.github.wulkanowy.data.repositories.PreferencesRepository +import io.github.wulkanowy.databinding.DialogLoginSupportBinding +import io.github.wulkanowy.sdk.scrapper.login.AccountPermissionException +import io.github.wulkanowy.sdk.scrapper.login.InvalidSymbolException +import io.github.wulkanowy.ui.base.BaseDialogFragment +import io.github.wulkanowy.utils.AppInfo +import io.github.wulkanowy.utils.openEmailClient +import io.github.wulkanowy.utils.serializable +import javax.inject.Inject + +@AndroidEntryPoint +class LoginSupportDialog : BaseDialogFragment() { + + @Inject + lateinit var appInfo: AppInfo + + @Inject + lateinit var preferencesRepository: PreferencesRepository + + private lateinit var supportInfo: LoginSupportInfo + + companion object { + private const val ARGUMENT_KEY = "info" + + fun newInstance(info: LoginSupportInfo) = LoginSupportDialog().apply { + arguments = bundleOf(ARGUMENT_KEY to info) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setStyle(STYLE_NO_FRAME, R.style.WulkanowyTheme_NoActionBar) + supportInfo = requireArguments().serializable(ARGUMENT_KEY) + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + val binding = DialogLoginSupportBinding.inflate(inflater) + .apply { binding = this } + binding.dialogLoginSupportToolbar.setNavigationOnClickListener { dismiss() } + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + with(binding) { + dialogLoginSupportSchoolInput.doOnTextChanged { _, _, _, _ -> + with(dialogLoginSupportSchoolLayout) { + isErrorEnabled = false + error = null + } + } + dialogLoginSupportSubmit.setOnClickListener { + if (dialogLoginSupportSchoolInput.text.isNullOrBlank()) { + with(dialogLoginSupportSchoolLayout) { + isErrorEnabled = true + error = getString(R.string.error_field_required) + } + } else { + onSubmitClick() + dismiss() + } + } + } + } + + private fun onSubmitClick() { + with(binding) { + context?.openEmailClient( + chooserTitle = requireContext().getString(R.string.login_email_intent_title), + email = "wulkanowyinc@gmail.com", + subject = requireContext().getString(R.string.login_email_subject), + body = requireContext().getString( + R.string.login_email_text, + "${appInfo.systemManufacturer} ${appInfo.systemModel}", + appInfo.systemVersion.toString(), + "${appInfo.versionName}-${appInfo.buildFlavor}", + supportInfo.loginData.baseUrl + "/" + supportInfo.loginData.symbol, + preferencesRepository.installationId, + getLastErrorFromStudentSelectScreen(), + dialogLoginSupportSchoolInput.text.takeIf { !it.isNullOrBlank() } + ?: return@with, + dialogLoginSupportAdditionalInput.text, + ) + ) + } + } + + private fun getLastErrorFromStudentSelectScreen(): String { + if (!supportInfo.lastErrorMessage.isNullOrBlank()) { + return supportInfo.lastErrorMessage!! + } + if (supportInfo.registerUser?.symbols.isNullOrEmpty()) { + return "" + } + + return "\n" + supportInfo.registerUser?.symbols?.filterNot { + (it.error is AccountPermissionException || it.error is InvalidSymbolException) && + it.symbol != supportInfo.enteredSymbol + }?.joinToString(";\n") { symbol -> + buildString { + append(" -") + append(symbol.symbol) + append("(${symbol.error?.message?.let { it.take(46) + "..." } ?: symbol.schools.size})") + if (symbol.schools.isNotEmpty()) { + append(": ") + } + append(symbol.schools.joinToString(", ") { unit -> + buildString { + append(unit.schoolShortName) + append("(${unit.error?.message?.let { it.take(46) + "..." } ?: unit.students.size})") + } + }) + } + } + "\nPozostałe: " + supportInfo.registerUser?.symbols?.filter { + it.error is AccountPermissionException || it.error is InvalidSymbolException + }?.joinToString(", ") { it.symbol } + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/support/LoginSupportInfo.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/support/LoginSupportInfo.kt new file mode 100644 index 00000000..3f101dd6 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/support/LoginSupportInfo.kt @@ -0,0 +1,12 @@ +package io.github.wulkanowy.ui.modules.login.support + +import io.github.wulkanowy.data.pojos.RegisterUser +import io.github.wulkanowy.ui.modules.login.LoginData +import java.io.Serializable + +data class LoginSupportInfo( + val loginData: LoginData, + val registerUser: RegisterUser?, + val lastErrorMessage: String?, + val enteredSymbol: String?, +) : Serializable diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolFragment.kt index 692aaeb7..23ebffe9 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolFragment.kt @@ -18,7 +18,13 @@ import io.github.wulkanowy.databinding.FragmentLoginSymbolBinding import io.github.wulkanowy.ui.base.BaseFragment import io.github.wulkanowy.ui.modules.login.LoginActivity import io.github.wulkanowy.ui.modules.login.LoginData -import io.github.wulkanowy.utils.* +import io.github.wulkanowy.ui.modules.login.support.LoginSupportDialog +import io.github.wulkanowy.ui.modules.login.support.LoginSupportInfo +import io.github.wulkanowy.utils.AppInfo +import io.github.wulkanowy.utils.hideSoftInput +import io.github.wulkanowy.utils.openInternetBrowser +import io.github.wulkanowy.utils.serializable +import io.github.wulkanowy.utils.showSoftInput import javax.inject.Inject @AndroidEntryPoint @@ -100,6 +106,13 @@ class LoginSymbolFragment : } } + override fun setErrorSymbolDefinitelyInvalid() { + with(binding.loginSymbolNameLayout) { + requestFocus() + error = getString(R.string.login_invalid_symbol_definitely) + } + } + override fun setErrorSymbolRequire() { setErrorSymbol(getString(R.string.error_field_required)) } @@ -163,20 +176,7 @@ class LoginSymbolFragment : ) } - override fun openEmail(host: String, lastError: String) { - context?.openEmailClient( - chooserTitle = requireContext().getString(R.string.login_email_intent_title), - email = "wulkanowyinc@gmail.com", - subject = requireContext().getString(R.string.login_email_subject), - body = requireContext().getString( - R.string.login_email_text, - "${appInfo.systemManufacturer} ${appInfo.systemModel}", - appInfo.systemVersion.toString(), - "${appInfo.versionName}-${appInfo.buildFlavor}", - "$host/${binding.loginSymbolName.text}", - preferencesRepository.installationId, - lastError - ) - ) + override fun openSupportDialog(supportInfo: LoginSupportInfo) { + LoginSupportDialog.newInstance(supportInfo).show(childFragmentManager, "support_dialog") } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolPresenter.kt index 91fe1ac3..02bfde5d 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolPresenter.kt @@ -11,6 +11,7 @@ import io.github.wulkanowy.sdk.scrapper.login.InvalidSymbolException import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.ui.modules.login.LoginData import io.github.wulkanowy.ui.modules.login.LoginErrorHandler +import io.github.wulkanowy.ui.modules.login.support.LoginSupportInfo import io.github.wulkanowy.utils.AnalyticsHelper import io.github.wulkanowy.utils.ifNullOrBlank import kotlinx.coroutines.flow.onEach @@ -53,6 +54,10 @@ class LoginSymbolPresenter @Inject constructor( view?.setErrorSymbolRequire() return } + if (isFormDefinitelyInvalid()) { + view?.setErrorSymbolDefinitelyInvalid() + return + } loginData = loginData.copy( symbol = view?.symbolValue?.getNormalizedSymbol(), @@ -74,6 +79,7 @@ class LoginSymbolPresenter @Inject constructor( showProgress(true) showContent(false) } + is Resource.Success -> { when (user.data.symbols.size) { 0 -> { @@ -83,6 +89,7 @@ class LoginSymbolPresenter @Inject constructor( showContact(true) } } + else -> { val enteredSymbolDetails = user.data.symbols .firstOrNull() @@ -107,6 +114,7 @@ class LoginSymbolPresenter @Inject constructor( "error" to "No error" ) } + is Resource.Error -> { Timber.i("Login with symbol result: An exception occurred") analytics.logEvent( @@ -130,17 +138,25 @@ class LoginSymbolPresenter @Inject constructor( }.launch("login") } + private fun isFormDefinitelyInvalid(): Boolean { + val definitelyInvalidSymbols = listOf("vulcan", "uonet", "wulkanowy", "standardowa") + val normalizedSymbol = view?.symbolValue.orEmpty().getNormalizedSymbol() + + return normalizedSymbol in definitelyInvalidSymbols + } + fun onFaqClick() { view?.openFaqPage() } fun onEmailClick() { - view?.openEmail(loginData.baseUrl, lastError?.message.ifNullOrBlank { - registerUser?.symbols?.flatMap { symbol -> - symbol.schools.map { it.error?.message } + symbol.error?.message - }?.filterNotNull()?.distinct()?.joinToString(";") { - it.take(46) + "..." - } ?: "blank" - }) + view?.openSupportDialog( + LoginSupportInfo( + loginData = loginData, + registerUser = registerUser, + lastErrorMessage = lastError?.message, + enteredSymbol = view?.symbolValue, + ) + ) } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolView.kt index 6585c00f..ace12f78 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolView.kt @@ -3,6 +3,7 @@ package io.github.wulkanowy.ui.modules.login.symbol import io.github.wulkanowy.data.pojos.RegisterUser import io.github.wulkanowy.ui.base.BaseView import io.github.wulkanowy.ui.modules.login.LoginData +import io.github.wulkanowy.ui.modules.login.support.LoginSupportInfo interface LoginSymbolView : BaseView { @@ -18,6 +19,8 @@ interface LoginSymbolView : BaseView { fun setErrorSymbolInvalid() + fun setErrorSymbolDefinitelyInvalid() + fun setErrorSymbolRequire() fun setErrorSymbol(message: String) @@ -40,5 +43,5 @@ interface LoginSymbolView : BaseView { fun openFaqPage() - fun openEmail(host: String, lastError: String) + fun openSupportDialog(supportInfo: LoginSupportInfo) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainActivity.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainActivity.kt index 091080a5..178d6e94 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainActivity.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainActivity.kt @@ -119,7 +119,6 @@ class MainActivity : BaseActivity(), MainVie //https://developer.android.com/guide/playcore/in-app-updates#status_callback @Deprecated("Deprecated in Java") - @Suppress("DEPRECATION") override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) updateHelper.onActivityResult(requestCode, resultCode) diff --git a/app/src/main/java/io/github/wulkanowy/utils/AppInfo.kt b/app/src/main/java/io/github/wulkanowy/utils/AppInfo.kt index 962e5b20..e16db53c 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/AppInfo.kt +++ b/app/src/main/java/io/github/wulkanowy/utils/AppInfo.kt @@ -25,7 +25,8 @@ open class AppInfo @Inject constructor() { open val systemModel: String get() = Build.MODEL - open val messagesBaseUrl = BuildConfig.MESSAGES_BASE_URL + open val messagesBaseUrl: String = BuildConfig.MESSAGES_BASE_URL + open val schoolsBaseUrl: String = BuildConfig.SCHOOLS_BASE_URL @Suppress("DEPRECATION") open val systemLanguage: String diff --git a/app/src/main/java/io/github/wulkanowy/utils/LoggerUtils.kt b/app/src/main/java/io/github/wulkanowy/utils/LoggerUtils.kt index 1e9f49a6..00ed2c11 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/LoggerUtils.kt +++ b/app/src/main/java/io/github/wulkanowy/utils/LoggerUtils.kt @@ -7,7 +7,7 @@ import android.os.Bundle import android.view.View import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager -import fr.bipi.tressence.common.filters.Filter +import fr.bipi.treessence.common.filters.Filter import io.github.wulkanowy.sdk.exception.FeatureNotAvailableException import io.github.wulkanowy.sdk.scrapper.exception.FeatureDisabledException import timber.log.Timber diff --git a/app/src/main/play/release-notes/pl-PL/default.txt b/app/src/main/play/release-notes/pl-PL/default.txt index aa934ce9..89825621 100644 --- a/app/src/main/play/release-notes/pl-PL/default.txt +++ b/app/src/main/play/release-notes/pl-PL/default.txt @@ -1,8 +1,5 @@ -Wersja 2.1.0 +Wersja 2.2.0 -— dodaliśmy tryb incognito w wiadomościach -— dodaliśmy wyświetlanie pustych lekcji (okienek) w planie lekcji -— poprawiliśmy widżet planu lekcji (będzie teraz trochę bardziej kompaktowy) -— zmieniliśmy datę rozpoczęcia roku szkolnego na 3 dni przed 1 września (sorry) +Dokonaliśmy drobnych usprawnień w obszarze logowania, które powinny pomóc Wam i nam Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases diff --git a/app/src/main/res/drawable/ic_login.xml b/app/src/main/res/drawable/ic_login.xml new file mode 100644 index 00000000..57aef3dc --- /dev/null +++ b/app/src/main/res/drawable/ic_login.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/layout/dialog_login_support.xml b/app/src/main/res/layout/dialog_login_support.xml new file mode 100644 index 00000000..c04d7812 --- /dev/null +++ b/app/src/main/res/layout/dialog_login_support.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_dashboard.xml b/app/src/main/res/layout/fragment_dashboard.xml index 30f85446..348602d7 100644 --- a/app/src/main/res/layout/fragment_dashboard.xml +++ b/app/src/main/res/layout/fragment_dashboard.xml @@ -26,7 +26,8 @@ android:layout_height="match_parent" android:clipToPadding="false" android:paddingTop="6dp" - android:paddingBottom="6dp" /> + android:paddingBottom="6dp" + tools:listitem="@layout/item_dashboard_grades" /> - \ No newline at end of file + diff --git a/app/src/main/res/layout/fragment_login_student_select.xml b/app/src/main/res/layout/fragment_login_student_select.xml index c47b9ae3..04c80885 100644 --- a/app/src/main/res/layout/fragment_login_student_select.xml +++ b/app/src/main/res/layout/fragment_login_student_select.xml @@ -56,6 +56,8 @@ android:layout_marginBottom="32dp" android:enabled="false" android:text="@string/login_sign_in" + app:icon="@drawable/ic_login" + app:iconGravity="end" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@id/loginStudentSelectRecycler" /> diff --git a/app/src/main/res/layout/fragment_login_symbol.xml b/app/src/main/res/layout/fragment_login_symbol.xml index d928d65f..37f4c731 100644 --- a/app/src/main/res/layout/fragment_login_symbol.xml +++ b/app/src/main/res/layout/fragment_login_symbol.xml @@ -141,7 +141,9 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@+id/loginSymbolHelper"> + app:layout_constraintTop_toBottomOf="@+id/loginSymbolHelper" + app:placeholderText="@string/login_symbol_placeholder" + app:placeholderTextColor="?colorTertiary"> Průměr známek z celého roku - Don\'t show - Only between lessons - Before and between lessons + Nezobrazovat + Pouze mezi lekcemi + Před a mezi lekcemi Šťastné číslo diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index a63a0aa1..a365942a 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -44,6 +44,7 @@ Token PIN Symbol + E.g. \"lodz\" or \"powiatjaroslawski\" Přihlásit Toto heslo je příliš krátké Přihlašovací údaje jsou nesprávné @@ -54,7 +55,8 @@ Neplatný e-mail Místo e-mailu použijte přiřazené přihlašovací údaje Použijte přiřazené přihlašovací nebo e-mail v @%1$s - Neplatný symbol + Invalid symbol. If you cannot find it, please contact the school + Don\'t make this up! If you cannot find it, please contact the school Žák nebyl nalezen. Zkontrolujte správnost symbolu a vybrané varianty deníku UONET+ Vybraný žák je už přihlášen Symbol najdete na stránce deníku v  Uczeń→ Dostęp Mobilny → Wygeneruj kod dostępu.\n\nUjistěte se, že jste nastavili správnou variantu deníku v poli Variace deníku UONET+ na první přihlašovací obrazovce @@ -69,7 +71,7 @@ Discord Poslat e-mail Ujistěte se, že jste vybrali správnou variantu deníku UONET+! - Zapomněl jsem své heslo + Reset password Obnovte svůj účet Obnovit Žák je už přihlášen @@ -77,6 +79,12 @@ Jiná místa vyhledávání Nebyli nalezeni žádní aktivní žáci Zadejte jiný symbol + Get help + Full school name (required) + Np. ZSTiO Jarosław lub SP nr 99 w Łodzi + Additional information in Polish (optional) + Np. \"Ostatnio zmieniłem szkołę i…\" albo \"Jestem rodzicem i nie widzę drugiego dziecka…\" + Submit Povolit oznámení Povolit upozornění, abyste nezmeškali zprávu od učitele nebo o nové známce @@ -186,10 +194,10 @@ Změna učitele z %1$s na %2$s Změna předmětu z %1$s na %2$s - No lesson - No lessons - No lessons - No lessons + Žádné lekce + Žádné lekce + Žádné lekce + Žádné lekce Změna plánu lekcí @@ -706,7 +714,7 @@ Rozvíjení známek Označit aktuální lekci Zobrazit skupiny vedle předmětů - Show empty tiles where there\'s no lesson + Zobrazit prázdné dlaždice, kde není žádná lekce Zobrazit seznam grafů v známkách třídy Zobrazit předměty bez známek Známky barevné schéma diff --git a/app/src/main/res/values-da-rDK/strings.xml b/app/src/main/res/values-da-rDK/strings.xml index 2abf1a4a..c8846684 100644 --- a/app/src/main/res/values-da-rDK/strings.xml +++ b/app/src/main/res/values-da-rDK/strings.xml @@ -44,6 +44,7 @@ Token PIN Symbol + E.g. \"lodz\" or \"powiatjaroslawski\" Sign in Password too short Login details are incorrect @@ -54,7 +55,8 @@ Invalid email Use the assigned login instead of email Use the assigned login or email in @%1$s - Invalid symbol + Invalid symbol. If you cannot find it, please contact the school + Don\'t make this up! If you cannot find it, please contact the school Student not found. Validate the symbol and the chosen variation of the UONET+ register Selected student is already logged in The symbol can be found on the register page in Uczeń → Dostęp Mobilny → Wygeneruj kod dostępu.\n\nMake sure that you have set the appropriate register variant in the UONET+ register variant field on the first login screen @@ -69,7 +71,7 @@ Discord Send email Make sure you select the correct UONET+ register variation! - I forgot my password + Reset password Recover your account Recover Student is already signed in @@ -77,6 +79,12 @@ Other search locations No active students found Enter a different symbol + Get help + Full school name (required) + Np. ZSTiO Jarosław lub SP nr 99 w Łodzi + Additional information in Polish (optional) + Np. \"Ostatnio zmieniłem szkołę i…\" albo \"Jestem rodzicem i nie widzę drugiego dziecka…\" + Submit Enable notifications Enable notifications so you don\'t miss message from teacher or new grade diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index f08a504a..a909a6b8 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -44,6 +44,7 @@ Token PIN Symbol + E.g. \"lodz\" or \"powiatjaroslawski\" Anmelden Passwort ist zu kurz Anmeldedaten sind falsch @@ -54,7 +55,8 @@ Ungültige email Den zugewiesenen Login anstelle von email verwenden Benutze den zugewiesenen Login oder E-Mail in @%1$s - Ungültige symbol + Invalid symbol. If you cannot find it, please contact the school + Don\'t make this up! If you cannot find it, please contact the school Schüler nicht gefunden. Überprüfen Sie das Symbol und die gewählte Variation des UONET+ Registers Ausgewählter Student ist bereits angemeldet. Das Symbol kann auf der Registerseite in Student → Tost Möbeln → Registrieren Sie Ihr Mobilgerätgefunden werden.\n\nStellen Sie sicher, dass Sie die entsprechende Registervariante im Feld UONET+ Registervariante auf dem vorherigen Bildschirm festgelegt haben @@ -69,7 +71,7 @@ Discord email senden Stellen Sie sicher, dass Sie die richtige UONET+ Registervariation wählen! - Ich habe mein Passwort vergessen. + Reset password Ihr Konto wiederherstellen Wiederherstellen Student ist bereits angemeldet @@ -77,6 +79,12 @@ Andere Suchorte Keine aktiven Schüler gefunden Geben Sie ein anderes Symbol ein + Get help + Full school name (required) + Np. ZSTiO Jarosław lub SP nr 99 w Łodzi + Additional information in Polish (optional) + Np. \"Ostatnio zmieniłem szkołę i…\" albo \"Jestem rodzicem i nie widzę drugiego dziecka…\" + Submit Benachrichtigungen aktivieren Aktivieren Sie Benachrichtigungen, damit Sie keine Nachricht vom Lehrer oder eine neue Klasse verpassen diff --git a/app/src/main/res/values-es-rES/strings.xml b/app/src/main/res/values-es-rES/strings.xml index 2abf1a4a..c8846684 100644 --- a/app/src/main/res/values-es-rES/strings.xml +++ b/app/src/main/res/values-es-rES/strings.xml @@ -44,6 +44,7 @@ Token PIN Symbol + E.g. \"lodz\" or \"powiatjaroslawski\" Sign in Password too short Login details are incorrect @@ -54,7 +55,8 @@ Invalid email Use the assigned login instead of email Use the assigned login or email in @%1$s - Invalid symbol + Invalid symbol. If you cannot find it, please contact the school + Don\'t make this up! If you cannot find it, please contact the school Student not found. Validate the symbol and the chosen variation of the UONET+ register Selected student is already logged in The symbol can be found on the register page in Uczeń → Dostęp Mobilny → Wygeneruj kod dostępu.\n\nMake sure that you have set the appropriate register variant in the UONET+ register variant field on the first login screen @@ -69,7 +71,7 @@ Discord Send email Make sure you select the correct UONET+ register variation! - I forgot my password + Reset password Recover your account Recover Student is already signed in @@ -77,6 +79,12 @@ Other search locations No active students found Enter a different symbol + Get help + Full school name (required) + Np. ZSTiO Jarosław lub SP nr 99 w Łodzi + Additional information in Polish (optional) + Np. \"Ostatnio zmieniłem szkołę i…\" albo \"Jestem rodzicem i nie widzę drugiego dziecka…\" + Submit Enable notifications Enable notifications so you don\'t miss message from teacher or new grade diff --git a/app/src/main/res/values-it-rIT/strings.xml b/app/src/main/res/values-it-rIT/strings.xml index 2abf1a4a..c8846684 100644 --- a/app/src/main/res/values-it-rIT/strings.xml +++ b/app/src/main/res/values-it-rIT/strings.xml @@ -44,6 +44,7 @@ Token PIN Symbol + E.g. \"lodz\" or \"powiatjaroslawski\" Sign in Password too short Login details are incorrect @@ -54,7 +55,8 @@ Invalid email Use the assigned login instead of email Use the assigned login or email in @%1$s - Invalid symbol + Invalid symbol. If you cannot find it, please contact the school + Don\'t make this up! If you cannot find it, please contact the school Student not found. Validate the symbol and the chosen variation of the UONET+ register Selected student is already logged in The symbol can be found on the register page in Uczeń → Dostęp Mobilny → Wygeneruj kod dostępu.\n\nMake sure that you have set the appropriate register variant in the UONET+ register variant field on the first login screen @@ -69,7 +71,7 @@ Discord Send email Make sure you select the correct UONET+ register variation! - I forgot my password + Reset password Recover your account Recover Student is already signed in @@ -77,6 +79,12 @@ Other search locations No active students found Enter a different symbol + Get help + Full school name (required) + Np. ZSTiO Jarosław lub SP nr 99 w Łodzi + Additional information in Polish (optional) + Np. \"Ostatnio zmieniłem szkołę i…\" albo \"Jestem rodzicem i nie widzę drugiego dziecka…\" + Submit Enable notifications Enable notifications so you don\'t miss message from teacher or new grade diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index a2b5510e..4ed2facc 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -44,6 +44,7 @@ Token PIN Symbol + Np. \"lodz\" czy \"powiatjaroslawski\" Zaloguj To hasło jest za krótkie Dane logowania są niepoprawne @@ -54,7 +55,8 @@ Nieprawidłowy adres e-mail Użyj loginu zamiast adresu e-mail Użyj loginu lub adresu e-mail w @%1$s - Nieprawidłowy symbol + Nieprawidłowy symbol. Jeśli nie możesz go znaleźć, skontaktuj się ze szkołą + Nie zmyślaj! Jeśli nie możesz znaleźć symbolu, skontaktuj się ze szkołą Nie znaleziono ucznia. Sprawdź poprawność symbolu i wybranej odmiany dziennika UONET+ Wybrany uczeń jest już zalogowany Symbol można znaleźć na stronie dziennika w Uczeń→ Dostęp Mobilny → Wygeneruj kod dostępu.\n\nUpewnij się, że ustawiłeś odpowiednią odmianę dziennika w polu Odmiana dziennika UONET+ na pierwszym ekranie logowania @@ -69,7 +71,7 @@ Discord Wyślij wiadomość e-mail Upewnij się, że została wybrana odpowiednia odmiana dziennika UONET+! - Nie pamiętam hasła + Zresetuj hasło Przywróć swoje konto Przywróć Uczeń jest już zalogowany @@ -77,6 +79,12 @@ Inne lokalizacje wyszukiwania Nie znaleziono aktywnych uczniów Wprowadź inny symbol + Uzyskaj pomoc + Pełna nazwa szkoły (wymagana) + Np. ZSTiO Jarosław lub SP nr 99 w Łodzi + Dodatkowe informacje (po polsku) (nieobowiązkowo) + Np. \"Ostatnio zmieniłem szkołę i…\" albo \"Jestem rodzicem i nie widzę drugiego dziecka…\" + Wyślij Włącz powiadomienia Włącz powiadomienia, aby nie przegapić wiadomości od nauczyciela lub nowej oceny diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index d075dac6..841fa9f9 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -44,6 +44,7 @@ Token PIN Symbol + E.g. \"lodz\" or \"powiatjaroslawski\" Войти Пароль слишком короткий Данные для входа указаны неверно @@ -54,7 +55,8 @@ Неверный e-mail Используйте назначенный логин вместо e-mail Используйте назначенный логин или email в @%1$s - Неверный symbol + Invalid symbol. If you cannot find it, please contact the school + Don\'t make this up! If you cannot find it, please contact the school Ученик не найден. Проверьте symbol и выбранный тип дненика UONET+ Данный ученик уже авторизован Symbol можно найти на странице регистрации в  Uczeń → Dostęp Mobilny → Wygeneruj kod dostępu.\n\nУбедитесь, что вы выбрали соответствующий тип дневника в поле Тип дневника UONET+ на первом экране входа @@ -69,7 +71,7 @@ Discord Отправить письмо Убедитесь, что вы выбрали правильный тип дневника UONET+ - Забыли пароль? + Reset password Восстановите свой аккаунт Восстановить Ученик уже авторизован @@ -77,6 +79,12 @@ Другие места поиска Не найдено активных учеников Введите другой symbol + Get help + Full school name (required) + Np. ZSTiO Jarosław lub SP nr 99 w Łodzi + Additional information in Polish (optional) + Np. \"Ostatnio zmieniłem szkołę i…\" albo \"Jestem rodzicem i nie widzę drugiego dziecka…\" + Submit Включить уведомления Включить уведомления, чтобы вы не пропустили сообщение от учителя или новую оценку diff --git a/app/src/main/res/values-sk/preferences_values.xml b/app/src/main/res/values-sk/preferences_values.xml index fd393394..6cd22154 100644 --- a/app/src/main/res/values-sk/preferences_values.xml +++ b/app/src/main/res/values-sk/preferences_values.xml @@ -52,9 +52,9 @@ Priemer známok z celého roka - Don\'t show - Only between lessons - Before and between lessons + Nezobrazovať + Iba medzi lekciami + Pred a medzi lekciami Šťastné číslo diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml index d1990e35..018806b6 100644 --- a/app/src/main/res/values-sk/strings.xml +++ b/app/src/main/res/values-sk/strings.xml @@ -44,6 +44,7 @@ Token PIN Symbol + E.g. \"lodz\" or \"powiatjaroslawski\" Prihlásiť Toto heslo je príliš krátke Prihlasovacie údaje sú nesprávne @@ -54,7 +55,8 @@ Neplatný e-mail Namiesto e-mailu použite priradené prihlasovacie údaje Použite priradené prihlasovacie alebo e-mail v @%1$s - Neplatný symbol + Invalid symbol. If you cannot find it, please contact the school + Don\'t make this up! If you cannot find it, please contact the school Žiak nebol nájdený. Skontrolujte správnosť symbolu a vybrané varianty denníka UONET+ Vybraný žiak už je prihlásený Symbol nájdete na stránke denníka v  Uczeń→ Dostęp Mobilny → Wygeneruj kod dostępu.\n\nUistite sa, že ste nastavili správny variant denníka v poli Variácia denníka UONET+ na prvej prihlasovacej obrazovke @@ -69,7 +71,7 @@ Discord Poslať e-mail Uistite sa, že ste vybrali správny variant denníka UONET+! - Zabudol som heslo + Reset password Obnovte svoj účet Obnoviť Žiak je už prihlásený @@ -77,6 +79,12 @@ Iné miesta vyhľadávania Neboli nájdení žiadni aktívni žiaci Zadajte iný symbol + Get help + Full school name (required) + Np. ZSTiO Jarosław lub SP nr 99 w Łodzi + Additional information in Polish (optional) + Np. \"Ostatnio zmieniłem szkołę i…\" albo \"Jestem rodzicem i nie widzę drugiego dziecka…\" + Submit Povoliť oznámenia Povoliť oznámenia, aby ste nezmeškali správu od učiteľa alebo o novej známke @@ -186,10 +194,10 @@ Zmena učiteľa z %1$s na %2$s Zmena predmetu z %1$s na %2$s - No lesson - No lessons - No lessons - No lessons + Žiadne lekcie + Žiadne lekcie + Žiadne lekcie + Žiadne lekcie Zmena plánu lekcií @@ -706,7 +714,7 @@ Rozvijanie známok Označiť aktuálne lekciu Zobraziť skupiny vedľa predmetov - Show empty tiles where there\'s no lesson + Zobraziť prázdne dlaždice, kde nie je žiadne lekcie Zobraziť zoznam grafov v známkach triedy Zobraziť predmety bez známok Známky farebnú schému diff --git a/app/src/main/res/values-uk/preferences_values.xml b/app/src/main/res/values-uk/preferences_values.xml index 55cf905b..c02efb54 100644 --- a/app/src/main/res/values-uk/preferences_values.xml +++ b/app/src/main/res/values-uk/preferences_values.xml @@ -52,9 +52,9 @@ Середня оцінка з цілого року - Don\'t show - Only between lessons - Before and between lessons + Не показувати + Тільки між уроками + Перед і між уроками Щасливий номер diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 876562d3..a05634cf 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -44,6 +44,7 @@ Token PIN Symbol + E.g. \"lodz\" or \"powiatjaroslawski\" Увійти Занадто короткий пароль Вказані невірні дані @@ -54,8 +55,9 @@ Недійсна адреса e-mail Використовуйте призначений логін замість адреси e-mail Використовуйте призначений логін або адресу e-mail в @%1$s - Неправильний symbol - Студента не знайдено. Перевірте symbol та обранний тип щоденника UONET+ + Invalid symbol. If you cannot find it, please contact the school + Don\'t make this up! If you cannot find it, please contact the school + Студента не знайдено. Перевірте symbol та обраний тип щоденника UONET+ Цього учня вже авторизовано Symbol можно знайти на сторінці щоденника у Uczeń → Dostęp Mobilny → Wygeneruj kod dostępu.\n\nПереконайтеся, що ви вказали відповідний щоденник у полі Тип щоденника UONET+ на першому екрані логування Виберіть учнів для авторизації в додатку @@ -69,7 +71,7 @@ Discord Надіслати електронний лист Переконайтеся, що ви вибрали правильний тип щоденника UONET+! - Забули пароль? + Reset password Відновіть свій обліковий запис Відновити Учня вже авторизовано @@ -77,6 +79,12 @@ Інші розташування пошуку Активних учнів не знайдено Введіть інший symbol + Get help + Full school name (required) + Np. ZSTiO Jarosław lub SP nr 99 w Łodzi + Additional information in Polish (optional) + Np. \"Ostatnio zmieniłem szkołę i…\" albo \"Jestem rodzicem i nie widzę drugiego dziecka…\" + Submit Увімкнути сповіщення Увімкнути сповіщення, щоб не пропустити лист від вчителя або нову оцінку @@ -186,10 +194,10 @@ Зміна вчителя з %1$s на %2$s Зміна теми з %1$s на %2$s - No lesson - No lessons - No lessons - No lessons + Немає уроку + Немає уроків + Немає уроків + Немає уроків Зміна у розкладі @@ -706,7 +714,7 @@ Розгортання оцінок Позначити поточний урок Показувати групи поруч з темами - Show empty tiles where there\'s no lesson + Показувати порожні плитки там, де немає уроків Показувати діаграми в оцінках класу Показати предмети без оцінок Схема кольорів оцінок diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ce277bdc..08e3ebe6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -49,6 +49,7 @@ Token PIN Symbol + E.g. \"lodz\" or \"powiatjaroslawski\" Sign in Password too short Login details are incorrect @@ -59,7 +60,8 @@ Invalid email Use the assigned login instead of email Use the assigned login or email in @%1$s - Invalid symbol + Invalid symbol. If you cannot find it, please contact the school + Don\'t make this up! If you cannot find it, please contact the school Student not found. Validate the symbol and the chosen variation of the UONET+ register Selected student is already logged in The symbol can be found on the register page in Uczeń → Dostęp Mobilny → Wygeneruj kod dostępu.\n\nMake sure that you have set the appropriate register variant in the UONET+ register variant field on the first login screen @@ -74,9 +76,9 @@ Discord Send email Zgłoszenie: Problemy z logowaniem - Informacje o aplikacji:\n\nUrządzenie: %1$s\nWersja SDK: %2$s\nWersja aplikacji: %3$s\nDodatkowe informacje: %4$s\nIdentyfikator instalacji: %5$s\nOstatni błąd: %6$s\n\nNazwa szkoły i miejscowość: + Informacje o aplikacji:\n\nUrządzenie: %1$s\nWersja SDK: %2$s\nWersja aplikacji: %3$s\nDodatkowe informacje: %4$s\nIdentyfikator instalacji: %5$s\nOstatni błąd: %6$s\n\nNazwa szkoły i miejscowość: %7$s\nDodatkowe informacje: %8$s Make sure you select the correct UONET+ register variation! - I forgot my password + Reset password Recover your account Recover Student is already signed in @@ -84,6 +86,12 @@ Other search locations No active students found Enter a different symbol + Get help + Full school name (required) + Np. ZSTiO Jarosław lub SP nr 99 w Łodzi + Additional information in Polish (optional) + Np. \"Ostatnio zmieniłem szkołę i…\" albo \"Jestem rodzicem i nie widzę drugiego dziecka…\" + Submit diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 603e22ab..a0023dda 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -82,7 +82,6 @@ diff --git a/app/src/play/java/io/github/wulkanowy/utils/CrashlyticsUtils.kt b/app/src/play/java/io/github/wulkanowy/utils/CrashlyticsUtils.kt index f980bc4b..2e5fad62 100644 --- a/app/src/play/java/io/github/wulkanowy/utils/CrashlyticsUtils.kt +++ b/app/src/play/java/io/github/wulkanowy/utils/CrashlyticsUtils.kt @@ -2,8 +2,8 @@ package io.github.wulkanowy.utils import android.util.Log import com.google.firebase.crashlytics.FirebaseCrashlytics -import fr.bipi.tressence.base.FormatterPriorityTree -import fr.bipi.tressence.common.StackTraceRecorder +import fr.bipi.treessence.base.FormatterPriorityTree +import fr.bipi.treessence.common.StackTraceRecorder class CrashLogTree : FormatterPriorityTree(Log.VERBOSE) { diff --git a/app/src/play/java/io/github/wulkanowy/utils/IntegrityHelper.kt b/app/src/play/java/io/github/wulkanowy/utils/IntegrityHelper.kt new file mode 100644 index 00000000..41df0487 --- /dev/null +++ b/app/src/play/java/io/github/wulkanowy/utils/IntegrityHelper.kt @@ -0,0 +1,27 @@ +package io.github.wulkanowy.utils + +import android.content.Context +import com.google.android.play.core.integrity.IntegrityManagerFactory +import com.google.android.play.core.integrity.IntegrityTokenRequest +import dagger.hilt.android.qualifiers.ApplicationContext +import kotlinx.coroutines.tasks.await +import java.util.UUID +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class IntegrityHelper @Inject constructor( + @ApplicationContext private val context: Context, +) { + + suspend fun getIntegrityToken(nonce: String): String? { + val integrityManager = IntegrityManagerFactory.create(context) + + val integrityTokenResponse = integrityManager.requestIntegrityToken( + IntegrityTokenRequest.builder() + .setNonce(nonce) + .build() + ) + return integrityTokenResponse.await().token() + } +} diff --git a/app/src/test/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenterTest.kt b/app/src/test/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenterTest.kt index 06aabec7..fad6436d 100644 --- a/app/src/test/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenterTest.kt +++ b/app/src/test/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenterTest.kt @@ -5,6 +5,7 @@ import io.github.wulkanowy.data.pojos.RegisterStudent import io.github.wulkanowy.data.pojos.RegisterSymbol import io.github.wulkanowy.data.pojos.RegisterUnit import io.github.wulkanowy.data.pojos.RegisterUser +import io.github.wulkanowy.data.repositories.SchoolsRepository import io.github.wulkanowy.data.repositories.StudentRepository import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.scrapper.Scrapper @@ -40,6 +41,9 @@ class LoginStudentSelectPresenterTest { @MockK lateinit var studentRepository: StudentRepository + @MockK + lateinit var schoolsRepository: SchoolsRepository + @MockK(relaxed = true) lateinit var analytics: AnalyticsHelper @@ -110,6 +114,7 @@ class LoginStudentSelectPresenterTest { clearMocks(studentRepository, loginStudentSelectView) coEvery { studentRepository.getSavedStudents(false) } returns emptyList() + coEvery { schoolsRepository.logSchoolLogin(any(), any()) } just Runs every { loginStudentSelectView.initView() } just Runs every { loginStudentSelectView.symbols } returns emptyMap() @@ -120,6 +125,7 @@ class LoginStudentSelectPresenterTest { presenter = LoginStudentSelectPresenter( studentRepository = studentRepository, + schoolsRepository = schoolsRepository, loginErrorHandler = errorHandler, syncManager = syncManager, analytics = analytics, diff --git a/build.gradle b/build.gradle index 2b52c068..651e9ca1 100644 --- a/build.gradle +++ b/build.gradle @@ -1,8 +1,8 @@ buildscript { ext { - kotlin_version = '1.9.0' - about_libraries = '10.8.3' - hilt_version = "2.47" + kotlin_version = '1.9.10' + about_libraries = '10.9.0' + hilt_version = "2.48" } repositories { mavenCentral() @@ -13,15 +13,15 @@ buildscript { dependencies { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version" - classpath "com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin:$kotlin_version-1.0.11" - classpath 'com.android.tools.build:gradle:8.1.0' + classpath "com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin:$kotlin_version-1.0.13" + classpath 'com.android.tools.build:gradle:8.1.1' classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version" - classpath 'com.google.gms:google-services:4.3.15' - classpath 'com.huawei.agconnect:agcp:1.9.1.300' - classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.8' + classpath 'com.google.gms:google-services:4.4.0' + classpath 'com.huawei.agconnect:agcp:1.9.1.301' + classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.9' classpath "com.github.triplet.gradle:play-publisher:3.8.4" classpath "ru.cian:huawei-publish-gradle-plugin:1.4.0" - classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:4.3.0.3225" + classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:4.3.1.3277" classpath "gradle.plugin.com.star-zero.gradle:githook:1.2.0" classpath "com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin:$about_libraries" }