Compare commits
64 Commits
Author | SHA1 | Date | |
---|---|---|---|
5f1bb7c1d0 | |||
c6f4c868b2 | |||
c634c64e70 | |||
da2b7dbf7e | |||
26267507eb | |||
24d0c5057b | |||
b05026a6e6 | |||
8036f3d7f7 | |||
23e309d38e | |||
bf92c6b2e9 | |||
c00b5edaf7 | |||
cb09ca13dc | |||
3d68b8e629 | |||
b3173581e5 | |||
ddac1d0f98 | |||
db6a359bea | |||
e7221e6a32 | |||
db9c2640c7 | |||
ca67e144e4 | |||
da2346ed83 | |||
a87818f3d0 | |||
5092f8c0bf | |||
af0787c0b1 | |||
721b4ac797 | |||
26a69092cc | |||
2bd0c75055 | |||
d6f3c57293 | |||
518387e7bb | |||
ca6dfbf2d0 | |||
da6d8a74fd | |||
e35e4ef152 | |||
40fc6ec2e0 | |||
b91973aec3 | |||
047e70ad46 | |||
112c1eb793 | |||
c479b31670 | |||
43ed8c8fce | |||
613fa44c27 | |||
f21216286d | |||
7298d0d75a | |||
ee0fbcdfd6 | |||
c362ad12c7 | |||
8a1a712d6d | |||
1f0f6b3e51 | |||
11487e77ca | |||
fd0fd4df55 | |||
d95a33787b | |||
e5661098d9 | |||
d020b01794 | |||
d8b1264024 | |||
cddd17650b | |||
a0f9c70036 | |||
2e05416fb5 | |||
d32ebd66de | |||
c6a99f1000 | |||
bafe52e310 | |||
e08abc1fc2 | |||
2a74b11cce | |||
b0b3ccfd53 | |||
6c68456f7a | |||
3e8e9b4ecc | |||
d6ebc343d5 | |||
73be416807 | |||
0cb65a29ba |
3
.gitignore
vendored
@ -113,3 +113,6 @@ Thumbs.db
|
||||
|
||||
!/gradle/wrapper/gradle-wrapper.jar
|
||||
.idea/jarRepositories.xml
|
||||
|
||||
|
||||
app/src/release/agconnect-services.json
|
||||
|
31
.travis.yml
@ -3,8 +3,8 @@ jdk: oraclejdk8
|
||||
|
||||
env:
|
||||
global:
|
||||
- ANDROID_API_LEVEL=29
|
||||
- ANDROID_BUILD_TOOLS_VERSION=29.0.3
|
||||
- ANDROID_API_LEVEL=30
|
||||
- ANDROID_BUILD_TOOLS_VERSION=30.0.2
|
||||
|
||||
cache:
|
||||
directories:
|
||||
@ -14,7 +14,7 @@ cache:
|
||||
branches:
|
||||
only:
|
||||
- develop
|
||||
- 0.20.4
|
||||
- 0.22.2
|
||||
|
||||
android:
|
||||
licenses:
|
||||
@ -28,32 +28,37 @@ android:
|
||||
- build-tools-$ANDROID_BUILD_TOOLS_VERSION
|
||||
# The SDK version used to compile your project
|
||||
- android-$ANDROID_API_LEVEL
|
||||
# Additional components
|
||||
# Additional components
|
||||
- extra-google-google_play_services
|
||||
- extra-google-m2repository
|
||||
- extra-android-m2repository
|
||||
- addon-google_apis-google-$ANDROID_API_LEVEL
|
||||
# Android emulator
|
||||
# Android emulator
|
||||
- android-22
|
||||
- sys-img-armeabi-v7a-android-22
|
||||
|
||||
before_install:
|
||||
- yes | sdkmanager "platforms;android-30"
|
||||
- yes | sdkmanager "build-tools;30.0.2"
|
||||
|
||||
before_script:
|
||||
# Launch emulator before the execution
|
||||
- echo no | android create avd --force -n test -t android-22 --abi armeabi-v7a
|
||||
- emulator -avd test -no-audio -no-window &
|
||||
- android-wait-for-emulator
|
||||
- adb shell input keyevent 82 &
|
||||
- "curl -H 'Cache-Control: no-cache' https://raw.githubusercontent.com/fossas/fossa-cli/master/install.sh | sudo bash"
|
||||
# Launch emulator before the execution
|
||||
- echo no | android create avd --force -n test -t android-22 --abi armeabi-v7a
|
||||
- emulator -avd test -no-audio -no-window &
|
||||
- android-wait-for-emulator
|
||||
- adb shell input keyevent 82 &
|
||||
- "curl -H 'Cache-Control: no-cache' https://raw.githubusercontent.com/fossas/fossa-cli/master/install.sh | sudo bash"
|
||||
|
||||
script:
|
||||
- ./gradlew dependencies --stacktrace --daemon
|
||||
- fossa --no-ansi || true
|
||||
- ./gradlew -Pcoverage testPlayDebugUnitTest --stacktrace --daemon
|
||||
- ./gradlew -Pcoverage createFdroidDebugCoverageReport --stacktrace --daemon
|
||||
- ./gradlew -Pcoverage testFdroidDebugUnitTest --stacktrace --daemon
|
||||
- ./gradlew -Pcoverage connectedFdroidDebugAndroidTest --stacktrace --daemon
|
||||
- ./gradlew -Pcoverage jacocoTestReport --stacktrace --daemon
|
||||
- |
|
||||
if [ $TRAVIS_TAG ]; then
|
||||
gpg --yes --batch --passphrase=$SERVICES_ENCRYPT_KEY ./app/src/release/google-services.json.gpg;
|
||||
gpg --yes --batch --passphrase=$SERVICES_ENCRYPT_KEY ./app/src/release/agconnect-services.json.gpg;
|
||||
gpg --yes --batch --passphrase=$ENCRYPT_KEY ./app/key.p12.gpg;
|
||||
gpg --yes --batch --passphrase=$ENCRYPT_KEY ./app/upload-key.jks.gpg;
|
||||
./gradlew publishPlayRelease -PenableFirebase --stacktrace;
|
||||
|
@ -32,14 +32,17 @@ Unofficial android VULCAN UONET+ register client for both students and their par
|
||||
|
||||
## Download
|
||||
|
||||
You can download the current beta version from the Google Play or the F-Droid store
|
||||
You can download the current beta version from the Google Play, F-Droid or Huawei AppGallery store
|
||||
|
||||
[<img src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png"
|
||||
alt="Get it on Google Play"
|
||||
height="80">](https://play.google.com/store/apps/details?id=io.github.wulkanowy)
|
||||
alt="Get it on Google Play"
|
||||
height="80">](https://play.google.com/store/apps/details?id=io.github.wulkanowy)
|
||||
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
|
||||
alt="Get it on F-Droid"
|
||||
height="80">](https://f-droid.org/packages/io.github.wulkanowy/)
|
||||
[<img src="appgallery_badge.png"
|
||||
alt="Explore it on AppGallery"
|
||||
height="80">](https://appgallery.cloud.huawei.com/ag/n/app/C101440411?channelId=Badge&id=1b3f7fbb700849a9be0dba6b520b2282&s=EB1D3BF9ED9D1564D869B7B94B18016D3CABFCA5AEFB8E29F675FA04E0DC131D&detailType=0&v=)
|
||||
|
||||
You can also download a [development version](https://wulkanowy.github.io/#download) that includes new features being prepared for the next release
|
||||
|
||||
|
@ -32,14 +32,17 @@ Nieoficjalny klient dziennika VULCAN UONET+ dla ucznia i rodzica
|
||||
|
||||
## Pobierz
|
||||
|
||||
Aktualną wersję beta możesz pobrać ze sklepu Google Play lub F-Droid
|
||||
Aktualną wersję beta możesz pobrać ze sklepu Google Play, F-Droid lub Huawei AppGallery
|
||||
|
||||
[<img src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png"
|
||||
alt="Pobierz z Google Play"
|
||||
height="80">](https://play.google.com/store/apps/details?id=io.github.wulkanowy)
|
||||
alt="Pobierz z Google Play"
|
||||
height="80">](https://play.google.com/store/apps/details?id=io.github.wulkanowy)
|
||||
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
|
||||
alt="Pobierz z F-Droid"
|
||||
height="80">](https://f-droid.org/packages/io.github.wulkanowy/)
|
||||
[<img src="appgallery_badge.png"
|
||||
alt="Odkrywaj w AppGallery"
|
||||
height="80">](https://appgallery.cloud.huawei.com/ag/n/app/C101440411?channelId=Badge&id=1b3f7fbb700849a9be0dba6b520b2282&s=EB1D3BF9ED9D1564D869B7B94B18016D3CABFCA5AEFB8E29F675FA04E0DC131D&detailType=0&v=)
|
||||
|
||||
|
||||
Możesz także pobrać [wersję rozwojową](https://wulkanowy.github.io/#download), która zawiera nowe funkcje przygotowywane do następnego wydania
|
||||
|
@ -10,16 +10,16 @@ apply from: 'sonarqube.gradle'
|
||||
apply from: 'hooks.gradle'
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
buildToolsVersion '29.0.3'
|
||||
compileSdkVersion 30
|
||||
buildToolsVersion '30.0.2'
|
||||
|
||||
defaultConfig {
|
||||
applicationId "io.github.wulkanowy"
|
||||
testApplicationId "io.github.tests.wulkanowy"
|
||||
minSdkVersion 17
|
||||
targetSdkVersion 29
|
||||
versionCode 68
|
||||
versionName "0.20.4"
|
||||
targetSdkVersion 30
|
||||
versionCode 75
|
||||
versionName "0.22.2"
|
||||
multiDexEnabled true
|
||||
resValue "string", "app_name", "Wulkanowy"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
@ -69,12 +69,26 @@ android {
|
||||
flavorDimensions "platform"
|
||||
|
||||
productFlavors {
|
||||
hms {
|
||||
dimension "platform"
|
||||
minSdkVersion 19
|
||||
manifestPlaceholders = [
|
||||
install_channel: "AppGallery"
|
||||
]
|
||||
}
|
||||
|
||||
play {
|
||||
dimension "platform"
|
||||
manifestPlaceholders = [
|
||||
install_channel: "Google Play"
|
||||
]
|
||||
}
|
||||
|
||||
fdroid {
|
||||
dimension "platform"
|
||||
manifestPlaceholders = [
|
||||
install_channel: "F-Droid"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@ -112,13 +126,15 @@ play {
|
||||
serviceAccountCredentials = file('key.p12')
|
||||
defaultToAppBundles = false
|
||||
track = 'alpha'
|
||||
updatePriority = 1
|
||||
}
|
||||
|
||||
ext {
|
||||
work_manager = "2.4.0"
|
||||
room = "2.2.5"
|
||||
chucker = "3.2.0"
|
||||
mockk = "1.10.0"
|
||||
chucker = "3.3.0"
|
||||
mockk = "1.10.2"
|
||||
moshi = "1.11.0"
|
||||
}
|
||||
|
||||
configurations.all {
|
||||
@ -126,14 +142,14 @@ configurations.all {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "io.github.wulkanowy:sdk:0.20.4"
|
||||
implementation "io.github.wulkanowy:sdk:0.22.2"
|
||||
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.10'
|
||||
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'
|
||||
|
||||
implementation "androidx.core:core-ktx:1.3.1"
|
||||
implementation "androidx.core:core-ktx:1.3.2"
|
||||
implementation "androidx.activity:activity-ktx:1.1.0"
|
||||
implementation "androidx.appcompat:appcompat:1.2.0"
|
||||
implementation "androidx.appcompat:appcompat-resources:1.2.0"
|
||||
@ -170,29 +186,35 @@ dependencies {
|
||||
implementation "com.ncapdevi:frag-nav:3.3.0"
|
||||
implementation "com.github.YarikSOffice:lingver:1.2.2"
|
||||
|
||||
implementation "com.google.code.gson:gson:2.8.6"
|
||||
implementation "com.squareup.moshi:moshi:$moshi"
|
||||
implementation "com.squareup.moshi:moshi-adapters:$moshi"
|
||||
kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi"
|
||||
implementation "com.jakewharton.timber:timber:4.7.1"
|
||||
implementation "at.favre.lib:slf4j-timber:1.0.1"
|
||||
implementation "fr.bipi.treessence:treessence:0.3.2"
|
||||
implementation "com.mikepenz:aboutlibraries-core:$about_libraries"
|
||||
implementation 'com.wdullaer:materialdatetimepicker:4.2.3'
|
||||
implementation "io.coil-kt:coil:1.0.0-rc2"
|
||||
implementation "io.coil-kt:coil:1.0.0-rc3"
|
||||
implementation "io.github.wulkanowy:AppKillerManager:3.0.0"
|
||||
implementation 'me.xdrop:fuzzywuzzy:1.3.1'
|
||||
|
||||
playImplementation 'com.google.firebase:firebase-analytics:17.5.0'
|
||||
playImplementation 'com.google.firebase:firebase-analytics:17.6.0'
|
||||
playImplementation 'com.google.firebase:firebase-inappmessaging-display-ktx:19.1.1'
|
||||
playImplementation "com.google.firebase:firebase-inappmessaging-ktx:19.1.1"
|
||||
playImplementation 'com.google.firebase:firebase-messaging:20.2.4'
|
||||
playImplementation 'com.google.firebase:firebase-crashlytics:17.2.1'
|
||||
playImplementation 'com.google.firebase:firebase-messaging:20.3.0'
|
||||
playImplementation 'com.google.firebase:firebase-crashlytics:17.2.2'
|
||||
playImplementation 'com.google.android.play:core-ktx:1.8.1'
|
||||
playImplementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava'
|
||||
|
||||
hmsImplementation 'com.huawei.hms:hianalytics:5.0.4.301'
|
||||
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.4.1.300'
|
||||
|
||||
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker"
|
||||
|
||||
debugImplementation "com.github.ChuckerTeam.Chucker:library:$chucker"
|
||||
debugImplementation "com.amitshekhar.android:debug-db:1.0.6"
|
||||
|
||||
testImplementation "junit:junit:4.13"
|
||||
testImplementation "junit:junit:4.13.1"
|
||||
testImplementation "io.mockk:mockk:$mockk"
|
||||
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.9'
|
||||
|
||||
@ -205,3 +227,4 @@ dependencies {
|
||||
}
|
||||
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
apply plugin: 'com.huawei.agconnect'
|
||||
|
@ -35,13 +35,13 @@ task jacocoTestReport(type: JacocoReport) {
|
||||
dir: "$buildDir/intermediates/classes/debug",
|
||||
excludes: excludes
|
||||
) + fileTree(
|
||||
dir: "$buildDir/tmp/kotlin-classes/playDebug",
|
||||
dir: "$buildDir/tmp/kotlin-classes/fdroidDebug",
|
||||
excludes: excludes
|
||||
))
|
||||
|
||||
sourceDirectories.setFrom(files([
|
||||
"src/main/java",
|
||||
"src/play/java"
|
||||
"src/fdroid/java"
|
||||
]))
|
||||
executionData.setFrom(fileTree(
|
||||
dir: project.projectDir,
|
||||
|
33
app/src/debug/agconnect-services.json
Normal file
@ -0,0 +1,33 @@
|
||||
{
|
||||
"agcgw":{
|
||||
"backurl":"connect-dre.dbankcloud.cn",
|
||||
"url":"connect-dre.hispace.hicloud.com"
|
||||
},
|
||||
"client":{
|
||||
"cp_id":"890048000024105546",
|
||||
"product_id":"",
|
||||
"client_id":"",
|
||||
"client_secret":"",
|
||||
"app_id":"101440411",
|
||||
"package_name":"io.github.wulkanowy.dev",
|
||||
"api_key":""
|
||||
},
|
||||
"service":{
|
||||
"analytics":{
|
||||
"collector_url":"datacollector-dre.dt.hicloud.com,datacollector-dre.dt.dbankcloud.cn",
|
||||
"resource_id":"p1",
|
||||
"channel_id":""
|
||||
},
|
||||
"search":{
|
||||
"url":"https://search-dre.cloud.huawei.com"
|
||||
},
|
||||
"cloudstorage":{
|
||||
"storage_url":"https://ops-dre.agcstorage.link"
|
||||
},
|
||||
"ml":{
|
||||
"mlservice_url":"ml-api-dre.ai.dbankcloud.com,ml-api-dre.ai.dbankcloud.cn"
|
||||
}
|
||||
},
|
||||
"region":"DE",
|
||||
"configuration_version":"1.0"
|
||||
}
|
@ -6,7 +6,7 @@ import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
class FirebaseAnalyticsHelper @Inject constructor() {
|
||||
class AnalyticsHelper @Inject constructor() {
|
||||
|
||||
fun logEvent(name: String, vararg params: Pair<String, Any?>) {
|
||||
// do nothing
|
@ -8,6 +8,6 @@ open class TimberTreeNoOp : Timber.Tree() {
|
||||
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {}
|
||||
}
|
||||
|
||||
class CrashlyticsTree : TimberTreeNoOp()
|
||||
class CrashLogTree : TimberTreeNoOp()
|
||||
|
||||
class CrashlyticsExceptionTree : TimberTreeNoOp()
|
||||
class CrashLogExceptionTree : TimberTreeNoOp()
|
@ -0,0 +1,17 @@
|
||||
package io.github.wulkanowy.utils
|
||||
|
||||
import android.app.Activity
|
||||
import android.view.View
|
||||
import javax.inject.Inject
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
class UpdateHelper @Inject constructor() {
|
||||
|
||||
lateinit var messageContainer: View
|
||||
|
||||
fun checkAndInstallUpdates(activity: Activity) {}
|
||||
|
||||
fun onActivityResult(requestCode: Int, resultCode: Int) {}
|
||||
|
||||
fun onResume(activity: Activity) {}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package io.github.wulkanowy.utils
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import com.huawei.hms.analytics.HiAnalytics
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class AnalyticsHelper @Inject constructor(
|
||||
@ApplicationContext private val context: Context
|
||||
) {
|
||||
|
||||
private val analytics by lazy { HiAnalytics.getInstance(context) }
|
||||
|
||||
fun logEvent(name: String, vararg params: Pair<String, Any?>) {
|
||||
Bundle().apply {
|
||||
params.forEach {
|
||||
if (it.second == null) return@forEach
|
||||
when (it.second) {
|
||||
is String, is String? -> putString(it.first, it.second as String)
|
||||
is Int, is Int? -> putInt(it.first, it.second as Int)
|
||||
is Boolean, is Boolean? -> putBoolean(it.first, it.second as Boolean)
|
||||
}
|
||||
}
|
||||
analytics.onEvent(name, this)
|
||||
}
|
||||
}
|
||||
|
||||
fun setCurrentScreen(activity: Activity, name: String?) {
|
||||
analytics.onEvent("screen_view", Bundle().apply {
|
||||
putString("screen_name", name)
|
||||
putString("screen_class", activity::class.simpleName)
|
||||
})
|
||||
}
|
||||
}
|
52
app/src/hms/java/io/github/wulkanowy/utils/CrashLogUtils.kt
Normal file
@ -0,0 +1,52 @@
|
||||
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 io.github.wulkanowy.sdk.exception.FeatureNotAvailableException
|
||||
import io.github.wulkanowy.sdk.scrapper.exception.FeatureDisabledException
|
||||
import java.io.InterruptedIOException
|
||||
import java.net.SocketTimeoutException
|
||||
import java.net.UnknownHostException
|
||||
|
||||
class CrashLogTree : FormatterPriorityTree(Log.VERBOSE) {
|
||||
|
||||
private val connectCrash by lazy { AGConnectCrash.getInstance() }
|
||||
|
||||
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
|
||||
if (skipLog(priority, tag, message, t)) return
|
||||
|
||||
connectCrash.log(format(priority, tag, message))
|
||||
}
|
||||
}
|
||||
|
||||
class CrashLogExceptionTree : FormatterPriorityTree(Log.ERROR) {
|
||||
|
||||
private val connectCrash by lazy { AGConnectCrash.getInstance() }
|
||||
|
||||
override fun skipLog(priority: Int, tag: String?, message: String, t: Throwable?): Boolean {
|
||||
return when (t) {
|
||||
is FeatureDisabledException,
|
||||
is FeatureNotAvailableException,
|
||||
is UnknownHostException,
|
||||
is SocketTimeoutException,
|
||||
is InterruptedIOException -> true
|
||||
else -> super.skipLog(priority, tag, message, t)
|
||||
}
|
||||
}
|
||||
|
||||
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
|
||||
if (skipLog(priority, tag, message, t)) return
|
||||
|
||||
connectCrash.setCustomKey("priority", priority)
|
||||
connectCrash.setCustomKey("tag", tag.orEmpty())
|
||||
connectCrash.setCustomKey("message", message)
|
||||
connectCrash.log(priority, t?.stackTraceToString())
|
||||
if (t != null) {
|
||||
connectCrash.log(priority, t.stackTraceToString())
|
||||
} else {
|
||||
connectCrash.log(priority, StackTraceRecorder(format(priority, tag, message)).stackTraceToString())
|
||||
}
|
||||
}
|
||||
}
|
17
app/src/hms/java/io/github/wulkanowy/utils/UpdateHelper.kt
Normal file
@ -0,0 +1,17 @@
|
||||
package io.github.wulkanowy.utils
|
||||
|
||||
import android.app.Activity
|
||||
import android.view.View
|
||||
import javax.inject.Inject
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
class UpdateHelper @Inject constructor() {
|
||||
|
||||
lateinit var messageContainer: View
|
||||
|
||||
fun checkAndInstallUpdates(activity: Activity) {}
|
||||
|
||||
fun onActivityResult(requestCode: Int, resultCode: Int) {}
|
||||
|
||||
fun onResume(activity: Activity) {}
|
||||
}
|
@ -110,6 +110,11 @@
|
||||
android:resource="@xml/provider_paths" />
|
||||
</provider>
|
||||
|
||||
<meta-data
|
||||
android:name="install_channel"
|
||||
android:value="${install_channel}">
|
||||
</meta-data>
|
||||
|
||||
<!-- workaround for https://github.com/firebase/firebase-android-sdk/issues/473 enabled:false -->
|
||||
<!-- https://firebase.googleblog.com/2017/03/take-control-of-your-firebase-init-on.html -->
|
||||
<provider
|
||||
|
@ -14,8 +14,8 @@ import fr.bipi.tressence.file.FileLoggerTree
|
||||
import io.github.wulkanowy.ui.base.ThemeManager
|
||||
import io.github.wulkanowy.utils.ActivityLifecycleLogger
|
||||
import io.github.wulkanowy.utils.AppInfo
|
||||
import io.github.wulkanowy.utils.CrashlyticsExceptionTree
|
||||
import io.github.wulkanowy.utils.CrashlyticsTree
|
||||
import io.github.wulkanowy.utils.CrashLogExceptionTree
|
||||
import io.github.wulkanowy.utils.CrashLogTree
|
||||
import io.github.wulkanowy.utils.DebugLogTree
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
@ -56,8 +56,8 @@ class WulkanowyApp : Application(), Configuration.Provider {
|
||||
.build()
|
||||
)
|
||||
} else {
|
||||
Timber.plant(CrashlyticsExceptionTree())
|
||||
Timber.plant(CrashlyticsTree())
|
||||
Timber.plant(CrashLogExceptionTree())
|
||||
Timber.plant(CrashLogTree())
|
||||
}
|
||||
registerActivityLifecycleCallbacks(ActivityLifecycleLogger())
|
||||
}
|
||||
|
@ -33,7 +33,11 @@ internal class RepositoryModule {
|
||||
setSimpleHttpLogger { Timber.d(it) }
|
||||
|
||||
// for debug only
|
||||
addInterceptor(ChuckerInterceptor(context, chuckerCollector), true)
|
||||
addInterceptor(ChuckerInterceptor(
|
||||
context = context,
|
||||
collector = chuckerCollector,
|
||||
alwaysReadResponseBody = true
|
||||
), true)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,9 @@
|
||||
package io.github.wulkanowy.data.db
|
||||
|
||||
import androidx.room.TypeConverter
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.Types
|
||||
import io.github.wulkanowy.data.db.adapters.PairAdapterFactory
|
||||
import java.time.Instant
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalDateTime
|
||||
@ -12,6 +13,16 @@ import java.util.Date
|
||||
|
||||
class Converters {
|
||||
|
||||
private val moshi by lazy { Moshi.Builder().add(PairAdapterFactory).build() }
|
||||
|
||||
private val integerListAdapter by lazy {
|
||||
moshi.adapter<List<Int>>(Types.newParameterizedType(List::class.java, Integer::class.java))
|
||||
}
|
||||
|
||||
private val stringListPairAdapter by lazy {
|
||||
moshi.adapter<List<Pair<String, String>>>(Types.newParameterizedType(List::class.java, Pair::class.java, String::class.java, String::class.java))
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun timestampToDate(value: Long?): LocalDate? = value?.run {
|
||||
Date(value).toInstant().atZone(ZoneOffset.UTC).toLocalDate()
|
||||
@ -39,22 +50,22 @@ class Converters {
|
||||
fun intToMonth(value: Int?) = value?.let { Month.of(it) }
|
||||
|
||||
@TypeConverter
|
||||
fun intListToGson(list: List<Int>): String {
|
||||
return Gson().toJson(list)
|
||||
fun intListToJson(list: List<Int>): String {
|
||||
return integerListAdapter.toJson(list)
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun gsonToIntList(value: String): List<Int> {
|
||||
return Gson().fromJson(value, object : TypeToken<List<Int>>() {}.type)
|
||||
fun jsonToIntList(value: String): List<Int> {
|
||||
return integerListAdapter.fromJson(value).orEmpty()
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun stringPairListToGson(list: List<Pair<String, String>>): String {
|
||||
return Gson().toJson(list)
|
||||
fun stringPairListToJson(list: List<Pair<String, String>>): String {
|
||||
return stringListPairAdapter.toJson(list)
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun gsonToStringPairList(value: String): List<Pair<String, String>> {
|
||||
return Gson().fromJson(value, object : TypeToken<List<Pair<String, String>>>() {}.type)
|
||||
fun jsonToStringPairList(value: String): List<Pair<String, String>> {
|
||||
return stringListPairAdapter.fromJson(value).orEmpty()
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,68 @@
|
||||
package io.github.wulkanowy.data.db.adapters
|
||||
|
||||
import com.squareup.moshi.JsonAdapter
|
||||
import com.squareup.moshi.JsonReader
|
||||
import com.squareup.moshi.JsonWriter
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.Types
|
||||
import java.lang.reflect.ParameterizedType
|
||||
import java.lang.reflect.Type
|
||||
|
||||
object PairAdapterFactory : JsonAdapter.Factory {
|
||||
|
||||
override fun create(type: Type, annotations: MutableSet<out Annotation>, moshi: Moshi): JsonAdapter<*>? {
|
||||
if (type !is ParameterizedType || List::class.java != type.rawType) return null
|
||||
if (type.actualTypeArguments[0] != Pair::class.java) return null
|
||||
|
||||
val listType = Types.newParameterizedType(List::class.java, Map::class.java, String::class.java)
|
||||
val listAdapter = moshi.adapter<List<Map<String, String>>>(listType)
|
||||
|
||||
val mapType = Types.newParameterizedType(MutableMap::class.java, String::class.java, String::class.java)
|
||||
val mapAdapter = moshi.adapter<Map<String, String>>(mapType)
|
||||
|
||||
return PairAdapter(listAdapter, mapAdapter)
|
||||
}
|
||||
|
||||
private class PairAdapter(
|
||||
private val listAdapter: JsonAdapter<List<Map<String, String>>>,
|
||||
private val mapAdapter: JsonAdapter<Map<String, String>>,
|
||||
) : JsonAdapter<List<Pair<String, String>>>() {
|
||||
|
||||
override fun toJson(writer: JsonWriter, value: List<Pair<String, String>>?) {
|
||||
writer.beginArray()
|
||||
value?.forEach {
|
||||
writer.beginObject()
|
||||
writer.name("first").value(it.first)
|
||||
writer.name("second").value(it.second)
|
||||
writer.endObject()
|
||||
}
|
||||
writer.endArray()
|
||||
}
|
||||
|
||||
override fun fromJson(reader: JsonReader): List<Pair<String, String>>? {
|
||||
return if (reader.peek() == JsonReader.Token.BEGIN_OBJECT) deserializeMoshiMap(reader)
|
||||
else deserializeGsonPair(reader)
|
||||
}
|
||||
|
||||
// for compatibility with 0.21.0
|
||||
private fun deserializeMoshiMap(reader: JsonReader): List<Pair<String, String>>? {
|
||||
val map = mapAdapter.fromJson(reader) ?: return null
|
||||
|
||||
return map.entries.map {
|
||||
it.key to it.value
|
||||
}
|
||||
}
|
||||
|
||||
private fun deserializeGsonPair(reader: JsonReader): List<Pair<String, String>>? {
|
||||
val list = listAdapter.fromJson(reader) ?: return null
|
||||
|
||||
return list.map {
|
||||
require(it.size == 2) {
|
||||
"pair with more or less than two elements: $list"
|
||||
}
|
||||
|
||||
it["first"].orEmpty() to it["second"].orEmpty()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@ interface MessagesDao : BaseDao<Message> {
|
||||
|
||||
@Transaction
|
||||
@Query("SELECT * FROM Messages WHERE student_id = :studentId AND message_id = :messageId")
|
||||
fun loadMessageWithAttachment(studentId: Int, messageId: Int): Flow<MessageWithAttachment>
|
||||
fun loadMessageWithAttachment(studentId: Int, messageId: Int): Flow<MessageWithAttachment?>
|
||||
|
||||
@Query("SELECT * FROM Messages WHERE student_id = :studentId AND folder_id = :folder ORDER BY date DESC")
|
||||
fun loadAll(studentId: Int, folder: Int): Flow<List<Message>>
|
||||
|
@ -36,12 +36,6 @@ data class Message(
|
||||
|
||||
var unread: Boolean,
|
||||
|
||||
@ColumnInfo(name = "unread_by")
|
||||
val unreadBy: Int,
|
||||
|
||||
@ColumnInfo(name = "read_by")
|
||||
val readBy: Int,
|
||||
|
||||
val removed: Boolean,
|
||||
|
||||
@ColumnInfo(name = "has_attachments")
|
||||
@ -54,5 +48,11 @@ data class Message(
|
||||
@ColumnInfo(name = "is_notified")
|
||||
var isNotified: Boolean = true
|
||||
|
||||
@ColumnInfo(name = "unread_by")
|
||||
var unreadBy: Int = 0
|
||||
|
||||
@ColumnInfo(name = "read_by")
|
||||
var readBy: Int = 0
|
||||
|
||||
var content: String = ""
|
||||
}
|
||||
|
@ -1,3 +1,9 @@
|
||||
package io.github.wulkanowy.data.pojos
|
||||
|
||||
class Contributor(val displayName: String, val githubUsername: String)
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
class Contributor(
|
||||
val displayName: String,
|
||||
val githubUsername: String
|
||||
)
|
||||
|
@ -1,7 +1,8 @@
|
||||
package io.github.wulkanowy.data.repositories.appcreator
|
||||
|
||||
import android.content.res.AssetManager
|
||||
import com.google.gson.Gson
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.Types
|
||||
import io.github.wulkanowy.data.pojos.Contributor
|
||||
import io.github.wulkanowy.utils.DispatchersProvider
|
||||
import kotlinx.coroutines.withContext
|
||||
@ -15,9 +16,9 @@ class AppCreatorRepository @Inject constructor(
|
||||
) {
|
||||
|
||||
suspend fun getAppCreators() = withContext(dispatchers.backgroundThread) {
|
||||
Gson().fromJson(
|
||||
assets.open("contributors.json").bufferedReader().use { it.readText() },
|
||||
Array<Contributor>::class.java
|
||||
).toList()
|
||||
val moshi = Moshi.Builder().build()
|
||||
val type = Types.newParameterizedType(List::class.java, Contributor::class.java)
|
||||
val adapter = moshi.adapter<List<Contributor>>(type)
|
||||
adapter.fromJson(assets.open("contributors.json").bufferedReader().use { it.readText() })
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ import io.github.wulkanowy.data.db.entities.Message
|
||||
import io.github.wulkanowy.data.db.entities.MessageAttachment
|
||||
import io.github.wulkanowy.data.db.entities.MessageWithAttachment
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.repositories.message.MessageFolder.TRASHED
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
@ -29,7 +28,7 @@ class MessageLocal @Inject constructor(
|
||||
messagesDb.deleteAll(messages)
|
||||
}
|
||||
|
||||
fun getMessageWithAttachment(student: Student, message: Message): Flow<MessageWithAttachment> {
|
||||
fun getMessageWithAttachment(student: Student, message: Message): Flow<MessageWithAttachment?> {
|
||||
return messagesDb.loadMessageWithAttachment(student.id.toInt(), message.messageId)
|
||||
}
|
||||
|
||||
|
@ -30,12 +30,12 @@ class MessageRemote @Inject constructor(private val sdk: Sdk) {
|
||||
date = it.date ?: now(),
|
||||
folderId = it.folderId,
|
||||
unread = it.unread ?: false,
|
||||
unreadBy = it.unreadBy ?: 0,
|
||||
readBy = it.readBy ?: 0,
|
||||
removed = it.removed,
|
||||
hasAttachments = it.hasAttachments
|
||||
).apply {
|
||||
content = it.content.orEmpty()
|
||||
unreadBy = it.unreadBy ?: 0
|
||||
readBy = it.readBy ?: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,12 +34,14 @@ class MessageRepository @Inject constructor(
|
||||
|
||||
fun getMessage(student: Student, message: Message, markAsRead: Boolean = false) = networkBoundResource(
|
||||
shouldFetch = {
|
||||
checkNotNull(it, { "This message no longer exist!" })
|
||||
Timber.d("Message content in db empty: ${it.message.content.isEmpty()}")
|
||||
it.message.unread || it.message.content.isEmpty()
|
||||
},
|
||||
query = { local.getMessageWithAttachment(student, message) },
|
||||
fetch = { remote.getMessagesContentDetails(student, it.message, markAsRead) },
|
||||
fetch = { remote.getMessagesContentDetails(student, it!!.message, markAsRead) },
|
||||
saveFetchResult = { old, (downloadedMessage, attachments) ->
|
||||
checkNotNull(old, { "Fetched message no longer exist!" })
|
||||
local.updateMessages(listOf(old.message.copy(unread = !markAsRead).apply {
|
||||
id = old.message.id
|
||||
content = content.ifBlank { downloadedMessage }
|
||||
|
@ -5,6 +5,7 @@ import android.content.SharedPreferences
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.ui.modules.grade.GradeAverageMode
|
||||
import io.github.wulkanowy.ui.modules.grade.GradeSortingMode
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@ -74,12 +75,25 @@ class PreferencesRepository @Inject constructor(
|
||||
val fillMessageContent: Boolean
|
||||
get() = getBoolean(R.string.pref_key_fill_message_content, R.bool.pref_default_fill_message_content)
|
||||
|
||||
val showGroupsInPlan: Boolean
|
||||
get() = getBoolean(R.string.pref_key_timetable_show_groups, R.bool.pref_default_timetable_show_groups)
|
||||
|
||||
val showWholeClassPlan: String
|
||||
get() = getString(R.string.pref_key_timetable_show_whole_class, R.string.pref_default_timetable_show_whole_class)
|
||||
|
||||
val gradeSortingMode: GradeSortingMode
|
||||
get() = GradeSortingMode.getByValue(getString(R.string.pref_key_grade_sorting_mode, R.string.pref_default_grade_sorting_mode))
|
||||
|
||||
val showTimetableTimers: Boolean
|
||||
get() = getBoolean(R.string.pref_key_timetable_show_timers, R.bool.pref_default_timetable_show_timers)
|
||||
|
||||
var isHomeworkFullscreen: Boolean
|
||||
get() = getBoolean(R.string.pref_key_homework_fullscreen, R.bool.pref_default_homework_fullscreen)
|
||||
set(value) = sharedPref.edit().putBoolean("homework_fullscreen", value).apply()
|
||||
|
||||
val showSubjectsWithoutGrades: Boolean
|
||||
get() = getBoolean(R.string.pref_key_subjects_without_grades, R.bool.pref_default_subjects_without_grades)
|
||||
|
||||
private fun getString(id: Int, default: Int) = getString(context.getString(id), default)
|
||||
|
||||
private fun getString(id: String, default: Int) = sharedPref.getString(id, context.getString(default)) ?: context.getString(default)
|
||||
|
@ -72,18 +72,22 @@ class TimetableNotificationSchedulerHelper @Inject constructor(
|
||||
withContext(dispatchersProvider.backgroundThread) {
|
||||
lessons.groupBy { it.date }
|
||||
.map { it.value.sortedBy { lesson -> lesson.start } }
|
||||
.map { it.filter { lesson -> !lesson.canceled && lesson.isStudentPlan } }
|
||||
.map { it.filter { lesson -> lesson.isStudentPlan } }
|
||||
.map { day ->
|
||||
day.forEachIndexed { index, lesson ->
|
||||
val intent = createIntent(student, lesson, day.getOrNull(index + 1))
|
||||
val canceled = day.filter { it.canceled }
|
||||
val active = day.filter { !it.canceled }
|
||||
|
||||
cancelScheduled(canceled)
|
||||
active.forEachIndexed { index, lesson ->
|
||||
val intent = createIntent(student, lesson, active.getOrNull(index + 1))
|
||||
|
||||
if (lesson.start > now()) {
|
||||
scheduleBroadcast(intent, student.studentId, NOTIFICATION_TYPE_UPCOMING, getUpcomingLessonTime(index, day, lesson))
|
||||
scheduleBroadcast(intent, student.studentId, NOTIFICATION_TYPE_UPCOMING, getUpcomingLessonTime(index, active, lesson))
|
||||
}
|
||||
|
||||
if (lesson.end > now()) {
|
||||
scheduleBroadcast(intent, student.studentId, NOTIFICATION_TYPE_CURRENT, lesson.start)
|
||||
if (day.lastIndex == index) {
|
||||
if (active.lastIndex == index) {
|
||||
scheduleBroadcast(intent, student.studentId, NOTIFICATION_TYPE_LAST_LESSON_CANCELLATION, lesson.end)
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,9 @@ import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.repositories.note.NoteRepository
|
||||
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
|
||||
import io.github.wulkanowy.sdk.scrapper.notes.NoteCategory
|
||||
import io.github.wulkanowy.sdk.scrapper.notes.NoteCategory.NEUTRAL
|
||||
import io.github.wulkanowy.sdk.scrapper.notes.NoteCategory.POSITIVE
|
||||
import io.github.wulkanowy.services.sync.channels.NewNotesChannel
|
||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||
import io.github.wulkanowy.ui.modules.main.MainView
|
||||
@ -41,8 +44,20 @@ class NoteWork @Inject constructor(
|
||||
|
||||
private fun notify(notes: List<Note>) {
|
||||
notificationManager.notify(Random.nextInt(Int.MAX_VALUE), NotificationCompat.Builder(context, NewNotesChannel.CHANNEL_ID)
|
||||
.setContentTitle(context.resources.getQuantityString(R.plurals.note_new_items, notes.size, notes.size))
|
||||
.setContentText(context.resources.getQuantityString(R.plurals.note_notify_new_items, notes.size, notes.size))
|
||||
.setContentTitle(
|
||||
when (NoteCategory.getByValue(notes.first().categoryType)) {
|
||||
POSITIVE -> context.resources.getQuantityString(R.plurals.praise_new_items, notes.size, notes.size)
|
||||
NEUTRAL -> context.resources.getQuantityString(R.plurals.neutral_note_new_items, notes.size, notes.size)
|
||||
else -> context.resources.getQuantityString(R.plurals.note_new_items, notes.size, notes.size)
|
||||
}
|
||||
)
|
||||
.setContentText(
|
||||
when (NoteCategory.getByValue(notes.first().categoryType)) {
|
||||
POSITIVE -> context.resources.getQuantityString(R.plurals.praise_notify_new_items, notes.size, notes.size)
|
||||
NEUTRAL -> context.resources.getQuantityString(R.plurals.neutral_note_notify_new_items, notes.size, notes.size)
|
||||
else -> context.resources.getQuantityString(R.plurals.note_notify_new_items, notes.size, notes.size)
|
||||
}
|
||||
)
|
||||
.setSmallIcon(R.drawable.ic_stat_note)
|
||||
.setAutoCancel(true)
|
||||
.setDefaults(DEFAULT_ALL)
|
||||
@ -52,7 +67,13 @@ class NoteWork @Inject constructor(
|
||||
PendingIntent.getActivity(context, MainView.Section.NOTE.id,
|
||||
MainActivity.getStartIntent(context, MainView.Section.NOTE, true), FLAG_UPDATE_CURRENT))
|
||||
.setStyle(NotificationCompat.InboxStyle().run {
|
||||
setSummaryText(context.resources.getQuantityString(R.plurals.note_number_item, notes.size, notes.size))
|
||||
setSummaryText(
|
||||
when (NoteCategory.getByValue(notes.first().categoryType)) {
|
||||
POSITIVE -> context.resources.getQuantityString(R.plurals.praise_number_item, notes.size, notes.size)
|
||||
NEUTRAL -> context.resources.getQuantityString(R.plurals.neutral_note_number_item, notes.size, notes.size)
|
||||
else -> context.resources.getQuantityString(R.plurals.note_number_item, notes.size, notes.size)
|
||||
}
|
||||
)
|
||||
notes.forEach { addLine("${it.teacher}: ${it.category}") }
|
||||
this
|
||||
})
|
||||
|
@ -22,9 +22,11 @@ import io.github.wulkanowy.utils.getString
|
||||
import io.github.wulkanowy.utils.openAppInMarket
|
||||
import io.github.wulkanowy.utils.openEmailClient
|
||||
import io.github.wulkanowy.utils.openInternetBrowser
|
||||
import okhttp3.internal.http2.StreamResetException
|
||||
import java.io.InterruptedIOException
|
||||
import java.io.PrintWriter
|
||||
import java.io.StringWriter
|
||||
import java.net.ConnectException
|
||||
import java.net.SocketTimeoutException
|
||||
import java.net.UnknownHostException
|
||||
import javax.inject.Inject
|
||||
@ -85,6 +87,8 @@ class ErrorDialog : BaseDialogFragment<DialogErrorBinding>() {
|
||||
errorDialogReport.isEnabled = when (error) {
|
||||
is UnknownHostException,
|
||||
is InterruptedIOException,
|
||||
is ConnectException,
|
||||
is StreamResetException,
|
||||
is SocketTimeoutException,
|
||||
is ServiceUnavailableException,
|
||||
is FeatureDisabledException,
|
||||
|
@ -4,7 +4,7 @@ import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.AppInfo
|
||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -12,7 +12,7 @@ class AboutPresenter @Inject constructor(
|
||||
errorHandler: ErrorHandler,
|
||||
studentRepository: StudentRepository,
|
||||
private val appInfo: AppInfo,
|
||||
private val analytics: FirebaseAnalyticsHelper
|
||||
private val analytics: AnalyticsHelper
|
||||
) : BasePresenter<AboutView>(errorHandler, studentRepository) {
|
||||
|
||||
override fun onAttachView(view: AboutView) {
|
||||
|
@ -9,7 +9,7 @@ import io.github.wulkanowy.data.repositories.semester.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import io.github.wulkanowy.utils.flowWithResourceIn
|
||||
@ -34,7 +34,7 @@ class AttendancePresenter @Inject constructor(
|
||||
private val attendanceRepository: AttendanceRepository,
|
||||
private val semesterRepository: SemesterRepository,
|
||||
private val prefRepository: PreferencesRepository,
|
||||
private val analytics: FirebaseAnalyticsHelper
|
||||
private val analytics: AnalyticsHelper
|
||||
) : BasePresenter<AttendanceView>(errorHandler, studentRepository) {
|
||||
|
||||
private var baseDate: LocalDate = now().previousOrSameSchoolDay
|
||||
|
@ -8,7 +8,7 @@ import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||
import io.github.wulkanowy.data.repositories.subject.SubjectRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResourceIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
@ -22,7 +22,7 @@ class AttendanceSummaryPresenter @Inject constructor(
|
||||
private val attendanceSummaryRepository: AttendanceSummaryRepository,
|
||||
private val subjectRepository: SubjectRepository,
|
||||
private val semesterRepository: SemesterRepository,
|
||||
private val analytics: FirebaseAnalyticsHelper
|
||||
private val analytics: AnalyticsHelper
|
||||
) : BasePresenter<AttendanceSummaryView>(errorHandler, studentRepository) {
|
||||
|
||||
private var subjects = emptyList<Subject>()
|
||||
|
@ -7,7 +7,7 @@ import io.github.wulkanowy.data.repositories.semester.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResourceIn
|
||||
import io.github.wulkanowy.utils.getLastSchoolDayIfHoliday
|
||||
@ -30,7 +30,7 @@ class ExamPresenter @Inject constructor(
|
||||
studentRepository: StudentRepository,
|
||||
private val examRepository: ExamRepository,
|
||||
private val semesterRepository: SemesterRepository,
|
||||
private val analytics: FirebaseAnalyticsHelper
|
||||
private val analytics: AnalyticsHelper
|
||||
) : BasePresenter<ExamView>(errorHandler, studentRepository) {
|
||||
|
||||
private var baseDate: LocalDate = now().nextOrSameSchoolDay
|
||||
|
@ -6,7 +6,7 @@ import io.github.wulkanowy.data.repositories.semester.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import io.github.wulkanowy.utils.getCurrentOrLast
|
||||
import kotlinx.coroutines.delay
|
||||
@ -18,7 +18,7 @@ class GradePresenter @Inject constructor(
|
||||
errorHandler: ErrorHandler,
|
||||
studentRepository: StudentRepository,
|
||||
private val semesterRepository: SemesterRepository,
|
||||
private val analytics: FirebaseAnalyticsHelper
|
||||
private val analytics: AnalyticsHelper
|
||||
) : BasePresenter<GradeView>(errorHandler, studentRepository) {
|
||||
|
||||
var selectedIndex = 0
|
||||
|
@ -0,0 +1,10 @@
|
||||
package io.github.wulkanowy.ui.modules.grade
|
||||
|
||||
enum class GradeSortingMode(val value: String) {
|
||||
ALPHABETIC("alphabetic"),
|
||||
DATE("date");
|
||||
|
||||
companion object {
|
||||
fun getByValue(value: String) = values().firstOrNull { it.value == value } ?: ALPHABETIC
|
||||
}
|
||||
}
|
@ -40,10 +40,6 @@ class GradeDetailsAdapter @Inject constructor() : BaseExpandableAdapter<Recycler
|
||||
}
|
||||
|
||||
fun updateDetailsItem(position: Int, grade: Grade) {
|
||||
if (items.getOrNull(position)?.viewType != ViewType.ITEM) {
|
||||
Timber.e("Trying to update item $position on list ${items.size} size, expanded position: $expandedPosition")
|
||||
return
|
||||
}
|
||||
items[position] = GradeDetailsItem(grade, ViewType.ITEM)
|
||||
notifyItemChanged(position)
|
||||
}
|
||||
@ -62,10 +58,6 @@ class GradeDetailsAdapter @Inject constructor() : BaseExpandableAdapter<Recycler
|
||||
val headerPosition = headers.indexOf(item)
|
||||
val itemPosition = items.indexOf(item)
|
||||
|
||||
if (headerPosition == NO_POSITION || itemPosition == NO_POSITION) {
|
||||
Timber.e("Invalid update header positions! Header: $headerPosition, item: $itemPosition")
|
||||
}
|
||||
|
||||
headers[headerPosition] = item
|
||||
items[itemPosition] = item
|
||||
notifyItemChanged(itemPosition)
|
||||
|
@ -14,6 +14,7 @@ data class GradeDetailsHeader(
|
||||
val subject: String,
|
||||
val average: Double?,
|
||||
val pointsSum: String?,
|
||||
var newGrades: Int,
|
||||
val grades: List<GradeDetailsItem>
|
||||
)
|
||||
) {
|
||||
var newGrades = 0
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package io.github.wulkanowy.ui.modules.grade.details
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.db.entities.Grade
|
||||
import io.github.wulkanowy.data.repositories.grade.GradeRepository
|
||||
@ -10,7 +11,9 @@ import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.ui.modules.grade.GradeAverageProvider
|
||||
import io.github.wulkanowy.ui.modules.grade.GradeDetailsWithAverage
|
||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||
import io.github.wulkanowy.ui.modules.grade.GradeSortingMode.ALPHABETIC
|
||||
import io.github.wulkanowy.ui.modules.grade.GradeSortingMode.DATE
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import io.github.wulkanowy.utils.flowWithResourceIn
|
||||
@ -26,7 +29,7 @@ class GradeDetailsPresenter @Inject constructor(
|
||||
private val semesterRepository: SemesterRepository,
|
||||
private val preferencesRepository: PreferencesRepository,
|
||||
private val averageProvider: GradeAverageProvider,
|
||||
private val analytics: FirebaseAnalyticsHelper
|
||||
private val analytics: AnalyticsHelper
|
||||
) : BasePresenter<GradeDetailsView>(errorHandler, studentRepository) {
|
||||
|
||||
private var newGradesAmount: Int = 0
|
||||
@ -78,7 +81,10 @@ class GradeDetailsPresenter @Inject constructor(
|
||||
}.onEach {
|
||||
when (it.status) {
|
||||
Status.LOADING -> Timber.i("Select mark grades as read")
|
||||
Status.SUCCESS -> Timber.i("Mark as read result: Success")
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Mark as read result: Success")
|
||||
loadData(currentSemesterId, false)
|
||||
}
|
||||
Status.ERROR -> {
|
||||
Timber.i("Mark as read result: An exception occurred")
|
||||
errorHandler.dispatch(it.error!!)
|
||||
@ -184,10 +190,20 @@ class GradeDetailsPresenter @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
private fun createGradeItems(items: List<GradeDetailsWithAverage>): List<GradeDetailsItem> {
|
||||
return items
|
||||
.filter { it.grades.isNotEmpty() }
|
||||
.sortedBy { it.subject }
|
||||
.let { gradesWithAverages ->
|
||||
if (!preferencesRepository.showSubjectsWithoutGrades) {
|
||||
gradesWithAverages.filter { it.grades.isNotEmpty() }
|
||||
} else gradesWithAverages
|
||||
}
|
||||
.let {
|
||||
when (preferencesRepository.gradeSortingMode) {
|
||||
DATE -> it.sortedByDescending { gradeDetailsWithAverage -> gradeDetailsWithAverage.grades.firstOrNull()?.date }
|
||||
ALPHABETIC -> it.sortedBy { gradeDetailsWithAverage -> gradeDetailsWithAverage.subject.toLowerCase() }
|
||||
}
|
||||
}
|
||||
.map { (subject, average, points, _, grades) ->
|
||||
val subItems = grades
|
||||
.sortedByDescending { it.date }
|
||||
@ -197,9 +213,10 @@ class GradeDetailsPresenter @Inject constructor(
|
||||
subject = subject,
|
||||
average = average,
|
||||
pointsSum = points,
|
||||
newGrades = grades.filter { grade -> !grade.isRead }.size,
|
||||
grades = subItems
|
||||
), ViewType.HEADER)) + if (preferencesRepository.isGradeExpandable) emptyList() else subItems
|
||||
).apply {
|
||||
newGrades = grades.filter { grade -> !grade.isRead }.size
|
||||
}, ViewType.HEADER)) + if (preferencesRepository.isGradeExpandable) emptyList() else subItems
|
||||
}.flatten()
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@ import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||
import io.github.wulkanowy.data.repositories.subject.SubjectRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResourceIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
@ -23,7 +23,7 @@ class GradeStatisticsPresenter @Inject constructor(
|
||||
private val subjectRepository: SubjectRepository,
|
||||
private val semesterRepository: SemesterRepository,
|
||||
private val preferencesRepository: PreferencesRepository,
|
||||
private val analytics: FirebaseAnalyticsHelper
|
||||
private val analytics: AnalyticsHelper
|
||||
) : BasePresenter<GradeStatisticsView>(errorHandler, studentRepository) {
|
||||
|
||||
private var subjects = emptyList<Subject>()
|
||||
|
@ -7,7 +7,7 @@ import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.ui.modules.grade.GradeAverageProvider
|
||||
import io.github.wulkanowy.ui.modules.grade.GradeDetailsWithAverage
|
||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResourceIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
@ -18,7 +18,7 @@ class GradeSummaryPresenter @Inject constructor(
|
||||
errorHandler: ErrorHandler,
|
||||
studentRepository: StudentRepository,
|
||||
private val averageProvider: GradeAverageProvider,
|
||||
private val analytics: FirebaseAnalyticsHelper
|
||||
private val analytics: AnalyticsHelper
|
||||
) : BasePresenter<GradeSummaryView>(errorHandler, studentRepository) {
|
||||
|
||||
private lateinit var lastError: Throwable
|
||||
|
@ -7,7 +7,7 @@ import io.github.wulkanowy.data.repositories.semester.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResourceIn
|
||||
import io.github.wulkanowy.utils.getLastSchoolDayIfHoliday
|
||||
@ -29,7 +29,7 @@ class HomeworkPresenter @Inject constructor(
|
||||
studentRepository: StudentRepository,
|
||||
private val homeworkRepository: HomeworkRepository,
|
||||
private val semesterRepository: SemesterRepository,
|
||||
private val analytics: FirebaseAnalyticsHelper
|
||||
private val analytics: AnalyticsHelper
|
||||
) : BasePresenter<HomeworkView>(errorHandler, studentRepository) {
|
||||
|
||||
private var baseDate: LocalDate = LocalDate.now().nextOrSameSchoolDay
|
||||
|
@ -29,6 +29,8 @@ class HomeworkDetailsAdapter @Inject constructor() :
|
||||
attachments = value?.attachments.orEmpty()
|
||||
}
|
||||
|
||||
var isHomeworkFullscreen = false
|
||||
|
||||
var onAttachmentClickListener: (url: String) -> Unit = {}
|
||||
|
||||
var onFullScreenClickListener = {}
|
||||
@ -67,6 +69,8 @@ class HomeworkDetailsAdapter @Inject constructor() :
|
||||
homeworkDialogSubject.text = homework?.subject
|
||||
homeworkDialogTeacher.text = homework?.teacher
|
||||
homeworkDialogContent.text = homework?.content
|
||||
homeworkDialogFullScreen.visibility = if (isHomeworkFullscreen) GONE else VISIBLE
|
||||
homeworkDialogFullScreenExit.visibility = if (isHomeworkFullscreen) VISIBLE else GONE
|
||||
homeworkDialogFullScreen.setOnClickListener {
|
||||
homeworkDialogFullScreen.visibility = GONE
|
||||
homeworkDialogFullScreenExit.visibility = VISIBLE
|
||||
|
@ -62,12 +62,25 @@ class HomeworkDetailsDialog : BaseDialogFragment<DialogHomeworkBinding>(), Homew
|
||||
homeworkDialogClose.setOnClickListener { dismiss() }
|
||||
}
|
||||
|
||||
if (presenter.isHomeworkFullscreen) {
|
||||
dialog?.window?.setLayout(MATCH_PARENT, MATCH_PARENT)
|
||||
} else {
|
||||
dialog?.window?.setLayout(WRAP_CONTENT, WRAP_CONTENT)
|
||||
}
|
||||
|
||||
with(binding.homeworkDialogRecycler) {
|
||||
layoutManager = LinearLayoutManager(context)
|
||||
adapter = detailsAdapter.apply {
|
||||
onAttachmentClickListener = { context.openInternetBrowser(it, ::showMessage) }
|
||||
onFullScreenClickListener = { dialog?.window?.setLayout(MATCH_PARENT, MATCH_PARENT) }
|
||||
onFullScreenExitClickListener = { dialog?.window?.setLayout(WRAP_CONTENT, WRAP_CONTENT) }
|
||||
onFullScreenClickListener = {
|
||||
dialog?.window?.setLayout(MATCH_PARENT, MATCH_PARENT)
|
||||
presenter.isHomeworkFullscreen = true
|
||||
}
|
||||
onFullScreenExitClickListener = {
|
||||
dialog?.window?.setLayout(WRAP_CONTENT, WRAP_CONTENT)
|
||||
presenter.isHomeworkFullscreen = false
|
||||
}
|
||||
isHomeworkFullscreen = presenter.isHomeworkFullscreen
|
||||
homework = this@HomeworkDetailsDialog.homework
|
||||
}
|
||||
}
|
||||
|
@ -3,10 +3,11 @@ package io.github.wulkanowy.ui.modules.homework.details
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.db.entities.Homework
|
||||
import io.github.wulkanowy.data.repositories.homework.HomeworkRepository
|
||||
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
|
||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import timber.log.Timber
|
||||
@ -16,9 +17,16 @@ class HomeworkDetailsPresenter @Inject constructor(
|
||||
errorHandler: ErrorHandler,
|
||||
studentRepository: StudentRepository,
|
||||
private val homeworkRepository: HomeworkRepository,
|
||||
private val analytics: FirebaseAnalyticsHelper
|
||||
private val analytics: AnalyticsHelper,
|
||||
private val preferencesRepository: PreferencesRepository
|
||||
) : BasePresenter<HomeworkDetailsView>(errorHandler, studentRepository) {
|
||||
|
||||
var isHomeworkFullscreen
|
||||
get() = preferencesRepository.isHomeworkFullscreen
|
||||
set(value) {
|
||||
preferencesRepository.isHomeworkFullscreen = value
|
||||
}
|
||||
|
||||
override fun onAttachView(view: HomeworkDetailsView) {
|
||||
super.onAttachView(view)
|
||||
view.initView()
|
||||
|
@ -14,6 +14,7 @@ import io.github.wulkanowy.ui.modules.login.form.LoginFormFragment
|
||||
import io.github.wulkanowy.ui.modules.login.recover.LoginRecoverFragment
|
||||
import io.github.wulkanowy.ui.modules.login.studentselect.LoginStudentSelectFragment
|
||||
import io.github.wulkanowy.ui.modules.login.symbol.LoginSymbolFragment
|
||||
import io.github.wulkanowy.utils.UpdateHelper
|
||||
import io.github.wulkanowy.utils.setOnSelectPageListener
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -25,6 +26,9 @@ class LoginActivity : BaseActivity<LoginPresenter, ActivityLoginBinding>(), Logi
|
||||
|
||||
private val loginAdapter = BaseFragmentPagerAdapter(supportFragmentManager)
|
||||
|
||||
@Inject
|
||||
lateinit var updateHelper: UpdateHelper
|
||||
|
||||
companion object {
|
||||
|
||||
fun getStartIntent(context: Context) = Intent(context, LoginActivity::class.java)
|
||||
@ -37,8 +41,20 @@ class LoginActivity : BaseActivity<LoginPresenter, ActivityLoginBinding>(), Logi
|
||||
setContentView(ActivityLoginBinding.inflate(layoutInflater).apply { binding = this }.root)
|
||||
setSupportActionBar(binding.loginToolbar)
|
||||
messageContainer = binding.loginContainer
|
||||
updateHelper.messageContainer = binding.loginContainer
|
||||
|
||||
presenter.onAttachView(this)
|
||||
updateHelper.checkAndInstallUpdates(this)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
updateHelper.onResume(this)
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
updateHelper.onActivityResult(requestCode, resultCode)
|
||||
}
|
||||
|
||||
override fun initView() {
|
||||
|
@ -6,7 +6,7 @@ import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
|
||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import io.github.wulkanowy.utils.ifNullOrBlank
|
||||
@ -17,7 +17,7 @@ import javax.inject.Inject
|
||||
class LoginAdvancedPresenter @Inject constructor(
|
||||
studentRepository: StudentRepository,
|
||||
private val loginErrorHandler: LoginErrorHandler,
|
||||
private val analytics: FirebaseAnalyticsHelper
|
||||
private val analytics: AnalyticsHelper
|
||||
) : BasePresenter<LoginAdvancedView>(loginErrorHandler, studentRepository) {
|
||||
|
||||
override fun onAttachView(view: LoginAdvancedView) {
|
||||
|
@ -4,7 +4,7 @@ import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
|
||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import io.github.wulkanowy.utils.ifNullOrBlank
|
||||
@ -15,7 +15,7 @@ import javax.inject.Inject
|
||||
class LoginFormPresenter @Inject constructor(
|
||||
studentRepository: StudentRepository,
|
||||
private val loginErrorHandler: LoginErrorHandler,
|
||||
private val analytics: FirebaseAnalyticsHelper
|
||||
private val analytics: AnalyticsHelper
|
||||
) : BasePresenter<LoginFormView>(loginErrorHandler, studentRepository) {
|
||||
|
||||
private var lastError: Throwable? = null
|
||||
|
@ -4,7 +4,7 @@ import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.repositories.recover.RecoverRepository
|
||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import io.github.wulkanowy.utils.ifNullOrBlank
|
||||
@ -15,7 +15,7 @@ import javax.inject.Inject
|
||||
class LoginRecoverPresenter @Inject constructor(
|
||||
studentRepository: StudentRepository,
|
||||
private val loginErrorHandler: RecoverErrorHandler,
|
||||
private val analytics: FirebaseAnalyticsHelper,
|
||||
private val analytics: AnalyticsHelper,
|
||||
private val recoverRepository: RecoverRepository
|
||||
) : BasePresenter<LoginRecoverView>(loginErrorHandler, studentRepository) {
|
||||
|
||||
|
@ -6,7 +6,7 @@ import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
|
||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import io.github.wulkanowy.utils.ifNullOrBlank
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
@ -17,7 +17,7 @@ import javax.inject.Inject
|
||||
class LoginStudentSelectPresenter @Inject constructor(
|
||||
studentRepository: StudentRepository,
|
||||
private val loginErrorHandler: LoginErrorHandler,
|
||||
private val analytics: FirebaseAnalyticsHelper
|
||||
private val analytics: AnalyticsHelper
|
||||
) : BasePresenter<LoginStudentSelectView>(loginErrorHandler, studentRepository) {
|
||||
|
||||
private var lastError: Throwable? = null
|
||||
|
@ -4,7 +4,7 @@ import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
|
||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import io.github.wulkanowy.utils.ifNullOrBlank
|
||||
@ -16,7 +16,7 @@ import javax.inject.Inject
|
||||
class LoginSymbolPresenter @Inject constructor(
|
||||
studentRepository: StudentRepository,
|
||||
private val loginErrorHandler: LoginErrorHandler,
|
||||
private val analytics: FirebaseAnalyticsHelper
|
||||
private val analytics: AnalyticsHelper
|
||||
) : BasePresenter<LoginSymbolView>(loginErrorHandler, studentRepository) {
|
||||
|
||||
private var lastError: Throwable? = null
|
||||
|
@ -5,7 +5,7 @@ import io.github.wulkanowy.data.repositories.luckynumber.LuckyNumberRepository
|
||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResourceIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
@ -16,7 +16,7 @@ class LuckyNumberPresenter @Inject constructor(
|
||||
errorHandler: ErrorHandler,
|
||||
studentRepository: StudentRepository,
|
||||
private val luckyNumberRepository: LuckyNumberRepository,
|
||||
private val analytics: FirebaseAnalyticsHelper
|
||||
private val analytics: AnalyticsHelper
|
||||
) : BasePresenter<LuckyNumberView>(errorHandler, studentRepository) {
|
||||
|
||||
private lateinit var lastError: Throwable
|
||||
|
@ -1,14 +1,21 @@
|
||||
package io.github.wulkanowy.ui.modules.main
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
import android.content.pm.ShortcutInfo
|
||||
import android.content.pm.ShortcutManager
|
||||
import android.graphics.drawable.Icon
|
||||
import android.os.Build
|
||||
import android.os.Build.VERSION.SDK_INT
|
||||
import android.os.Build.VERSION_CODES.LOLLIPOP
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.fragment.app.Fragment
|
||||
@ -31,7 +38,9 @@ import io.github.wulkanowy.ui.modules.message.MessageFragment
|
||||
import io.github.wulkanowy.ui.modules.more.MoreFragment
|
||||
import io.github.wulkanowy.ui.modules.note.NoteFragment
|
||||
import io.github.wulkanowy.ui.modules.timetable.TimetableFragment
|
||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||
import io.github.wulkanowy.utils.AppInfo
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.UpdateHelper
|
||||
import io.github.wulkanowy.utils.dpToPx
|
||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||
import io.github.wulkanowy.utils.safelyPopFragments
|
||||
@ -46,7 +55,13 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
||||
override lateinit var presenter: MainPresenter
|
||||
|
||||
@Inject
|
||||
lateinit var analytics: FirebaseAnalyticsHelper
|
||||
lateinit var analytics: AnalyticsHelper
|
||||
|
||||
@Inject
|
||||
lateinit var updateHelper: UpdateHelper
|
||||
|
||||
@Inject
|
||||
lateinit var appInfo: AppInfo
|
||||
|
||||
private val overlayProvider by lazy { ElevationOverlayProvider(this) }
|
||||
|
||||
@ -59,7 +74,7 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
||||
return Intent(context, MainActivity::class.java)
|
||||
.apply {
|
||||
if (clear) flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_CLEAR_TASK
|
||||
startMenu?.let { putExtra(EXTRA_START_MENU, it) }
|
||||
startMenu?.let { putExtra(EXTRA_START_MENU, it.id) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -83,18 +98,58 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
||||
MainView.Section.LUCKY_NUMBER.id to LuckyNumberFragment.newInstance()
|
||||
)
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(ActivityMainBinding.inflate(layoutInflater).apply { binding = this }.root)
|
||||
setSupportActionBar(binding.mainToolbar)
|
||||
messageContainer = binding.mainFragmentContainer
|
||||
updateHelper.messageContainer = binding.mainFragmentContainer
|
||||
|
||||
presenter.onAttachView(this, intent.getSerializableExtra(EXTRA_START_MENU) as? MainView.Section)
|
||||
presenter.onAttachView(this, MainView.Section.values().singleOrNull { it.id == intent.getIntExtra(EXTRA_START_MENU, -1) })
|
||||
|
||||
with(navController) {
|
||||
initialize(startMenuIndex, savedInstanceState)
|
||||
pushFragment(moreMenuFragments[startMenuMoreIndex])
|
||||
}
|
||||
updateHelper.checkAndInstallUpdates(this)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
updateHelper.onResume(this)
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
updateHelper.onActivityResult(requestCode, resultCode)
|
||||
if (appInfo.systemVersion >= Build.VERSION_CODES.N_MR1) initShortcuts()
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.N_MR1)
|
||||
fun initShortcuts() {
|
||||
val shortcutsList = mutableListOf<ShortcutInfo>()
|
||||
|
||||
listOf(
|
||||
Triple(getString(R.string.grade_title), R.drawable.ic_shortcut_grade, MainView.Section.GRADE),
|
||||
Triple(getString(R.string.attendance_title), R.drawable.ic_shortcut_attendance, MainView.Section.ATTENDANCE),
|
||||
Triple(getString(R.string.exam_title), R.drawable.ic_shortcut_exam, MainView.Section.EXAM),
|
||||
Triple(getString(R.string.timetable_title), R.drawable.ic_shortcut_timetable, MainView.Section.TIMETABLE),
|
||||
Triple(getString(R.string.message_title), R.drawable.ic_shortcut_message, MainView.Section.MESSAGE)
|
||||
).forEach { (title, icon, enum) ->
|
||||
shortcutsList.add(ShortcutInfo.Builder(applicationContext, title)
|
||||
.setShortLabel(title)
|
||||
.setLongLabel(title)
|
||||
.setIcon(Icon.createWithResource(applicationContext, icon))
|
||||
.setIntents(arrayOf(
|
||||
Intent(applicationContext, MainActivity::class.java).setAction(Intent.ACTION_VIEW),
|
||||
Intent(applicationContext, MainActivity::class.java).putExtra(EXTRA_START_MENU, enum.id)
|
||||
.setAction(Intent.ACTION_VIEW).addFlags(FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_CLEAR_TASK)))
|
||||
.build())
|
||||
}
|
||||
|
||||
getSystemService<ShortcutManager>()?.dynamicShortcuts = shortcutsList
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
||||
@ -143,8 +198,8 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
||||
analytics.setCurrentScreen(this, name)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
|
||||
return if (item?.itemId == R.id.mainMenuAccount) presenter.onAccountManagerSelected()
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return if (item.itemId == R.id.mainMenuAccount) presenter.onAccountManagerSelected()
|
||||
else false
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@ import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.ui.modules.main.MainView.Section.GRADE
|
||||
import io.github.wulkanowy.ui.modules.main.MainView.Section.MESSAGE
|
||||
import io.github.wulkanowy.ui.modules.main.MainView.Section.SCHOOL
|
||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -17,7 +17,7 @@ class MainPresenter @Inject constructor(
|
||||
studentRepository: StudentRepository,
|
||||
private val prefRepository: PreferencesRepository,
|
||||
private val syncManager: SyncManager,
|
||||
private val analytics: FirebaseAnalyticsHelper
|
||||
private val analytics: AnalyticsHelper
|
||||
) : BasePresenter<MainView>(errorHandler, studentRepository) {
|
||||
|
||||
fun onAttachView(view: MainView, initMenu: MainView.Section?) {
|
||||
|
@ -174,7 +174,7 @@ class MessagePreviewFragment :
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
override fun printDocument(html: String, jobName: String) {
|
||||
val webView = WebView(activity)
|
||||
val webView = WebView(requireContext())
|
||||
webView.webViewClient = object : WebViewClient() {
|
||||
|
||||
override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest) = false
|
||||
|
@ -11,7 +11,7 @@ import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.AppInfo
|
||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import io.github.wulkanowy.utils.flowWithResourceIn
|
||||
@ -24,7 +24,7 @@ class MessagePreviewPresenter @Inject constructor(
|
||||
errorHandler: ErrorHandler,
|
||||
studentRepository: StudentRepository,
|
||||
private val messageRepository: MessageRepository,
|
||||
private val analytics: FirebaseAnalyticsHelper,
|
||||
private val analytics: AnalyticsHelper,
|
||||
private var appInfo: AppInfo
|
||||
) : BasePresenter<MessagePreviewView>(errorHandler, studentRepository) {
|
||||
|
||||
@ -64,7 +64,8 @@ class MessagePreviewPresenter @Inject constructor(
|
||||
when (it.status) {
|
||||
Status.LOADING -> Timber.i("Loading message ${message.messageId} preview started")
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Loading message ${it.data!!.message.messageId} preview result: Success ")
|
||||
Timber.i("Loading message ${message.messageId} preview result: Success ")
|
||||
checkNotNull(it.data, { "Can't find message in local db! Probably no longer exist in this folder" })
|
||||
this@MessagePreviewPresenter.message = it.data.message
|
||||
this@MessagePreviewPresenter.attachments = it.data.attachments
|
||||
view?.apply {
|
||||
@ -194,6 +195,7 @@ class MessagePreviewPresenter @Inject constructor(
|
||||
view?.run {
|
||||
lastError = error
|
||||
setErrorDetails(message)
|
||||
showContent(false)
|
||||
showErrorView(true)
|
||||
setErrorRetryCallback { retryCallback() }
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package io.github.wulkanowy.ui.modules.message.send
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Rect
|
||||
@ -74,6 +75,7 @@ class SendMessageActivity : BaseActivity<SendMessagePresenter, ActivitySendMessa
|
||||
presenter.onAttachView(this, intent.getSerializableExtra(EXTRA_MESSAGE) as? Message, intent.getSerializableExtra(EXTRA_REPLY) as? Boolean)
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
override fun initView() {
|
||||
setUpExtendedHitArea()
|
||||
with(binding) {
|
||||
@ -87,8 +89,8 @@ class SendMessageActivity : BaseActivity<SendMessagePresenter, ActivitySendMessa
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
|
||||
return if (item?.itemId == R.id.sendMessageMenuSend) presenter.onSend()
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return if (item.itemId == R.id.sendMessageMenuSend) presenter.onSend()
|
||||
else false
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@ import io.github.wulkanowy.data.repositories.semester.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
@ -27,7 +27,7 @@ class SendMessagePresenter @Inject constructor(
|
||||
private val reportingUnitRepository: ReportingUnitRepository,
|
||||
private val recipientRepository: RecipientRepository,
|
||||
private val preferencesRepository: PreferencesRepository,
|
||||
private val analytics: FirebaseAnalyticsHelper
|
||||
private val analytics: AnalyticsHelper
|
||||
) : BasePresenter<SendMessageView>(errorHandler, studentRepository) {
|
||||
|
||||
fun onAttachView(view: SendMessageView, message: Message?, reply: Boolean?) {
|
||||
|
@ -8,7 +8,7 @@ import io.github.wulkanowy.data.repositories.semester.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResourceIn
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
@ -32,7 +32,7 @@ class MessageTabPresenter @Inject constructor(
|
||||
studentRepository: StudentRepository,
|
||||
private val messageRepository: MessageRepository,
|
||||
private val semesterRepository: SemesterRepository,
|
||||
private val analytics: FirebaseAnalyticsHelper
|
||||
private val analytics: AnalyticsHelper
|
||||
) : BasePresenter<MessageTabView>(errorHandler, studentRepository) {
|
||||
|
||||
lateinit var folder: MessageFolder
|
||||
|
@ -7,7 +7,7 @@ import io.github.wulkanowy.data.repositories.semester.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import io.github.wulkanowy.utils.flowWithResourceIn
|
||||
@ -21,7 +21,7 @@ class MobileDevicePresenter @Inject constructor(
|
||||
studentRepository: StudentRepository,
|
||||
private val semesterRepository: SemesterRepository,
|
||||
private val mobileDeviceRepository: MobileDeviceRepository,
|
||||
private val analytics: FirebaseAnalyticsHelper
|
||||
private val analytics: AnalyticsHelper
|
||||
) : BasePresenter<MobileDeviceView>(errorHandler, studentRepository) {
|
||||
|
||||
private lateinit var lastError: Throwable
|
||||
|
@ -6,7 +6,7 @@ import io.github.wulkanowy.data.repositories.semester.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
@ -18,7 +18,7 @@ class MobileDeviceTokenPresenter @Inject constructor(
|
||||
studentRepository: StudentRepository,
|
||||
private val semesterRepository: SemesterRepository,
|
||||
private val mobileDeviceRepository: MobileDeviceRepository,
|
||||
private val analytics: FirebaseAnalyticsHelper
|
||||
private val analytics: AnalyticsHelper
|
||||
) : BasePresenter<MobileDeviceTokenVIew>(errorHandler, studentRepository) {
|
||||
|
||||
override fun onAttachView(view: MobileDeviceTokenVIew) {
|
||||
|
@ -7,7 +7,7 @@ import io.github.wulkanowy.data.repositories.semester.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResource
|
||||
import io.github.wulkanowy.utils.flowWithResourceIn
|
||||
@ -21,7 +21,7 @@ class NotePresenter @Inject constructor(
|
||||
studentRepository: StudentRepository,
|
||||
private val noteRepository: NoteRepository,
|
||||
private val semesterRepository: SemesterRepository,
|
||||
private val analytics: FirebaseAnalyticsHelper
|
||||
private val analytics: AnalyticsHelper
|
||||
) : BasePresenter<NoteView>(errorHandler, studentRepository) {
|
||||
|
||||
private lateinit var lastError: Throwable
|
||||
|
@ -6,7 +6,7 @@ import io.github.wulkanowy.data.repositories.semester.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResourceIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
@ -18,7 +18,7 @@ class SchoolPresenter @Inject constructor(
|
||||
studentRepository: StudentRepository,
|
||||
private val semesterRepository: SemesterRepository,
|
||||
private val schoolRepository: SchoolRepository,
|
||||
private val analytics: FirebaseAnalyticsHelper
|
||||
private val analytics: AnalyticsHelper
|
||||
) : BasePresenter<SchoolView>(errorHandler, studentRepository) {
|
||||
|
||||
private var address: String? = null
|
||||
|
@ -6,7 +6,7 @@ import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||
import io.github.wulkanowy.data.repositories.teacher.TeacherRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResourceIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
@ -18,7 +18,7 @@ class TeacherPresenter @Inject constructor(
|
||||
studentRepository: StudentRepository,
|
||||
private val semesterRepository: SemesterRepository,
|
||||
private val teacherRepository: TeacherRepository,
|
||||
private val analytics: FirebaseAnalyticsHelper
|
||||
private val analytics: AnalyticsHelper
|
||||
) : BasePresenter<TeacherView>(errorHandler, studentRepository) {
|
||||
|
||||
private lateinit var lastError: Throwable
|
||||
|
@ -9,7 +9,7 @@ import io.github.wulkanowy.services.sync.SyncManager
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.AppInfo
|
||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.isHolidays
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
@ -22,7 +22,7 @@ class SettingsPresenter @Inject constructor(
|
||||
studentRepository: StudentRepository,
|
||||
private val preferencesRepository: PreferencesRepository,
|
||||
private val timetableNotificationHelper: TimetableNotificationSchedulerHelper,
|
||||
private val analytics: FirebaseAnalyticsHelper,
|
||||
private val analytics: AnalyticsHelper,
|
||||
private val syncManager: SyncManager,
|
||||
private val chuckerCollector: ChuckerCollector,
|
||||
private val appInfo: AppInfo
|
||||
|
@ -41,6 +41,8 @@ class TimetableAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
||||
|
||||
var showWholeClassPlan: String = "no"
|
||||
|
||||
var showGroupsInPlan: Boolean = false
|
||||
|
||||
var showTimers: Boolean = false
|
||||
|
||||
private val timers = mutableMapOf<Int, Timer>()
|
||||
@ -99,6 +101,7 @@ class TimetableAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
||||
with(binding) {
|
||||
timetableItemNumber.text = lesson.number.toString()
|
||||
timetableItemSubject.text = lesson.subject
|
||||
timetableItemGroup.text = lesson.group
|
||||
timetableItemRoom.text = lesson.room
|
||||
timetableItemTeacher.text = lesson.teacher
|
||||
timetableItemTimeStart.text = lesson.start.toFormattedString("HH:mm")
|
||||
@ -218,6 +221,7 @@ class TimetableAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
||||
timetableItemDescription.text = lesson.info
|
||||
|
||||
timetableItemRoom.visibility = GONE
|
||||
timetableItemGroup.visibility = GONE
|
||||
timetableItemTeacher.visibility = GONE
|
||||
|
||||
timetableItemDescription.setTextColor(root.context.getThemeAttrColor(
|
||||
@ -227,6 +231,7 @@ class TimetableAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
||||
} else {
|
||||
timetableItemDescription.visibility = GONE
|
||||
timetableItemRoom.visibility = VISIBLE
|
||||
timetableItemGroup.visibility = if (showGroupsInPlan && lesson.group.isNotBlank()) VISIBLE else GONE
|
||||
timetableItemTeacher.visibility = VISIBLE
|
||||
}
|
||||
}
|
||||
|
@ -88,11 +88,12 @@ class TimetableFragment : BaseFragment<FragmentTimetableBinding>(R.layout.fragme
|
||||
else false
|
||||
}
|
||||
|
||||
override fun updateData(data: List<Timetable>, showWholeClassPlanType: String, showTimetableTimers: Boolean) {
|
||||
override fun updateData(data: List<Timetable>, showWholeClassPlanType: String, showGroupsInPlanType: Boolean, showTimetableTimers: Boolean) {
|
||||
with(timetableAdapter) {
|
||||
items = data.toMutableList()
|
||||
showTimers = showTimetableTimers
|
||||
showWholeClassPlan = showWholeClassPlanType
|
||||
showGroupsInPlan = showGroupsInPlanType
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||
import io.github.wulkanowy.data.repositories.timetable.TimetableRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResourceIn
|
||||
import io.github.wulkanowy.utils.getLastSchoolDayIfHoliday
|
||||
@ -22,7 +22,6 @@ import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import timber.log.Timber
|
||||
import java.lang.NullPointerException
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalDate.now
|
||||
import java.time.LocalDate.of
|
||||
@ -35,7 +34,7 @@ class TimetablePresenter @Inject constructor(
|
||||
private val timetableRepository: TimetableRepository,
|
||||
private val semesterRepository: SemesterRepository,
|
||||
private val prefRepository: PreferencesRepository,
|
||||
private val analytics: FirebaseAnalyticsHelper
|
||||
private val analytics: AnalyticsHelper
|
||||
) : BasePresenter<TimetableView>(errorHandler, studentRepository) {
|
||||
|
||||
private var baseDate: LocalDate = now().nextOrSameSchoolDay
|
||||
@ -143,6 +142,7 @@ class TimetablePresenter @Inject constructor(
|
||||
view?.apply {
|
||||
updateData(
|
||||
showWholeClassPlanType = prefRepository.showWholeClassPlan,
|
||||
showGroupsInPlanType = prefRepository.showGroupsInPlan,
|
||||
showTimetableTimers = prefRepository.showTimetableTimers,
|
||||
data = it.data!!
|
||||
.filter { item -> if (prefRepository.showWholeClassPlan == "no") item.isStudentPlan else true }
|
||||
|
@ -12,7 +12,7 @@ interface TimetableView : BaseView {
|
||||
|
||||
fun initView()
|
||||
|
||||
fun updateData(data: List<Timetable>, showWholeClassPlanType: String, showTimetableTimers: Boolean)
|
||||
fun updateData(data: List<Timetable>, showWholeClassPlanType: String, showGroupsInPlanType: Boolean, showTimetableTimers: Boolean)
|
||||
|
||||
fun updateNavigationDay(date: String)
|
||||
|
||||
|
@ -7,7 +7,7 @@ import io.github.wulkanowy.data.repositories.completedlessons.CompletedLessonsRe
|
||||
import io.github.wulkanowy.data.repositories.semester.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.afterLoading
|
||||
import io.github.wulkanowy.utils.flowWithResourceIn
|
||||
import io.github.wulkanowy.utils.getLastSchoolDayIfHoliday
|
||||
@ -30,7 +30,7 @@ class CompletedLessonsPresenter @Inject constructor(
|
||||
private val completedLessonsErrorHandler: CompletedLessonsErrorHandler,
|
||||
private val semesterRepository: SemesterRepository,
|
||||
private val completedLessonsRepository: CompletedLessonsRepository,
|
||||
private val analytics: FirebaseAnalyticsHelper
|
||||
private val analytics: AnalyticsHelper
|
||||
) : BasePresenter<CompletedLessonsView>(completedLessonsErrorHandler, studentRepository) {
|
||||
|
||||
private var baseDate: LocalDate = now().nextOrSameSchoolDay
|
||||
|
@ -24,7 +24,7 @@ import io.github.wulkanowy.services.HiltBroadcastReceiver
|
||||
import io.github.wulkanowy.services.widgets.TimetableWidgetService
|
||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||
import io.github.wulkanowy.ui.modules.main.MainView
|
||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.nextOrSameSchoolDay
|
||||
import io.github.wulkanowy.utils.nextSchoolDay
|
||||
import io.github.wulkanowy.utils.previousSchoolDay
|
||||
@ -49,7 +49,7 @@ class TimetableWidgetProvider : HiltBroadcastReceiver() {
|
||||
lateinit var sharedPref: SharedPrefProvider
|
||||
|
||||
@Inject
|
||||
lateinit var analytics: FirebaseAnalyticsHelper
|
||||
lateinit var analytics: AnalyticsHelper
|
||||
|
||||
companion object {
|
||||
|
||||
|
@ -80,17 +80,13 @@ fun <T> flowWithResource(block: suspend () -> T) = flow {
|
||||
fun <T> flowWithResourceIn(block: suspend () -> Flow<Resource<T>>) = flow {
|
||||
emit(Resource.loading())
|
||||
|
||||
try {
|
||||
block()
|
||||
.catch { emit(Resource.error(it)) }
|
||||
.collect {
|
||||
if (it.status != Status.LOADING) { // LOADING is already emitted
|
||||
emit(it)
|
||||
}
|
||||
block()
|
||||
.catch { emit(Resource.error(it)) }
|
||||
.collect {
|
||||
if (it.status != Status.LOADING) { // LOADING is already emitted
|
||||
emit(it)
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
emit(Resource.error<T>(e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> Flow<Resource<T>>.afterLoading(callback: () -> Unit) = onEach {
|
||||
|
@ -22,32 +22,32 @@ private fun Bundle?.checkSavedState() = if (this == null) "(STATE IS NULL)" else
|
||||
|
||||
class ActivityLifecycleLogger : Application.ActivityLifecycleCallbacks {
|
||||
|
||||
override fun onActivityPaused(activity: Activity?) {
|
||||
activity?.let { Timber.d("${it::class.java.simpleName} PAUSED") }
|
||||
override fun onActivityPaused(activity: Activity) {
|
||||
Timber.d("${activity::class.java.simpleName} PAUSED")
|
||||
}
|
||||
|
||||
override fun onActivityResumed(activity: Activity?) {
|
||||
activity?.let { Timber.d("${it::class.java.simpleName} RESUMED") }
|
||||
override fun onActivityResumed(activity: Activity) {
|
||||
Timber.d("${activity::class.java.simpleName} RESUMED")
|
||||
}
|
||||
|
||||
override fun onActivityStarted(activity: Activity?) {
|
||||
activity?.let { Timber.d("${it::class.java.simpleName} STARTED") }
|
||||
override fun onActivityStarted(activity: Activity) {
|
||||
Timber.d("${activity::class.java.simpleName} STARTED")
|
||||
}
|
||||
|
||||
override fun onActivityDestroyed(activity: Activity?) {
|
||||
activity?.let { Timber.d("${it::class.java.simpleName} DESTROYED") }
|
||||
override fun onActivityDestroyed(activity: Activity) {
|
||||
Timber.d("${activity::class.java.simpleName} DESTROYED")
|
||||
}
|
||||
|
||||
override fun onActivitySaveInstanceState(activity: Activity?, outState: Bundle?) {
|
||||
activity?.let { Timber.d("${it::class.java.simpleName} SAVED INSTANCE STATE") }
|
||||
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
|
||||
Timber.d("${activity::class.java.simpleName} SAVED INSTANCE STATE")
|
||||
}
|
||||
|
||||
override fun onActivityStopped(activity: Activity?) {
|
||||
activity?.let { Timber.d("${it::class.java.simpleName} STOPPED") }
|
||||
override fun onActivityStopped(activity: Activity) {
|
||||
Timber.d("${activity::class.java.simpleName} STOPPED")
|
||||
}
|
||||
|
||||
override fun onActivityCreated(activity: Activity?, savedInstanceState: Bundle?) {
|
||||
activity?.let { Timber.d("${it::class.java.simpleName} CREATED ${savedInstanceState.checkSavedState()}") }
|
||||
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
|
||||
Timber.d("${activity::class.java.simpleName} CREATED ${savedInstanceState.checkSavedState()}")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,20 +4,26 @@ import android.content.res.Resources
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.sdk.exception.FeatureNotAvailableException
|
||||
import io.github.wulkanowy.sdk.scrapper.exception.FeatureDisabledException
|
||||
import io.github.wulkanowy.sdk.scrapper.exception.ScrapperException
|
||||
import io.github.wulkanowy.sdk.scrapper.exception.ServiceUnavailableException
|
||||
import io.github.wulkanowy.sdk.scrapper.exception.VulcanException
|
||||
import io.github.wulkanowy.sdk.scrapper.login.NotLoggedInException
|
||||
import io.github.wulkanowy.sdk.scrapper.login.PasswordChangeRequiredException
|
||||
import okhttp3.internal.http2.StreamResetException
|
||||
import java.io.InterruptedIOException
|
||||
import java.net.ConnectException
|
||||
import java.net.SocketTimeoutException
|
||||
import java.net.UnknownHostException
|
||||
|
||||
fun Resources.getString(error: Throwable) = when (error) {
|
||||
is UnknownHostException -> getString(R.string.error_no_internet)
|
||||
is SocketTimeoutException, is InterruptedIOException -> getString(R.string.error_timeout)
|
||||
is SocketTimeoutException, is InterruptedIOException, is ConnectException, is StreamResetException -> getString(R.string.error_timeout)
|
||||
is NotLoggedInException -> getString(R.string.error_login_failed)
|
||||
is PasswordChangeRequiredException -> getString(R.string.error_password_change_required)
|
||||
is ServiceUnavailableException -> getString(R.string.error_service_unavailable)
|
||||
is FeatureDisabledException -> getString(R.string.error_feature_disabled)
|
||||
is FeatureNotAvailableException -> getString(R.string.error_feature_not_available)
|
||||
is VulcanException -> getString(R.string.error_unknown_uonet)
|
||||
is ScrapperException -> getString(R.string.error_unknown_app)
|
||||
else -> getString(R.string.error_unknown)
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
Wersja 0.20.4
|
||||
- dodaliśmy obsługę koszalińskiego dziennika
|
||||
- poprawiliśmy synchronizację sprawdzianów
|
||||
- wyłączyliśmy dźwięk powiadomienia przy włączonej opcji pokazywania nadchodzących lekcji w powiadomieniu
|
||||
- poprawiliśmy problemy ze stabilnością we frekwencji i planie lekcji
|
||||
Wersja 0.22.2
|
||||
- naprawiliśmy problem z wyświetlaniem pozycji na liście ocen
|
||||
- zmieniliśmy komunikaty o błędach, które powinny być teraz czytelniejsze dla większej liczby użytkowników
|
||||
- zwiększyliśmy maksymalny czas, przez który aplikacja będzie próbowała łączyć się z dziennikiem do 1 minuty
|
||||
|
||||
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases
|
||||
|
BIN
app/src/main/res/drawable-hdpi/ic_shortcut_attendance.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
app/src/main/res/drawable-hdpi/ic_shortcut_exam.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
app/src/main/res/drawable-hdpi/ic_shortcut_grade.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
app/src/main/res/drawable-hdpi/ic_shortcut_message.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
app/src/main/res/drawable-hdpi/ic_shortcut_timetable.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
app/src/main/res/drawable-mdpi/ic_shortcut_attendance.png
Normal file
After Width: | Height: | Size: 902 B |
BIN
app/src/main/res/drawable-mdpi/ic_shortcut_exam.png
Normal file
After Width: | Height: | Size: 913 B |
BIN
app/src/main/res/drawable-mdpi/ic_shortcut_grade.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
app/src/main/res/drawable-mdpi/ic_shortcut_message.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
app/src/main/res/drawable-mdpi/ic_shortcut_timetable.png
Normal file
After Width: | Height: | Size: 937 B |
BIN
app/src/main/res/drawable-xhdpi/ic_shortcut_attendance.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
app/src/main/res/drawable-xhdpi/ic_shortcut_exam.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
app/src/main/res/drawable-xhdpi/ic_shortcut_grade.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
app/src/main/res/drawable-xhdpi/ic_shortcut_message.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
app/src/main/res/drawable-xhdpi/ic_shortcut_timetable.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
app/src/main/res/drawable-xxhdpi/ic_shortcut_attendance.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
app/src/main/res/drawable-xxhdpi/ic_shortcut_exam.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
app/src/main/res/drawable-xxhdpi/ic_shortcut_grade.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
app/src/main/res/drawable-xxhdpi/ic_shortcut_message.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
app/src/main/res/drawable-xxhdpi/ic_shortcut_timetable.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/ic_shortcut_attendance.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/ic_shortcut_exam.png
Normal file
After Width: | Height: | Size: 4.9 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/ic_shortcut_grade.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/ic_shortcut_message.png
Normal file
After Width: | Height: | Size: 5.9 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/ic_shortcut_timetable.png
Normal file
After Width: | Height: | Size: 5.0 KiB |
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/mainContainer"
|
||||
android:layout_width="match_parent"
|
||||
@ -10,18 +10,19 @@
|
||||
style="@style/Widget.MaterialComponents.Toolbar.Surface"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:contentInsetStartWithNavigation="0dp" />
|
||||
app:contentInsetStartWithNavigation="0dp"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/mainFragmentContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="?actionBarSize"
|
||||
android:layout_marginBottom="@dimen/bottom_navigation_height" />
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toTopOf="@id/mainBottomNav"
|
||||
app:layout_constraintTop_toBottomOf="@id/mainToolbar" />
|
||||
|
||||
<com.aurelhubert.ahbottomnavigation.AHBottomNavigation
|
||||
android:id="@+id/mainBottomNav"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom" />
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|