Compare commits
36 Commits
Author | SHA1 | Date | |
---|---|---|---|
6e2bcfbe02 | |||
1c0df6c145 | |||
2b61e883c5 | |||
31a7ae6d15 | |||
4b3b4a21fa | |||
440cc7ae89 | |||
9a6b17c9d9 | |||
729e0f547b | |||
faa8d34e79 | |||
b6f5ac91ad | |||
51dd343299 | |||
d1d0caa1e3 | |||
c40779f48f | |||
5ee7fee09d | |||
594d2dbec5 | |||
26596e8254 | |||
ff56348586 | |||
6e472d6c5c | |||
6f4826249c | |||
2f3e1b6aae | |||
a69361708e | |||
567d868f76 | |||
12030efee2 | |||
3cbe98d7b8 | |||
503a97bc4c | |||
04c382643d | |||
fc140ad9c1 | |||
ae6a35121b | |||
78a2cc89e9 | |||
dbfe5c8918 | |||
c697ca7ad1 | |||
1b00f4e518 | |||
fb77bf882f | |||
466ebbef3a | |||
458a4c8164 | |||
0363c0854f |
1
.gitignore
vendored
1
.gitignore
vendored
@ -127,3 +127,4 @@ google-services.json
|
|||||||
!app/google-services.json
|
!app/google-services.json
|
||||||
|
|
||||||
|
|
||||||
|
.idea/appInsightsSettings.xml
|
||||||
|
@ -27,8 +27,8 @@ android {
|
|||||||
testApplicationId "io.github.tests.wulkanowy"
|
testApplicationId "io.github.tests.wulkanowy"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 34
|
targetSdkVersion 34
|
||||||
versionCode 161
|
versionCode 169
|
||||||
versionName "2.6.1"
|
versionName "2.6.9"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
|
||||||
resValue "string", "app_name", "Wulkanowy"
|
resValue "string", "app_name", "Wulkanowy"
|
||||||
@ -160,8 +160,8 @@ play {
|
|||||||
defaultToAppBundles = false
|
defaultToAppBundles = false
|
||||||
track = 'production'
|
track = 'production'
|
||||||
releaseStatus = ReleaseStatus.IN_PROGRESS
|
releaseStatus = ReleaseStatus.IN_PROGRESS
|
||||||
userFraction = 0.25d
|
userFraction = 0.99d
|
||||||
updatePriority = 1
|
updatePriority = 2
|
||||||
enabled.set(false)
|
enabled.set(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,23 +191,25 @@ ext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'io.github.wulkanowy:sdk:2.6.0'
|
implementation 'io.github.wulkanowy:sdk:2.6.8'
|
||||||
|
|
||||||
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.3"
|
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 "org.jetbrains.kotlinx:kotlinx-coroutines-guava:$coroutines"
|
||||||
|
|
||||||
implementation 'androidx.core:core-ktx:1.13.0'
|
implementation 'androidx.core:core-ktx:1.13.1'
|
||||||
implementation 'androidx.core:core-splashscreen:1.0.1'
|
implementation 'androidx.core:core-splashscreen:1.0.1'
|
||||||
implementation "androidx.activity:activity-ktx:1.9.0"
|
implementation "androidx.activity:activity-ktx:1.9.0"
|
||||||
implementation "androidx.appcompat:appcompat:1.6.1"
|
implementation "androidx.appcompat:appcompat:1.6.1"
|
||||||
implementation "androidx.fragment:fragment-ktx:1.6.2"
|
implementation "androidx.fragment:fragment-ktx:1.7.0"
|
||||||
implementation "androidx.annotation:annotation:1.7.1"
|
implementation "androidx.annotation:annotation:1.7.1"
|
||||||
|
implementation "androidx.javascriptengine:javascriptengine:1.0.0-beta01"
|
||||||
|
|
||||||
implementation "androidx.preference:preference-ktx:1.2.1"
|
implementation "androidx.preference:preference-ktx:1.2.1"
|
||||||
implementation "androidx.recyclerview:recyclerview:1.3.2"
|
implementation "androidx.recyclerview:recyclerview:1.3.2"
|
||||||
implementation "androidx.viewpager2:viewpager2:1.1.0-beta02"
|
implementation "androidx.viewpager2:viewpager2:1.1.0-rc01"
|
||||||
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
|
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
|
||||||
implementation "androidx.constraintlayout:constraintlayout:2.1.4"
|
implementation "androidx.constraintlayout:constraintlayout:2.1.4"
|
||||||
implementation "androidx.coordinatorlayout:coordinatorlayout:1.2.0"
|
implementation "androidx.coordinatorlayout:coordinatorlayout:1.2.0"
|
||||||
@ -248,7 +250,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.12.0'
|
implementation 'org.apache.commons:commons-text:1.12.0'
|
||||||
|
|
||||||
playImplementation platform('com.google.firebase:firebase-bom:32.8.1')
|
playImplementation platform('com.google.firebase:firebase-bom:33.0.0')
|
||||||
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:'
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:installLocation="internalOnly">
|
android:installLocation="internalOnly">
|
||||||
|
|
||||||
|
<uses-sdk tools:overrideLibrary="androidx.javascriptengine" />
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
@ -42,9 +44,9 @@
|
|||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:networkSecurityConfig="@xml/network_security_config"
|
android:networkSecurityConfig="@xml/network_security_config"
|
||||||
|
android:resizeableActivity="true"
|
||||||
android:supportsRtl="false"
|
android:supportsRtl="false"
|
||||||
android:theme="@style/WulkanowyTheme"
|
android:theme="@style/WulkanowyTheme"
|
||||||
android:resizeableActivity="true"
|
|
||||||
tools:ignore="DataExtractionRules,UnusedAttribute">
|
tools:ignore="DataExtractionRules,UnusedAttribute">
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.modules.splash.SplashActivity"
|
android:name=".ui.modules.splash.SplashActivity"
|
||||||
|
@ -13,8 +13,8 @@ import dagger.Provides
|
|||||||
import dagger.hilt.InstallIn
|
import dagger.hilt.InstallIn
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import dagger.hilt.components.SingletonComponent
|
import dagger.hilt.components.SingletonComponent
|
||||||
import io.github.wulkanowy.data.api.AdminMessageService
|
import io.github.wulkanowy.data.api.services.SchoolsService
|
||||||
import io.github.wulkanowy.data.api.SchoolsService
|
import io.github.wulkanowy.data.api.services.WulkanowyService
|
||||||
import io.github.wulkanowy.data.db.AppDatabase
|
import io.github.wulkanowy.data.db.AppDatabase
|
||||||
import io.github.wulkanowy.data.db.SharedPrefProvider
|
import io.github.wulkanowy.data.db.SharedPrefProvider
|
||||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
@ -71,7 +71,7 @@ internal class DataModule {
|
|||||||
okHttpClient: OkHttpClient,
|
okHttpClient: OkHttpClient,
|
||||||
json: Json,
|
json: Json,
|
||||||
appInfo: AppInfo
|
appInfo: AppInfo
|
||||||
): AdminMessageService = Retrofit.Builder()
|
): WulkanowyService = Retrofit.Builder()
|
||||||
.baseUrl(appInfo.messagesBaseUrl)
|
.baseUrl(appInfo.messagesBaseUrl)
|
||||||
.client(okHttpClient)
|
.client(okHttpClient)
|
||||||
.addConverterFactory(json.asConverterFactory("application/json".toMediaType()))
|
.addConverterFactory(json.asConverterFactory("application/json".toMediaType()))
|
||||||
|
@ -1,13 +1,21 @@
|
|||||||
package io.github.wulkanowy.data
|
package io.github.wulkanowy.data
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.javascriptengine.JavaScriptSandbox
|
||||||
import com.chuckerteam.chucker.api.ChuckerInterceptor
|
import com.chuckerteam.chucker.api.ChuckerInterceptor
|
||||||
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import io.github.wulkanowy.data.db.dao.StudentDao
|
import io.github.wulkanowy.data.db.dao.StudentDao
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.github.wulkanowy.data.db.entities.StudentIsEduOne
|
import io.github.wulkanowy.data.db.entities.StudentIsEduOne
|
||||||
|
import io.github.wulkanowy.data.repositories.WulkanowyRepository
|
||||||
import io.github.wulkanowy.sdk.Sdk
|
import io.github.wulkanowy.sdk.Sdk
|
||||||
|
import io.github.wulkanowy.sdk.scrapper.EvaluateHandler
|
||||||
import io.github.wulkanowy.utils.RemoteConfigHelper
|
import io.github.wulkanowy.utils.RemoteConfigHelper
|
||||||
import io.github.wulkanowy.utils.WebkitCookieManagerProxy
|
import io.github.wulkanowy.utils.WebkitCookieManagerProxy
|
||||||
|
import kotlinx.coroutines.guava.await
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
@ -16,18 +24,24 @@ import javax.inject.Singleton
|
|||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class WulkanowySdkFactory @Inject constructor(
|
class WulkanowySdkFactory @Inject constructor(
|
||||||
|
@ApplicationContext private val context: Context,
|
||||||
private val chuckerInterceptor: ChuckerInterceptor,
|
private val chuckerInterceptor: ChuckerInterceptor,
|
||||||
private val remoteConfig: RemoteConfigHelper,
|
private val remoteConfig: RemoteConfigHelper,
|
||||||
private val webkitCookieManagerProxy: WebkitCookieManagerProxy,
|
private val webkitCookieManagerProxy: WebkitCookieManagerProxy,
|
||||||
private val studentDb: StudentDao,
|
private val studentDb: StudentDao,
|
||||||
|
private val wulkanowyRepository: WulkanowyRepository,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val eduOneMutex = Mutex()
|
private val eduOneMutex = Mutex()
|
||||||
private val migrationFailedStudentIds = mutableSetOf<Long>()
|
private val migrationFailedStudentIds = mutableSetOf<Long>()
|
||||||
|
private val sandbox: ListenableFuture<JavaScriptSandbox>? =
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && JavaScriptSandbox.isSupported())
|
||||||
|
JavaScriptSandbox.createConnectedInstanceAsync(context)
|
||||||
|
else null
|
||||||
|
|
||||||
private val sdk = Sdk().apply {
|
private val sdk = Sdk().apply {
|
||||||
androidVersion = android.os.Build.VERSION.RELEASE
|
androidVersion = Build.VERSION.RELEASE
|
||||||
buildTag = android.os.Build.MODEL
|
buildTag = Build.MODEL
|
||||||
userAgentTemplate = remoteConfig.userAgentTemplate
|
userAgentTemplate = remoteConfig.userAgentTemplate
|
||||||
setSimpleHttpLogger { Timber.d(it) }
|
setSimpleHttpLogger { Timber.d(it) }
|
||||||
setAdditionalCookieManager(webkitCookieManagerProxy)
|
setAdditionalCookieManager(webkitCookieManagerProxy)
|
||||||
@ -36,14 +50,46 @@ class WulkanowySdkFactory @Inject constructor(
|
|||||||
addInterceptor(chuckerInterceptor, network = true)
|
addInterceptor(chuckerInterceptor, network = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun create() = sdk
|
fun createBase() = sdk
|
||||||
|
|
||||||
|
suspend fun create(): Sdk {
|
||||||
|
val mapping = wulkanowyRepository.getMapping()
|
||||||
|
|
||||||
|
return createBase().apply {
|
||||||
|
if (mapping != null) {
|
||||||
|
endpointsMapping = mapping.endpoints
|
||||||
|
vTokenMapping = mapping.vTokens
|
||||||
|
vTokenSchemeMapping = mapping.vTokenScheme
|
||||||
|
vParamsEvaluation = createIsolate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun createIsolate(): suspend () -> EvaluateHandler {
|
||||||
|
return {
|
||||||
|
val isolate = sandbox?.await()?.createIsolate()
|
||||||
|
object : EvaluateHandler {
|
||||||
|
override suspend fun evaluate(code: String): String? {
|
||||||
|
return isolate?.evaluateJavaScriptAsync(code)?.await()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun close() {
|
||||||
|
isolate?.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun create(student: Student, semester: Semester? = null): Sdk {
|
suspend fun create(student: Student, semester: Semester? = null): Sdk {
|
||||||
val overrideIsEduOne = checkEduOneAndMigrateIfNecessary(student)
|
val overrideIsEduOne = checkEduOneAndMigrateIfNecessary(student)
|
||||||
return buildSdk(student, semester, overrideIsEduOne)
|
return buildSdk(student, semester, overrideIsEduOne)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildSdk(student: Student, semester: Semester?, isStudentEduOne: Boolean): Sdk {
|
private suspend fun buildSdk(
|
||||||
|
student: Student,
|
||||||
|
semester: Semester?,
|
||||||
|
isStudentEduOne: Boolean
|
||||||
|
): Sdk {
|
||||||
return create().apply {
|
return create().apply {
|
||||||
email = student.email
|
email = student.email
|
||||||
password = student.password
|
password = student.password
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
package io.github.wulkanowy.data.api.models
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class Mapping(
|
||||||
|
|
||||||
|
@SerialName("endpoints")
|
||||||
|
val endpoints: Map<String, Map<String, Map<String, String>>>,
|
||||||
|
|
||||||
|
@SerialName("vTokens")
|
||||||
|
val vTokens: Map<String, Map<String, Map<String, String>>>,
|
||||||
|
|
||||||
|
@SerialName("vTokenScheme")
|
||||||
|
val vTokenScheme: Map<String, Map<String, String>> = emptyMap(),
|
||||||
|
)
|
@ -1,4 +1,4 @@
|
|||||||
package io.github.wulkanowy.data.api
|
package io.github.wulkanowy.data.api.services
|
||||||
|
|
||||||
import io.github.wulkanowy.data.pojos.IntegrityRequest
|
import io.github.wulkanowy.data.pojos.IntegrityRequest
|
||||||
import io.github.wulkanowy.data.pojos.LoginEvent
|
import io.github.wulkanowy.data.pojos.LoginEvent
|
@ -1,12 +1,16 @@
|
|||||||
package io.github.wulkanowy.data.api
|
package io.github.wulkanowy.data.api.services
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.api.models.Mapping
|
||||||
import io.github.wulkanowy.data.db.entities.AdminMessage
|
import io.github.wulkanowy.data.db.entities.AdminMessage
|
||||||
import retrofit2.http.GET
|
import retrofit2.http.GET
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
interface AdminMessageService {
|
interface WulkanowyService {
|
||||||
|
|
||||||
@GET("/v1.json")
|
@GET("/v1.json")
|
||||||
suspend fun getAdminMessages(): List<AdminMessage>
|
suspend fun getAdminMessages(): List<AdminMessage>
|
||||||
}
|
|
||||||
|
@GET("/mapping2.json")
|
||||||
|
suspend fun getMapping(): Mapping
|
||||||
|
}
|
@ -9,6 +9,7 @@ import com.fredporciuncula.flow.preferences.Preference
|
|||||||
import com.fredporciuncula.flow.preferences.Serializer
|
import com.fredporciuncula.flow.preferences.Serializer
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.data.api.models.Mapping
|
||||||
import io.github.wulkanowy.data.enums.AppTheme
|
import io.github.wulkanowy.data.enums.AppTheme
|
||||||
import io.github.wulkanowy.data.enums.AttendanceCalculatorSortingMode
|
import io.github.wulkanowy.data.enums.AttendanceCalculatorSortingMode
|
||||||
import io.github.wulkanowy.data.enums.GradeColorTheme
|
import io.github.wulkanowy.data.enums.GradeColorTheme
|
||||||
@ -375,6 +376,15 @@ class PreferencesRepository @Inject constructor(
|
|||||||
get() = sharedPref.getString(PREF_KEY_INSTALLATION_ID, null).orEmpty()
|
get() = sharedPref.getString(PREF_KEY_INSTALLATION_ID, null).orEmpty()
|
||||||
private set(value) = sharedPref.edit { putString(PREF_KEY_INSTALLATION_ID, value) }
|
private set(value) = sharedPref.edit { putString(PREF_KEY_INSTALLATION_ID, value) }
|
||||||
|
|
||||||
|
var mapping: Mapping?
|
||||||
|
get() {
|
||||||
|
val value = sharedPref.getString("mapping", null)
|
||||||
|
return value?.let { json.decodeFromString(it) }
|
||||||
|
}
|
||||||
|
set(value) = sharedPref.edit(commit = true) {
|
||||||
|
putString("mapping", value?.let { json.encodeToString(it) })
|
||||||
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if (installationId.isEmpty()) {
|
if (installationId.isEmpty()) {
|
||||||
installationId = UUID.randomUUID().toString()
|
installationId = UUID.randomUUID().toString()
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package io.github.wulkanowy.data.repositories
|
package io.github.wulkanowy.data.repositories
|
||||||
|
|
||||||
import io.github.wulkanowy.data.WulkanowySdkFactory
|
import io.github.wulkanowy.data.WulkanowySdkFactory
|
||||||
import io.github.wulkanowy.data.api.SchoolsService
|
import io.github.wulkanowy.data.api.services.SchoolsService
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||||
|
@ -1,20 +1,23 @@
|
|||||||
package io.github.wulkanowy.data.repositories
|
package io.github.wulkanowy.data.repositories
|
||||||
|
|
||||||
import io.github.wulkanowy.data.Resource
|
import io.github.wulkanowy.data.Resource
|
||||||
import io.github.wulkanowy.data.api.AdminMessageService
|
import io.github.wulkanowy.data.api.models.Mapping
|
||||||
|
import io.github.wulkanowy.data.api.services.WulkanowyService
|
||||||
import io.github.wulkanowy.data.db.dao.AdminMessageDao
|
import io.github.wulkanowy.data.db.dao.AdminMessageDao
|
||||||
import io.github.wulkanowy.data.db.entities.AdminMessage
|
import io.github.wulkanowy.data.db.entities.AdminMessage
|
||||||
import io.github.wulkanowy.data.networkBoundResource
|
import io.github.wulkanowy.data.networkBoundResource
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.filterNot
|
import kotlinx.coroutines.flow.filterNot
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class AdminMessageRepository @Inject constructor(
|
class WulkanowyRepository @Inject constructor(
|
||||||
private val adminMessageService: AdminMessageService,
|
private val wulkanowyService: WulkanowyService,
|
||||||
private val adminMessageDao: AdminMessageDao,
|
private val adminMessageDao: AdminMessageDao,
|
||||||
|
private val preferencesRepository: PreferencesRepository,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val saveFetchResultMutex = Mutex()
|
private val saveFetchResultMutex = Mutex()
|
||||||
@ -24,11 +27,28 @@ class AdminMessageRepository @Inject constructor(
|
|||||||
mutex = saveFetchResultMutex,
|
mutex = saveFetchResultMutex,
|
||||||
isResultEmpty = { false },
|
isResultEmpty = { false },
|
||||||
query = { adminMessageDao.loadAll() },
|
query = { adminMessageDao.loadAll() },
|
||||||
fetch = { adminMessageService.getAdminMessages() },
|
fetch = { wulkanowyService.getAdminMessages() },
|
||||||
shouldFetch = { true },
|
shouldFetch = { true },
|
||||||
saveFetchResult = { oldItems, newItems ->
|
saveFetchResult = { oldItems, newItems ->
|
||||||
adminMessageDao.removeOldAndSaveNew(oldItems, newItems)
|
adminMessageDao.removeOldAndSaveNew(oldItems, newItems)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.filterNot { it is Resource.Intermediate }
|
.filterNot { it is Resource.Intermediate }
|
||||||
|
|
||||||
|
suspend fun getMapping(): Mapping? {
|
||||||
|
var savedMapping = preferencesRepository.mapping
|
||||||
|
|
||||||
|
if (savedMapping == null) {
|
||||||
|
fetchMapping()
|
||||||
|
savedMapping = preferencesRepository.mapping
|
||||||
|
}
|
||||||
|
|
||||||
|
return savedMapping
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun fetchMapping() {
|
||||||
|
runCatching { wulkanowyService.getMapping() }
|
||||||
|
.onFailure { Timber.e(it) }
|
||||||
|
.onSuccess { preferencesRepository.mapping = it }
|
||||||
|
}
|
||||||
}
|
}
|
@ -5,14 +5,14 @@ import io.github.wulkanowy.data.db.entities.AdminMessage
|
|||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.github.wulkanowy.data.enums.MessageType
|
import io.github.wulkanowy.data.enums.MessageType
|
||||||
import io.github.wulkanowy.data.mapResourceData
|
import io.github.wulkanowy.data.mapResourceData
|
||||||
import io.github.wulkanowy.data.repositories.AdminMessageRepository
|
|
||||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
|
import io.github.wulkanowy.data.repositories.WulkanowyRepository
|
||||||
import io.github.wulkanowy.utils.AppInfo
|
import io.github.wulkanowy.utils.AppInfo
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class GetAppropriateAdminMessageUseCase @Inject constructor(
|
class GetAppropriateAdminMessageUseCase @Inject constructor(
|
||||||
private val adminMessageRepository: AdminMessageRepository,
|
private val wulkanowyRepository: WulkanowyRepository,
|
||||||
private val preferencesRepository: PreferencesRepository,
|
private val preferencesRepository: PreferencesRepository,
|
||||||
private val appInfo: AppInfo
|
private val appInfo: AppInfo
|
||||||
) {
|
) {
|
||||||
@ -22,7 +22,7 @@ class GetAppropriateAdminMessageUseCase @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
operator fun invoke(scrapperBaseUrl: String, type: MessageType): Flow<Resource<AdminMessage?>> {
|
operator fun invoke(scrapperBaseUrl: String, type: MessageType): Flow<Resource<AdminMessage?>> {
|
||||||
return adminMessageRepository.getAdminMessages().mapResourceData { adminMessages ->
|
return wulkanowyRepository.getAdminMessages().mapResourceData { adminMessages ->
|
||||||
adminMessages
|
adminMessages
|
||||||
.asSequence()
|
.asSequence()
|
||||||
.filter { it.isNotDismissed() }
|
.filter { it.isNotDismissed() }
|
||||||
|
@ -59,7 +59,7 @@ class GetMailboxByStudentUseCase @Inject constructor(
|
|||||||
private fun String.getUnauthorizedVersion(): String {
|
private fun String.getUnauthorizedVersion(): String {
|
||||||
return normalizeStudentName().split(" ")
|
return normalizeStudentName().split(" ")
|
||||||
.joinToString(" ") {
|
.joinToString(" ") {
|
||||||
it.first() + "*".repeat(it.length - 1)
|
it.firstOrNull()?.toString().orEmpty() + "*".repeat((it.length - 1).coerceAtLeast(0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ class CaptchaDialog : BaseDialogFragment<DialogCaptchaBinding>() {
|
|||||||
webView = this
|
webView = this
|
||||||
with(settings) {
|
with(settings) {
|
||||||
javaScriptEnabled = true
|
javaScriptEnabled = true
|
||||||
userAgentString = wulkanowySdkFactory.create().userAgent
|
userAgentString = wulkanowySdkFactory.createBase().userAgent
|
||||||
}
|
}
|
||||||
|
|
||||||
webViewClient = object : WebViewClient() {
|
webViewClient = object : WebViewClient() {
|
||||||
|
@ -118,5 +118,6 @@ class LoginActivity : BaseActivity<LoginPresenter, ActivityLoginBinding>(), Logi
|
|||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
inAppUpdateHelper.onResume()
|
inAppUpdateHelper.onResume()
|
||||||
|
presenter.updateSdkMappings()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
package io.github.wulkanowy.ui.modules.login
|
package io.github.wulkanowy.ui.modules.login
|
||||||
|
|
||||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||||
|
import io.github.wulkanowy.data.repositories.WulkanowyRepository
|
||||||
import io.github.wulkanowy.ui.base.BasePresenter
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class LoginPresenter @Inject constructor(
|
class LoginPresenter @Inject constructor(
|
||||||
|
private val wulkanowyRepository: WulkanowyRepository,
|
||||||
errorHandler: ErrorHandler,
|
errorHandler: ErrorHandler,
|
||||||
studentRepository: StudentRepository
|
studentRepository: StudentRepository
|
||||||
) : BasePresenter<LoginView>(errorHandler, studentRepository) {
|
) : BasePresenter<LoginView>(errorHandler, studentRepository) {
|
||||||
@ -16,4 +19,11 @@ class LoginPresenter @Inject constructor(
|
|||||||
view.initView()
|
view.initView()
|
||||||
Timber.i("Login view was initialized")
|
Timber.i("Login view was initialized")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun updateSdkMappings() {
|
||||||
|
presenterScope.launch {
|
||||||
|
runCatching { wulkanowyRepository.fetchMapping() }
|
||||||
|
.onFailure { Timber.e(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -138,6 +138,7 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
|||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
inAppUpdateHelper.onResume()
|
inAppUpdateHelper.onResume()
|
||||||
|
presenter.updateSdkMappings()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||||
|
@ -6,6 +6,7 @@ import io.github.wulkanowy.data.onResourceError
|
|||||||
import io.github.wulkanowy.data.onResourceSuccess
|
import io.github.wulkanowy.data.onResourceSuccess
|
||||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||||
|
import io.github.wulkanowy.data.repositories.WulkanowyRepository
|
||||||
import io.github.wulkanowy.data.resourceFlow
|
import io.github.wulkanowy.data.resourceFlow
|
||||||
import io.github.wulkanowy.services.sync.SyncManager
|
import io.github.wulkanowy.services.sync.SyncManager
|
||||||
import io.github.wulkanowy.ui.base.BasePresenter
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
@ -29,6 +30,7 @@ class MainPresenter @Inject constructor(
|
|||||||
errorHandler: ErrorHandler,
|
errorHandler: ErrorHandler,
|
||||||
studentRepository: StudentRepository,
|
studentRepository: StudentRepository,
|
||||||
private val preferencesRepository: PreferencesRepository,
|
private val preferencesRepository: PreferencesRepository,
|
||||||
|
private val wulkanowyRepository: WulkanowyRepository,
|
||||||
private val syncManager: SyncManager,
|
private val syncManager: SyncManager,
|
||||||
private val analytics: AnalyticsHelper,
|
private val analytics: AnalyticsHelper,
|
||||||
private val json: Json,
|
private val json: Json,
|
||||||
@ -199,4 +201,11 @@ class MainPresenter @Inject constructor(
|
|||||||
.onFailure { errorHandler.dispatch(it) }
|
.onFailure { errorHandler.dispatch(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun updateSdkMappings() {
|
||||||
|
presenterScope.launch {
|
||||||
|
runCatching { wulkanowyRepository.fetchMapping() }
|
||||||
|
.onFailure { Timber.e(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
Wersja 2.6.1
|
Wersja 2.6.9
|
||||||
|
|
||||||
— dodaliśmy kalkulator frekwencji
|
— naprawiliśmy obsługę eduOne (w piątek wieczorem, więc jak widzisz to później to może już nie działać)
|
||||||
— dodaliśmy wyświetlanie lekcji dodatkowych w planie lekcji
|
|
||||||
— ulepszyliśmy wyjaśnienie na ekranie z miejscem na wpisanie numeru PESEL
|
|
||||||
— naprawiliśmy rzadkie sytuacje, gdy plan lekcji nakładał się na informację o jego braku
|
|
||||||
|
|
||||||
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases
|
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
<string name="student_info_title">Student info</string>
|
<string name="student_info_title">Student info</string>
|
||||||
<string name="dashboard_title">Dashboard</string>
|
<string name="dashboard_title">Dashboard</string>
|
||||||
<string name="notifications_center_title">Notifications center</string>
|
<string name="notifications_center_title">Notifications center</string>
|
||||||
<string name="menu_order_title">Menu configuartion</string>
|
<string name="menu_order_title">Menu configuration</string>
|
||||||
|
|
||||||
|
|
||||||
<!--Subtitles-->
|
<!--Subtitles-->
|
||||||
|
@ -8,6 +8,7 @@ import io.mockk.mockk
|
|||||||
|
|
||||||
fun createWulkanowySdkFactoryMock(sdk: Sdk) = mockk<WulkanowySdkFactory>()
|
fun createWulkanowySdkFactoryMock(sdk: Sdk) = mockk<WulkanowySdkFactory>()
|
||||||
.apply {
|
.apply {
|
||||||
every { create() } returns sdk
|
every { createBase() } returns sdk
|
||||||
|
coEvery { create() } returns sdk
|
||||||
coEvery { create(any(), any()) } returns sdk
|
coEvery { create(any(), any()) } returns sdk
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,6 @@ import io.github.wulkanowy.sdk.pojo.RegisterStudent
|
|||||||
import io.mockk.Runs
|
import io.mockk.Runs
|
||||||
import io.mockk.coEvery
|
import io.mockk.coEvery
|
||||||
import io.mockk.coVerify
|
import io.mockk.coVerify
|
||||||
import io.mockk.every
|
|
||||||
import io.mockk.just
|
import io.mockk.just
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
import io.mockk.spyk
|
import io.mockk.spyk
|
||||||
@ -40,11 +39,13 @@ class WulkanowySdkFactoryTest {
|
|||||||
chuckerInterceptor = mockk(),
|
chuckerInterceptor = mockk(),
|
||||||
remoteConfig = mockk(relaxed = true),
|
remoteConfig = mockk(relaxed = true),
|
||||||
webkitCookieManagerProxy = mockk(),
|
webkitCookieManagerProxy = mockk(),
|
||||||
studentDb = studentDao
|
studentDb = studentDao,
|
||||||
|
wulkanowyRepository = mockk(relaxed = true),
|
||||||
|
context = mockk(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
every { wulkanowySdkFactory.create() } returns sdk
|
coEvery { wulkanowySdkFactory.create() } returns sdk
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -3,6 +3,7 @@ package io.github.wulkanowy.ui.modules.main
|
|||||||
import io.github.wulkanowy.MainCoroutineRule
|
import io.github.wulkanowy.MainCoroutineRule
|
||||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||||
|
import io.github.wulkanowy.data.repositories.WulkanowyRepository
|
||||||
import io.github.wulkanowy.services.sync.SyncManager
|
import io.github.wulkanowy.services.sync.SyncManager
|
||||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||||
import io.github.wulkanowy.utils.AdsHelper
|
import io.github.wulkanowy.utils.AdsHelper
|
||||||
@ -31,6 +32,9 @@ class MainPresenterTest {
|
|||||||
@MockK
|
@MockK
|
||||||
lateinit var studentRepository: StudentRepository
|
lateinit var studentRepository: StudentRepository
|
||||||
|
|
||||||
|
@MockK(relaxed = true)
|
||||||
|
lateinit var wulkanowyRepository: WulkanowyRepository
|
||||||
|
|
||||||
@MockK(relaxed = true)
|
@MockK(relaxed = true)
|
||||||
lateinit var prefRepository: PreferencesRepository
|
lateinit var prefRepository: PreferencesRepository
|
||||||
|
|
||||||
@ -65,7 +69,8 @@ class MainPresenterTest {
|
|||||||
analytics = analytics,
|
analytics = analytics,
|
||||||
json = Json,
|
json = Json,
|
||||||
appInfo = appInfo,
|
appInfo = appInfo,
|
||||||
adsHelper = adsHelper
|
adsHelper = adsHelper,
|
||||||
|
wulkanowyRepository = wulkanowyRepository
|
||||||
)
|
)
|
||||||
presenter.onAttachView(mainView, null)
|
presenter.onAttachView(mainView, null)
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
buildscript {
|
buildscript {
|
||||||
ext {
|
ext {
|
||||||
kotlin_version = '1.9.23'
|
kotlin_version = '1.9.23'
|
||||||
about_libraries = '11.1.3'
|
about_libraries = '11.1.4'
|
||||||
hilt_version = '2.51.1'
|
hilt_version = '2.51.1'
|
||||||
}
|
}
|
||||||
repositories {
|
repositories {
|
||||||
@ -14,7 +14,7 @@ buildscript {
|
|||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
|
||||||
classpath "com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin:$kotlin_version-1.0.19"
|
classpath "com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin:$kotlin_version-1.0.19"
|
||||||
classpath 'com.android.tools.build:gradle:8.3.2'
|
classpath 'com.android.tools.build:gradle:8.4.0'
|
||||||
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.1'
|
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'
|
||||||
|
Reference in New Issue
Block a user