Compare commits
28 Commits
Author | SHA1 | Date | |
---|---|---|---|
a191f03cdf | |||
63404b8576 | |||
1b7760ff88 | |||
24f58835e7 | |||
b032c459d1 | |||
df0a1e59cc | |||
dbbc8069b1 | |||
f84040109c | |||
baf1420193 | |||
4a36d78709 | |||
4464812651 | |||
72a35481e5 | |||
017c200115 | |||
2bf7755157 | |||
269af4b7ba | |||
7431738366 | |||
034b99c7ab | |||
74e98e4430 | |||
cbf3215dd1 | |||
c18877466f | |||
6cd6cae1e0 | |||
333f7bfa16 | |||
aa6dcaff94 | |||
2bff468e56 | |||
f2855d598d | |||
1ebc296bfe | |||
a2a18e5652 | |||
cd1ceea860 |
@ -7,11 +7,11 @@ references:
|
|||||||
|
|
||||||
container_config: &container_config
|
container_config: &container_config
|
||||||
docker:
|
docker:
|
||||||
- image: circleci/android:api-28-alpha
|
- image: circleci/android:api-28
|
||||||
working_directory: *workspace_root
|
working_directory: *workspace_root
|
||||||
environment:
|
environment:
|
||||||
environment:
|
environment:
|
||||||
JVM_OPTS: -Xmx3200m
|
_JAVA_OPTS: -Xmx3072m
|
||||||
|
|
||||||
attach_workspace: &attach_workspace
|
attach_workspace: &attach_workspace
|
||||||
attach_workspace:
|
attach_workspace:
|
||||||
|
25
.idea/codeStyles/Project.xml
generated
25
.idea/codeStyles/Project.xml
generated
@ -21,31 +21,6 @@
|
|||||||
<option name="CONTINUATION_INDENT_IN_ELVIS" value="false" />
|
<option name="CONTINUATION_INDENT_IN_ELVIS" value="false" />
|
||||||
<option name="WRAP_ELVIS_EXPRESSIONS" value="0" />
|
<option name="WRAP_ELVIS_EXPRESSIONS" value="0" />
|
||||||
</JetCodeStyleSettings>
|
</JetCodeStyleSettings>
|
||||||
<Objective-C-extensions>
|
|
||||||
<file>
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
|
|
||||||
</file>
|
|
||||||
<class>
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
|
|
||||||
</class>
|
|
||||||
<extensions>
|
|
||||||
<pair source="cpp" header="h" fileNamingConvention="NONE" />
|
|
||||||
<pair source="c" header="h" fileNamingConvention="NONE" />
|
|
||||||
</extensions>
|
|
||||||
</Objective-C-extensions>
|
|
||||||
<XML>
|
<XML>
|
||||||
<option name="XML_KEEP_LINE_BREAKS" value="false" />
|
<option name="XML_KEEP_LINE_BREAKS" value="false" />
|
||||||
<option name="XML_ALIGN_ATTRIBUTES" value="false" />
|
<option name="XML_ALIGN_ATTRIBUTES" value="false" />
|
||||||
|
@ -11,10 +11,10 @@ cache:
|
|||||||
- $HOME/.gradle/caches/
|
- $HOME/.gradle/caches/
|
||||||
- $HOME/.gradle/wrapper/
|
- $HOME/.gradle/wrapper/
|
||||||
|
|
||||||
#branches:
|
branches:
|
||||||
# only:
|
only:
|
||||||
# - master
|
- master
|
||||||
# - 0.7.x
|
- 0.7.x
|
||||||
|
|
||||||
android:
|
android:
|
||||||
licenses:
|
licenses:
|
||||||
|
@ -16,13 +16,13 @@ android {
|
|||||||
testApplicationId "io.github.tests.wulkanowy"
|
testApplicationId "io.github.tests.wulkanowy"
|
||||||
minSdkVersion 15
|
minSdkVersion 15
|
||||||
targetSdkVersion 28
|
targetSdkVersion 28
|
||||||
versionCode 31
|
versionCode 34
|
||||||
versionName "0.7.5"
|
versionName "0.8.1"
|
||||||
multiDexEnabled true
|
multiDexEnabled true
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
vectorDrawables.useSupportLibrary = true
|
vectorDrawables.useSupportLibrary = true
|
||||||
manifestPlaceholders = [
|
manifestPlaceholders = [
|
||||||
fabric_api_key: System.getenv("FABRIC_API_KEY") ?: "null",
|
fabric_api_key : System.getenv("FABRIC_API_KEY") ?: "null",
|
||||||
crashlytics_enabled: project.hasProperty("enableCrashlytics")
|
crashlytics_enabled: project.hasProperty("enableCrashlytics")
|
||||||
]
|
]
|
||||||
javaCompileOptions {
|
javaCompileOptions {
|
||||||
@ -85,48 +85,49 @@ play {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
implementation 'io.github.wulkanowy:api:0.8.1'
|
||||||
implementation('io.github.wulkanowy:api:0.7.5') { exclude module: "threetenbp" }
|
|
||||||
|
|
||||||
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||||
implementation "androidx.legacy:legacy-support-v4:1.0.0"
|
implementation "androidx.legacy:legacy-support-v4:1.0.0"
|
||||||
implementation "androidx.appcompat:appcompat:1.0.2"
|
implementation "androidx.appcompat:appcompat:1.0.2"
|
||||||
implementation "androidx.cardview:cardview:1.0.0"
|
|
||||||
implementation "com.google.android.material:material:1.0.0"
|
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
|
||||||
implementation 'androidx.multidex:multidex:2.0.1'
|
implementation 'androidx.multidex:multidex:2.0.1'
|
||||||
|
|
||||||
implementation "android.arch.work:work-runtime:1.0.0"
|
implementation "androidx.cardview:cardview:1.0.0"
|
||||||
implementation "android.arch.work:work-rxjava2:1.0.0"
|
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||||
|
implementation "com.google.android.material:material:1.1.0-alpha05"
|
||||||
|
implementation 'com.github.wulkanowy:MaterialChipsInput:b72fd0ee6f'
|
||||||
|
implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'
|
||||||
|
|
||||||
implementation "androidx.room:room-runtime:2.1.0-alpha06"
|
implementation "androidx.work:work-runtime:2.0.1"
|
||||||
implementation "androidx.room:room-rxjava2:2.1.0-alpha06"
|
implementation "androidx.work:work-rxjava2:2.0.1"
|
||||||
kapt "androidx.room:room-compiler:2.1.0-alpha06"
|
|
||||||
|
|
||||||
implementation 'com.takisoft.preferencex:preferencex:1.0.0'
|
implementation "androidx.room:room-runtime:2.1.0-alpha07"
|
||||||
|
implementation "androidx.room:room-rxjava2:2.1.0-alpha07"
|
||||||
|
kapt "androidx.room:room-compiler:2.1.0-alpha07"
|
||||||
|
|
||||||
implementation 'com.squareup.inject:assisted-inject-annotations-dagger2:0.3.3'
|
implementation "com.google.dagger:dagger-android-support:2.22.1"
|
||||||
kapt 'com.squareup.inject:assisted-inject-processor-dagger2:0.3.3'
|
kapt "com.google.dagger:dagger-compiler:2.22.1"
|
||||||
|
kapt "com.google.dagger:dagger-android-processor:2.22.1"
|
||||||
implementation "com.google.dagger:dagger-android-support:2.21"
|
implementation 'com.squareup.inject:assisted-inject-annotations-dagger2:0.4.0'
|
||||||
kapt "com.google.dagger:dagger-compiler:2.21"
|
kapt 'com.squareup.inject:assisted-inject-processor-dagger2:0.4.0'
|
||||||
kapt "com.google.dagger:dagger-android-processor:2.21"
|
|
||||||
|
|
||||||
implementation "eu.davidea:flexible-adapter:5.1.0"
|
implementation "eu.davidea:flexible-adapter:5.1.0"
|
||||||
implementation "eu.davidea:flexible-adapter-ui:1.0.0"
|
implementation "eu.davidea:flexible-adapter-ui:1.0.0"
|
||||||
implementation "com.aurelhubert:ahbottomnavigation:2.3.4"
|
implementation "com.aurelhubert:ahbottomnavigation:2.3.4"
|
||||||
implementation 'com.ncapdevi:frag-nav:3.2.0'
|
implementation 'com.ncapdevi:frag-nav:3.2.0'
|
||||||
|
|
||||||
implementation 'com.github.wulkanowy:MaterialChipsInput:b72fd0ee6f'
|
|
||||||
implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'
|
|
||||||
|
|
||||||
implementation 'com.github.pwittchen:reactivenetwork-rx2:3.0.2'
|
implementation 'com.github.pwittchen:reactivenetwork-rx2:3.0.2'
|
||||||
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
|
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
|
||||||
implementation "io.reactivex.rxjava2:rxjava:2.2.7"
|
implementation "io.reactivex.rxjava2:rxjava:2.2.8"
|
||||||
|
|
||||||
|
implementation 'com.google.code.gson:gson:2.8.5'
|
||||||
implementation "com.jakewharton.threetenabp:threetenabp:1.2.0"
|
implementation "com.jakewharton.threetenabp:threetenabp:1.2.0"
|
||||||
implementation "com.jakewharton.timber:timber:4.7.1"
|
implementation "com.jakewharton.timber:timber:4.7.1"
|
||||||
implementation "at.favre.lib:slf4j-timber:1.0.1"
|
implementation "at.favre.lib:slf4j-timber:1.0.1"
|
||||||
|
implementation "com.squareup.okhttp3:logging-interceptor:3.12.1"
|
||||||
|
|
||||||
implementation "com.mikepenz:aboutlibraries:6.2.3"
|
implementation "com.mikepenz:aboutlibraries:6.2.3"
|
||||||
|
implementation 'com.takisoft.preferencex:preferencex:1.0.0'
|
||||||
|
|
||||||
implementation 'com.google.firebase:firebase-core:16.0.8'
|
implementation 'com.google.firebase:firebase-core:16.0.8'
|
||||||
implementation 'com.crashlytics.sdk.android:crashlytics:2.9.9'
|
implementation 'com.crashlytics.sdk.android:crashlytics:2.9.9'
|
||||||
@ -138,15 +139,15 @@ dependencies {
|
|||||||
|
|
||||||
testImplementation "junit:junit:4.12"
|
testImplementation "junit:junit:4.12"
|
||||||
testImplementation "io.mockk:mockk:1.9.2"
|
testImplementation "io.mockk:mockk:1.9.2"
|
||||||
testImplementation "org.mockito:mockito-inline:2.25.1"
|
testImplementation "org.mockito:mockito-inline:2.27.0"
|
||||||
testImplementation 'org.threeten:threetenbp:1.3.8'
|
testImplementation 'org.threeten:threetenbp:1.3.8'
|
||||||
|
|
||||||
androidTestImplementation 'androidx.test:core:1.1.0'
|
androidTestImplementation 'androidx.test:core:1.1.0'
|
||||||
androidTestImplementation 'androidx.test:runner:1.1.1'
|
androidTestImplementation 'androidx.test:runner:1.1.1'
|
||||||
androidTestImplementation 'androidx.test.ext:junit:1.1.0'
|
androidTestImplementation 'androidx.test.ext:junit:1.1.0'
|
||||||
androidTestImplementation "io.mockk:mockk-android:1.9.2"
|
androidTestImplementation "io.mockk:mockk-android:1.9.2"
|
||||||
androidTestImplementation 'org.mockito:mockito-android:2.25.1'
|
androidTestImplementation 'org.mockito:mockito-android:2.27.0'
|
||||||
androidTestImplementation "androidx.room:room-testing:2.1.0-alpha06"
|
androidTestImplementation "androidx.room:room-testing:2.1.0-alpha07"
|
||||||
androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,17 +31,17 @@ task jacocoTestReport(type: JacocoReport) {
|
|||||||
'**/*_Provide*Factory*.*',
|
'**/*_Provide*Factory*.*',
|
||||||
'**/*_Factory.*']
|
'**/*_Factory.*']
|
||||||
|
|
||||||
classDirectories = fileTree(
|
classDirectories.setFrom(fileTree(
|
||||||
dir: "$buildDir/intermediates/classes/debug",
|
dir: "$buildDir/intermediates/classes/debug",
|
||||||
excludes: excludes
|
excludes: excludes
|
||||||
) + fileTree(
|
) + fileTree(
|
||||||
dir: "$buildDir/tmp/kotlin-classes/debug",
|
dir: "$buildDir/tmp/kotlin-classes/debug",
|
||||||
excludes: excludes
|
excludes: excludes
|
||||||
)
|
))
|
||||||
|
|
||||||
sourceDirectories = files("$project.projectDir/src/main/java")
|
sourceDirectories.setFrom(files("$project.projectDir/src/main/java"))
|
||||||
executionData = fileTree(
|
executionData.setFrom(fileTree(
|
||||||
dir: project.projectDir,
|
dir: project.projectDir,
|
||||||
includes: ["**/*.exec", "**/*.ec"]
|
includes: ["**/*.exec", "**/*.ec"]
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ import org.junit.Test
|
|||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.threeten.bp.LocalDate.of
|
import org.threeten.bp.LocalDate.of
|
||||||
import org.threeten.bp.LocalDateTime
|
import org.threeten.bp.LocalDateTime
|
||||||
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertFalse
|
import kotlin.test.assertFalse
|
||||||
import kotlin.test.assertTrue
|
import kotlin.test.assertTrue
|
||||||
import io.github.wulkanowy.api.grades.Grade as GradeApi
|
import io.github.wulkanowy.api.grades.Grade as GradeApi
|
||||||
@ -109,4 +110,73 @@ class GradeRepositoryTest {
|
|||||||
assertTrue { grades[2].isRead }
|
assertTrue { grades[2].isRead }
|
||||||
assertTrue { grades[3].isRead }
|
assertTrue { grades[3].isRead }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun subtractLocaleDuplicateGrades() {
|
||||||
|
gradeLocal.saveGrades(listOf(
|
||||||
|
createGradeLocal(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
|
||||||
|
createGradeLocal(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
|
||||||
|
createGradeLocal(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
|
||||||
|
))
|
||||||
|
|
||||||
|
every { mockApi.getGrades(1) } returns Single.just(listOf(
|
||||||
|
createGradeApi(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
|
||||||
|
createGradeApi(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
|
||||||
|
))
|
||||||
|
|
||||||
|
val grades = GradeRepository(settings, gradeLocal, gradeRemote)
|
||||||
|
.getGrades(studentMock, semesterMock, true).blockingGet()
|
||||||
|
|
||||||
|
assertEquals(2, grades.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun subtractRemoteDuplicateGrades() {
|
||||||
|
gradeLocal.saveGrades(listOf(
|
||||||
|
createGradeLocal(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
|
||||||
|
createGradeLocal(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
|
||||||
|
))
|
||||||
|
|
||||||
|
every { mockApi.getGrades(1) } returns Single.just(listOf(
|
||||||
|
createGradeApi(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
|
||||||
|
createGradeApi(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
|
||||||
|
createGradeApi(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
|
||||||
|
))
|
||||||
|
|
||||||
|
val grades = GradeRepository(settings, gradeLocal, gradeRemote)
|
||||||
|
.getGrades(studentMock, semesterMock, true).blockingGet()
|
||||||
|
|
||||||
|
assertEquals(3, grades.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun emptyLocal() {
|
||||||
|
gradeLocal.saveGrades(listOf())
|
||||||
|
|
||||||
|
every { mockApi.getGrades(1) } returns Single.just(listOf(
|
||||||
|
createGradeApi(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
|
||||||
|
createGradeApi(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
|
||||||
|
createGradeApi(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
|
||||||
|
))
|
||||||
|
|
||||||
|
val grades = GradeRepository(settings, gradeLocal, gradeRemote)
|
||||||
|
.getGrades(studentMock, semesterMock, true).blockingGet()
|
||||||
|
|
||||||
|
assertEquals(3, grades.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun emptyRemote() {
|
||||||
|
gradeLocal.saveGrades(listOf(
|
||||||
|
createGradeLocal(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
|
||||||
|
createGradeLocal(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
|
||||||
|
))
|
||||||
|
|
||||||
|
every { mockApi.getGrades(1) } returns Single.just(listOf())
|
||||||
|
|
||||||
|
val grades = GradeRepository(settings, gradeLocal, gradeRemote)
|
||||||
|
.getGrades(studentMock, semesterMock, true).blockingGet()
|
||||||
|
|
||||||
|
assertEquals(0, grades.size)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ class StudentLocalTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun saveAndReadTest() {
|
fun saveAndReadTest() {
|
||||||
studentLocal.saveStudent(Student(email = "test", password = "test123", schoolSymbol = "23", endpoint = "fakelog.cf", loginType = "AUTO", isCurrent = true, studentName = "", schoolName = "", studentId = 0, classId = 1, symbol = "", registrationDate = now(), className = ""))
|
studentLocal.saveStudents(listOf(Student(email = "test", password = "test123", schoolSymbol = "23", endpoint = "fakelog.cf", loginType = "AUTO", isCurrent = true, studentName = "", schoolName = "", studentId = 0, classId = 1, symbol = "", registrationDate = now(), className = "")))
|
||||||
.blockingGet()
|
.blockingGet()
|
||||||
|
|
||||||
val student = studentLocal.getCurrentStudent(true).blockingGet()
|
val student = studentLocal.getCurrentStudent(true).blockingGet()
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
android:name=".ui.modules.login.LoginActivity"
|
android:name=".ui.modules.login.LoginActivity"
|
||||||
android:configChanges="orientation|screenSize"
|
android:configChanges="orientation|screenSize"
|
||||||
android:label="@string/login_title"
|
android:label="@string/login_title"
|
||||||
|
android:theme="@style/WulkanowyTheme.NoActionBar"
|
||||||
android:windowSoftInputMode="adjustResize" />
|
android:windowSoftInputMode="adjustResize" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.modules.main.MainActivity"
|
android:name=".ui.modules.main.MainActivity"
|
||||||
@ -45,13 +46,31 @@
|
|||||||
android:configChanges="orientation|screenSize"
|
android:configChanges="orientation|screenSize"
|
||||||
android:label="@string/send_message_title"
|
android:label="@string/send_message_title"
|
||||||
android:theme="@style/WulkanowyTheme.NoActionBar" />
|
android:theme="@style/WulkanowyTheme.NoActionBar" />
|
||||||
|
<activity
|
||||||
|
android:name=".ui.modules.timetablewidget.TimetableWidgetConfigureActivity"
|
||||||
|
android:excludeFromRecents="true"
|
||||||
|
android:noHistory="true"
|
||||||
|
android:theme="@style/WulkanowyTheme.WidgetAccountSwitcher">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
<activity
|
||||||
|
android:name=".ui.modules.luckynumberwidget.LuckyNumberWidgetConfigureActivity"
|
||||||
|
android:excludeFromRecents="true"
|
||||||
|
android:noHistory="true"
|
||||||
|
android:theme="@style/WulkanowyTheme.WidgetAccountSwitcher">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:name=".services.widgets.TimetableWidgetService"
|
android:name=".services.widgets.TimetableWidgetService"
|
||||||
android:permission="android.permission.BIND_REMOTEVIEWS" />
|
android:permission="android.permission.BIND_REMOTEVIEWS" />
|
||||||
|
|
||||||
<receiver
|
<receiver
|
||||||
android:name=".ui.widgets.timetable.TimetableWidgetProvider"
|
android:name=".ui.modules.timetablewidget.TimetableWidgetProvider"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:label="@string/timetable_title">
|
android:label="@string/timetable_title">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
@ -62,6 +81,17 @@
|
|||||||
android:resource="@xml/provider_widget_timetable" />
|
android:resource="@xml/provider_widget_timetable" />
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
|
<receiver
|
||||||
|
android:name=".ui.modules.luckynumberwidget.LuckyNumberWidgetProvider"
|
||||||
|
android:label="@string/lucky_number_title">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||||
|
</intent-filter>
|
||||||
|
<meta-data
|
||||||
|
android:name="android.appwidget.provider"
|
||||||
|
android:resource="@xml/provider_widget_lucky_number" />
|
||||||
|
</receiver>
|
||||||
|
|
||||||
<provider
|
<provider
|
||||||
android:name="androidx.work.impl.WorkManagerInitializer"
|
android:name="androidx.work.impl.WorkManagerInitializer"
|
||||||
android:authorities="${applicationId}.workmanager-init"
|
android:authorities="${applicationId}.workmanager-init"
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package io.github.wulkanowy
|
package io.github.wulkanowy
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.appcompat.app.AppCompatDelegate
|
|
||||||
import androidx.multidex.MultiDex
|
import androidx.multidex.MultiDex
|
||||||
import androidx.work.Configuration
|
import androidx.work.Configuration
|
||||||
import androidx.work.WorkManager
|
import androidx.work.WorkManager
|
||||||
@ -13,24 +12,21 @@ import dagger.android.support.DaggerApplication
|
|||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
import eu.davidea.flexibleadapter.utils.Log
|
import eu.davidea.flexibleadapter.utils.Log
|
||||||
import io.fabric.sdk.android.Fabric
|
import io.fabric.sdk.android.Fabric
|
||||||
|
import io.github.wulkanowy.BuildConfig.CRASHLYTICS_ENABLED
|
||||||
import io.github.wulkanowy.BuildConfig.DEBUG
|
import io.github.wulkanowy.BuildConfig.DEBUG
|
||||||
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
|
|
||||||
import io.github.wulkanowy.di.DaggerAppComponent
|
import io.github.wulkanowy.di.DaggerAppComponent
|
||||||
import io.github.wulkanowy.services.sync.SyncWorkerFactory
|
import io.github.wulkanowy.services.sync.SyncWorkerFactory
|
||||||
|
import io.github.wulkanowy.utils.ActivityLifecycleLogger
|
||||||
import io.github.wulkanowy.utils.CrashlyticsTree
|
import io.github.wulkanowy.utils.CrashlyticsTree
|
||||||
import io.github.wulkanowy.utils.DebugLogTree
|
import io.github.wulkanowy.utils.DebugLogTree
|
||||||
import io.reactivex.exceptions.UndeliverableException
|
import io.reactivex.exceptions.UndeliverableException
|
||||||
import io.reactivex.plugins.RxJavaPlugins
|
import io.reactivex.plugins.RxJavaPlugins
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.lang.Exception
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class WulkanowyApp : DaggerApplication() {
|
class WulkanowyApp : DaggerApplication() {
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var prefRepository: PreferencesRepository
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var workerFactory: SyncWorkerFactory
|
lateinit var workerFactory: SyncWorkerFactory
|
||||||
|
|
||||||
@ -42,32 +38,36 @@ class WulkanowyApp : DaggerApplication() {
|
|||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
AndroidThreeTen.init(this)
|
AndroidThreeTen.init(this)
|
||||||
initializeFabric()
|
|
||||||
if (DEBUG) enableDebugLog()
|
|
||||||
AppCompatDelegate.setDefaultNightMode(prefRepository.currentTheme)
|
|
||||||
WorkManager.initialize(this, Configuration.Builder().setWorkerFactory(workerFactory).build())
|
WorkManager.initialize(this, Configuration.Builder().setWorkerFactory(workerFactory).build())
|
||||||
RxJavaPlugins.setErrorHandler(::onError)
|
RxJavaPlugins.setErrorHandler(::onError)
|
||||||
|
|
||||||
|
initCrashlytics()
|
||||||
|
initLogging()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun enableDebugLog() {
|
private fun initLogging() {
|
||||||
|
if (DEBUG) {
|
||||||
Timber.plant(DebugLogTree())
|
Timber.plant(DebugLogTree())
|
||||||
FlexibleAdapter.enableLogs(Log.Level.DEBUG)
|
FlexibleAdapter.enableLogs(Log.Level.DEBUG)
|
||||||
}
|
} else {
|
||||||
|
|
||||||
private fun initializeFabric() {
|
|
||||||
Fabric.with(Fabric.Builder(this).kits(
|
|
||||||
Crashlytics.Builder().core(CrashlyticsCore.Builder().disabled(!BuildConfig.CRASHLYTICS_ENABLED).build()).build()
|
|
||||||
).debuggable(BuildConfig.DEBUG).build())
|
|
||||||
Timber.plant(CrashlyticsTree())
|
Timber.plant(CrashlyticsTree())
|
||||||
}
|
}
|
||||||
|
registerActivityLifecycleCallbacks(ActivityLifecycleLogger())
|
||||||
|
}
|
||||||
|
|
||||||
private fun onError(t: Throwable) {
|
private fun initCrashlytics() {
|
||||||
if (t is UndeliverableException && t.cause is IOException || t.cause is InterruptedException) {
|
Fabric.with(Fabric.Builder(this).kits(
|
||||||
Timber.e(t.cause, "An undeliverable error occurred")
|
Crashlytics.Builder().core(CrashlyticsCore.Builder().disabled(!CRASHLYTICS_ENABLED).build()).build()
|
||||||
} else throw t
|
).debuggable(DEBUG).build())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onError(error: Throwable) {
|
||||||
|
if (error is UndeliverableException && error.cause is IOException || error.cause is InterruptedException) {
|
||||||
|
Timber.e(error.cause, "An undeliverable error occurred")
|
||||||
|
} else throw error
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
|
override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
|
||||||
return DaggerAppComponent.builder().create(this)
|
return DaggerAppComponent.factory().create(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,18 +6,16 @@ import javax.inject.Inject
|
|||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
|
@SuppressLint("ApplySharedPref")
|
||||||
class SharedPrefHelper @Inject constructor(private val sharedPref: SharedPreferences) {
|
class SharedPrefHelper @Inject constructor(private val sharedPref: SharedPreferences) {
|
||||||
|
|
||||||
@SuppressLint("ApplySharedPref")
|
|
||||||
fun putLong(key: String, value: Long, sync: Boolean = false) {
|
fun putLong(key: String, value: Long, sync: Boolean = false) {
|
||||||
sharedPref.edit().putLong(key, value).apply {
|
sharedPref.edit().putLong(key, value).apply {
|
||||||
if (sync) commit() else apply()
|
if (sync) commit() else apply()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getLong(key: String, defaultValue: Long): Long {
|
fun getLong(key: String, defaultValue: Long) = sharedPref.getLong(key, defaultValue)
|
||||||
return sharedPref.getLong(key, defaultValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun delete(key: String) {
|
fun delete(key: String) {
|
||||||
sharedPref.edit().remove(key).apply()
|
sharedPref.edit().remove(key).apply()
|
||||||
|
@ -14,7 +14,7 @@ import javax.inject.Singleton
|
|||||||
interface StudentDao {
|
interface StudentDao {
|
||||||
|
|
||||||
@Insert(onConflict = ABORT)
|
@Insert(onConflict = ABORT)
|
||||||
fun insert(student: Student): Long
|
fun insertAll(student: List<Student>): List<Long>
|
||||||
|
|
||||||
@Delete
|
@Delete
|
||||||
fun delete(student: Student)
|
fun delete(student: Student)
|
||||||
|
@ -8,7 +8,7 @@ class Migration11 : Migration(10, 11) {
|
|||||||
override fun migrate(database: SupportSQLiteDatabase) {
|
override fun migrate(database: SupportSQLiteDatabase) {
|
||||||
database.execSQL("""
|
database.execSQL("""
|
||||||
CREATE TABLE IF NOT EXISTS Grades_temp (
|
CREATE TABLE IF NOT EXISTS Grades_temp (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
is_read INTEGER NOT NULL,
|
is_read INTEGER NOT NULL,
|
||||||
is_notified INTEGER NOT NULL,
|
is_notified INTEGER NOT NULL,
|
||||||
semester_id INTEGER NOT NULL,
|
semester_id INTEGER NOT NULL,
|
||||||
|
@ -6,6 +6,7 @@ import io.github.wulkanowy.data.db.entities.Attendance
|
|||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.utils.friday
|
import io.github.wulkanowy.utils.friday
|
||||||
import io.github.wulkanowy.utils.monday
|
import io.github.wulkanowy.utils.monday
|
||||||
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import org.threeten.bp.LocalDate
|
import org.threeten.bp.LocalDate
|
||||||
import java.net.UnknownHostException
|
import java.net.UnknownHostException
|
||||||
@ -31,8 +32,8 @@ class AttendanceRepository @Inject constructor(
|
|||||||
local.getAttendance(semester, dates.first, dates.second)
|
local.getAttendance(semester, dates.first, dates.second)
|
||||||
.toSingle(emptyList())
|
.toSingle(emptyList())
|
||||||
.doOnSuccess { oldAttendance ->
|
.doOnSuccess { oldAttendance ->
|
||||||
local.deleteAttendance(oldAttendance - newAttendance)
|
local.deleteAttendance(oldAttendance.uniqueSubtract(newAttendance))
|
||||||
local.saveAttendance(newAttendance - oldAttendance)
|
local.saveAttendance(newAttendance.uniqueSubtract(oldAttendance))
|
||||||
}
|
}
|
||||||
}.flatMap {
|
}.flatMap {
|
||||||
local.getAttendance(semester, dates.first, dates.second)
|
local.getAttendance(semester, dates.first, dates.second)
|
||||||
|
@ -4,6 +4,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
|
|||||||
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
||||||
import io.github.wulkanowy.data.db.entities.AttendanceSummary
|
import io.github.wulkanowy.data.db.entities.AttendanceSummary
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import java.net.UnknownHostException
|
import java.net.UnknownHostException
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -25,8 +26,8 @@ class AttendanceSummaryRepository @Inject constructor(
|
|||||||
}.flatMap { new ->
|
}.flatMap { new ->
|
||||||
local.getAttendanceSummary(semester, subjectId).toSingle(emptyList())
|
local.getAttendanceSummary(semester, subjectId).toSingle(emptyList())
|
||||||
.doOnSuccess { old ->
|
.doOnSuccess { old ->
|
||||||
local.deleteAttendanceSummary(old - new)
|
local.deleteAttendanceSummary(old.uniqueSubtract(new))
|
||||||
local.saveAttendanceSummary(new - old)
|
local.saveAttendanceSummary(new.uniqueSubtract(old))
|
||||||
}
|
}
|
||||||
}.flatMap { local.getAttendanceSummary(semester, subjectId).toSingle(emptyList()) })
|
}.flatMap { local.getAttendanceSummary(semester, subjectId).toSingle(emptyList()) })
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import io.github.wulkanowy.data.db.entities.CompletedLesson
|
|||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.utils.friday
|
import io.github.wulkanowy.utils.friday
|
||||||
import io.github.wulkanowy.utils.monday
|
import io.github.wulkanowy.utils.monday
|
||||||
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import org.threeten.bp.LocalDate
|
import org.threeten.bp.LocalDate
|
||||||
import java.net.UnknownHostException
|
import java.net.UnknownHostException
|
||||||
@ -31,8 +32,8 @@ class CompletedLessonsRepository @Inject constructor(
|
|||||||
local.getCompletedLessons(semester, dates.first, dates.second)
|
local.getCompletedLessons(semester, dates.first, dates.second)
|
||||||
.toSingle(emptyList())
|
.toSingle(emptyList())
|
||||||
.doOnSuccess { old ->
|
.doOnSuccess { old ->
|
||||||
local.deleteCompleteLessons(old - new)
|
local.deleteCompleteLessons(old.uniqueSubtract(new))
|
||||||
local.saveCompletedLessons(new - old)
|
local.saveCompletedLessons(new.uniqueSubtract(old))
|
||||||
}
|
}
|
||||||
}.flatMap {
|
}.flatMap {
|
||||||
local.getCompletedLessons(semester, dates.first, dates.second)
|
local.getCompletedLessons(semester, dates.first, dates.second)
|
||||||
|
@ -6,6 +6,7 @@ import io.github.wulkanowy.data.db.entities.Exam
|
|||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.utils.friday
|
import io.github.wulkanowy.utils.friday
|
||||||
import io.github.wulkanowy.utils.monday
|
import io.github.wulkanowy.utils.monday
|
||||||
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import org.threeten.bp.LocalDate
|
import org.threeten.bp.LocalDate
|
||||||
import java.net.UnknownHostException
|
import java.net.UnknownHostException
|
||||||
@ -27,12 +28,12 @@ class ExamRepository @Inject constructor(
|
|||||||
.flatMap {
|
.flatMap {
|
||||||
if (it) remote.getExams(semester, dates.first, dates.second)
|
if (it) remote.getExams(semester, dates.first, dates.second)
|
||||||
else Single.error(UnknownHostException())
|
else Single.error(UnknownHostException())
|
||||||
}.flatMap { newExams ->
|
}.flatMap { new ->
|
||||||
local.getExams(semester, dates.first, dates.second)
|
local.getExams(semester, dates.first, dates.second)
|
||||||
.toSingle(emptyList())
|
.toSingle(emptyList())
|
||||||
.doOnSuccess { oldExams ->
|
.doOnSuccess { old ->
|
||||||
local.deleteExams(oldExams - newExams)
|
local.deleteExams(old.uniqueSubtract(new))
|
||||||
local.saveExams(newExams - oldExams)
|
local.saveExams(new.uniqueSubtract(old))
|
||||||
}
|
}
|
||||||
}.flatMap {
|
}.flatMap {
|
||||||
local.getExams(semester, dates.first, dates.second)
|
local.getExams(semester, dates.first, dates.second)
|
||||||
|
@ -5,6 +5,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.Inter
|
|||||||
import io.github.wulkanowy.data.db.entities.Grade
|
import io.github.wulkanowy.data.db.entities.Grade
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import io.reactivex.Completable
|
import io.reactivex.Completable
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import java.net.UnknownHostException
|
import java.net.UnknownHostException
|
||||||
@ -24,13 +25,12 @@ class GradeRepository @Inject constructor(
|
|||||||
.flatMap {
|
.flatMap {
|
||||||
if (it) remote.getGrades(semester)
|
if (it) remote.getGrades(semester)
|
||||||
else Single.error(UnknownHostException())
|
else Single.error(UnknownHostException())
|
||||||
}.flatMap { newGrades ->
|
}.flatMap { new ->
|
||||||
local.getGrades(semester).toSingle(emptyList())
|
local.getGrades(semester).toSingle(emptyList())
|
||||||
.doOnSuccess { oldGrades ->
|
.doOnSuccess { old ->
|
||||||
val notifyBreakDate = oldGrades.maxBy { it.date }?.date
|
val notifyBreakDate = old.maxBy { it.date }?.date ?: student.registrationDate.toLocalDate()
|
||||||
?: student.registrationDate.toLocalDate()
|
local.deleteGrades(old.uniqueSubtract(new))
|
||||||
local.deleteGrades(oldGrades - newGrades)
|
local.saveGrades(new.uniqueSubtract(old)
|
||||||
local.saveGrades((newGrades - oldGrades)
|
|
||||||
.onEach {
|
.onEach {
|
||||||
if (it.date >= notifyBreakDate) it.apply {
|
if (it.date >= notifyBreakDate) it.apply {
|
||||||
isRead = false
|
isRead = false
|
||||||
|
@ -4,6 +4,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
|
|||||||
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
||||||
import io.github.wulkanowy.data.db.entities.GradeSummary
|
import io.github.wulkanowy.data.db.entities.GradeSummary
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import java.net.UnknownHostException
|
import java.net.UnknownHostException
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -22,11 +23,11 @@ class GradeSummaryRepository @Inject constructor(
|
|||||||
.flatMap {
|
.flatMap {
|
||||||
if (it) remote.getGradeSummary(semester)
|
if (it) remote.getGradeSummary(semester)
|
||||||
else Single.error(UnknownHostException())
|
else Single.error(UnknownHostException())
|
||||||
}.flatMap { newGradesSummary ->
|
}.flatMap { new ->
|
||||||
local.getGradesSummary(semester).toSingle(emptyList())
|
local.getGradesSummary(semester).toSingle(emptyList())
|
||||||
.doOnSuccess { oldGradesSummary ->
|
.doOnSuccess { old ->
|
||||||
local.deleteGradesSummary(oldGradesSummary - newGradesSummary)
|
local.deleteGradesSummary(old.uniqueSubtract(new))
|
||||||
local.saveGradesSummary(newGradesSummary - oldGradesSummary)
|
local.saveGradesSummary(new.uniqueSubtract(old))
|
||||||
}
|
}
|
||||||
}.flatMap { local.getGradesSummary(semester).toSingle(emptyList()) })
|
}.flatMap { local.getGradesSummary(semester).toSingle(emptyList()) })
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
|
|||||||
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
||||||
import io.github.wulkanowy.data.db.entities.GradeStatistics
|
import io.github.wulkanowy.data.db.entities.GradeStatistics
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import java.net.UnknownHostException
|
import java.net.UnknownHostException
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -22,11 +23,11 @@ class GradeStatisticsRepository @Inject constructor(
|
|||||||
.flatMap {
|
.flatMap {
|
||||||
if (it) remote.getGradeStatistics(semester, isSemester)
|
if (it) remote.getGradeStatistics(semester, isSemester)
|
||||||
else Single.error(UnknownHostException())
|
else Single.error(UnknownHostException())
|
||||||
}.flatMap { newGradesStats ->
|
}.flatMap { new ->
|
||||||
local.getGradesStatistics(semester, isSemester).toSingle(emptyList())
|
local.getGradesStatistics(semester, isSemester).toSingle(emptyList())
|
||||||
.doOnSuccess { oldGradesStats ->
|
.doOnSuccess { old ->
|
||||||
local.deleteGradesStatistics(oldGradesStats - newGradesStats)
|
local.deleteGradesStatistics(old.uniqueSubtract(new))
|
||||||
local.saveGradesStatistics(newGradesStats - oldGradesStats)
|
local.saveGradesStatistics(new.uniqueSubtract(old))
|
||||||
}
|
}
|
||||||
}.flatMap { local.getGradesStatistics(semester, isSemester, subjectName).toSingle(emptyList()) })
|
}.flatMap { local.getGradesStatistics(semester, isSemester, subjectName).toSingle(emptyList()) })
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import io.github.wulkanowy.data.db.entities.Homework
|
|||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.utils.friday
|
import io.github.wulkanowy.utils.friday
|
||||||
import io.github.wulkanowy.utils.monday
|
import io.github.wulkanowy.utils.monday
|
||||||
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import org.threeten.bp.LocalDate
|
import org.threeten.bp.LocalDate
|
||||||
import java.net.UnknownHostException
|
import java.net.UnknownHostException
|
||||||
@ -26,11 +27,11 @@ class HomeworkRepository @Inject constructor(
|
|||||||
.flatMap {
|
.flatMap {
|
||||||
if (it) remote.getHomework(semester, monday, friday)
|
if (it) remote.getHomework(semester, monday, friday)
|
||||||
else Single.error(UnknownHostException())
|
else Single.error(UnknownHostException())
|
||||||
}.flatMap { newGrades ->
|
}.flatMap { new ->
|
||||||
local.getHomework(semester, monday, friday).toSingle(emptyList())
|
local.getHomework(semester, monday, friday).toSingle(emptyList())
|
||||||
.doOnSuccess { oldGrades ->
|
.doOnSuccess { old ->
|
||||||
local.deleteHomework(oldGrades - newGrades)
|
local.deleteHomework(old.uniqueSubtract(new))
|
||||||
local.saveHomework(newGrades - oldGrades)
|
local.saveHomework(new.uniqueSubtract(old))
|
||||||
}
|
}
|
||||||
}.flatMap { local.getHomework(semester, monday, friday).toSingle(emptyList()) })
|
}.flatMap { local.getHomework(semester, monday, friday).toSingle(emptyList()) })
|
||||||
}
|
}
|
||||||
|
@ -59,4 +59,8 @@ class MessageRemote @Inject constructor(private val api: Api) {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun deleteMessage(message: Message): Single<Boolean> {
|
||||||
|
return api.deleteMessages(listOf(Pair(message.realId, message.folderId)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,9 @@ import io.github.wulkanowy.data.db.entities.Message
|
|||||||
import io.github.wulkanowy.data.db.entities.Recipient
|
import io.github.wulkanowy.data.db.entities.Recipient
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.github.wulkanowy.data.repositories.message.MessageFolder.RECEIVED
|
import io.github.wulkanowy.data.repositories.message.MessageFolder.RECEIVED
|
||||||
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import io.reactivex.Completable
|
import io.reactivex.Completable
|
||||||
|
import io.reactivex.Maybe
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import java.net.UnknownHostException
|
import java.net.UnknownHostException
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -33,8 +35,8 @@ class MessageRepository @Inject constructor(
|
|||||||
}.flatMap { new ->
|
}.flatMap { new ->
|
||||||
local.getMessages(student, folder).toSingle(emptyList())
|
local.getMessages(student, folder).toSingle(emptyList())
|
||||||
.doOnSuccess { old ->
|
.doOnSuccess { old ->
|
||||||
local.deleteMessages(old - new)
|
local.deleteMessages(old.uniqueSubtract(new))
|
||||||
local.saveMessages((new - old)
|
local.saveMessages(new.uniqueSubtract(old)
|
||||||
.onEach {
|
.onEach {
|
||||||
it.isNotified = !notify
|
it.isNotified = !notify
|
||||||
})
|
})
|
||||||
@ -89,4 +91,20 @@ class MessageRepository @Inject constructor(
|
|||||||
else Single.error(UnknownHostException())
|
else Single.error(UnknownHostException())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun deleteMessage(message: Message): Maybe<Boolean> {
|
||||||
|
return ReactiveNetwork.checkInternetConnectivity(settings)
|
||||||
|
.flatMap {
|
||||||
|
if (it) remote.deleteMessage(message)
|
||||||
|
else Single.error(UnknownHostException())
|
||||||
|
}
|
||||||
|
.filter { it }
|
||||||
|
.doOnSuccess {
|
||||||
|
if (!message.removed) local.updateMessages(listOf(message.copy(removed = true).apply {
|
||||||
|
id = message.id
|
||||||
|
content = message.content
|
||||||
|
}))
|
||||||
|
else local.deleteMessages(listOf(message))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.Inter
|
|||||||
import io.github.wulkanowy.data.db.entities.Note
|
import io.github.wulkanowy.data.db.entities.Note
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import io.reactivex.Completable
|
import io.reactivex.Completable
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import java.net.UnknownHostException
|
import java.net.UnknownHostException
|
||||||
@ -27,8 +28,8 @@ class NoteRepository @Inject constructor(
|
|||||||
}.flatMap { new ->
|
}.flatMap { new ->
|
||||||
local.getNotes(student).toSingle(emptyList())
|
local.getNotes(student).toSingle(emptyList())
|
||||||
.doOnSuccess { old ->
|
.doOnSuccess { old ->
|
||||||
local.deleteNotes(old - new)
|
local.deleteNotes(old.uniqueSubtract(new))
|
||||||
local.saveNotes((new - old)
|
local.saveNotes(new.uniqueSubtract(old)
|
||||||
.onEach {
|
.onEach {
|
||||||
if (it.date >= student.registrationDate.toLocalDate()) it.apply {
|
if (it.date >= student.registrationDate.toLocalDate()) it.apply {
|
||||||
isRead = false
|
isRead = false
|
||||||
|
@ -17,12 +17,15 @@ class PreferencesRepository @Inject constructor(
|
|||||||
val isShowPresent: Boolean
|
val isShowPresent: Boolean
|
||||||
get() = sharedPref.getBoolean(context.getString(R.string.pref_key_attendance_present), true)
|
get() = sharedPref.getBoolean(context.getString(R.string.pref_key_attendance_present), true)
|
||||||
|
|
||||||
|
val gradeAverageMode: String
|
||||||
|
get() = sharedPref.getString(context.getString(R.string.pref_key_grade_average_mode), "only_one_semester") ?: "only_one_semester"
|
||||||
|
|
||||||
val isGradeExpandable: Boolean
|
val isGradeExpandable: Boolean
|
||||||
get() = !sharedPref.getBoolean(context.getString(R.string.pref_key_expand_grade), false)
|
get() = !sharedPref.getBoolean(context.getString(R.string.pref_key_expand_grade), false)
|
||||||
|
|
||||||
val currentThemeKey: String = context.getString(R.string.pref_key_theme)
|
val appThemeKey: String = context.getString(R.string.pref_key_app_theme)
|
||||||
val currentTheme: Int
|
val appTheme: String
|
||||||
get() = sharedPref.getString(currentThemeKey, "1")?.toIntOrNull() ?: 1
|
get() = sharedPref.getString(appThemeKey, "light") ?: "light"
|
||||||
|
|
||||||
val gradeColorTheme: String
|
val gradeColorTheme: String
|
||||||
get() = sharedPref.getString(context.getString(R.string.pref_key_grade_color_scheme), "vulcan") ?: "vulcan"
|
get() = sharedPref.getString(context.getString(R.string.pref_key_grade_color_scheme), "vulcan") ?: "vulcan"
|
||||||
@ -50,8 +53,7 @@ class PreferencesRepository @Inject constructor(
|
|||||||
get() = sharedPref.getString(context.getString(R.string.pref_key_grade_modifier_plus), "0.0")?.toDouble() ?: 0.0
|
get() = sharedPref.getString(context.getString(R.string.pref_key_grade_modifier_plus), "0.0")?.toDouble() ?: 0.0
|
||||||
|
|
||||||
val gradeMinusModifier: Double
|
val gradeMinusModifier: Double
|
||||||
get() = sharedPref.getString(context.getString(R.string.pref_key_grade_modifier_minus), "0.0")?.toDouble()
|
get() = sharedPref.getString(context.getString(R.string.pref_key_grade_modifier_minus), "0.0")?.toDouble() ?: 0.0
|
||||||
?: 0.0
|
|
||||||
|
|
||||||
val fillMessageContent: Boolean
|
val fillMessageContent: Boolean
|
||||||
get() = sharedPref.getBoolean(context.getString(R.string.pref_key_fill_message_content), true)
|
get() = sharedPref.getBoolean(context.getString(R.string.pref_key_fill_message_content), true)
|
||||||
|
@ -7,6 +7,7 @@ import io.github.wulkanowy.data.db.entities.Message
|
|||||||
import io.github.wulkanowy.data.db.entities.Recipient
|
import io.github.wulkanowy.data.db.entities.Recipient
|
||||||
import io.github.wulkanowy.data.db.entities.ReportingUnit
|
import io.github.wulkanowy.data.db.entities.ReportingUnit
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import java.net.UnknownHostException
|
import java.net.UnknownHostException
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -31,8 +32,8 @@ class RecipientRepository @Inject constructor(
|
|||||||
}.flatMap { new ->
|
}.flatMap { new ->
|
||||||
local.getRecipients(student, role, unit).toSingle(emptyList())
|
local.getRecipients(student, role, unit).toSingle(emptyList())
|
||||||
.doOnSuccess { old ->
|
.doOnSuccess { old ->
|
||||||
local.deleteRecipients(old - new)
|
local.deleteRecipients(old.uniqueSubtract(new))
|
||||||
local.saveRecipients(new - old)
|
local.saveRecipients(new.uniqueSubtract(old))
|
||||||
}
|
}
|
||||||
}.flatMap {
|
}.flatMap {
|
||||||
local.getRecipients(student, role, unit).toSingle(emptyList())
|
local.getRecipients(student, role, unit).toSingle(emptyList())
|
||||||
|
@ -5,6 +5,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.Inter
|
|||||||
import io.github.wulkanowy.data.ApiHelper
|
import io.github.wulkanowy.data.ApiHelper
|
||||||
import io.github.wulkanowy.data.db.entities.ReportingUnit
|
import io.github.wulkanowy.data.db.entities.ReportingUnit
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import io.reactivex.Maybe
|
import io.reactivex.Maybe
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import java.net.UnknownHostException
|
import java.net.UnknownHostException
|
||||||
@ -30,8 +31,8 @@ class ReportingUnitRepository @Inject constructor(
|
|||||||
}.flatMap { new ->
|
}.flatMap { new ->
|
||||||
local.getReportingUnits(student).toSingle(emptyList())
|
local.getReportingUnits(student).toSingle(emptyList())
|
||||||
.doOnSuccess { old ->
|
.doOnSuccess { old ->
|
||||||
local.deleteReportingUnits(old - new)
|
local.deleteReportingUnits(old.uniqueSubtract(new))
|
||||||
local.saveReportingUnits(new - old)
|
local.saveReportingUnits(new.uniqueSubtract(old))
|
||||||
}
|
}
|
||||||
}.flatMap { local.getReportingUnits(student).toSingle(emptyList()) }
|
}.flatMap { local.getReportingUnits(student).toSingle(emptyList()) }
|
||||||
)
|
)
|
||||||
|
@ -5,6 +5,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.Inter
|
|||||||
import io.github.wulkanowy.data.ApiHelper
|
import io.github.wulkanowy.data.ApiHelper
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import io.reactivex.Maybe
|
import io.reactivex.Maybe
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
@ -31,8 +32,8 @@ class SemesterRepository @Inject constructor(
|
|||||||
if (currentSemesters.size == 1) {
|
if (currentSemesters.size == 1) {
|
||||||
local.getSemesters(student).toSingle(emptyList())
|
local.getSemesters(student).toSingle(emptyList())
|
||||||
.doOnSuccess { old ->
|
.doOnSuccess { old ->
|
||||||
local.deleteSemesters(old - new)
|
local.deleteSemesters(old.uniqueSubtract(new))
|
||||||
local.saveSemesters(new - old)
|
local.saveSemesters(new.uniqueSubtract(old))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Timber.i("Current semesters list:\n${currentSemesters.joinToString(separator = "\n")}")
|
Timber.i("Current semesters list:\n${currentSemesters.joinToString(separator = "\n")}")
|
||||||
|
@ -17,8 +17,8 @@ class StudentLocal @Inject constructor(
|
|||||||
private val context: Context
|
private val context: Context
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun saveStudent(student: Student): Single<Long> {
|
fun saveStudents(students: List<Student>): Single<List<Long>> {
|
||||||
return Single.fromCallable { studentDb.insert(student.copy(password = encrypt(student.password, context))) }
|
return Single.fromCallable { studentDb.insertAll(students.map { it.copy(password = encrypt(it.password, context)) }) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getStudents(decryptPass: Boolean): Maybe<List<Student>> {
|
fun getStudents(decryptPass: Boolean): Maybe<List<Student>> {
|
||||||
|
@ -41,8 +41,8 @@ class StudentRepository @Inject constructor(
|
|||||||
.toSingle()
|
.toSingle()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun saveStudent(student: Student): Single<Long> {
|
fun saveStudents(students: List<Student>): Single<List<Long>> {
|
||||||
return local.saveStudent(student)
|
return local.saveStudents(students)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun switchStudent(student: Student): Completable {
|
fun switchStudent(student: Student): Completable {
|
||||||
|
@ -4,6 +4,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
|
|||||||
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.data.db.entities.Subject
|
import io.github.wulkanowy.data.db.entities.Subject
|
||||||
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import java.net.UnknownHostException
|
import java.net.UnknownHostException
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -26,8 +27,8 @@ class SubjectRepository @Inject constructor(
|
|||||||
local.getSubjects(semester)
|
local.getSubjects(semester)
|
||||||
.toSingle(emptyList())
|
.toSingle(emptyList())
|
||||||
.doOnSuccess { old ->
|
.doOnSuccess { old ->
|
||||||
local.deleteSubjects(old - new)
|
local.deleteSubjects(old.uniqueSubtract(new))
|
||||||
local.saveSubjects(new - old)
|
local.saveSubjects(new.uniqueSubtract(old))
|
||||||
}
|
}
|
||||||
}.flatMap {
|
}.flatMap {
|
||||||
local.getSubjects(semester).toSingle(emptyList())
|
local.getSubjects(semester).toSingle(emptyList())
|
||||||
|
@ -6,6 +6,7 @@ import io.github.wulkanowy.data.db.entities.Semester
|
|||||||
import io.github.wulkanowy.data.db.entities.Timetable
|
import io.github.wulkanowy.data.db.entities.Timetable
|
||||||
import io.github.wulkanowy.utils.friday
|
import io.github.wulkanowy.utils.friday
|
||||||
import io.github.wulkanowy.utils.monday
|
import io.github.wulkanowy.utils.monday
|
||||||
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import org.threeten.bp.LocalDate
|
import org.threeten.bp.LocalDate
|
||||||
import java.net.UnknownHostException
|
import java.net.UnknownHostException
|
||||||
@ -25,14 +26,14 @@ class TimetableRepository @Inject constructor(
|
|||||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings).flatMap {
|
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings).flatMap {
|
||||||
if (it) remote.getTimetable(semester, monday, friday)
|
if (it) remote.getTimetable(semester, monday, friday)
|
||||||
else Single.error(UnknownHostException())
|
else Single.error(UnknownHostException())
|
||||||
}.flatMap { newTimetable ->
|
}.flatMap { new ->
|
||||||
local.getTimetable(semester, monday, friday)
|
local.getTimetable(semester, monday, friday)
|
||||||
.toSingle(emptyList())
|
.toSingle(emptyList())
|
||||||
.doOnSuccess { oldTimetable ->
|
.doOnSuccess { old ->
|
||||||
local.deleteTimetable(oldTimetable - newTimetable)
|
local.deleteTimetable(old.uniqueSubtract(new))
|
||||||
local.saveTimetable((newTimetable - oldTimetable).map { item ->
|
local.saveTimetable(new.uniqueSubtract(old).map { item ->
|
||||||
item.apply {
|
item.apply {
|
||||||
oldTimetable.singleOrNull { this.start == it.start }?.let {
|
old.singleOrNull { this.start == it.start }?.let {
|
||||||
return@map copy(
|
return@map copy(
|
||||||
room = if (room.isEmpty()) it.room else room,
|
room = if (room.isEmpty()) it.room else room,
|
||||||
teacher = if (teacher.isEmpty()) it.teacher else teacher
|
teacher = if (teacher.isEmpty()) it.teacher else teacher
|
||||||
|
@ -17,6 +17,6 @@ import javax.inject.Singleton
|
|||||||
BuilderModule::class])
|
BuilderModule::class])
|
||||||
interface AppComponent : AndroidInjector<WulkanowyApp> {
|
interface AppComponent : AndroidInjector<WulkanowyApp> {
|
||||||
|
|
||||||
@Component.Builder
|
@Component.Factory
|
||||||
abstract class Builder : AndroidInjector.Builder<WulkanowyApp>()
|
interface Factory : AndroidInjector.Factory<WulkanowyApp>
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,6 @@ import eu.davidea.flexibleadapter.FlexibleAdapter
|
|||||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||||
import io.github.wulkanowy.BuildConfig.DEBUG
|
import io.github.wulkanowy.BuildConfig.DEBUG
|
||||||
import io.github.wulkanowy.WulkanowyApp
|
import io.github.wulkanowy.WulkanowyApp
|
||||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
|
||||||
import io.github.wulkanowy.utils.SchedulersProvider
|
import io.github.wulkanowy.utils.SchedulersProvider
|
||||||
import javax.inject.Named
|
import javax.inject.Named
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
@ -30,11 +29,11 @@ internal class AppModule {
|
|||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
fun provideFirebaseAnalyticsHelper(context: Context) = FirebaseAnalyticsHelper(FirebaseAnalytics.getInstance(context))
|
fun provideFirebaseAnalytics(context: Context) = FirebaseAnalytics.getInstance(context)
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
fun provideAppWidgetManager(context: Context) = AppWidgetManager.getInstance(context)
|
fun provideAppWidgetManager(context: Context): AppWidgetManager = AppWidgetManager.getInstance(context)
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Named("isDebug")
|
@Named("isDebug")
|
||||||
|
@ -5,11 +5,14 @@ import dagger.android.ContributesAndroidInjector
|
|||||||
import io.github.wulkanowy.di.scopes.PerActivity
|
import io.github.wulkanowy.di.scopes.PerActivity
|
||||||
import io.github.wulkanowy.ui.modules.login.LoginActivity
|
import io.github.wulkanowy.ui.modules.login.LoginActivity
|
||||||
import io.github.wulkanowy.ui.modules.login.LoginModule
|
import io.github.wulkanowy.ui.modules.login.LoginModule
|
||||||
|
import io.github.wulkanowy.ui.modules.luckynumberwidget.LuckyNumberWidgetConfigureActivity
|
||||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||||
import io.github.wulkanowy.ui.modules.main.MainModule
|
import io.github.wulkanowy.ui.modules.main.MainModule
|
||||||
import io.github.wulkanowy.ui.modules.message.send.SendMessageActivity
|
import io.github.wulkanowy.ui.modules.message.send.SendMessageActivity
|
||||||
import io.github.wulkanowy.ui.modules.splash.SplashActivity
|
import io.github.wulkanowy.ui.modules.splash.SplashActivity
|
||||||
import io.github.wulkanowy.ui.widgets.timetable.TimetableWidgetProvider
|
import io.github.wulkanowy.ui.modules.luckynumberwidget.LuckyNumberWidgetProvider
|
||||||
|
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetConfigureActivity
|
||||||
|
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
internal abstract class BuilderModule {
|
internal abstract class BuilderModule {
|
||||||
@ -29,6 +32,15 @@ internal abstract class BuilderModule {
|
|||||||
@ContributesAndroidInjector
|
@ContributesAndroidInjector
|
||||||
abstract fun bindMessageSendActivity(): SendMessageActivity
|
abstract fun bindMessageSendActivity(): SendMessageActivity
|
||||||
|
|
||||||
|
@ContributesAndroidInjector
|
||||||
|
abstract fun bindTimetableWidgetAccountActivity(): TimetableWidgetConfigureActivity
|
||||||
|
|
||||||
@ContributesAndroidInjector
|
@ContributesAndroidInjector
|
||||||
abstract fun bindTimetableWidgetProvider(): TimetableWidgetProvider
|
abstract fun bindTimetableWidgetProvider(): TimetableWidgetProvider
|
||||||
|
|
||||||
|
@ContributesAndroidInjector
|
||||||
|
abstract fun bindLuckyNumberWidgetAccountActivity(): LuckyNumberWidgetConfigureActivity
|
||||||
|
|
||||||
|
@ContributesAndroidInjector
|
||||||
|
abstract fun bindLuckyNumberWidgetProvider(): LuckyNumberWidgetProvider
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ import io.github.wulkanowy.data.repositories.grade.GradeRepository
|
|||||||
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
|
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
|
||||||
import io.github.wulkanowy.services.sync.channels.NewEntriesChannel
|
import io.github.wulkanowy.services.sync.channels.NewEntriesChannel
|
||||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||||
import io.github.wulkanowy.ui.modules.main.MainActivity.Companion.EXTRA_START_MENU_INDEX
|
import io.github.wulkanowy.ui.modules.main.MainView.MenuView
|
||||||
import io.github.wulkanowy.utils.getCompatColor
|
import io.github.wulkanowy.utils.getCompatColor
|
||||||
import io.reactivex.Completable
|
import io.reactivex.Completable
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -47,8 +47,8 @@ class GradeWork @Inject constructor(
|
|||||||
.setDefaults(DEFAULT_ALL)
|
.setDefaults(DEFAULT_ALL)
|
||||||
.setColor(context.getCompatColor(R.color.colorPrimary))
|
.setColor(context.getCompatColor(R.color.colorPrimary))
|
||||||
.setContentIntent(
|
.setContentIntent(
|
||||||
PendingIntent.getActivity(context, 0,
|
PendingIntent.getActivity(context, MenuView.GRADE.id,
|
||||||
MainActivity.getStartIntent(context).putExtra(EXTRA_START_MENU_INDEX, 0), FLAG_UPDATE_CURRENT))
|
MainActivity.getStartIntent(context, MenuView.GRADE, true), FLAG_UPDATE_CURRENT))
|
||||||
.setStyle(NotificationCompat.InboxStyle().run {
|
.setStyle(NotificationCompat.InboxStyle().run {
|
||||||
setSummaryText(context.resources.getQuantityString(R.plurals.grade_number_item, grades.size, grades.size))
|
setSummaryText(context.resources.getQuantityString(R.plurals.grade_number_item, grades.size, grades.size))
|
||||||
grades.forEach { addLine("${it.subject}: ${it.entry}") }
|
grades.forEach { addLine("${it.subject}: ${it.entry}") }
|
||||||
|
@ -15,7 +15,7 @@ import io.github.wulkanowy.data.repositories.luckynumber.LuckyNumberRepository
|
|||||||
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
|
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
|
||||||
import io.github.wulkanowy.services.sync.channels.NewEntriesChannel
|
import io.github.wulkanowy.services.sync.channels.NewEntriesChannel
|
||||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||||
import io.github.wulkanowy.ui.modules.main.MainActivity.Companion.EXTRA_START_MENU_INDEX
|
import io.github.wulkanowy.ui.modules.main.MainView.MenuView
|
||||||
import io.github.wulkanowy.utils.getCompatColor
|
import io.github.wulkanowy.utils.getCompatColor
|
||||||
import io.reactivex.Completable
|
import io.reactivex.Completable
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -47,9 +47,8 @@ class LuckyNumberWork @Inject constructor(
|
|||||||
.setPriority(PRIORITY_HIGH)
|
.setPriority(PRIORITY_HIGH)
|
||||||
.setColor(context.getCompatColor(R.color.colorPrimary))
|
.setColor(context.getCompatColor(R.color.colorPrimary))
|
||||||
.setContentIntent(
|
.setContentIntent(
|
||||||
PendingIntent.getActivity(context, 0,
|
PendingIntent.getActivity(context, MenuView.MESSAGE.id,
|
||||||
MainActivity.getStartIntent(context).putExtra(EXTRA_START_MENU_INDEX, 4), FLAG_UPDATE_CURRENT)
|
MainActivity.getStartIntent(context, MenuView.LUCKY_NUMBER, true), FLAG_UPDATE_CURRENT))
|
||||||
)
|
|
||||||
.build())
|
.build())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ import io.github.wulkanowy.data.repositories.message.MessageRepository
|
|||||||
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
|
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
|
||||||
import io.github.wulkanowy.services.sync.channels.NewEntriesChannel
|
import io.github.wulkanowy.services.sync.channels.NewEntriesChannel
|
||||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||||
import io.github.wulkanowy.ui.modules.main.MainActivity.Companion.EXTRA_START_MENU_INDEX
|
import io.github.wulkanowy.ui.modules.main.MainView.MenuView
|
||||||
import io.github.wulkanowy.utils.getCompatColor
|
import io.github.wulkanowy.utils.getCompatColor
|
||||||
import io.reactivex.Completable
|
import io.reactivex.Completable
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -48,8 +48,8 @@ class MessageWork @Inject constructor(
|
|||||||
.setPriority(PRIORITY_HIGH)
|
.setPriority(PRIORITY_HIGH)
|
||||||
.setColor(context.getCompatColor(R.color.colorPrimary))
|
.setColor(context.getCompatColor(R.color.colorPrimary))
|
||||||
.setContentIntent(
|
.setContentIntent(
|
||||||
PendingIntent.getActivity(context, 0,
|
PendingIntent.getActivity(context, MenuView.MESSAGE.id,
|
||||||
MainActivity.getStartIntent(context).putExtra(EXTRA_START_MENU_INDEX, 4), FLAG_UPDATE_CURRENT)
|
MainActivity.getStartIntent(context, MenuView.MESSAGE, true), FLAG_UPDATE_CURRENT)
|
||||||
)
|
)
|
||||||
.setStyle(NotificationCompat.InboxStyle().run {
|
.setStyle(NotificationCompat.InboxStyle().run {
|
||||||
setSummaryText(context.resources.getQuantityString(R.plurals.message_number_item, messages.size, messages.size))
|
setSummaryText(context.resources.getQuantityString(R.plurals.message_number_item, messages.size, messages.size))
|
||||||
|
@ -15,7 +15,7 @@ import io.github.wulkanowy.data.repositories.note.NoteRepository
|
|||||||
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
|
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
|
||||||
import io.github.wulkanowy.services.sync.channels.NewEntriesChannel
|
import io.github.wulkanowy.services.sync.channels.NewEntriesChannel
|
||||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||||
import io.github.wulkanowy.ui.modules.main.MainActivity.Companion.EXTRA_START_MENU_INDEX
|
import io.github.wulkanowy.ui.modules.main.MainView.MenuView
|
||||||
import io.github.wulkanowy.utils.getCompatColor
|
import io.github.wulkanowy.utils.getCompatColor
|
||||||
import io.reactivex.Completable
|
import io.reactivex.Completable
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -47,9 +47,8 @@ class NoteWork @Inject constructor(
|
|||||||
.setPriority(PRIORITY_HIGH)
|
.setPriority(PRIORITY_HIGH)
|
||||||
.setColor(context.getCompatColor(R.color.colorPrimary))
|
.setColor(context.getCompatColor(R.color.colorPrimary))
|
||||||
.setContentIntent(
|
.setContentIntent(
|
||||||
PendingIntent.getActivity(context, 0,
|
PendingIntent.getActivity(context, MenuView.NOTE.id,
|
||||||
MainActivity.getStartIntent(context).putExtra(EXTRA_START_MENU_INDEX, 4), FLAG_UPDATE_CURRENT)
|
MainActivity.getStartIntent(context, MenuView.NOTE, true), FLAG_UPDATE_CURRENT))
|
||||||
)
|
|
||||||
.setStyle(NotificationCompat.InboxStyle().run {
|
.setStyle(NotificationCompat.InboxStyle().run {
|
||||||
setSummaryText(context.resources.getQuantityString(R.plurals.note_number_item, notes.size, notes.size))
|
setSummaryText(context.resources.getQuantityString(R.plurals.note_number_item, notes.size, notes.size))
|
||||||
notes.forEach { addLine("${it.teacher}: ${it.category}") }
|
notes.forEach { addLine("${it.teacher}: ${it.category}") }
|
||||||
|
@ -7,7 +7,7 @@ import io.github.wulkanowy.data.db.SharedPrefHelper
|
|||||||
import io.github.wulkanowy.data.repositories.semester.SemesterRepository
|
import io.github.wulkanowy.data.repositories.semester.SemesterRepository
|
||||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||||
import io.github.wulkanowy.data.repositories.timetable.TimetableRepository
|
import io.github.wulkanowy.data.repositories.timetable.TimetableRepository
|
||||||
import io.github.wulkanowy.ui.widgets.timetable.TimetableWidgetFactory
|
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetFactory
|
||||||
import io.github.wulkanowy.utils.SchedulersProvider
|
import io.github.wulkanowy.utils.SchedulersProvider
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@ -2,18 +2,36 @@ package io.github.wulkanowy.ui.base
|
|||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.app.AppCompatDelegate
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import com.google.android.material.snackbar.Snackbar.LENGTH_LONG
|
import com.google.android.material.snackbar.Snackbar.LENGTH_LONG
|
||||||
import dagger.android.support.DaggerAppCompatActivity
|
import dagger.android.AndroidInjection
|
||||||
|
import dagger.android.DispatchingAndroidInjector
|
||||||
|
import dagger.android.support.HasSupportFragmentInjector
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.utils.FragmentLifecycleLogger
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
abstract class BaseActivity : DaggerAppCompatActivity(), BaseView {
|
abstract class BaseActivity : AppCompatActivity(), BaseView, HasSupportFragmentInjector {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var supportFragmentInjector: DispatchingAndroidInjector<Fragment>
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var fragmentLifecycleLogger: FragmentLifecycleLogger
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var themeManager: ThemeManager
|
||||||
|
|
||||||
protected lateinit var messageContainer: View
|
protected lateinit var messageContainer: View
|
||||||
|
|
||||||
public override fun onCreate(savedInstanceState: Bundle?) {
|
public override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
AndroidInjection.inject(this)
|
||||||
|
themeManager.applyTheme(this)
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleLogger, true)
|
||||||
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
|
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,4 +49,6 @@ abstract class BaseActivity : DaggerAppCompatActivity(), BaseView {
|
|||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
invalidateOptionsMenu()
|
invalidateOptionsMenu()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun supportFragmentInjector() = supportFragmentInjector
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
package io.github.wulkanowy.ui.base
|
||||||
|
|
||||||
|
import android.content.pm.PackageManager.GET_ACTIVITIES
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_NO
|
||||||
|
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_YES
|
||||||
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class ThemeManager @Inject constructor(private val preferencesRepository: PreferencesRepository) {
|
||||||
|
|
||||||
|
fun applyTheme(activity: AppCompatActivity) {
|
||||||
|
if (isThemeApplicable(activity)) {
|
||||||
|
activity.delegate.apply {
|
||||||
|
when (preferencesRepository.appTheme) {
|
||||||
|
"light" -> setLocalNightMode(MODE_NIGHT_NO)
|
||||||
|
"dark" -> setLocalNightMode(MODE_NIGHT_YES)
|
||||||
|
"black" -> {
|
||||||
|
setLocalNightMode(MODE_NIGHT_YES)
|
||||||
|
activity.setTheme(R.style.WulkanowyTheme_Black)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isThemeApplicable(activity: AppCompatActivity): Boolean {
|
||||||
|
return activity.packageManager.getPackageInfo(activity.packageName, GET_ACTIVITIES)
|
||||||
|
.activities.singleOrNull { it.name == activity::class.java.canonicalName }?.theme
|
||||||
|
.let { it == R.style.WulkanowyTheme_Black || it == R.style.WulkanowyTheme_NoActionBar }
|
||||||
|
}
|
||||||
|
}
|
@ -44,7 +44,7 @@ class AboutFragment : BaseFragment(), AboutView, MainView.TitledView {
|
|||||||
.withFields(R.string::class.java.fields)
|
.withFields(R.string::class.java.fields)
|
||||||
.withCheckCachedDetection(false)
|
.withCheckCachedDetection(false)
|
||||||
.withExcludedLibraries("fastadapter", "AndroidIconics", "Jsoup", "Retrofit", "okio",
|
.withExcludedLibraries("fastadapter", "AndroidIconics", "Jsoup", "Retrofit", "okio",
|
||||||
"OkHttp", "Butterknife", "CircleImageView")
|
"Butterknife", "CircleImageView")
|
||||||
.withOnExtraListener { presenter.onExtraSelect(it) })
|
.withOnExtraListener { presenter.onExtraSelect(it) })
|
||||||
}.let {
|
}.let {
|
||||||
fragmentCompat.onCreateView(inflater.context, inflater, container, savedInstanceState, it)
|
fragmentCompat.onCreateView(inflater.context, inflater, container, savedInstanceState, it)
|
||||||
|
@ -17,7 +17,7 @@ class AboutPresenter @Inject constructor(
|
|||||||
|
|
||||||
override fun onAttachView(view: AboutView) {
|
override fun onAttachView(view: AboutView) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
Timber.i("About view is attached")
|
Timber.i("About view was initialized")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onExtraSelect(type: Libs.SpecialButton?) {
|
fun onExtraSelect(type: Libs.SpecialButton?) {
|
||||||
|
@ -15,7 +15,6 @@ import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
|
|||||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.ui.modules.login.LoginActivity
|
import io.github.wulkanowy.ui.modules.login.LoginActivity
|
||||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
|
||||||
import io.github.wulkanowy.utils.setOnItemClickListener
|
import io.github.wulkanowy.utils.setOnItemClickListener
|
||||||
import kotlinx.android.synthetic.main.dialog_account.*
|
import kotlinx.android.synthetic.main.dialog_account.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -97,11 +96,8 @@ class AccountDialog : DaggerAppCompatDialogFragment(), AccountView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun recreateView() {
|
override fun recreateMainView() {
|
||||||
activity?.also {
|
activity?.recreate()
|
||||||
startActivity(MainActivity.getStartIntent(it))
|
|
||||||
it.finish()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
|
@ -19,8 +19,8 @@ class AccountPresenter @Inject constructor(
|
|||||||
|
|
||||||
override fun onAttachView(view: AccountView) {
|
override fun onAttachView(view: AccountView) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
Timber.i("Account dialog is attached")
|
|
||||||
view.initView()
|
view.initView()
|
||||||
|
Timber.i("Account dialog view was initialized")
|
||||||
loadData()
|
loadData()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,7 +54,7 @@ class AccountPresenter @Inject constructor(
|
|||||||
openClearLoginView()
|
openClearLoginView()
|
||||||
} else {
|
} else {
|
||||||
Timber.i("Logout result: Switch to another student")
|
Timber.i("Logout result: Switch to another student")
|
||||||
recreateView()
|
recreateMainView()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
@ -73,9 +73,10 @@ class AccountPresenter @Inject constructor(
|
|||||||
disposable.add(studentRepository.switchStudent(item.student)
|
disposable.add(studentRepository.switchStudent(item.student)
|
||||||
.subscribeOn(schedulers.backgroundThread)
|
.subscribeOn(schedulers.backgroundThread)
|
||||||
.observeOn(schedulers.mainThread)
|
.observeOn(schedulers.mainThread)
|
||||||
|
.doFinally { view?.dismissView() }
|
||||||
.subscribe({
|
.subscribe({
|
||||||
Timber.i("Change a student result: Success")
|
Timber.i("Change a student result: Success")
|
||||||
view?.recreateView()
|
view?.recreateMainView()
|
||||||
}, {
|
}, {
|
||||||
Timber.i("Change a student result: An exception occurred")
|
Timber.i("Change a student result: An exception occurred")
|
||||||
errorHandler.dispatch(it)
|
errorHandler.dispatch(it)
|
||||||
|
@ -16,6 +16,6 @@ interface AccountView : BaseView {
|
|||||||
|
|
||||||
fun openClearLoginView()
|
fun openClearLoginView()
|
||||||
|
|
||||||
fun recreateView()
|
fun recreateMainView()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,12 +77,12 @@ class AttendanceFragment : BaseSessionFragment(), AttendanceView, MainView.MainC
|
|||||||
attendanceNextButton.setOnClickListener { presenter.onNextDay() }
|
attendanceNextButton.setOnClickListener { presenter.onNextDay() }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
inflater?.inflate(R.menu.action_menu_attendance, menu)
|
inflater.inflate(R.menu.action_menu_attendance, menu)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
return if (item?.itemId == R.id.attendanceMenuSummary) presenter.onSummarySwitchSelected()
|
return if (item.itemId == R.id.attendanceMenuSummary) presenter.onSummarySwitchSelected()
|
||||||
else false
|
else false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,8 +37,8 @@ class AttendancePresenter @Inject constructor(
|
|||||||
|
|
||||||
fun onAttachView(view: AttendanceView, date: Long?) {
|
fun onAttachView(view: AttendanceView, date: Long?) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
Timber.i("Attendance view is attached")
|
|
||||||
view.initView()
|
view.initView()
|
||||||
|
Timber.i("Attendance view was initialized")
|
||||||
loadData(ofEpochDay(date ?: now().previousOrSameSchoolDay.toEpochDay()))
|
loadData(ofEpochDay(date ?: now().previousOrSameSchoolDay.toEpochDay()))
|
||||||
reloadView()
|
reloadView()
|
||||||
}
|
}
|
||||||
|
@ -35,8 +35,8 @@ class AttendanceSummaryPresenter @Inject constructor(
|
|||||||
|
|
||||||
fun onAttachView(view: AttendanceSummaryView, subjectId: Int?) {
|
fun onAttachView(view: AttendanceSummaryView, subjectId: Int?) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
Timber.i("Attendance summary view is attached with subject id ${subjectId ?: -1}")
|
|
||||||
view.initView()
|
view.initView()
|
||||||
|
Timber.i("Attendance summary view was initialized with subject id ${subjectId ?: -1}")
|
||||||
loadData(subjectId ?: -1)
|
loadData(subjectId ?: -1)
|
||||||
loadSubjects()
|
loadSubjects()
|
||||||
}
|
}
|
||||||
|
@ -36,8 +36,8 @@ class ExamPresenter @Inject constructor(
|
|||||||
|
|
||||||
fun onAttachView(view: ExamView, date: Long?) {
|
fun onAttachView(view: ExamView, date: Long?) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
Timber.i("Exam view is attached")
|
|
||||||
view.initView()
|
view.initView()
|
||||||
|
Timber.i("Exam view was initialized")
|
||||||
loadData(ofEpochDay(date ?: now().nextOrSameSchoolDay.toEpochDay()))
|
loadData(ofEpochDay(date ?: now().nextOrSameSchoolDay.toEpochDay()))
|
||||||
reloadView()
|
reloadView()
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,54 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.grade
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
|
import io.github.wulkanowy.data.repositories.grade.GradeRepository
|
||||||
|
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
|
||||||
|
import io.github.wulkanowy.utils.calcAverage
|
||||||
|
import io.github.wulkanowy.utils.changeModifier
|
||||||
|
import io.reactivex.Single
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class GradeAverageProvider @Inject constructor(
|
||||||
|
private val preferencesRepository: PreferencesRepository,
|
||||||
|
private val gradeRepository: GradeRepository
|
||||||
|
) {
|
||||||
|
fun getGradeAverage(student: Student, semesters: List<Semester>, selectedSemesterId: Int, forceRefresh: Boolean): Single<Map<String, Double>> {
|
||||||
|
return when (preferencesRepository.gradeAverageMode) {
|
||||||
|
"all_year" -> getAllYearAverage(student, semesters, selectedSemesterId, forceRefresh)
|
||||||
|
"only_one_semester" -> getOnlyOneSemesterAverage(student, semesters, selectedSemesterId, forceRefresh)
|
||||||
|
else -> throw IllegalArgumentException("Incorrect grade average mode: ${preferencesRepository.gradeAverageMode} ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getAllYearAverage(student: Student, semesters: List<Semester>, semesterId: Int, forceRefresh: Boolean): Single<Map<String, Double>> {
|
||||||
|
val selectedSemester = semesters.single { it.semesterId == semesterId }
|
||||||
|
val firstSemester = semesters.single { it.diaryId == selectedSemester.diaryId && it.semesterName == 1 }
|
||||||
|
val plusModifier = preferencesRepository.gradePlusModifier
|
||||||
|
val minusModifier = preferencesRepository.gradeMinusModifier
|
||||||
|
|
||||||
|
return gradeRepository.getGrades(student, selectedSemester, forceRefresh)
|
||||||
|
.flatMap { firstGrades ->
|
||||||
|
if (selectedSemester == firstSemester) Single.just(firstGrades)
|
||||||
|
else gradeRepository.getGrades(student, firstSemester)
|
||||||
|
.map { secondGrades -> secondGrades + firstGrades }
|
||||||
|
}.map { grades ->
|
||||||
|
grades.map { it.changeModifier(plusModifier, minusModifier) }
|
||||||
|
.groupBy { it.subject }
|
||||||
|
.mapValues { it.value.calcAverage() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getOnlyOneSemesterAverage(student: Student, semesters: List<Semester>, semesterId: Int, forceRefresh: Boolean): Single<Map<String, Double>> {
|
||||||
|
val selectedSemester = semesters.single { it.semesterId == semesterId }
|
||||||
|
val plusModifier = preferencesRepository.gradePlusModifier
|
||||||
|
val minusModifier = preferencesRepository.gradeMinusModifier
|
||||||
|
|
||||||
|
return gradeRepository.getGrades(student, selectedSemester, forceRefresh)
|
||||||
|
.map { grades ->
|
||||||
|
grades.map { it.changeModifier(plusModifier, minusModifier) }
|
||||||
|
.groupBy { it.subject }
|
||||||
|
.mapValues { it.value.calcAverage() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -57,9 +57,9 @@ class GradeFragment : BaseSessionFragment(), GradeView, MainView.MainChildView,
|
|||||||
presenter.onAttachView(this, savedInstanceState?.getInt(SAVED_SEMESTER_KEY))
|
presenter.onAttachView(this, savedInstanceState?.getInt(SAVED_SEMESTER_KEY))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
inflater?.inflate(R.menu.action_menu_grade, menu)
|
inflater.inflate(R.menu.action_menu_grade, menu)
|
||||||
semesterSwitchMenu = menu?.findItem(R.id.gradeMenuSemester)
|
semesterSwitchMenu = menu.findItem(R.id.gradeMenuSemester)
|
||||||
presenter.onCreateMenu()
|
presenter.onCreateMenu()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,8 +82,8 @@ class GradeFragment : BaseSessionFragment(), GradeView, MainView.MainChildView,
|
|||||||
gradeSwipe.setOnRefreshListener { presenter.onSwipeRefresh() }
|
gradeSwipe.setOnRefreshListener { presenter.onSwipeRefresh() }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
return if (item?.itemId == R.id.gradeMenuSemester) presenter.onSemesterSwitch()
|
return if (item.itemId == R.id.gradeMenuSemester) presenter.onSemesterSwitch()
|
||||||
else false
|
else false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,12 +27,12 @@ class GradePresenter @Inject constructor(
|
|||||||
|
|
||||||
fun onAttachView(view: GradeView, savedIndex: Int?) {
|
fun onAttachView(view: GradeView, savedIndex: Int?) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
Timber.i("Grade view is attached")
|
|
||||||
selectedIndex = savedIndex ?: 0
|
selectedIndex = savedIndex ?: 0
|
||||||
view.run {
|
view.run {
|
||||||
initView()
|
initView()
|
||||||
enableSwipe(false)
|
enableSwipe(false)
|
||||||
}
|
}
|
||||||
|
Timber.i("Grade view was initialized with $selectedIndex index")
|
||||||
loadData()
|
loadData()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,8 +67,8 @@ class GradeDetailsFragment : BaseSessionFragment(), GradeDetailsView, GradeView.
|
|||||||
presenter.onAttachView(this)
|
presenter.onAttachView(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
inflater?.inflate(R.menu.action_menu_grade_details, menu)
|
inflater.inflate(R.menu.action_menu_grade_details, menu)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun initView() {
|
override fun initView() {
|
||||||
@ -88,8 +88,8 @@ class GradeDetailsFragment : BaseSessionFragment(), GradeDetailsView, GradeView.
|
|||||||
gradeDetailsSwipe.setOnRefreshListener { presenter.onSwipeRefresh() }
|
gradeDetailsSwipe.setOnRefreshListener { presenter.onSwipeRefresh() }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
return if (item?.itemId == R.id.gradeDetailsMenuRead) presenter.onMarkAsReadSelected()
|
return if (item.itemId == R.id.gradeDetailsMenuRead) presenter.onMarkAsReadSelected()
|
||||||
else false
|
else false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,10 +8,9 @@ import io.github.wulkanowy.data.repositories.semester.SemesterRepository
|
|||||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||||
import io.github.wulkanowy.ui.base.session.BaseSessionPresenter
|
import io.github.wulkanowy.ui.base.session.BaseSessionPresenter
|
||||||
import io.github.wulkanowy.ui.base.session.SessionErrorHandler
|
import io.github.wulkanowy.ui.base.session.SessionErrorHandler
|
||||||
|
import io.github.wulkanowy.ui.modules.grade.GradeAverageProvider
|
||||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||||
import io.github.wulkanowy.utils.SchedulersProvider
|
import io.github.wulkanowy.utils.SchedulersProvider
|
||||||
import io.github.wulkanowy.utils.calcAverage
|
|
||||||
import io.github.wulkanowy.utils.changeModifier
|
|
||||||
import io.github.wulkanowy.utils.getBackgroundColor
|
import io.github.wulkanowy.utils.getBackgroundColor
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -23,6 +22,7 @@ class GradeDetailsPresenter @Inject constructor(
|
|||||||
private val studentRepository: StudentRepository,
|
private val studentRepository: StudentRepository,
|
||||||
private val semesterRepository: SemesterRepository,
|
private val semesterRepository: SemesterRepository,
|
||||||
private val preferencesRepository: PreferencesRepository,
|
private val preferencesRepository: PreferencesRepository,
|
||||||
|
private val averageProvider: GradeAverageProvider,
|
||||||
private val analytics: FirebaseAnalyticsHelper
|
private val analytics: FirebaseAnalyticsHelper
|
||||||
) : BaseSessionPresenter<GradeDetailsView>(errorHandler) {
|
) : BaseSessionPresenter<GradeDetailsView>(errorHandler) {
|
||||||
|
|
||||||
@ -109,11 +109,16 @@ class GradeDetailsPresenter @Inject constructor(
|
|||||||
private fun loadData(semesterId: Int, forceRefresh: Boolean) {
|
private fun loadData(semesterId: Int, forceRefresh: Boolean) {
|
||||||
Timber.i("Loading grade details data started")
|
Timber.i("Loading grade details data started")
|
||||||
disposable.add(studentRepository.getCurrentStudent()
|
disposable.add(studentRepository.getCurrentStudent()
|
||||||
.flatMap { semesterRepository.getSemesters(it).map { semester -> semester to it } }
|
.flatMap { semesterRepository.getSemesters(it).map { semester -> it to semester } }
|
||||||
.flatMap { gradeRepository.getGrades(it.second, it.first.first { item -> item.semesterId == semesterId }, forceRefresh) }
|
.flatMap { (student, semesters) ->
|
||||||
|
averageProvider.getGradeAverage(student, semesters, semesterId, forceRefresh)
|
||||||
|
.flatMap { averages ->
|
||||||
|
gradeRepository.getGrades(student, semesters.first { semester -> semester.semesterId == semesterId })
|
||||||
.map { it.sortedByDescending { grade -> grade.date } }
|
.map { it.sortedByDescending { grade -> grade.date } }
|
||||||
.map { it.map { item -> item.changeModifier(preferencesRepository.gradePlusModifier, preferencesRepository.gradeMinusModifier) } }
|
.map { it.groupBy { grade -> grade.subject }.toSortedMap() }
|
||||||
.map { createGradeItems(it.groupBy { grade -> grade.subject }.toSortedMap()) }
|
.map { createGradeItems(it, averages) }
|
||||||
|
}
|
||||||
|
}
|
||||||
.subscribeOn(schedulers.backgroundThread)
|
.subscribeOn(schedulers.backgroundThread)
|
||||||
.observeOn(schedulers.mainThread)
|
.observeOn(schedulers.mainThread)
|
||||||
.doFinally {
|
.doFinally {
|
||||||
@ -139,32 +144,36 @@ class GradeDetailsPresenter @Inject constructor(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createGradeItems(items: Map<String, List<Grade>>): List<GradeDetailsHeader> {
|
private fun createGradeItems(items: Map<String, List<Grade>>, averages: Map<String, Double>): List<GradeDetailsHeader> {
|
||||||
|
val isGradeExpandable = preferencesRepository.isGradeExpandable
|
||||||
|
val gradeColorTheme = preferencesRepository.gradeColorTheme
|
||||||
|
|
||||||
|
val noDescriptionString = view?.noDescriptionString.orEmpty()
|
||||||
|
val weightString = view?.weightString.orEmpty()
|
||||||
|
|
||||||
return items.map {
|
return items.map {
|
||||||
it.value.calcAverage().let { average ->
|
|
||||||
GradeDetailsHeader(
|
GradeDetailsHeader(
|
||||||
subject = it.key,
|
subject = it.key,
|
||||||
average = formatAverage(average),
|
average = formatAverage(averages[it.key]),
|
||||||
number = view?.getGradeNumberString(it.value.size).orEmpty(),
|
number = view?.getGradeNumberString(it.value.size).orEmpty(),
|
||||||
newGrades = it.value.filter { grade -> !grade.isRead }.size,
|
newGrades = it.value.filter { grade -> !grade.isRead }.size,
|
||||||
isExpandable = preferencesRepository.isGradeExpandable
|
isExpandable = isGradeExpandable
|
||||||
).apply {
|
).apply {
|
||||||
subItems = it.value.map { item ->
|
subItems = it.value.map { item ->
|
||||||
GradeDetailsItem(
|
GradeDetailsItem(
|
||||||
grade = item,
|
grade = item,
|
||||||
valueBgColor = item.getBackgroundColor(preferencesRepository.gradeColorTheme),
|
valueBgColor = item.getBackgroundColor(gradeColorTheme),
|
||||||
weightString = view?.weightString.orEmpty(),
|
weightString = weightString,
|
||||||
noDescriptionString = view?.noDescriptionString.orEmpty()
|
noDescriptionString = noDescriptionString
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private fun formatAverage(average: Double): String {
|
private fun formatAverage(average: Double?): String {
|
||||||
return view?.run {
|
return view?.run {
|
||||||
if (average == 0.0) emptyAverageString
|
if (average == null || average == .0) emptyAverageString
|
||||||
else averageString.format(average)
|
else averageString.format(average)
|
||||||
}.orEmpty()
|
}.orEmpty()
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,15 @@
|
|||||||
package io.github.wulkanowy.ui.modules.grade.summary
|
package io.github.wulkanowy.ui.modules.grade.summary
|
||||||
|
|
||||||
import io.github.wulkanowy.data.db.entities.GradeSummary
|
import io.github.wulkanowy.data.db.entities.GradeSummary
|
||||||
import io.github.wulkanowy.data.repositories.grade.GradeRepository
|
|
||||||
import io.github.wulkanowy.data.repositories.gradessummary.GradeSummaryRepository
|
import io.github.wulkanowy.data.repositories.gradessummary.GradeSummaryRepository
|
||||||
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
|
|
||||||
import io.github.wulkanowy.data.repositories.semester.SemesterRepository
|
import io.github.wulkanowy.data.repositories.semester.SemesterRepository
|
||||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||||
import io.github.wulkanowy.ui.base.session.BaseSessionPresenter
|
import io.github.wulkanowy.ui.base.session.BaseSessionPresenter
|
||||||
import io.github.wulkanowy.ui.base.session.SessionErrorHandler
|
import io.github.wulkanowy.ui.base.session.SessionErrorHandler
|
||||||
|
import io.github.wulkanowy.ui.modules.grade.GradeAverageProvider
|
||||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||||
import io.github.wulkanowy.utils.SchedulersProvider
|
import io.github.wulkanowy.utils.SchedulersProvider
|
||||||
import io.github.wulkanowy.utils.calcAverage
|
import io.github.wulkanowy.utils.calcAverage
|
||||||
import io.github.wulkanowy.utils.changeModifier
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.lang.String.format
|
import java.lang.String.format
|
||||||
import java.util.Locale.FRANCE
|
import java.util.Locale.FRANCE
|
||||||
@ -20,10 +18,9 @@ import javax.inject.Inject
|
|||||||
class GradeSummaryPresenter @Inject constructor(
|
class GradeSummaryPresenter @Inject constructor(
|
||||||
private val errorHandler: SessionErrorHandler,
|
private val errorHandler: SessionErrorHandler,
|
||||||
private val gradeSummaryRepository: GradeSummaryRepository,
|
private val gradeSummaryRepository: GradeSummaryRepository,
|
||||||
private val gradeRepository: GradeRepository,
|
|
||||||
private val studentRepository: StudentRepository,
|
private val studentRepository: StudentRepository,
|
||||||
private val semesterRepository: SemesterRepository,
|
private val semesterRepository: SemesterRepository,
|
||||||
private val preferencesRepository: PreferencesRepository,
|
private val averageProvider: GradeAverageProvider,
|
||||||
private val schedulers: SchedulersProvider,
|
private val schedulers: SchedulersProvider,
|
||||||
private val analytics: FirebaseAnalyticsHelper
|
private val analytics: FirebaseAnalyticsHelper
|
||||||
) : BaseSessionPresenter<GradeSummaryView>(errorHandler) {
|
) : BaseSessionPresenter<GradeSummaryView>(errorHandler) {
|
||||||
@ -36,25 +33,13 @@ class GradeSummaryPresenter @Inject constructor(
|
|||||||
fun onParentViewLoadData(semesterId: Int, forceRefresh: Boolean) {
|
fun onParentViewLoadData(semesterId: Int, forceRefresh: Boolean) {
|
||||||
Timber.i("Loading grade summary data started")
|
Timber.i("Loading grade summary data started")
|
||||||
disposable.add(studentRepository.getCurrentStudent()
|
disposable.add(studentRepository.getCurrentStudent()
|
||||||
.flatMap { semesterRepository.getSemesters(it).map { semester -> semester to it } }
|
.flatMap { semesterRepository.getSemesters(it).map { semesters -> it to semesters } }
|
||||||
.map { pair -> pair.first.first { it.semesterId == semesterId } to pair.second }
|
.flatMap { (student, semesters) ->
|
||||||
.flatMap {
|
gradeSummaryRepository.getGradesSummary(semesters.first { it.semesterId == semesterId }, forceRefresh)
|
||||||
gradeSummaryRepository.getGradesSummary(it.first, forceRefresh)
|
.map { it.sortedBy { subject -> subject.subject } }
|
||||||
.flatMap { gradesSummary ->
|
.flatMap { gradesSummary ->
|
||||||
gradeRepository.getGrades(it.second, it.first, forceRefresh)
|
averageProvider.getGradeAverage(student, semesters, semesterId, forceRefresh)
|
||||||
.map { grades ->
|
.map { averages -> createGradeSummaryItemsAndHeader(gradesSummary, averages) }
|
||||||
grades.map { item -> item.changeModifier(preferencesRepository.gradePlusModifier, preferencesRepository.gradeMinusModifier) }
|
|
||||||
.groupBy { grade -> grade.subject }
|
|
||||||
.mapValues { entry -> entry.value.calcAverage() }
|
|
||||||
.filterValues { value -> value != 0.0 }
|
|
||||||
.let { averages ->
|
|
||||||
createGradeSummaryItems(gradesSummary, averages) to
|
|
||||||
GradeSummaryScrollableHeader(
|
|
||||||
formatAverage(gradesSummary.calcAverage()),
|
|
||||||
formatAverage(averages.values.average())
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.subscribeOn(schedulers.backgroundThread)
|
.subscribeOn(schedulers.backgroundThread)
|
||||||
@ -66,14 +51,14 @@ class GradeSummaryPresenter @Inject constructor(
|
|||||||
enableSwipe(true)
|
enableSwipe(true)
|
||||||
notifyParentDataLoaded(semesterId)
|
notifyParentDataLoaded(semesterId)
|
||||||
}
|
}
|
||||||
}.subscribe({
|
}.subscribe({ (gradeSummaryItems, gradeSummaryHeader) ->
|
||||||
Timber.i("Loading grade summary result: Success")
|
Timber.i("Loading grade summary result: Success")
|
||||||
view?.run {
|
view?.run {
|
||||||
showEmpty(it.first.isEmpty())
|
showEmpty(gradeSummaryItems.isEmpty())
|
||||||
showContent(it.first.isNotEmpty())
|
showContent(gradeSummaryItems.isNotEmpty())
|
||||||
updateData(it.first, it.second)
|
updateData(gradeSummaryItems, gradeSummaryHeader)
|
||||||
}
|
}
|
||||||
analytics.logEvent("load_grade_summary", "items" to it.first.size, "force_refresh" to forceRefresh)
|
analytics.logEvent("load_grade_summary", "items" to gradeSummaryItems.size, "force_refresh" to forceRefresh)
|
||||||
}) {
|
}) {
|
||||||
Timber.i("Loading grade summary result: An exception occurred")
|
Timber.i("Loading grade summary result: An exception occurred")
|
||||||
view?.run { showEmpty(isViewEmpty) }
|
view?.run { showEmpty(isViewEmpty) }
|
||||||
@ -104,15 +89,23 @@ class GradeSummaryPresenter @Inject constructor(
|
|||||||
disposable.clear()
|
disposable.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createGradeSummaryItems(gradesSummary: List<GradeSummary>, averages: Map<String, Double>)
|
private fun createGradeSummaryItemsAndHeader(gradesSummary: List<GradeSummary>, averages: Map<String, Double>)
|
||||||
: List<GradeSummaryItem> {
|
: Pair<List<GradeSummaryItem>, GradeSummaryScrollableHeader> {
|
||||||
return gradesSummary.filter { !checkEmpty(it, averages) }.map { it ->
|
return averages.filterValues { value -> value != 0.0 }
|
||||||
|
.let { filteredAverages ->
|
||||||
|
gradesSummary.filter { !checkEmpty(it, filteredAverages) }
|
||||||
|
.map {
|
||||||
GradeSummaryItem(
|
GradeSummaryItem(
|
||||||
title = it.subject,
|
title = it.subject,
|
||||||
average = formatAverage(averages.getOrElse(it.subject) { 0.0 }, ""),
|
average = formatAverage(filteredAverages.getOrElse(it.subject) { 0.0 }, ""),
|
||||||
predictedGrade = it.predictedGrade,
|
predictedGrade = it.predictedGrade,
|
||||||
finalGrade = it.finalGrade
|
finalGrade = it.finalGrade
|
||||||
)
|
)
|
||||||
|
}.let {
|
||||||
|
it to GradeSummaryScrollableHeader(
|
||||||
|
formatAverage(gradesSummary.calcAverage()),
|
||||||
|
formatAverage(filteredAverages.values.average()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,8 +34,8 @@ class HomeworkPresenter @Inject constructor(
|
|||||||
|
|
||||||
fun onAttachView(view: HomeworkView, date: Long?) {
|
fun onAttachView(view: HomeworkView, date: Long?) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
Timber.i("Homework view is attached")
|
|
||||||
view.initView()
|
view.initView()
|
||||||
|
Timber.i("Homework view was initialized")
|
||||||
loadData(LocalDate.ofEpochDay(date ?: LocalDate.now().nextOrSameSchoolDay.toEpochDay()))
|
loadData(LocalDate.ofEpochDay(date ?: LocalDate.now().nextOrSameSchoolDay.toEpochDay()))
|
||||||
reloadView()
|
reloadView()
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ class LoginPresenter @Inject constructor(errorHandler: ErrorHandler) : BasePrese
|
|||||||
initAdapter()
|
initAdapter()
|
||||||
showActionBar(false)
|
showActionBar(false)
|
||||||
}
|
}
|
||||||
Timber.i("Login view is attached")
|
Timber.i("Login view was initialized")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onFormViewAccountLogged(students: List<Student>, loginData: Triple<String, String, String>) {
|
fun onFormViewAccountLogged(students: List<Student>, loginData: Triple<String, String, String>) {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package io.github.wulkanowy.ui.modules.login.form
|
package io.github.wulkanowy.ui.modules.login.form
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@ -53,7 +54,8 @@ class LoginFormFragment : BaseFragment(), LoginFormView {
|
|||||||
loginFormName.setOnTextChangedListener { presenter.onNameTextChanged() }
|
loginFormName.setOnTextChangedListener { presenter.onNameTextChanged() }
|
||||||
loginFormPass.setOnTextChangedListener { presenter.onPassTextChanged() }
|
loginFormPass.setOnTextChangedListener { presenter.onPassTextChanged() }
|
||||||
loginFormHost.setOnItemSelectedListener { presenter.onHostSelected() }
|
loginFormHost.setOnItemSelectedListener { presenter.onHostSelected() }
|
||||||
loginFormSignIn.setOnClickListener { presenter.attemptLogin() }
|
loginFormSignIn.setOnClickListener { presenter.onSignInClick() }
|
||||||
|
loginFormPrivacyLink.setOnClickListener { presenter.onPrivacyLinkClick() }
|
||||||
|
|
||||||
loginFormPass.setOnEditorActionListener { _, id, _ ->
|
loginFormPass.setOnEditorActionListener { _, id, _ ->
|
||||||
if (id == IME_ACTION_DONE || id == IME_NULL) loginFormSignIn.callOnClick() else false
|
if (id == IME_ACTION_DONE || id == IME_NULL) loginFormSignIn.callOnClick() else false
|
||||||
@ -130,6 +132,10 @@ class LoginFormFragment : BaseFragment(), LoginFormView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun showPrivacyPolicy() {
|
||||||
|
loginFormPrivacyLink.visibility = VISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
override fun notifyParentAccountLogged(students: List<Student>) {
|
override fun notifyParentAccountLogged(students: List<Student>) {
|
||||||
(activity as? LoginActivity)?.onFormFragmentAccountLogged(students, Triple(
|
(activity as? LoginActivity)?.onFormFragmentAccountLogged(students, Triple(
|
||||||
loginFormName.text.toString(),
|
loginFormName.text.toString(),
|
||||||
@ -138,6 +144,10 @@ class LoginFormFragment : BaseFragment(), LoginFormView {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun openPrivacyPolicyPage() {
|
||||||
|
startActivity(Intent.parseUri("https://wulkanowy.github.io/polityka-prywatnosci.html", 0))
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
presenter.onDetachView()
|
presenter.onDetachView()
|
||||||
|
@ -22,7 +22,8 @@ class LoginFormPresenter @Inject constructor(
|
|||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
view.run {
|
view.run {
|
||||||
initView()
|
initView()
|
||||||
if (isDebug) showVersion()
|
if (isDebug) showVersion() else showPrivacyPolicy()
|
||||||
|
|
||||||
errorHandler.onBadCredentials = {
|
errorHandler.onBadCredentials = {
|
||||||
setErrorPassIncorrect()
|
setErrorPassIncorrect()
|
||||||
showSoftKeyboard()
|
showSoftKeyboard()
|
||||||
@ -31,6 +32,10 @@ class LoginFormPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onPrivacyLinkClick() {
|
||||||
|
view?.openPrivacyPolicyPage()
|
||||||
|
}
|
||||||
|
|
||||||
fun onHostSelected() {
|
fun onHostSelected() {
|
||||||
view?.apply {
|
view?.apply {
|
||||||
clearPassError()
|
clearPassError()
|
||||||
@ -47,7 +52,7 @@ class LoginFormPresenter @Inject constructor(
|
|||||||
view?.clearNameError()
|
view?.clearNameError()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun attemptLogin() {
|
fun onSignInClick() {
|
||||||
val email = view?.formNameValue.orEmpty()
|
val email = view?.formNameValue.orEmpty()
|
||||||
val password = view?.formPassValue.orEmpty()
|
val password = view?.formPassValue.orEmpty()
|
||||||
val endpoint = view?.formHostValue.orEmpty()
|
val endpoint = view?.formHostValue.orEmpty()
|
||||||
|
@ -37,5 +37,9 @@ interface LoginFormView : BaseView {
|
|||||||
|
|
||||||
fun showVersion()
|
fun showVersion()
|
||||||
|
|
||||||
|
fun showPrivacyPolicy()
|
||||||
|
|
||||||
fun notifyParentAccountLogged(students: List<Student>)
|
fun notifyParentAccountLogged(students: List<Student>)
|
||||||
|
|
||||||
|
fun openPrivacyPolicyPage()
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
package io.github.wulkanowy.ui.modules.login.studentselect
|
package io.github.wulkanowy.ui.modules.login.studentselect
|
||||||
|
|
||||||
import android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK
|
|
||||||
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.View.GONE
|
import android.view.View.GONE
|
||||||
import android.view.View.VISIBLE
|
import android.view.View.VISIBLE
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
|
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
|
||||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||||
@ -45,6 +42,7 @@ class LoginStudentSelectFragment : BaseFragment(), LoginStudentSelectView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun initView() {
|
override fun initView() {
|
||||||
|
loginStudentSelectSignIn.setOnClickListener { presenter.onSignIn() }
|
||||||
loginAdapter.apply { setOnItemClickListener { presenter.onItemSelected(it) } }
|
loginAdapter.apply { setOnItemClickListener { presenter.onItemSelected(it) } }
|
||||||
|
|
||||||
loginStudentSelectRecycler.apply {
|
loginStudentSelectRecycler.apply {
|
||||||
@ -54,14 +52,11 @@ class LoginStudentSelectFragment : BaseFragment(), LoginStudentSelectView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun updateData(data: List<LoginStudentSelectItem>) {
|
override fun updateData(data: List<LoginStudentSelectItem>) {
|
||||||
loginAdapter.updateDataSet(data, true)
|
loginAdapter.updateDataSet(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun openMainView() {
|
override fun openMainView() {
|
||||||
activity?.let {
|
activity?.let { startActivity(MainActivity.getStartIntent(context = it, clear = true)) }
|
||||||
startActivity(MainActivity.getStartIntent(it)
|
|
||||||
.apply { addFlags(FLAG_ACTIVITY_CLEAR_TASK or FLAG_ACTIVITY_NEW_TASK) })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showProgress(show: Boolean) {
|
override fun showProgress(show: Boolean) {
|
||||||
@ -69,11 +64,11 @@ class LoginStudentSelectFragment : BaseFragment(), LoginStudentSelectView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun showContent(show: Boolean) {
|
override fun showContent(show: Boolean) {
|
||||||
loginStudentSelectRecycler.visibility = if (show) VISIBLE else GONE
|
loginStudentSelectContent.visibility = if (show) VISIBLE else GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showActionBar(show: Boolean) {
|
override fun enableSignIn(enable: Boolean) {
|
||||||
(activity as? AppCompatActivity)?.supportActionBar?.run { if (show) show() else hide() }
|
loginStudentSelectSignIn.isEnabled = enable
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onParentInitStudentSelectFragment(students: List<Student>) {
|
fun onParentInitStudentSelectFragment(students: List<Student>) {
|
||||||
|
@ -13,15 +13,15 @@ import kotlinx.android.synthetic.main.item_login_student_select.*
|
|||||||
|
|
||||||
class LoginStudentSelectItem(val student: Student) : AbstractFlexibleItem<LoginStudentSelectItem.ItemViewHolder>() {
|
class LoginStudentSelectItem(val student: Student) : AbstractFlexibleItem<LoginStudentSelectItem.ItemViewHolder>() {
|
||||||
|
|
||||||
override fun getLayoutRes(): Int = R.layout.item_login_student_select
|
override fun getLayoutRes() = R.layout.item_login_student_select
|
||||||
|
|
||||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<*>>): ItemViewHolder {
|
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<*>>): ItemViewHolder {
|
||||||
return ItemViewHolder(view, adapter)
|
return ItemViewHolder(view, adapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ItemViewHolder, position: Int, payloads: MutableList<Any>?) {
|
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ItemViewHolder, position: Int, payloads: MutableList<Any>) {
|
||||||
holder.run {
|
holder.apply {
|
||||||
loginItemName.text = "${student.studentName} ${student.className}"
|
loginItemName.text = "${student.studentName} ${student.className}"
|
||||||
loginItemSchool.text = student.schoolName
|
loginItemSchool.text = student.schoolName
|
||||||
}
|
}
|
||||||
@ -43,7 +43,17 @@ class LoginStudentSelectItem(val student: Student) : AbstractFlexibleItem<LoginS
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ItemViewHolder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer {
|
class ItemViewHolder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer {
|
||||||
|
|
||||||
override val containerView: View
|
override val containerView: View
|
||||||
get() = itemView
|
get() = itemView
|
||||||
|
|
||||||
|
init {
|
||||||
|
loginItemCheck.setOnClickListener { super.onClick(loginItemContainer) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onClick(view: View?) {
|
||||||
|
super.onClick(view)
|
||||||
|
loginItemCheck.apply { isChecked = !isChecked }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ import io.github.wulkanowy.ui.base.BasePresenter
|
|||||||
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
|
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
|
||||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||||
import io.github.wulkanowy.utils.SchedulersProvider
|
import io.github.wulkanowy.utils.SchedulersProvider
|
||||||
import io.reactivex.Single
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -22,10 +21,13 @@ class LoginStudentSelectPresenter @Inject constructor(
|
|||||||
|
|
||||||
var students = emptyList<Student>()
|
var students = emptyList<Student>()
|
||||||
|
|
||||||
|
var selectedStudents = mutableListOf<Student>()
|
||||||
|
|
||||||
fun onAttachView(view: LoginStudentSelectView, students: Serializable?) {
|
fun onAttachView(view: LoginStudentSelectView, students: Serializable?) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
view.run {
|
view.run {
|
||||||
initView()
|
initView()
|
||||||
|
enableSignIn(false)
|
||||||
errorHandler.onStudentDuplicate = {
|
errorHandler.onStudentDuplicate = {
|
||||||
showMessage(it)
|
showMessage(it)
|
||||||
Timber.i("The student already registered in the app was selected")
|
Timber.i("The student already registered in the app was selected")
|
||||||
@ -37,13 +39,21 @@ class LoginStudentSelectPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onSignIn() {
|
||||||
|
registerStudents(selectedStudents)
|
||||||
|
}
|
||||||
|
|
||||||
fun onParentInitStudentSelectView(students: List<Student>) {
|
fun onParentInitStudentSelectView(students: List<Student>) {
|
||||||
loadData(students)
|
loadData(students)
|
||||||
|
if (students.size == 1) registerStudents(students)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onItemSelected(item: AbstractFlexibleItem<*>?) {
|
fun onItemSelected(item: AbstractFlexibleItem<*>?) {
|
||||||
if (item is LoginStudentSelectItem) {
|
if (item is LoginStudentSelectItem) {
|
||||||
registerStudent(item.student)
|
selectedStudents.removeAll { it == item.student }
|
||||||
|
.let { if (!it) selectedStudents.add(item.student) }
|
||||||
|
|
||||||
|
view?.enableSignIn(selectedStudents.isNotEmpty())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,33 +64,30 @@ class LoginStudentSelectPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun registerStudent(student: Student) {
|
private fun registerStudents(students: List<Student>) {
|
||||||
disposable.add(studentRepository.saveStudent(student)
|
disposable.add(studentRepository.saveStudents(students)
|
||||||
.map { student.apply { id = it } }
|
.map { students.first().apply { id = it.first() } }
|
||||||
.onErrorResumeNext { studentRepository.logoutStudent(student).andThen(Single.error(it)) }
|
.flatMapCompletable { studentRepository.switchStudent(it) }
|
||||||
.flatMapCompletable { studentRepository.switchStudent(student) }
|
|
||||||
.subscribeOn(schedulers.backgroundThread)
|
.subscribeOn(schedulers.backgroundThread)
|
||||||
.observeOn(schedulers.mainThread)
|
.observeOn(schedulers.mainThread)
|
||||||
.doOnSubscribe {
|
.doOnSubscribe {
|
||||||
view?.apply {
|
view?.apply {
|
||||||
showProgress(true)
|
showProgress(true)
|
||||||
showContent(false)
|
showContent(false)
|
||||||
showActionBar(false)
|
|
||||||
}
|
}
|
||||||
Timber.i("Registration started")
|
Timber.i("Registration started")
|
||||||
}
|
}
|
||||||
.subscribe({
|
.subscribe({
|
||||||
analytics.logEvent("registration_student_select", SUCCESS to true, "endpoint" to student.endpoint, "symbol" to student.symbol, "error" to "No error")
|
students.forEach { analytics.logEvent("registration_student_select", SUCCESS to true, "endpoint" to it.endpoint, "symbol" to it.symbol, "error" to "No error") }
|
||||||
Timber.i("Registration result: Success")
|
Timber.i("Registration result: Success")
|
||||||
view?.openMainView()
|
view?.openMainView()
|
||||||
}, {
|
}, { error ->
|
||||||
analytics.logEvent("registration_student_select", SUCCESS to false, "endpoint" to student.endpoint, "symbol" to student.symbol, "error" to it.localizedMessage)
|
students.forEach { analytics.logEvent("registration_student_select", SUCCESS to false, "endpoint" to it.endpoint, "symbol" to it.symbol, "error" to error.localizedMessage) }
|
||||||
Timber.i("Registration result: An exception occurred ")
|
Timber.i("Registration result: An exception occurred ")
|
||||||
errorHandler.dispatch(it)
|
errorHandler.dispatch(error)
|
||||||
view?.apply {
|
view?.apply {
|
||||||
showProgress(false)
|
showProgress(false)
|
||||||
showContent(true)
|
showContent(true)
|
||||||
showActionBar(true)
|
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
@ -14,5 +14,5 @@ interface LoginStudentSelectView : BaseView {
|
|||||||
|
|
||||||
fun showContent(show: Boolean)
|
fun showContent(show: Boolean)
|
||||||
|
|
||||||
fun showActionBar(show: Boolean)
|
fun enableSignIn(enable: Boolean)
|
||||||
}
|
}
|
||||||
|
@ -21,12 +21,12 @@ class LuckyNumberPresenter @Inject constructor(
|
|||||||
|
|
||||||
override fun onAttachView(view: LuckyNumberView) {
|
override fun onAttachView(view: LuckyNumberView) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
Timber.i("Lucky number view is attached")
|
|
||||||
view.run {
|
view.run {
|
||||||
initView()
|
initView()
|
||||||
showContent(false)
|
showContent(false)
|
||||||
enableSwipe(false)
|
enableSwipe(false)
|
||||||
}
|
}
|
||||||
|
Timber.i("Lucky number view was initialized")
|
||||||
loadData()
|
loadData()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,77 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.luckynumberwidget
|
||||||
|
|
||||||
|
import android.appwidget.AppWidgetManager.ACTION_APPWIDGET_UPDATE
|
||||||
|
import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID
|
||||||
|
import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_IDS
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.widget.Toast
|
||||||
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
|
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
|
||||||
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||||
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.ui.base.BaseActivity
|
||||||
|
import io.github.wulkanowy.ui.modules.login.LoginActivity
|
||||||
|
import io.github.wulkanowy.utils.setOnItemClickListener
|
||||||
|
import kotlinx.android.synthetic.main.activity_widget_configure.*
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class LuckyNumberWidgetConfigureActivity : BaseActivity(), LuckyNumberWidgetConfigureView {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var configureAdapter: FlexibleAdapter<AbstractFlexibleItem<*>>
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var presenter: LuckyNumberWidgetConfigurePresenter
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setResult(RESULT_CANCELED)
|
||||||
|
setContentView(R.layout.activity_widget_configure)
|
||||||
|
|
||||||
|
intent.extras.let {
|
||||||
|
presenter.onAttachView(this, it?.getInt(EXTRA_APPWIDGET_ID))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun initView() {
|
||||||
|
widgetConfigureRecycler.apply {
|
||||||
|
adapter = configureAdapter
|
||||||
|
layoutManager = SmoothScrollLinearLayoutManager(context)
|
||||||
|
}
|
||||||
|
configureAdapter.setOnItemClickListener { presenter.onItemSelect(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateData(data: List<LuckyNumberWidgetConfigureItem>) {
|
||||||
|
configureAdapter.updateDataSet(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateLuckyNumberWidget(widgetId: Int) {
|
||||||
|
sendBroadcast(Intent(this, LuckyNumberWidgetProvider::class.java)
|
||||||
|
.apply {
|
||||||
|
action = ACTION_APPWIDGET_UPDATE
|
||||||
|
putExtra(EXTRA_APPWIDGET_IDS, intArrayOf(widgetId))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setSuccessResult(widgetId: Int) {
|
||||||
|
setResult(RESULT_OK, Intent().apply { putExtra(EXTRA_APPWIDGET_ID, widgetId) })
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showError(text: String, error: Throwable) {
|
||||||
|
Toast.makeText(this, text, Toast.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun finishView() {
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun openLoginView() {
|
||||||
|
startActivity(LoginActivity.getStartIntent(this))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
presenter.onDetachView()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.luckynumberwidget
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.view.View
|
||||||
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||||
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
|
import eu.davidea.viewholders.FlexibleViewHolder
|
||||||
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
|
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetConfigureItem
|
||||||
|
import kotlinx.android.extensions.LayoutContainer
|
||||||
|
import kotlinx.android.synthetic.main.item_account.*
|
||||||
|
|
||||||
|
class LuckyNumberWidgetConfigureItem(var student: Student, val isCurrent: Boolean) :
|
||||||
|
AbstractFlexibleItem<LuckyNumberWidgetConfigureItem.ViewHolder>() {
|
||||||
|
|
||||||
|
override fun getLayoutRes() = R.layout.item_account
|
||||||
|
|
||||||
|
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<*>>): ViewHolder {
|
||||||
|
return ViewHolder(view, adapter)
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("SetTextI18n")
|
||||||
|
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder, position: Int, payloads: MutableList<Any>) {
|
||||||
|
holder.apply {
|
||||||
|
accountItemName.text = "${student.studentName} ${student.className}"
|
||||||
|
accountItemSchool.text = student.schoolName
|
||||||
|
accountItemImage.setBackgroundResource(if (isCurrent) R.drawable.ic_account_circular_border else 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
|
||||||
|
other as TimetableWidgetConfigureItem
|
||||||
|
|
||||||
|
if (student != other.student) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
var result = student.hashCode()
|
||||||
|
result = 31 * result + student.id.toInt()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
class ViewHolder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer {
|
||||||
|
override val containerView: View
|
||||||
|
get() = contentView
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,62 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.luckynumberwidget
|
||||||
|
|
||||||
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||||
|
import io.github.wulkanowy.data.db.SharedPrefHelper
|
||||||
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
|
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.ui.modules.luckynumberwidget.LuckyNumberWidgetProvider.Companion.getStudentWidgetKey
|
||||||
|
import io.github.wulkanowy.utils.SchedulersProvider
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class LuckyNumberWidgetConfigurePresenter @Inject constructor(
|
||||||
|
private val errorHandler: ErrorHandler,
|
||||||
|
private val schedulers: SchedulersProvider,
|
||||||
|
private val studentRepository: StudentRepository,
|
||||||
|
private val sharedPref: SharedPrefHelper
|
||||||
|
) : BasePresenter<LuckyNumberWidgetConfigureView>(errorHandler) {
|
||||||
|
|
||||||
|
private var appWidgetId: Int? = null
|
||||||
|
|
||||||
|
fun onAttachView(view: LuckyNumberWidgetConfigureView, appWidgetId: Int?) {
|
||||||
|
super.onAttachView(view)
|
||||||
|
this.appWidgetId = appWidgetId
|
||||||
|
view.initView()
|
||||||
|
loadData()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onItemSelect(item: AbstractFlexibleItem<*>) {
|
||||||
|
if (item is LuckyNumberWidgetConfigureItem) {
|
||||||
|
registerStudent(item.student)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadData() {
|
||||||
|
disposable.add(studentRepository.getSavedStudents(false)
|
||||||
|
.map { it to appWidgetId?.let { id -> sharedPref.getLong(getStudentWidgetKey(id), 0) } }
|
||||||
|
.map { (students, currentStudentId) ->
|
||||||
|
students.map { student -> LuckyNumberWidgetConfigureItem(student, student.id == currentStudentId) }
|
||||||
|
}
|
||||||
|
.subscribeOn(schedulers.backgroundThread)
|
||||||
|
.observeOn(schedulers.mainThread)
|
||||||
|
.subscribe({
|
||||||
|
when {
|
||||||
|
it.isEmpty() -> view?.openLoginView()
|
||||||
|
it.size == 1 -> registerStudent(it.single().student)
|
||||||
|
else -> view?.updateData(it)
|
||||||
|
}
|
||||||
|
}, { errorHandler.dispatch(it) }))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun registerStudent(student: Student) {
|
||||||
|
appWidgetId?.also {
|
||||||
|
sharedPref.putLong(getStudentWidgetKey(it), student.id)
|
||||||
|
view?.apply {
|
||||||
|
updateLuckyNumberWidget(it)
|
||||||
|
setSuccessResult(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
view?.finishView()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.luckynumberwidget
|
||||||
|
|
||||||
|
import io.github.wulkanowy.ui.base.BaseView
|
||||||
|
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetConfigureItem
|
||||||
|
|
||||||
|
interface LuckyNumberWidgetConfigureView : BaseView {
|
||||||
|
|
||||||
|
fun initView()
|
||||||
|
|
||||||
|
fun updateData(data: List<LuckyNumberWidgetConfigureItem>)
|
||||||
|
|
||||||
|
fun updateLuckyNumberWidget(widgetId: Int)
|
||||||
|
|
||||||
|
fun setSuccessResult(widgetId: Int)
|
||||||
|
|
||||||
|
fun finishView()
|
||||||
|
|
||||||
|
fun openLoginView()
|
||||||
|
}
|
@ -0,0 +1,182 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.luckynumberwidget
|
||||||
|
|
||||||
|
import android.annotation.TargetApi
|
||||||
|
import android.app.PendingIntent
|
||||||
|
import android.app.PendingIntent.FLAG_UPDATE_CURRENT
|
||||||
|
import android.appwidget.AppWidgetManager
|
||||||
|
import android.appwidget.AppWidgetManager.ACTION_APPWIDGET_DELETED
|
||||||
|
import android.appwidget.AppWidgetManager.ACTION_APPWIDGET_OPTIONS_CHANGED
|
||||||
|
import android.appwidget.AppWidgetManager.ACTION_APPWIDGET_UPDATE
|
||||||
|
import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID
|
||||||
|
import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_IDS
|
||||||
|
import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_OPTIONS
|
||||||
|
import android.appwidget.AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT
|
||||||
|
import android.appwidget.AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Build
|
||||||
|
import android.view.View.GONE
|
||||||
|
import android.view.View.VISIBLE
|
||||||
|
import android.widget.RemoteViews
|
||||||
|
import dagger.android.AndroidInjection
|
||||||
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.data.db.SharedPrefHelper
|
||||||
|
import io.github.wulkanowy.data.db.entities.LuckyNumber
|
||||||
|
import io.github.wulkanowy.data.repositories.luckynumber.LuckyNumberRepository
|
||||||
|
import io.github.wulkanowy.data.repositories.semester.SemesterRepository
|
||||||
|
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||||
|
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||||
|
import io.github.wulkanowy.ui.modules.main.MainView.MenuView
|
||||||
|
import io.github.wulkanowy.utils.SchedulersProvider
|
||||||
|
import io.reactivex.Maybe
|
||||||
|
import timber.log.Timber
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class LuckyNumberWidgetProvider : BroadcastReceiver() {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var studentRepository: StudentRepository
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var semesterRepository: SemesterRepository
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var luckyNumberRepository: LuckyNumberRepository
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var schedulers: SchedulersProvider
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var appWidgetManager: AppWidgetManager
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var sharedPref: SharedPrefHelper
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun getStudentWidgetKey(appWidgetId: Int) = "lucky_number_widget_student_$appWidgetId"
|
||||||
|
}
|
||||||
|
|
||||||
|
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
|
||||||
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
AndroidInjection.inject(this, context)
|
||||||
|
when (intent.action) {
|
||||||
|
ACTION_APPWIDGET_UPDATE -> onUpdate(context, intent)
|
||||||
|
ACTION_APPWIDGET_DELETED -> onDelete(intent)
|
||||||
|
ACTION_APPWIDGET_OPTIONS_CHANGED -> onOptionsChange(context, intent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onUpdate(context: Context, intent: Intent) {
|
||||||
|
intent.getIntArrayExtra(EXTRA_APPWIDGET_IDS).forEach { appWidgetId ->
|
||||||
|
RemoteViews(context.packageName, R.layout.widget_luckynumber).apply {
|
||||||
|
setTextViewText(R.id.luckyNumberWidgetNumber,
|
||||||
|
getLuckyNumber(sharedPref.getLong(getStudentWidgetKey(appWidgetId), 0), appWidgetId)?.luckyNumber?.toString() ?: "#"
|
||||||
|
)
|
||||||
|
setOnClickPendingIntent(R.id.luckyNumberWidgetContainer,
|
||||||
|
PendingIntent.getActivity(context, MenuView.LUCKY_NUMBER.id,
|
||||||
|
MainActivity.getStartIntent(context, MenuView.LUCKY_NUMBER, true), FLAG_UPDATE_CURRENT))
|
||||||
|
}.also {
|
||||||
|
setStyles(it, intent)
|
||||||
|
appWidgetManager.updateAppWidget(appWidgetId, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onDelete(intent: Intent) {
|
||||||
|
intent.getIntExtra(EXTRA_APPWIDGET_ID, 0).let {
|
||||||
|
if (it != 0) sharedPref.delete(getStudentWidgetKey(it))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getLuckyNumber(studentId: Long, appWidgetId: Int): LuckyNumber? {
|
||||||
|
return try {
|
||||||
|
studentRepository.isStudentSaved()
|
||||||
|
.filter { true }
|
||||||
|
.flatMap { studentRepository.getSavedStudents().toMaybe() }
|
||||||
|
.flatMap { students ->
|
||||||
|
students.singleOrNull { student -> student.id == studentId }
|
||||||
|
.let { student ->
|
||||||
|
when {
|
||||||
|
student != null -> Maybe.just(student)
|
||||||
|
studentId != 0L -> {
|
||||||
|
studentRepository.getCurrentStudent(false)
|
||||||
|
.toMaybe()
|
||||||
|
.doOnSuccess { sharedPref.putLong(getStudentWidgetKey(appWidgetId), it.id) }
|
||||||
|
}
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.flatMap { semesterRepository.getCurrentSemester(it).toMaybe() }
|
||||||
|
.flatMap { luckyNumberRepository.getLuckyNumber(it) }
|
||||||
|
.subscribeOn(schedulers.backgroundThread)
|
||||||
|
.blockingGet()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Timber.e(e, "An error has occurred in lucky number provider")
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onOptionsChange(context: Context, intent: Intent) {
|
||||||
|
intent.extras?.let { extras ->
|
||||||
|
RemoteViews(context.packageName, R.layout.widget_luckynumber).apply {
|
||||||
|
setStyles(this, intent)
|
||||||
|
appWidgetManager.updateAppWidget(extras.getInt(EXTRA_APPWIDGET_ID), this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
|
||||||
|
private fun setStyles(views: RemoteViews, intent: Intent) {
|
||||||
|
val options = intent.extras?.getBundle(EXTRA_APPWIDGET_OPTIONS)
|
||||||
|
|
||||||
|
val maxWidth = options?.getInt(OPTION_APPWIDGET_MAX_WIDTH) ?: 150
|
||||||
|
val maxHeight = options?.getInt(OPTION_APPWIDGET_MAX_HEIGHT) ?: 40
|
||||||
|
|
||||||
|
Timber.d("New lucky number widget measurement: %dx%d", maxWidth, maxHeight)
|
||||||
|
|
||||||
|
when {
|
||||||
|
// 1x1
|
||||||
|
maxWidth < 150 && maxHeight < 110 -> {
|
||||||
|
Timber.d("Lucky number widget size: 1x1")
|
||||||
|
views.run {
|
||||||
|
setViewVisibility(R.id.luckyNumberWidgetImageTop, GONE)
|
||||||
|
setViewVisibility(R.id.luckyNumberWidgetImageLeft, GONE)
|
||||||
|
setViewVisibility(R.id.luckyNumberWidgetTitle, GONE)
|
||||||
|
setViewVisibility(R.id.luckyNumberWidgetNumber, VISIBLE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 1x2
|
||||||
|
maxWidth < 150 && maxHeight > 110 -> {
|
||||||
|
Timber.d("Lucky number widget size: 1x2")
|
||||||
|
views.run {
|
||||||
|
setViewVisibility(R.id.luckyNumberWidgetImageTop, VISIBLE)
|
||||||
|
setViewVisibility(R.id.luckyNumberWidgetImageLeft, GONE)
|
||||||
|
setViewVisibility(R.id.luckyNumberWidgetTitle, GONE)
|
||||||
|
setViewVisibility(R.id.luckyNumberWidgetNumber, VISIBLE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 2x1
|
||||||
|
maxWidth >= 150 && maxHeight <= 110 -> {
|
||||||
|
Timber.d("Lucky number widget size: 2x1")
|
||||||
|
views.run {
|
||||||
|
setViewVisibility(R.id.luckyNumberWidgetImageTop, GONE)
|
||||||
|
setViewVisibility(R.id.luckyNumberWidgetImageLeft, VISIBLE)
|
||||||
|
setViewVisibility(R.id.luckyNumberWidgetTitle, GONE)
|
||||||
|
setViewVisibility(R.id.luckyNumberWidgetNumber, VISIBLE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 2x2 and bigger
|
||||||
|
else -> {
|
||||||
|
Timber.d("Lucky number widget size: 2x2 and bigger")
|
||||||
|
views.run {
|
||||||
|
setViewVisibility(R.id.luckyNumberWidgetImageTop, GONE)
|
||||||
|
setViewVisibility(R.id.luckyNumberWidgetImageLeft, GONE)
|
||||||
|
setViewVisibility(R.id.luckyNumberWidgetTitle, VISIBLE)
|
||||||
|
setViewVisibility(R.id.luckyNumberWidgetNumber, VISIBLE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -22,8 +22,12 @@ import io.github.wulkanowy.ui.modules.account.AccountDialog
|
|||||||
import io.github.wulkanowy.ui.modules.attendance.AttendanceFragment
|
import io.github.wulkanowy.ui.modules.attendance.AttendanceFragment
|
||||||
import io.github.wulkanowy.ui.modules.exam.ExamFragment
|
import io.github.wulkanowy.ui.modules.exam.ExamFragment
|
||||||
import io.github.wulkanowy.ui.modules.grade.GradeFragment
|
import io.github.wulkanowy.ui.modules.grade.GradeFragment
|
||||||
|
import io.github.wulkanowy.ui.modules.homework.HomeworkFragment
|
||||||
import io.github.wulkanowy.ui.modules.login.LoginActivity
|
import io.github.wulkanowy.ui.modules.login.LoginActivity
|
||||||
|
import io.github.wulkanowy.ui.modules.luckynumber.LuckyNumberFragment
|
||||||
|
import io.github.wulkanowy.ui.modules.message.MessageFragment
|
||||||
import io.github.wulkanowy.ui.modules.more.MoreFragment
|
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.ui.modules.timetable.TimetableFragment
|
||||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||||
import io.github.wulkanowy.utils.safelyPopFragment
|
import io.github.wulkanowy.utils.safelyPopFragment
|
||||||
@ -40,9 +44,15 @@ class MainActivity : BaseActivity(), MainView {
|
|||||||
lateinit var navController: FragNavController
|
lateinit var navController: FragNavController
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val EXTRA_START_MENU_INDEX = "extraStartMenuIndex"
|
const val EXTRA_START_MENU = "extraStartMenu"
|
||||||
|
|
||||||
fun getStartIntent(context: Context) = Intent(context, MainActivity::class.java)
|
fun getStartIntent(context: Context, startMenu: MainView.MenuView? = null, clear: Boolean = false): Intent {
|
||||||
|
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) }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override val isRootView: Boolean
|
override val isRootView: Boolean
|
||||||
@ -56,14 +66,27 @@ class MainActivity : BaseActivity(), MainView {
|
|||||||
|
|
||||||
override var startMenuIndex = 0
|
override var startMenuIndex = 0
|
||||||
|
|
||||||
|
override var startMenuMoreIndex = -1
|
||||||
|
|
||||||
|
private val moreMenuFragments = listOf<Fragment>(
|
||||||
|
MessageFragment.newInstance(),
|
||||||
|
HomeworkFragment.newInstance(),
|
||||||
|
NoteFragment.newInstance(),
|
||||||
|
LuckyNumberFragment.newInstance()
|
||||||
|
)
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(R.layout.activity_main)
|
setContentView(R.layout.activity_main)
|
||||||
setSupportActionBar(mainToolbar)
|
setSupportActionBar(mainToolbar)
|
||||||
messageContainer = mainFragmentContainer
|
messageContainer = mainFragmentContainer
|
||||||
|
|
||||||
presenter.onAttachView(this, intent.getIntExtra(EXTRA_START_MENU_INDEX, -1))
|
presenter.onAttachView(this, intent.getSerializableExtra(EXTRA_START_MENU) as? MainView.MenuView)
|
||||||
navController.initialize(startMenuIndex, savedInstanceState)
|
|
||||||
|
navController.run {
|
||||||
|
initialize(startMenuIndex, savedInstanceState)
|
||||||
|
pushFragment(moreMenuFragments.getOrNull(startMenuMoreIndex))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
||||||
@ -74,7 +97,7 @@ class MainActivity : BaseActivity(), MainView {
|
|||||||
override fun initView() {
|
override fun initView() {
|
||||||
mainBottomNav.run {
|
mainBottomNav.run {
|
||||||
addItems(
|
addItems(
|
||||||
mutableListOf(
|
listOf(
|
||||||
AHBottomNavigationItem(R.string.grade_title, R.drawable.ic_menu_main_grade_26dp, 0),
|
AHBottomNavigationItem(R.string.grade_title, R.drawable.ic_menu_main_grade_26dp, 0),
|
||||||
AHBottomNavigationItem(R.string.attendance_title, R.drawable.ic_menu_main_attendance_24dp, 0),
|
AHBottomNavigationItem(R.string.attendance_title, R.drawable.ic_menu_main_attendance_24dp, 0),
|
||||||
AHBottomNavigationItem(R.string.exam_title, R.drawable.ic_menu_main_exam_24dp, 0),
|
AHBottomNavigationItem(R.string.exam_title, R.drawable.ic_menu_main_exam_24dp, 0),
|
||||||
@ -168,9 +191,10 @@ class MainActivity : BaseActivity(), MainView {
|
|||||||
.apply { addFlags(FLAG_ACTIVITY_CLEAR_TASK or FLAG_ACTIVITY_NEW_TASK) })
|
.apply { addFlags(FLAG_ACTIVITY_CLEAR_TASK or FLAG_ACTIVITY_NEW_TASK) })
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSaveInstanceState(outState: Bundle?) {
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
super.onSaveInstanceState(outState)
|
super.onSaveInstanceState(outState)
|
||||||
navController.onSaveInstanceState(outState)
|
navController.onSaveInstanceState(outState)
|
||||||
|
intent.removeExtra(EXTRA_START_MENU)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
|
@ -22,22 +22,19 @@ class MainPresenter @Inject constructor(
|
|||||||
private val analytics: FirebaseAnalyticsHelper
|
private val analytics: FirebaseAnalyticsHelper
|
||||||
) : BasePresenter<MainView>(errorHandler) {
|
) : BasePresenter<MainView>(errorHandler) {
|
||||||
|
|
||||||
fun onAttachView(view: MainView, initMenuIndex: Int) {
|
fun onAttachView(view: MainView, initMenu: MainView.MenuView?) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
view.run {
|
view.apply {
|
||||||
startMenuIndex = if (initMenuIndex != -1) initMenuIndex else prefRepository.startMenuIndex
|
getProperViewIndexes(initMenu).let { (main, more) ->
|
||||||
Timber.i("Main view is attached with $startMenuIndex menu index")
|
startMenuIndex = main
|
||||||
|
startMenuMoreIndex = more
|
||||||
|
}
|
||||||
initView()
|
initView()
|
||||||
|
Timber.i("Main view was initialized with $startMenuIndex menu index and $startMenuMoreIndex more index")
|
||||||
}
|
}
|
||||||
|
|
||||||
syncManager.startSyncWorker()
|
syncManager.startSyncWorker()
|
||||||
|
analytics.logEvent(APP_OPEN, DESTINATION to initMenu?.name)
|
||||||
analytics.logEvent(APP_OPEN, DESTINATION to when (initMenuIndex) {
|
|
||||||
1 -> "Grades"
|
|
||||||
3 -> "Timetable"
|
|
||||||
4 -> "More"
|
|
||||||
else -> "User action"
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onViewChange() {
|
fun onViewChange() {
|
||||||
@ -104,4 +101,12 @@ class MainPresenter @Inject constructor(
|
|||||||
errorHandler.dispatch(it)
|
errorHandler.dispatch(it)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getProperViewIndexes(initMenu: MainView.MenuView?): Pair<Int, Int> {
|
||||||
|
return when {
|
||||||
|
initMenu?.id in 0..3 -> initMenu!!.id to -1
|
||||||
|
(initMenu?.id ?: 0) > 3 -> 4 to initMenu!!.id - 4
|
||||||
|
else -> prefRepository.startMenuIndex to -1
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,8 @@ interface MainView : BaseView {
|
|||||||
|
|
||||||
var startMenuIndex: Int
|
var startMenuIndex: Int
|
||||||
|
|
||||||
|
var startMenuMoreIndex: Int
|
||||||
|
|
||||||
val isRootView: Boolean
|
val isRootView: Boolean
|
||||||
|
|
||||||
val currentViewTitle: String?
|
val currentViewTitle: String?
|
||||||
@ -37,4 +39,15 @@ interface MainView : BaseView {
|
|||||||
|
|
||||||
val titleStringId: Int
|
val titleStringId: Int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class MenuView(val id: Int) {
|
||||||
|
GRADE(0),
|
||||||
|
ATTENDANCE(1),
|
||||||
|
EXAM(2),
|
||||||
|
TIMETABLE(3),
|
||||||
|
MESSAGE(4),
|
||||||
|
HOMEWORK(5),
|
||||||
|
NOTE(6),
|
||||||
|
LUCKY_NUMBER(7),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import android.view.View.INVISIBLE
|
|||||||
import android.view.View.VISIBLE
|
import android.view.View.VISIBLE
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.data.db.entities.Message
|
||||||
import io.github.wulkanowy.data.repositories.message.MessageFolder.RECEIVED
|
import io.github.wulkanowy.data.repositories.message.MessageFolder.RECEIVED
|
||||||
import io.github.wulkanowy.data.repositories.message.MessageFolder.SENT
|
import io.github.wulkanowy.data.repositories.message.MessageFolder.SENT
|
||||||
import io.github.wulkanowy.data.repositories.message.MessageFolder.TRASHED
|
import io.github.wulkanowy.data.repositories.message.MessageFolder.TRASHED
|
||||||
@ -75,12 +76,20 @@ class MessageFragment : BaseFragment(), MessageView, MainView.TitledView {
|
|||||||
messageProgress.visibility = if (show) VISIBLE else INVISIBLE
|
messageProgress.visibility = if (show) VISIBLE else INVISIBLE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onDeleteMessage(message: Message) {
|
||||||
|
presenter.onDeleteMessage(message)
|
||||||
|
}
|
||||||
|
|
||||||
fun onChildFragmentLoaded() {
|
fun onChildFragmentLoaded() {
|
||||||
presenter.onChildViewLoaded()
|
presenter.onChildViewLoaded()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun notifyChildMessageDeleted(tabId: Int) {
|
||||||
|
(pagerAdapter.getFragmentInstance(tabId) as? MessageTabFragment)?.onParentDeleteMessage()
|
||||||
|
}
|
||||||
|
|
||||||
override fun notifyChildLoadData(index: Int, forceRefresh: Boolean) {
|
override fun notifyChildLoadData(index: Int, forceRefresh: Boolean) {
|
||||||
(pagerAdapter.getFragmentInstance(index) as? MessageView.MessageChildView)?.onParentLoadData(forceRefresh)
|
(pagerAdapter.getFragmentInstance(index) as? MessageTabFragment)?.onParentLoadData(forceRefresh)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun openSendMessage() {
|
override fun openSendMessage() {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package io.github.wulkanowy.ui.modules.message
|
package io.github.wulkanowy.ui.modules.message
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.db.entities.Message
|
||||||
import io.github.wulkanowy.ui.base.BasePresenter
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||||
import io.github.wulkanowy.utils.SchedulersProvider
|
import io.github.wulkanowy.utils.SchedulersProvider
|
||||||
@ -15,10 +16,10 @@ class MessagePresenter @Inject constructor(
|
|||||||
|
|
||||||
override fun onAttachView(view: MessageView) {
|
override fun onAttachView(view: MessageView) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
Timber.i("Message view is attached")
|
|
||||||
disposable.add(Completable.timer(150, MILLISECONDS, schedulers.mainThread)
|
disposable.add(Completable.timer(150, MILLISECONDS, schedulers.mainThread)
|
||||||
.subscribe {
|
.subscribe {
|
||||||
view.initView()
|
view.initView()
|
||||||
|
Timber.i("Message view was initialized")
|
||||||
loadData()
|
loadData()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -43,6 +44,15 @@ class MessagePresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onDeleteMessage(message: Message) {
|
||||||
|
view?.notifyChildMessageDeleted(
|
||||||
|
when (message.removed) {
|
||||||
|
true -> 2
|
||||||
|
else -> message.folderId - 1
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fun onSendMessageButtonClicked() {
|
fun onSendMessageButtonClicked() {
|
||||||
view?.openSendMessage()
|
view?.openSendMessage()
|
||||||
}
|
}
|
||||||
|
@ -14,10 +14,7 @@ interface MessageView : BaseView {
|
|||||||
|
|
||||||
fun notifyChildLoadData(index: Int, forceRefresh: Boolean)
|
fun notifyChildLoadData(index: Int, forceRefresh: Boolean)
|
||||||
|
|
||||||
|
fun notifyChildMessageDeleted(tabId: Int)
|
||||||
|
|
||||||
fun openSendMessage()
|
fun openSendMessage()
|
||||||
|
|
||||||
interface MessageChildView {
|
|
||||||
|
|
||||||
fun onParentLoadData(forceRefresh: Boolean)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,9 @@ import android.view.ViewGroup
|
|||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.db.entities.Message
|
import io.github.wulkanowy.data.db.entities.Message
|
||||||
import io.github.wulkanowy.ui.base.session.BaseSessionFragment
|
import io.github.wulkanowy.ui.base.session.BaseSessionFragment
|
||||||
|
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||||
import io.github.wulkanowy.ui.modules.main.MainView
|
import io.github.wulkanowy.ui.modules.main.MainView
|
||||||
|
import io.github.wulkanowy.ui.modules.message.MessageFragment
|
||||||
import io.github.wulkanowy.ui.modules.message.send.SendMessageActivity
|
import io.github.wulkanowy.ui.modules.message.send.SendMessageActivity
|
||||||
import kotlinx.android.synthetic.main.fragment_message_preview.*
|
import kotlinx.android.synthetic.main.fragment_message_preview.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -25,6 +27,8 @@ class MessagePreviewFragment : BaseSessionFragment(), MessagePreviewView, MainVi
|
|||||||
lateinit var presenter: MessagePreviewPresenter
|
lateinit var presenter: MessagePreviewPresenter
|
||||||
|
|
||||||
private var menuReplyButton: MenuItem? = null
|
private var menuReplyButton: MenuItem? = null
|
||||||
|
private var menuForwardButton: MenuItem? = null
|
||||||
|
private var menuDeleteButton: MenuItem? = null
|
||||||
|
|
||||||
override val titleStringId: Int
|
override val titleStringId: Int
|
||||||
get() = R.string.message_title
|
get() = R.string.message_title
|
||||||
@ -32,6 +36,9 @@ class MessagePreviewFragment : BaseSessionFragment(), MessagePreviewView, MainVi
|
|||||||
override val noSubjectString: String
|
override val noSubjectString: String
|
||||||
get() = getString(R.string.message_no_subject)
|
get() = getString(R.string.message_no_subject)
|
||||||
|
|
||||||
|
override val deleteMessageSuccessString: String
|
||||||
|
get() = getString(R.string.message_delete_success)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val MESSAGE_ID_KEY = "message_id"
|
const val MESSAGE_ID_KEY = "message_id"
|
||||||
|
|
||||||
@ -57,15 +64,21 @@ class MessagePreviewFragment : BaseSessionFragment(), MessagePreviewView, MainVi
|
|||||||
presenter.onAttachView(this, (savedInstanceState ?: arguments)?.getInt(MESSAGE_ID_KEY) ?: 0)
|
presenter.onAttachView(this, (savedInstanceState ?: arguments)?.getInt(MESSAGE_ID_KEY) ?: 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
inflater?.inflate(R.menu.action_menu_message_preview, menu)
|
inflater.inflate(R.menu.action_menu_message_preview, menu)
|
||||||
menuReplyButton = menu?.findItem(R.id.messagePreviewMenuReply)
|
menuReplyButton = menu.findItem(R.id.messagePreviewMenuReply)
|
||||||
|
menuForwardButton = menu.findItem(R.id.messagePreviewMenuForward)
|
||||||
|
menuDeleteButton = menu.findItem(R.id.messagePreviewMenuDelete)
|
||||||
presenter.onCreateOptionsMenu()
|
presenter.onCreateOptionsMenu()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
return if (item?.itemId == R.id.messagePreviewMenuReply) presenter.onReply()
|
return when (item.itemId) {
|
||||||
else false
|
R.id.messagePreviewMenuReply -> presenter.onReply()
|
||||||
|
R.id.messagePreviewMenuForward -> presenter.onForward()
|
||||||
|
R.id.messagePreviewMenuDelete -> presenter.onMessageDelete()
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setSubject(subject: String) {
|
override fun setSubject(subject: String) {
|
||||||
@ -92,8 +105,22 @@ class MessagePreviewFragment : BaseSessionFragment(), MessagePreviewView, MainVi
|
|||||||
messagePreviewProgress.visibility = if (show) VISIBLE else GONE
|
messagePreviewProgress.visibility = if (show) VISIBLE else GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showReplyButton(show: Boolean) {
|
override fun showContent(show: Boolean) {
|
||||||
|
messagePreviewContentContainer.visibility = if (show) VISIBLE else GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showOptions(show: Boolean) {
|
||||||
menuReplyButton?.isVisible = show
|
menuReplyButton?.isVisible = show
|
||||||
|
menuForwardButton?.isVisible = show
|
||||||
|
menuDeleteButton?.isVisible = show
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setDeletedOptionsLabels() {
|
||||||
|
menuDeleteButton?.setTitle(R.string.message_delete_forever)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setNotDeletedOptionsLabels() {
|
||||||
|
menuDeleteButton?.setTitle(R.string.message_move_to_bin)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showMessageError() {
|
override fun showMessageError() {
|
||||||
@ -101,9 +128,21 @@ class MessagePreviewFragment : BaseSessionFragment(), MessagePreviewView, MainVi
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun openMessageReply(message: Message?) {
|
override fun openMessageReply(message: Message?) {
|
||||||
|
context?.let { it.startActivity(SendMessageActivity.getStartIntent(it, message, true)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun openMessageForward(message: Message?) {
|
||||||
context?.let { it.startActivity(SendMessageActivity.getStartIntent(it, message)) }
|
context?.let { it.startActivity(SendMessageActivity.getStartIntent(it, message)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun popView() {
|
||||||
|
(activity as MainActivity).popView()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun notifyParentMessageDeleted(message: Message) {
|
||||||
|
fragmentManager?.fragments?.forEach { if (it is MessageFragment) it.onDeleteMessage(message) }
|
||||||
|
}
|
||||||
|
|
||||||
override fun onSaveInstanceState(outState: Bundle) {
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
super.onSaveInstanceState(outState)
|
super.onSaveInstanceState(outState)
|
||||||
outState.putInt(MESSAGE_ID_KEY, presenter.messageId)
|
outState.putInt(MESSAGE_ID_KEY, presenter.messageId)
|
||||||
|
@ -22,7 +22,7 @@ class MessagePreviewPresenter @Inject constructor(
|
|||||||
|
|
||||||
var messageId: Int = 0
|
var messageId: Int = 0
|
||||||
|
|
||||||
private var replyMessage: Message? = null
|
private var message: Message? = null
|
||||||
|
|
||||||
fun onAttachView(view: MessagePreviewView, id: Int) {
|
fun onAttachView(view: MessagePreviewView, id: Int) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
@ -41,13 +41,13 @@ class MessagePreviewPresenter @Inject constructor(
|
|||||||
.doFinally { view?.showProgress(false) }
|
.doFinally { view?.showProgress(false) }
|
||||||
.subscribe({ message ->
|
.subscribe({ message ->
|
||||||
Timber.i("Loading message $id preview result: Success ")
|
Timber.i("Loading message $id preview result: Success ")
|
||||||
replyMessage = message
|
this@MessagePreviewPresenter.message = message
|
||||||
view?.run {
|
view?.run {
|
||||||
message.let {
|
message.let {
|
||||||
setSubject(if (it.subject.isNotBlank()) it.subject else noSubjectString)
|
setSubject(if (it.subject.isNotBlank()) it.subject else noSubjectString)
|
||||||
setDate(it.date.toFormattedString("yyyy-MM-dd HH:mm:ss"))
|
setDate(it.date.toFormattedString("yyyy-MM-dd HH:mm:ss"))
|
||||||
setContent(it.content.orEmpty())
|
setContent(it.content.orEmpty())
|
||||||
showReplyButton(true)
|
initOptions()
|
||||||
|
|
||||||
if (it.recipient.isNotBlank()) setRecipient(it.recipient)
|
if (it.recipient.isNotBlank()) setRecipient(it.recipient)
|
||||||
else setSender(it.sender)
|
else setSender(it.sender)
|
||||||
@ -63,13 +63,69 @@ class MessagePreviewPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun onReply(): Boolean {
|
fun onReply(): Boolean {
|
||||||
return if (replyMessage != null) {
|
return if (message != null) {
|
||||||
view?.openMessageReply(replyMessage)
|
view?.openMessageReply(message)
|
||||||
true
|
true
|
||||||
} else false
|
} else false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onForward(): Boolean {
|
||||||
|
return if (message != null) {
|
||||||
|
view?.openMessageForward(message)
|
||||||
|
true
|
||||||
|
} else false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun deleteMessage() {
|
||||||
|
message?.let { message ->
|
||||||
|
disposable.add(messageRepository.deleteMessage(message)
|
||||||
|
.subscribeOn(schedulers.backgroundThread)
|
||||||
|
.observeOn(schedulers.mainThread)
|
||||||
|
.doOnSubscribe {
|
||||||
|
view?.run {
|
||||||
|
showContent(false)
|
||||||
|
showProgress(true)
|
||||||
|
showOptions(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.doFinally {
|
||||||
|
view?.showProgress(false)
|
||||||
|
}
|
||||||
|
.subscribe({
|
||||||
|
view?.run {
|
||||||
|
notifyParentMessageDeleted(message)
|
||||||
|
showMessage(deleteMessageSuccessString)
|
||||||
|
popView()
|
||||||
|
}
|
||||||
|
}, { error ->
|
||||||
|
view?.showMessageError()
|
||||||
|
errorHandler.dispatch(error)
|
||||||
|
}, {
|
||||||
|
view?.showMessageError()
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onMessageDelete(): Boolean {
|
||||||
|
deleteMessage()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initOptions() {
|
||||||
|
view?.apply {
|
||||||
|
showOptions(message != null)
|
||||||
|
message?.let {
|
||||||
|
when (it.removed) {
|
||||||
|
true -> setDeletedOptionsLabels()
|
||||||
|
false -> setNotDeletedOptionsLabels()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun onCreateOptionsMenu() {
|
fun onCreateOptionsMenu() {
|
||||||
view?.showReplyButton(replyMessage != null)
|
initOptions()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,8 @@ interface MessagePreviewView : BaseSessionView {
|
|||||||
|
|
||||||
val noSubjectString: String
|
val noSubjectString: String
|
||||||
|
|
||||||
|
val deleteMessageSuccessString: String
|
||||||
|
|
||||||
fun setSubject(subject: String)
|
fun setSubject(subject: String)
|
||||||
|
|
||||||
fun setRecipient(recipient: String)
|
fun setRecipient(recipient: String)
|
||||||
@ -19,9 +21,21 @@ interface MessagePreviewView : BaseSessionView {
|
|||||||
|
|
||||||
fun showProgress(show: Boolean)
|
fun showProgress(show: Boolean)
|
||||||
|
|
||||||
fun showReplyButton(show: Boolean)
|
fun showContent(show: Boolean)
|
||||||
|
|
||||||
|
fun showOptions(show: Boolean)
|
||||||
|
|
||||||
|
fun setDeletedOptionsLabels()
|
||||||
|
|
||||||
|
fun setNotDeletedOptionsLabels()
|
||||||
|
|
||||||
fun showMessageError()
|
fun showMessageError()
|
||||||
|
|
||||||
fun openMessageReply(message: Message?)
|
fun openMessageReply(message: Message?)
|
||||||
|
|
||||||
|
fun openMessageForward(message: Message?)
|
||||||
|
|
||||||
|
fun popView()
|
||||||
|
|
||||||
|
fun notifyParentMessageDeleted(message: Message)
|
||||||
}
|
}
|
||||||
|
@ -26,11 +26,14 @@ class SendMessageActivity : BaseActivity(), SendMessageView {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val EXTRA_MESSAGE = "EXTRA_MESSAGE"
|
private const val EXTRA_MESSAGE = "EXTRA_MESSAGE"
|
||||||
|
private const val EXTRA_REPLY = "EXTRA_REPLY"
|
||||||
|
|
||||||
fun getStartIntent(context: Context) = Intent(context, SendMessageActivity::class.java)
|
fun getStartIntent(context: Context) = Intent(context, SendMessageActivity::class.java)
|
||||||
|
|
||||||
fun getStartIntent(context: Context, message: Message?): Intent {
|
fun getStartIntent(context: Context, message: Message?, reply: Boolean = false): Intent {
|
||||||
return getStartIntent(context).putExtra(EXTRA_MESSAGE, message)
|
return getStartIntent(context)
|
||||||
|
.putExtra(EXTRA_MESSAGE, message)
|
||||||
|
.putExtra(EXTRA_REPLY, reply)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,7 +62,7 @@ class SendMessageActivity : BaseActivity(), SendMessageView {
|
|||||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||||
messageContainer = sendMessageContainer
|
messageContainer = sendMessageContainer
|
||||||
|
|
||||||
presenter.onAttachView(this, intent.getSerializableExtra(EXTRA_MESSAGE) as? Message)
|
presenter.onAttachView(this, intent.getSerializableExtra(EXTRA_MESSAGE) as? Message, intent.getSerializableExtra(EXTRA_REPLY) as? Boolean)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
||||||
|
@ -30,17 +30,24 @@ class SendMessagePresenter @Inject constructor(
|
|||||||
private val analytics: FirebaseAnalyticsHelper
|
private val analytics: FirebaseAnalyticsHelper
|
||||||
) : BasePresenter<SendMessageView>(errorHandler) {
|
) : BasePresenter<SendMessageView>(errorHandler) {
|
||||||
|
|
||||||
fun onAttachView(view: SendMessageView, message: Message?) {
|
fun onAttachView(view: SendMessageView, message: Message?, reply: Boolean?) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
Timber.i("Send message view is attached")
|
Timber.i("Send message view was initialized")
|
||||||
loadData(message)
|
loadData(message, reply)
|
||||||
view.apply {
|
view.apply {
|
||||||
message?.let {
|
message?.let {
|
||||||
setSubject("RE: ${message.subject}")
|
setSubject(when (reply) {
|
||||||
if (preferencesRepository.fillMessageContent) {
|
true -> "RE: "
|
||||||
setContent(when (message.sender.isNotEmpty()) {
|
else -> "FW: "
|
||||||
true -> "\n\nOd: ${message.sender}\n"
|
} + message.subject)
|
||||||
false -> "\n\nDo: ${message.recipient}\n"
|
if (preferencesRepository.fillMessageContent || reply != true) {
|
||||||
|
setContent(
|
||||||
|
when (reply) {
|
||||||
|
true -> "\n\n"
|
||||||
|
else -> ""
|
||||||
|
} + when (message.sender.isNotEmpty()) {
|
||||||
|
true -> "Od: ${message.sender}\n"
|
||||||
|
false -> "Do: ${message.recipient}\n"
|
||||||
} + "Data: ${message.date.toFormattedString("yyyy-MM-dd HH:mm:ss")}\n\n${message.content}")
|
} + "Data: ${message.date.toFormattedString("yyyy-MM-dd HH:mm:ss")}\n\n${message.content}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -52,7 +59,7 @@ class SendMessagePresenter @Inject constructor(
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadData(message: Message?) {
|
private fun loadData(message: Message?, reply: Boolean?) {
|
||||||
var reportingUnit: ReportingUnit? = null
|
var reportingUnit: ReportingUnit? = null
|
||||||
var recipients: List<Recipient> = emptyList()
|
var recipients: List<Recipient> = emptyList()
|
||||||
var selectedRecipient: List<Recipient> = emptyList()
|
var selectedRecipient: List<Recipient> = emptyList()
|
||||||
@ -69,7 +76,7 @@ class SendMessagePresenter @Inject constructor(
|
|||||||
recipients = it
|
recipients = it
|
||||||
}
|
}
|
||||||
.flatMapCompletable {
|
.flatMapCompletable {
|
||||||
if (message == null) Completable.complete()
|
if (message == null || reply != true) Completable.complete()
|
||||||
else recipientRepository.getMessageRecipients(student, message)
|
else recipientRepository.getMessageRecipients(student, message)
|
||||||
.doOnSuccess {
|
.doOnSuccess {
|
||||||
Timber.i("Loaded message recipients to reply result: Success, fetched %d recipients", it.size)
|
Timber.i("Loaded message recipients to reply result: Success, fetched %d recipients", it.size)
|
||||||
|
@ -17,13 +17,12 @@ import io.github.wulkanowy.ui.base.session.BaseSessionFragment
|
|||||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||||
import io.github.wulkanowy.ui.modules.message.MessageFragment
|
import io.github.wulkanowy.ui.modules.message.MessageFragment
|
||||||
import io.github.wulkanowy.ui.modules.message.MessageItem
|
import io.github.wulkanowy.ui.modules.message.MessageItem
|
||||||
import io.github.wulkanowy.ui.modules.message.MessageView
|
|
||||||
import io.github.wulkanowy.ui.modules.message.preview.MessagePreviewFragment
|
import io.github.wulkanowy.ui.modules.message.preview.MessagePreviewFragment
|
||||||
import io.github.wulkanowy.utils.setOnItemClickListener
|
import io.github.wulkanowy.utils.setOnItemClickListener
|
||||||
import kotlinx.android.synthetic.main.fragment_message_tab.*
|
import kotlinx.android.synthetic.main.fragment_message_tab.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class MessageTabFragment : BaseSessionFragment(), MessageTabView, MessageView.MessageChildView {
|
class MessageTabFragment : BaseSessionFragment(), MessageTabView {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var presenter: MessageTabPresenter
|
lateinit var presenter: MessageTabPresenter
|
||||||
@ -76,7 +75,7 @@ class MessageTabFragment : BaseSessionFragment(), MessageTabView, MessageView.Me
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun updateData(data: List<MessageItem>) {
|
override fun updateData(data: List<MessageItem>) {
|
||||||
tabAdapter.updateDataSet(data, true)
|
tabAdapter.updateDataSet(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updateItem(item: AbstractFlexibleItem<*>) {
|
override fun updateItem(item: AbstractFlexibleItem<*>) {
|
||||||
@ -115,10 +114,14 @@ class MessageTabFragment : BaseSessionFragment(), MessageTabView, MessageView.Me
|
|||||||
(parentFragment as? MessageFragment)?.onChildFragmentLoaded()
|
(parentFragment as? MessageFragment)?.onChildFragmentLoaded()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onParentLoadData(forceRefresh: Boolean) {
|
fun onParentLoadData(forceRefresh: Boolean) {
|
||||||
presenter.onParentViewLoadData(forceRefresh)
|
presenter.onParentViewLoadData(forceRefresh)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onParentDeleteMessage() {
|
||||||
|
presenter.onDeleteMessage()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onSaveInstanceState(outState: Bundle) {
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
super.onSaveInstanceState(outState)
|
super.onSaveInstanceState(outState)
|
||||||
outState.putString(MessageTabFragment.MESSAGE_TAB_FOLDER_ID, presenter.folder.name)
|
outState.putString(MessageTabFragment.MESSAGE_TAB_FOLDER_ID, presenter.folder.name)
|
||||||
|
@ -34,7 +34,29 @@ class MessageTabPresenter @Inject constructor(
|
|||||||
onParentViewLoadData(true)
|
onParentViewLoadData(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onDeleteMessage() {
|
||||||
|
loadData(false)
|
||||||
|
}
|
||||||
|
|
||||||
fun onParentViewLoadData(forceRefresh: Boolean) {
|
fun onParentViewLoadData(forceRefresh: Boolean) {
|
||||||
|
loadData(forceRefresh)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onMessageItemSelected(item: AbstractFlexibleItem<*>) {
|
||||||
|
if (item is MessageItem) {
|
||||||
|
Timber.i("Select message ${item.message.realId} item")
|
||||||
|
view?.run {
|
||||||
|
openMessage(item.message.realId)
|
||||||
|
if (item.message.unread) {
|
||||||
|
item.message.unread = false
|
||||||
|
updateItem(item)
|
||||||
|
updateMessage(item.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadData(forceRefresh: Boolean) {
|
||||||
Timber.i("Loading $folder message data started")
|
Timber.i("Loading $folder message data started")
|
||||||
disposable.apply {
|
disposable.apply {
|
||||||
clear()
|
clear()
|
||||||
@ -67,20 +89,6 @@ class MessageTabPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onMessageItemSelected(item: AbstractFlexibleItem<*>) {
|
|
||||||
if (item is MessageItem) {
|
|
||||||
Timber.i("Select message ${item.message.realId} item")
|
|
||||||
view?.run {
|
|
||||||
openMessage(item.message.realId)
|
|
||||||
if (item.message.unread) {
|
|
||||||
item.message.unread = false
|
|
||||||
updateItem(item)
|
|
||||||
updateMessage(item.message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateMessage(message: Message) {
|
private fun updateMessage(message: Message) {
|
||||||
Timber.i("Attempt to update message ${message.realId}")
|
Timber.i("Attempt to update message ${message.realId}")
|
||||||
disposable.add(messageRepository.updateMessage(message)
|
disposable.add(messageRepository.updateMessage(message)
|
||||||
|
@ -10,8 +10,8 @@ class MorePresenter @Inject constructor(errorHandler: ErrorHandler) : BasePresen
|
|||||||
|
|
||||||
override fun onAttachView(view: MoreView) {
|
override fun onAttachView(view: MoreView) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
Timber.i("More view is attached")
|
|
||||||
view.initView()
|
view.initView()
|
||||||
|
Timber.i("More view was initialized")
|
||||||
loadData()
|
loadData()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,8 +23,8 @@ class NotePresenter @Inject constructor(
|
|||||||
|
|
||||||
override fun onAttachView(view: NoteView) {
|
override fun onAttachView(view: NoteView) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
Timber.i("Note view is attached")
|
|
||||||
view.initView()
|
view.initView()
|
||||||
|
Timber.i("Note view was initialized")
|
||||||
loadData()
|
loadData()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@ package io.github.wulkanowy.ui.modules.settings
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.appcompat.app.AppCompatDelegate
|
|
||||||
import com.takisoft.preferencex.PreferenceFragmentCompat
|
import com.takisoft.preferencex.PreferenceFragmentCompat
|
||||||
import dagger.android.support.AndroidSupportInjection
|
import dagger.android.support.AndroidSupportInjection
|
||||||
import io.github.wulkanowy.BuildConfig.DEBUG
|
import io.github.wulkanowy.BuildConfig.DEBUG
|
||||||
@ -44,8 +43,7 @@ class SettingsFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedP
|
|||||||
presenter.onSharedPreferenceChanged(key)
|
presenter.onSharedPreferenceChanged(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setTheme(theme: Int) {
|
override fun recreateView() {
|
||||||
AppCompatDelegate.setDefaultNightMode(theme)
|
|
||||||
activity?.recreate()
|
activity?.recreate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ class SettingsPresenter @Inject constructor(
|
|||||||
|
|
||||||
override fun onAttachView(view: SettingsView) {
|
override fun onAttachView(view: SettingsView) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
Timber.i("Settings view is attached")
|
Timber.i("Settings view was initialized")
|
||||||
view.setServicesSuspended(preferencesRepository.serviceEnableKey, now().isHolidays)
|
view.setServicesSuspended(preferencesRepository.serviceEnableKey, now().isHolidays)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,8 +31,8 @@ class SettingsPresenter @Inject constructor(
|
|||||||
when (key) {
|
when (key) {
|
||||||
serviceEnableKey -> syncManager.run { if (isServiceEnabled) startSyncWorker() else stopSyncWorker() }
|
serviceEnableKey -> syncManager.run { if (isServiceEnabled) startSyncWorker() else stopSyncWorker() }
|
||||||
servicesIntervalKey, servicesOnlyWifiKey -> syncManager.startSyncWorker(true)
|
servicesIntervalKey, servicesOnlyWifiKey -> syncManager.startSyncWorker(true)
|
||||||
currentThemeKey -> view?.setTheme(currentTheme)
|
|
||||||
isDebugNotificationEnableKey -> chuckCollector.showNotification(isDebugNotificationEnable)
|
isDebugNotificationEnableKey -> chuckCollector.showNotification(isDebugNotificationEnable)
|
||||||
|
appThemeKey -> view?.recreateView()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
analytics.logEvent("setting_changed", "name" to key)
|
analytics.logEvent("setting_changed", "name" to key)
|
||||||
|
@ -4,7 +4,7 @@ import io.github.wulkanowy.ui.base.BaseView
|
|||||||
|
|
||||||
interface SettingsView : BaseView {
|
interface SettingsView : BaseView {
|
||||||
|
|
||||||
fun setTheme(theme: Int)
|
fun recreateView()
|
||||||
|
|
||||||
fun setServicesSuspended(serviceEnablesKey: String, isHolidays: Boolean)
|
fun setServicesSuspended(serviceEnablesKey: String, isHolidays: Boolean)
|
||||||
}
|
}
|
||||||
|
@ -80,12 +80,12 @@ class TimetableFragment : BaseSessionFragment(), TimetableView, MainView.MainChi
|
|||||||
timetableNextButton.setOnClickListener { presenter.onNextDay() }
|
timetableNextButton.setOnClickListener { presenter.onNextDay() }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
inflater?.inflate(R.menu.action_menu_timetable, menu)
|
inflater.inflate(R.menu.action_menu_timetable, menu)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
return if (item?.itemId == R.id.timetableMenuCompletedLessons) presenter.onCompletedLessonsSwitchSelected()
|
return if (item.itemId == R.id.timetableMenuCompletedLessons) presenter.onCompletedLessonsSwitchSelected()
|
||||||
else false
|
else false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,8 +35,8 @@ class TimetablePresenter @Inject constructor(
|
|||||||
|
|
||||||
fun onAttachView(view: TimetableView, date: Long?) {
|
fun onAttachView(view: TimetableView, date: Long?) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
Timber.i("Timetable is attached")
|
|
||||||
view.initView()
|
view.initView()
|
||||||
|
Timber.i("Timetable was initialized")
|
||||||
loadData(ofEpochDay(date ?: now().nextOrSameSchoolDay.toEpochDay()))
|
loadData(ofEpochDay(date ?: now().nextOrSameSchoolDay.toEpochDay()))
|
||||||
reloadView()
|
reloadView()
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,79 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.timetablewidget
|
||||||
|
|
||||||
|
import android.appwidget.AppWidgetManager.ACTION_APPWIDGET_UPDATE
|
||||||
|
import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID
|
||||||
|
import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_IDS
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.widget.Toast
|
||||||
|
import android.widget.Toast.LENGTH_LONG
|
||||||
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
|
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
|
||||||
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||||
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.ui.base.BaseActivity
|
||||||
|
import io.github.wulkanowy.ui.modules.login.LoginActivity
|
||||||
|
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider.Companion.EXTRA_FROM_PROVIDER
|
||||||
|
import io.github.wulkanowy.utils.setOnItemClickListener
|
||||||
|
import kotlinx.android.synthetic.main.activity_widget_configure.*
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class TimetableWidgetConfigureActivity : BaseActivity(), TimetableWidgetConfigureView {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var configureAdapter: FlexibleAdapter<AbstractFlexibleItem<*>>
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var presenter: TimetableWidgetConfigurePresenter
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setResult(RESULT_CANCELED)
|
||||||
|
setContentView(R.layout.activity_widget_configure)
|
||||||
|
|
||||||
|
intent.extras.let {
|
||||||
|
presenter.onAttachView(this, it?.getInt(EXTRA_APPWIDGET_ID), it?.getBoolean(EXTRA_FROM_PROVIDER))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun initView() {
|
||||||
|
widgetConfigureRecycler.apply {
|
||||||
|
adapter = configureAdapter
|
||||||
|
layoutManager = SmoothScrollLinearLayoutManager(context)
|
||||||
|
}
|
||||||
|
configureAdapter.setOnItemClickListener { presenter.onItemSelect(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateData(data: List<TimetableWidgetConfigureItem>) {
|
||||||
|
configureAdapter.updateDataSet(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateTimetableWidget(widgetId: Int) {
|
||||||
|
sendBroadcast(Intent(this, TimetableWidgetProvider::class.java)
|
||||||
|
.apply {
|
||||||
|
action = ACTION_APPWIDGET_UPDATE
|
||||||
|
putExtra(EXTRA_APPWIDGET_IDS, intArrayOf(widgetId))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setSuccessResult(widgetId: Int) {
|
||||||
|
setResult(RESULT_OK, Intent().apply { putExtra(EXTRA_APPWIDGET_ID, widgetId) })
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showError(text: String, error: Throwable) {
|
||||||
|
Toast.makeText(this, text, LENGTH_LONG).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun finishView() {
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun openLoginView() {
|
||||||
|
startActivity(LoginActivity.getStartIntent(this))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
presenter.onDetachView()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.timetablewidget
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.view.View
|
||||||
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||||
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
|
import eu.davidea.viewholders.FlexibleViewHolder
|
||||||
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
|
import kotlinx.android.extensions.LayoutContainer
|
||||||
|
import kotlinx.android.synthetic.main.item_account.*
|
||||||
|
|
||||||
|
class TimetableWidgetConfigureItem(val student: Student, private val isCurrent: Boolean) :
|
||||||
|
AbstractFlexibleItem<TimetableWidgetConfigureItem.ViewHolder>() {
|
||||||
|
|
||||||
|
override fun getLayoutRes() = R.layout.item_account
|
||||||
|
|
||||||
|
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<*>>): ViewHolder {
|
||||||
|
return ViewHolder(view, adapter)
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("SetTextI18n")
|
||||||
|
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder, position: Int, payloads: MutableList<Any>) {
|
||||||
|
holder.apply {
|
||||||
|
accountItemName.text = "${student.studentName} ${student.className}"
|
||||||
|
accountItemSchool.text = student.schoolName
|
||||||
|
accountItemImage.setBackgroundResource(if (isCurrent) R.drawable.ic_account_circular_border else 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
|
||||||
|
other as TimetableWidgetConfigureItem
|
||||||
|
|
||||||
|
if (student != other.student) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
var result = student.hashCode()
|
||||||
|
result = 31 * result + student.id.toInt()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
class ViewHolder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer {
|
||||||
|
override val containerView: View
|
||||||
|
get() = contentView
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.timetablewidget
|
||||||
|
|
||||||
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||||
|
import io.github.wulkanowy.data.db.SharedPrefHelper
|
||||||
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
|
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.ui.modules.timetablewidget.TimetableWidgetProvider.Companion.getStudentWidgetKey
|
||||||
|
import io.github.wulkanowy.utils.SchedulersProvider
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class TimetableWidgetConfigurePresenter @Inject constructor(
|
||||||
|
private val errorHandler: ErrorHandler,
|
||||||
|
private val schedulers: SchedulersProvider,
|
||||||
|
private val studentRepository: StudentRepository,
|
||||||
|
private val sharedPref: SharedPrefHelper
|
||||||
|
) : BasePresenter<TimetableWidgetConfigureView>(errorHandler) {
|
||||||
|
|
||||||
|
private var appWidgetId: Int? = null
|
||||||
|
|
||||||
|
private var isFromProvider = false
|
||||||
|
|
||||||
|
fun onAttachView(view: TimetableWidgetConfigureView, appWidgetId: Int?, isFromProvider: Boolean?) {
|
||||||
|
super.onAttachView(view)
|
||||||
|
this.appWidgetId = appWidgetId
|
||||||
|
this.isFromProvider = isFromProvider ?: false
|
||||||
|
view.initView()
|
||||||
|
loadData()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onItemSelect(item: AbstractFlexibleItem<*>) {
|
||||||
|
if (item is TimetableWidgetConfigureItem) {
|
||||||
|
registerStudent(item.student)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadData() {
|
||||||
|
disposable.add(studentRepository.getSavedStudents(false)
|
||||||
|
.map { it to appWidgetId?.let { id -> sharedPref.getLong(getStudentWidgetKey(id), 0) } }
|
||||||
|
.map { (students, currentStudentId) ->
|
||||||
|
students.map { student -> TimetableWidgetConfigureItem(student, student.id == currentStudentId) }
|
||||||
|
}
|
||||||
|
.subscribeOn(schedulers.backgroundThread)
|
||||||
|
.observeOn(schedulers.mainThread)
|
||||||
|
.subscribe({
|
||||||
|
when {
|
||||||
|
it.isEmpty() -> view?.openLoginView()
|
||||||
|
it.size == 1 && !isFromProvider -> registerStudent(it.single().student)
|
||||||
|
else -> view?.updateData(it)
|
||||||
|
}
|
||||||
|
}, { errorHandler.dispatch(it) }))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun registerStudent(student: Student) {
|
||||||
|
appWidgetId?.also {
|
||||||
|
sharedPref.putLong(getStudentWidgetKey(it), student.id)
|
||||||
|
view?.apply {
|
||||||
|
updateTimetableWidget(it)
|
||||||
|
setSuccessResult(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
view?.finishView()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.timetablewidget
|
||||||
|
|
||||||
|
import io.github.wulkanowy.ui.base.BaseView
|
||||||
|
|
||||||
|
interface TimetableWidgetConfigureView : BaseView {
|
||||||
|
|
||||||
|
fun initView()
|
||||||
|
|
||||||
|
fun updateData(data: List<TimetableWidgetConfigureItem>)
|
||||||
|
|
||||||
|
fun updateTimetableWidget(widgetId: Int)
|
||||||
|
|
||||||
|
fun setSuccessResult(widgetId: Int)
|
||||||
|
|
||||||
|
fun finishView()
|
||||||
|
|
||||||
|
fun openLoginView()
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
package io.github.wulkanowy.ui.widgets.timetable
|
package io.github.wulkanowy.ui.modules.timetablewidget
|
||||||
|
|
||||||
|
import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.Paint.ANTI_ALIAS_FLAG
|
import android.graphics.Paint.ANTI_ALIAS_FLAG
|
||||||
@ -15,9 +16,11 @@ import io.github.wulkanowy.data.db.entities.Timetable
|
|||||||
import io.github.wulkanowy.data.repositories.semester.SemesterRepository
|
import io.github.wulkanowy.data.repositories.semester.SemesterRepository
|
||||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||||
import io.github.wulkanowy.data.repositories.timetable.TimetableRepository
|
import io.github.wulkanowy.data.repositories.timetable.TimetableRepository
|
||||||
|
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider.Companion.getDateWidgetKey
|
||||||
|
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider.Companion.getStudentWidgetKey
|
||||||
import io.github.wulkanowy.utils.SchedulersProvider
|
import io.github.wulkanowy.utils.SchedulersProvider
|
||||||
import io.github.wulkanowy.utils.toFormattedString
|
import io.github.wulkanowy.utils.toFormattedString
|
||||||
import io.reactivex.Single
|
import io.reactivex.Maybe
|
||||||
import org.threeten.bp.LocalDate
|
import org.threeten.bp.LocalDate
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
@ -48,28 +51,37 @@ class TimetableWidgetFactory(
|
|||||||
override fun onDestroy() {}
|
override fun onDestroy() {}
|
||||||
|
|
||||||
override fun onDataSetChanged() {
|
override fun onDataSetChanged() {
|
||||||
intent?.action?.let { LocalDate.ofEpochDay(sharedPref.getLong(it, 0)) }
|
intent?.extras?.getInt(EXTRA_APPWIDGET_ID)?.let { appWidgetId ->
|
||||||
?.let { date ->
|
val date = LocalDate.ofEpochDay(sharedPref.getLong(getDateWidgetKey(appWidgetId), 0))
|
||||||
try {
|
val studentId = sharedPref.getLong(getStudentWidgetKey(appWidgetId), 0)
|
||||||
lessons = studentRepository.isStudentSaved()
|
|
||||||
.flatMap { isSaved ->
|
lessons = try {
|
||||||
if (isSaved) {
|
studentRepository.isStudentSaved()
|
||||||
studentRepository.getCurrentStudent()
|
.filter { true }
|
||||||
.flatMap { semesterRepository.getCurrentSemester(it) }
|
.flatMap { studentRepository.getSavedStudents().toMaybe() }
|
||||||
.flatMap { timetableRepository.getTimetable(it, date, date) }
|
.flatMap {
|
||||||
} else Single.just(emptyList())
|
if (studentId == 0L) throw IllegalArgumentException("Student id is 0")
|
||||||
|
|
||||||
|
it.singleOrNull { student -> student.id == studentId }
|
||||||
|
.let { student ->
|
||||||
|
if (student != null) Maybe.just(student)
|
||||||
|
else Maybe.empty()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
.flatMap { semesterRepository.getCurrentSemester(it).toMaybe() }
|
||||||
|
.flatMap { timetableRepository.getTimetable(it, date, date).toMaybe() }
|
||||||
.map { item -> item.sortedBy { it.number } }
|
.map { item -> item.sortedBy { it.number } }
|
||||||
.subscribeOn(schedulers.backgroundThread)
|
.subscribeOn(schedulers.backgroundThread)
|
||||||
.blockingGet()
|
.blockingGet(emptyList())
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Timber.e(e, "An error has occurred while downloading data for the widget")
|
Timber.e(e, "An error has occurred in timetable widget factory")
|
||||||
|
emptyList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getViewAt(position: Int): RemoteViews? {
|
override fun getViewAt(position: Int): RemoteViews? {
|
||||||
if (position == INVALID_POSITION || lessons.getOrNull(position) === null) return null
|
if (position == INVALID_POSITION || lessons.getOrNull(position) == null) return null
|
||||||
|
|
||||||
return RemoteViews(context.packageName, R.layout.item_widget_timetable).apply {
|
return RemoteViews(context.packageName, R.layout.item_widget_timetable).apply {
|
||||||
lessons[position].let {
|
lessons[position].let {
|
@ -1,4 +1,4 @@
|
|||||||
package io.github.wulkanowy.ui.widgets.timetable
|
package io.github.wulkanowy.ui.modules.timetablewidget
|
||||||
|
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
import android.app.PendingIntent.FLAG_UPDATE_CURRENT
|
import android.app.PendingIntent.FLAG_UPDATE_CURRENT
|
||||||
@ -10,21 +10,28 @@ import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_IDS
|
|||||||
import android.content.BroadcastReceiver
|
import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||||
|
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
import android.widget.RemoteViews
|
import android.widget.RemoteViews
|
||||||
import dagger.android.AndroidInjection
|
import dagger.android.AndroidInjection
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.db.SharedPrefHelper
|
import io.github.wulkanowy.data.db.SharedPrefHelper
|
||||||
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
|
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||||
import io.github.wulkanowy.services.widgets.TimetableWidgetService
|
import io.github.wulkanowy.services.widgets.TimetableWidgetService
|
||||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||||
import io.github.wulkanowy.ui.modules.main.MainActivity.Companion.EXTRA_START_MENU_INDEX
|
import io.github.wulkanowy.ui.modules.main.MainView.MenuView
|
||||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||||
|
import io.github.wulkanowy.utils.SchedulersProvider
|
||||||
import io.github.wulkanowy.utils.nextOrSameSchoolDay
|
import io.github.wulkanowy.utils.nextOrSameSchoolDay
|
||||||
import io.github.wulkanowy.utils.nextSchoolDay
|
import io.github.wulkanowy.utils.nextSchoolDay
|
||||||
import io.github.wulkanowy.utils.previousSchoolDay
|
import io.github.wulkanowy.utils.previousSchoolDay
|
||||||
|
import io.github.wulkanowy.utils.shortcutWeekDayName
|
||||||
import io.github.wulkanowy.utils.toFormattedString
|
import io.github.wulkanowy.utils.toFormattedString
|
||||||
import io.github.wulkanowy.utils.weekDayName
|
import io.reactivex.Maybe
|
||||||
import org.threeten.bp.LocalDate
|
import org.threeten.bp.LocalDate
|
||||||
import org.threeten.bp.LocalDate.now
|
import org.threeten.bp.LocalDate.now
|
||||||
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class TimetableWidgetProvider : BroadcastReceiver() {
|
class TimetableWidgetProvider : BroadcastReceiver() {
|
||||||
@ -32,13 +39,21 @@ class TimetableWidgetProvider : BroadcastReceiver() {
|
|||||||
@Inject
|
@Inject
|
||||||
lateinit var appWidgetManager: AppWidgetManager
|
lateinit var appWidgetManager: AppWidgetManager
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var studentRepository: StudentRepository
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var sharedPref: SharedPrefHelper
|
lateinit var sharedPref: SharedPrefHelper
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var schedulers: SchedulersProvider
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var analytics: FirebaseAnalyticsHelper
|
lateinit var analytics: FirebaseAnalyticsHelper
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
const val EXTRA_FROM_PROVIDER = "extraFromProvider"
|
||||||
|
|
||||||
const val EXTRA_TOGGLED_WIDGET_ID = "extraToggledWidget"
|
const val EXTRA_TOGGLED_WIDGET_ID = "extraToggledWidget"
|
||||||
|
|
||||||
const val EXTRA_BUTTON_TYPE = "extraButtonType"
|
const val EXTRA_BUTTON_TYPE = "extraButtonType"
|
||||||
@ -49,7 +64,9 @@ class TimetableWidgetProvider : BroadcastReceiver() {
|
|||||||
|
|
||||||
const val BUTTON_RESET = "buttonReset"
|
const val BUTTON_RESET = "buttonReset"
|
||||||
|
|
||||||
fun createWidgetKey(appWidgetId: Int) = "timetable_widget_$appWidgetId"
|
fun getDateWidgetKey(appWidgetId: Int) = "timetable_widget_date_$appWidgetId"
|
||||||
|
|
||||||
|
fun getStudentWidgetKey(appWidgetId: Int) = "timetable_widget_student_$appWidgetId"
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
@ -63,12 +80,14 @@ class TimetableWidgetProvider : BroadcastReceiver() {
|
|||||||
private fun onUpdate(context: Context, intent: Intent) {
|
private fun onUpdate(context: Context, intent: Intent) {
|
||||||
if (intent.getStringExtra(EXTRA_BUTTON_TYPE) === null) {
|
if (intent.getStringExtra(EXTRA_BUTTON_TYPE) === null) {
|
||||||
intent.getIntArrayExtra(EXTRA_APPWIDGET_IDS)?.forEach { appWidgetId ->
|
intent.getIntArrayExtra(EXTRA_APPWIDGET_IDS)?.forEach { appWidgetId ->
|
||||||
updateWidget(context, appWidgetId, now().nextOrSameSchoolDay)
|
val student = getStudent(sharedPref.getLong(getStudentWidgetKey(appWidgetId), 0), appWidgetId)
|
||||||
|
updateWidget(context, appWidgetId, now().nextOrSameSchoolDay, student)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val buttonType = intent.getStringExtra(EXTRA_BUTTON_TYPE)
|
val buttonType = intent.getStringExtra(EXTRA_BUTTON_TYPE)
|
||||||
val toggledWidgetId = intent.getIntExtra(EXTRA_TOGGLED_WIDGET_ID, 0)
|
val toggledWidgetId = intent.getIntExtra(EXTRA_TOGGLED_WIDGET_ID, 0)
|
||||||
val savedDate = LocalDate.ofEpochDay(sharedPref.getLong(createWidgetKey(toggledWidgetId), 0))
|
val student = getStudent(sharedPref.getLong(getStudentWidgetKey(toggledWidgetId), 0), toggledWidgetId)
|
||||||
|
val savedDate = LocalDate.ofEpochDay(sharedPref.getLong(getDateWidgetKey(toggledWidgetId), 0))
|
||||||
val date = when (buttonType) {
|
val date = when (buttonType) {
|
||||||
BUTTON_RESET -> now().nextOrSameSchoolDay
|
BUTTON_RESET -> now().nextOrSameSchoolDay
|
||||||
BUTTON_NEXT -> savedDate.nextSchoolDay
|
BUTTON_NEXT -> savedDate.nextSchoolDay
|
||||||
@ -76,35 +95,45 @@ class TimetableWidgetProvider : BroadcastReceiver() {
|
|||||||
else -> now().nextOrSameSchoolDay
|
else -> now().nextOrSameSchoolDay
|
||||||
}
|
}
|
||||||
if (!buttonType.isNullOrBlank()) analytics.logEvent("changed_timetable_widget_day", "button" to buttonType)
|
if (!buttonType.isNullOrBlank()) analytics.logEvent("changed_timetable_widget_day", "button" to buttonType)
|
||||||
updateWidget(context, toggledWidgetId, date)
|
updateWidget(context, toggledWidgetId, date, student)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onDelete(intent: Intent) {
|
private fun onDelete(intent: Intent) {
|
||||||
intent.getIntExtra(EXTRA_APPWIDGET_ID, 0).let {
|
intent.getIntExtra(EXTRA_APPWIDGET_ID, 0).let {
|
||||||
if (it != 0) sharedPref.delete(createWidgetKey(it))
|
if (it != 0) {
|
||||||
|
sharedPref.apply {
|
||||||
|
delete(getStudentWidgetKey(it))
|
||||||
|
delete(getDateWidgetKey(it))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateWidget(context: Context, appWidgetId: Int, date: LocalDate) {
|
private fun updateWidget(context: Context, appWidgetId: Int, date: LocalDate, student: Student?) {
|
||||||
RemoteViews(context.packageName, R.layout.widget_timetable).apply {
|
RemoteViews(context.packageName, R.layout.widget_timetable).apply {
|
||||||
setEmptyView(R.id.timetableWidgetList, R.id.timetableWidgetEmpty)
|
setEmptyView(R.id.timetableWidgetList, R.id.timetableWidgetEmpty)
|
||||||
setTextViewText(R.id.timetableWidgetDay, date.weekDayName.capitalize())
|
setTextViewText(R.id.timetableWidgetDate, "${date.shortcutWeekDayName.capitalize()} ${date.toFormattedString()}")
|
||||||
setTextViewText(R.id.timetableWidgetDate, date.toFormattedString())
|
setTextViewText(R.id.timetableWidgetName, student?.studentName ?: context.getString(R.string.all_no_data))
|
||||||
setRemoteAdapter(R.id.timetableWidgetList, Intent(context, TimetableWidgetService::class.java)
|
setRemoteAdapter(R.id.timetableWidgetList, Intent(context, TimetableWidgetService::class.java)
|
||||||
.apply { action = createWidgetKey(appWidgetId) })
|
.apply { putExtra(EXTRA_APPWIDGET_ID, appWidgetId) })
|
||||||
setOnClickPendingIntent(R.id.timetableWidgetNext, createNavIntent(context, appWidgetId, appWidgetId, BUTTON_NEXT))
|
setOnClickPendingIntent(R.id.timetableWidgetNext, createNavIntent(context, appWidgetId, appWidgetId, BUTTON_NEXT))
|
||||||
setOnClickPendingIntent(R.id.timetableWidgetPrev, createNavIntent(context, -appWidgetId, appWidgetId, BUTTON_PREV))
|
setOnClickPendingIntent(R.id.timetableWidgetPrev, createNavIntent(context, -appWidgetId, appWidgetId, BUTTON_PREV))
|
||||||
createNavIntent(context, Int.MAX_VALUE - appWidgetId, appWidgetId, BUTTON_RESET).also {
|
createNavIntent(context, Int.MAX_VALUE - appWidgetId, appWidgetId, BUTTON_RESET).let {
|
||||||
setOnClickPendingIntent(R.id.timetableWidgetDate, it)
|
setOnClickPendingIntent(R.id.timetableWidgetDate, it)
|
||||||
setOnClickPendingIntent(R.id.timetableWidgetDay, it)
|
setOnClickPendingIntent(R.id.timetableWidgetName, it)
|
||||||
}
|
}
|
||||||
setPendingIntentTemplate(R.id.timetableWidgetList,
|
setOnClickPendingIntent(R.id.timetableWidgetAccount, PendingIntent.getActivity(context, -Int.MAX_VALUE + appWidgetId,
|
||||||
PendingIntent.getActivity(context, 1, MainActivity.getStartIntent(context).apply {
|
Intent(context, TimetableWidgetConfigureActivity::class.java).apply {
|
||||||
putExtra(EXTRA_START_MENU_INDEX, 3)
|
addFlags(FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_CLEAR_TASK)
|
||||||
|
putExtra(EXTRA_APPWIDGET_ID, appWidgetId)
|
||||||
|
putExtra(EXTRA_FROM_PROVIDER, true)
|
||||||
}, FLAG_UPDATE_CURRENT))
|
}, FLAG_UPDATE_CURRENT))
|
||||||
|
setPendingIntentTemplate(R.id.timetableWidgetList,
|
||||||
|
PendingIntent.getActivity(context, MenuView.TIMETABLE.id,
|
||||||
|
MainActivity.getStartIntent(context, MenuView.TIMETABLE, true), FLAG_UPDATE_CURRENT))
|
||||||
}.also {
|
}.also {
|
||||||
sharedPref.putLong(createWidgetKey(appWidgetId), date.toEpochDay(), true)
|
sharedPref.putLong(getDateWidgetKey(appWidgetId), date.toEpochDay(), true)
|
||||||
appWidgetManager.apply {
|
appWidgetManager.apply {
|
||||||
notifyAppWidgetViewDataChanged(appWidgetId, R.id.timetableWidgetList)
|
notifyAppWidgetViewDataChanged(appWidgetId, R.id.timetableWidgetList)
|
||||||
updateAppWidget(appWidgetId, it)
|
updateAppWidget(appWidgetId, it)
|
||||||
@ -120,4 +149,31 @@ class TimetableWidgetProvider : BroadcastReceiver() {
|
|||||||
putExtra(EXTRA_TOGGLED_WIDGET_ID, appWidgetId)
|
putExtra(EXTRA_TOGGLED_WIDGET_ID, appWidgetId)
|
||||||
}, FLAG_UPDATE_CURRENT)
|
}, FLAG_UPDATE_CURRENT)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getStudent(studentId: Long, appWidgetId: Int): Student? {
|
||||||
|
return try {
|
||||||
|
studentRepository.isStudentSaved()
|
||||||
|
.filter { true }
|
||||||
|
.flatMap { studentRepository.getSavedStudents(false).toMaybe() }
|
||||||
|
.flatMap { students ->
|
||||||
|
students.singleOrNull { student -> student.id == studentId }
|
||||||
|
.let { student ->
|
||||||
|
when {
|
||||||
|
student != null -> Maybe.just(student)
|
||||||
|
studentId != 0L -> {
|
||||||
|
studentRepository.getCurrentStudent(false)
|
||||||
|
.toMaybe()
|
||||||
|
.doOnSuccess { sharedPref.putLong(getStudentWidgetKey(appWidgetId), it.id) }
|
||||||
|
}
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.subscribeOn(schedulers.backgroundThread)
|
||||||
|
.blockingGet()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Timber.e(e, "An error has occurred in timetable widget provider")
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -2,10 +2,11 @@ package io.github.wulkanowy.utils
|
|||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import com.google.firebase.analytics.FirebaseAnalytics
|
import com.google.firebase.analytics.FirebaseAnalytics
|
||||||
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class FirebaseAnalyticsHelper(private val analytics: FirebaseAnalytics) {
|
class FirebaseAnalyticsHelper @Inject constructor(private val analytics: FirebaseAnalytics) {
|
||||||
|
|
||||||
fun logEvent(name: String, vararg params: Pair<String, Any?>) {
|
fun logEvent(name: String, vararg params: Pair<String, Any?>) {
|
||||||
Bundle().apply {
|
Bundle().apply {
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
package io.github.wulkanowy.utils
|
||||||
|
|
||||||
|
infix fun <T> List<T>.uniqueSubtract(other: List<T>): List<T> {
|
||||||
|
val list = toMutableList()
|
||||||
|
other.forEach {
|
||||||
|
list.remove(it)
|
||||||
|
}
|
||||||
|
return list.toList()
|
||||||
|
}
|
@ -1,7 +1,16 @@
|
|||||||
package io.github.wulkanowy.utils
|
package io.github.wulkanowy.utils
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.app.Application
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.fragment.app.FragmentManager
|
||||||
import com.crashlytics.android.Crashlytics
|
import com.crashlytics.android.Crashlytics
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
class DebugLogTree : Timber.DebugTree() {
|
class DebugLogTree : Timber.DebugTree() {
|
||||||
|
|
||||||
@ -20,3 +29,88 @@ class CrashlyticsTree : Timber.Tree() {
|
|||||||
else Crashlytics.logException(t)
|
else Crashlytics.logException(t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ActivityLifecycleLogger : Application.ActivityLifecycleCallbacks {
|
||||||
|
|
||||||
|
override fun onActivityPaused(activity: Activity?) {
|
||||||
|
activity?.let { Timber.d("${it::class.java.simpleName} PAUSED") }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityResumed(activity: Activity?) {
|
||||||
|
activity?.let { Timber.d("${it::class.java.simpleName} RESUMED") }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityStarted(activity: Activity?) {
|
||||||
|
activity?.let { Timber.d("${it::class.java.simpleName} STARTED") }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityDestroyed(activity: Activity?) {
|
||||||
|
activity?.let { Timber.d("${it::class.java.simpleName} DESTROYED") }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivitySaveInstanceState(activity: Activity?, outState: Bundle?) {
|
||||||
|
activity?.let { Timber.d("${it::class.java.simpleName} SAVED INSTANCE STATE") }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityStopped(activity: Activity?) {
|
||||||
|
activity?.let { Timber.d("${it::class.java.simpleName} STOPPED") }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityCreated(activity: Activity?, savedInstanceState: Bundle?) {
|
||||||
|
activity?.let { Timber.d("${it::class.java.simpleName} CREATED ${checkSavedState(savedInstanceState)}") }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class FragmentLifecycleLogger @Inject constructor() : FragmentManager.FragmentLifecycleCallbacks() {
|
||||||
|
|
||||||
|
override fun onFragmentViewCreated(fm: FragmentManager, f: Fragment, v: View, savedInstanceState: Bundle?) {
|
||||||
|
Timber.d("${f::class.java.simpleName} VIEW CREATED ${checkSavedState(savedInstanceState)}")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFragmentStopped(fm: FragmentManager, f: Fragment) {
|
||||||
|
Timber.d("${f::class.java.simpleName} STOPPED")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFragmentCreated(fm: FragmentManager, f: Fragment, savedInstanceState: Bundle?) {
|
||||||
|
Timber.d("${f::class.java.simpleName} CREATED ${checkSavedState(savedInstanceState)}")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFragmentResumed(fm: FragmentManager, f: Fragment) {
|
||||||
|
Timber.d("${f::class.java.simpleName} RESUMED")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFragmentAttached(fm: FragmentManager, f: Fragment, context: Context) {
|
||||||
|
Timber.d("${f::class.java.simpleName} ATTACHED")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFragmentDestroyed(fm: FragmentManager, f: Fragment) {
|
||||||
|
Timber.d("${f::class.java.simpleName} DESTROYED")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFragmentSaveInstanceState(fm: FragmentManager, f: Fragment, outState: Bundle) {
|
||||||
|
Timber.d("${f::class.java.simpleName} SAVED INSTANCE STATE")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFragmentStarted(fm: FragmentManager, f: Fragment) {
|
||||||
|
Timber.d("${f::class.java.simpleName} STARTED")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFragmentViewDestroyed(fm: FragmentManager, f: Fragment) {
|
||||||
|
Timber.d("${f::class.java.simpleName} VIEW DESTROYED")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFragmentActivityCreated(fm: FragmentManager, f: Fragment, savedInstanceState: Bundle?) {
|
||||||
|
Timber.d("${f::class.java.simpleName} ACTIVITY CREATED ${checkSavedState(savedInstanceState)}")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFragmentPaused(fm: FragmentManager, f: Fragment) {
|
||||||
|
Timber.d("${f::class.java.simpleName} PAUSED")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFragmentDetached(fm: FragmentManager, f: Fragment) {
|
||||||
|
Timber.d("${f::class.java.simpleName} DETACHED")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkSavedState(savedInstanceState: Bundle?) = if (savedInstanceState == null) "(STATE IS NULL)" else ""
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user