mirror of
https://github.com/wulkanowy/wulkanowy.git
synced 2025-01-18 13:36:47 -06:00
Services refactor (#168)
This commit is contained in:
parent
ab71dd3fde
commit
70879945f2
@ -38,7 +38,7 @@ jobs:
|
|||||||
command: ./gradlew build -x test -x lint -x fabricGenerateResourcesRelease -x packageRelease --no-daemon --stacktrace --console=plain -PdisablePreDex
|
command: ./gradlew build -x test -x lint -x fabricGenerateResourcesRelease -x packageRelease --no-daemon --stacktrace --console=plain -PdisablePreDex
|
||||||
- run:
|
- run:
|
||||||
name: Run FOSSA
|
name: Run FOSSA
|
||||||
command: fossa --no-ansi
|
command: fossa --no-ansi || true
|
||||||
- persist_to_workspace:
|
- persist_to_workspace:
|
||||||
root: *workspace_root
|
root: *workspace_root
|
||||||
paths:
|
paths:
|
||||||
@ -113,7 +113,7 @@ jobs:
|
|||||||
adb shell input keyevent 82
|
adb shell input keyevent 82
|
||||||
- run:
|
- run:
|
||||||
name: Run instrumented tests
|
name: Run instrumented tests
|
||||||
command: ./gradlew clean createDebugCoverageReport jacocoTestReport --no-daemon --stacktrace --console=plain -PdisablePreDex
|
command: ./gradlew clean createDebugCoverageReport jacocoTestReport --no-daemon --stacktrace --console=plain -PdisablePreDex -PdisableCrashlytics
|
||||||
- run:
|
- run:
|
||||||
name: Collect logs from emulator
|
name: Collect logs from emulator
|
||||||
command: adb logcat -d > ./app/build/reports/logcat_emulator.txt
|
command: adb logcat -d > ./app/build/reports/logcat_emulator.txt
|
||||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -33,7 +33,6 @@ local.properties
|
|||||||
.idea/vcs.xml
|
.idea/vcs.xml
|
||||||
.idea/workspace.xml
|
.idea/workspace.xml
|
||||||
.idea/caches/
|
.idea/caches/
|
||||||
.idea/codeStyles/
|
|
||||||
*.iml
|
*.iml
|
||||||
|
|
||||||
# OS-specific files
|
# OS-specific files
|
||||||
@ -44,7 +43,7 @@ local.properties
|
|||||||
.Trashes
|
.Trashes
|
||||||
ehthumbs.db
|
ehthumbs.db
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
.idea/codeStyles/
|
|
||||||
.idea/caches/
|
.idea/caches/
|
||||||
./app/key.p12
|
./app/key.p12
|
||||||
./app/upload-key.jks
|
./app/upload-key.jks
|
||||||
|
*.log
|
||||||
|
174
.idea/codeStyles/Project.xml
generated
Normal file
174
.idea/codeStyles/Project.xml
generated
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<code_scheme name="Project" version="173">
|
||||||
|
<option name="LINE_SEPARATOR" value=" " />
|
||||||
|
<AndroidXmlCodeStyleSettings>
|
||||||
|
<option name="USE_CUSTOM_SETTINGS" value="true" />
|
||||||
|
</AndroidXmlCodeStyleSettings>
|
||||||
|
<JetCodeStyleSettings>
|
||||||
|
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
|
||||||
|
<value>
|
||||||
|
<package name="kotlinx.android.synthetic" withSubpackages="true" static="false" />
|
||||||
|
</value>
|
||||||
|
</option>
|
||||||
|
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />
|
||||||
|
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="2147483647" />
|
||||||
|
<option name="CONTINUATION_INDENT_IN_PARAMETER_LISTS" value="false" />
|
||||||
|
<option name="CONTINUATION_INDENT_IN_ARGUMENT_LISTS" value="false" />
|
||||||
|
<option name="CONTINUATION_INDENT_FOR_EXPRESSION_BODIES" value="false" />
|
||||||
|
<option name="CONTINUATION_INDENT_FOR_CHAINED_CALLS" value="false" />
|
||||||
|
<option name="CONTINUATION_INDENT_IN_SUPERTYPE_LISTS" value="false" />
|
||||||
|
<option name="CONTINUATION_INDENT_IN_IF_CONDITIONS" value="false" />
|
||||||
|
<option name="CONTINUATION_INDENT_IN_ELVIS" value="false" />
|
||||||
|
<option name="WRAP_EXPRESSION_BODY_FUNCTIONS" value="1" />
|
||||||
|
</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>
|
||||||
|
<option name="XML_KEEP_LINE_BREAKS" value="false" />
|
||||||
|
<option name="XML_ALIGN_ATTRIBUTES" value="false" />
|
||||||
|
<option name="XML_SPACE_INSIDE_EMPTY_TAG" value="true" />
|
||||||
|
</XML>
|
||||||
|
<codeStyleSettings language="XML">
|
||||||
|
<option name="FORCE_REARRANGE_MODE" value="1" />
|
||||||
|
<indentOptions>
|
||||||
|
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||||
|
</indentOptions>
|
||||||
|
<arrangement>
|
||||||
|
<rules>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>xmlns:android</NAME>
|
||||||
|
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>xmlns:.*</NAME>
|
||||||
|
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
<order>BY_NAME</order>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>.*:id</NAME>
|
||||||
|
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>.*:name</NAME>
|
||||||
|
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>name</NAME>
|
||||||
|
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>style</NAME>
|
||||||
|
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>.*</NAME>
|
||||||
|
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
<order>BY_NAME</order>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>.*</NAME>
|
||||||
|
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
<order>ANDROID_ATTRIBUTE_ORDER</order>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>.*</NAME>
|
||||||
|
<XML_NAMESPACE>.*</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
<order>BY_NAME</order>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
</rules>
|
||||||
|
</arrangement>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="kotlin">
|
||||||
|
<option name="KEEP_BLANK_LINES_IN_DECLARATIONS" value="1" />
|
||||||
|
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
|
||||||
|
<option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="0" />
|
||||||
|
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
|
||||||
|
<option name="METHOD_PARAMETERS_WRAP" value="5" />
|
||||||
|
<option name="METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE" value="true" />
|
||||||
|
<option name="METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE" value="true" />
|
||||||
|
<option name="EXTENDS_LIST_WRAP" value="1" />
|
||||||
|
<option name="METHOD_CALL_CHAIN_WRAP" value="1" />
|
||||||
|
<option name="ASSIGNMENT_WRAP" value="1" />
|
||||||
|
<indentOptions>
|
||||||
|
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
</code_scheme>
|
||||||
|
</component>
|
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<state>
|
||||||
|
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||||
|
</state>
|
||||||
|
</component>
|
@ -7,6 +7,8 @@ apply plugin: 'com.github.triplet.play'
|
|||||||
apply from: 'jacoco.gradle'
|
apply from: 'jacoco.gradle'
|
||||||
apply from: 'sonarqube.gradle'
|
apply from: 'sonarqube.gradle'
|
||||||
|
|
||||||
|
def fabricApiKey = System.getenv("FABRIC_API_KEY") ?: "null"
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 28
|
compileSdkVersion 28
|
||||||
buildToolsVersion '28.0.3'
|
buildToolsVersion '28.0.3'
|
||||||
@ -29,9 +31,7 @@ android {
|
|||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
vectorDrawables.useSupportLibrary = true
|
vectorDrawables.useSupportLibrary = true
|
||||||
playAccountConfig = playAccountConfigs.defaultAccountConfig
|
playAccountConfig = playAccountConfigs.defaultAccountConfig
|
||||||
manifestPlaceholders = [
|
manifestPlaceholders = [ fabricApiKey: fabricApiKey ]
|
||||||
fabricApiKey: System.getenv("FABRIC_API_KEY") ?: "null"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
signingConfigs {
|
signingConfigs {
|
||||||
@ -45,18 +45,24 @@ android {
|
|||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
|
buildConfigField "boolean", "FABRIC_ENABLED", "true"
|
||||||
minifyEnabled false
|
minifyEnabled false
|
||||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||||
signingConfig signingConfigs.release
|
signingConfig signingConfigs.release
|
||||||
}
|
}
|
||||||
debug {
|
debug {
|
||||||
|
buildConfigField "boolean", "FABRIC_ENABLED", fabricApiKey == "null" ? "false" : "true"
|
||||||
applicationIdSuffix ".dev"
|
applicationIdSuffix ".dev"
|
||||||
versionNameSuffix "-dev"
|
versionNameSuffix "-dev"
|
||||||
testCoverageEnabled = true
|
testCoverageEnabled = true
|
||||||
ext.enableCrashlytics = false
|
ext.enableCrashlytics = fabricApiKey != "null" && !project.hasProperty("disableCrashlytics")
|
||||||
multiDexKeepProguard file('proguard-multidex-rules.pro')
|
multiDexKeepProguard file('proguard-multidex-rules.pro')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lintOptions {
|
||||||
|
disable 'HardwareIds'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
androidExtensions {
|
androidExtensions {
|
||||||
@ -72,7 +78,7 @@ ext.androidx_version = "1.0.0"
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||||
implementation('com.github.wulkanowy:api:1400211f0d') { exclude module: "threetenbp" }
|
implementation('com.github.wulkanowy:api:e829b094de') { exclude module: "threetenbp" }
|
||||||
|
|
||||||
implementation "androidx.legacy:legacy-support-v4:$androidx_version"
|
implementation "androidx.legacy:legacy-support-v4:$androidx_version"
|
||||||
implementation "androidx.appcompat:appcompat:$androidx_version"
|
implementation "androidx.appcompat:appcompat:$androidx_version"
|
||||||
@ -89,12 +95,13 @@ dependencies {
|
|||||||
kapt "com.google.dagger:dagger-compiler:2.16"
|
kapt "com.google.dagger:dagger-compiler:2.16"
|
||||||
kapt "com.google.dagger:dagger-android-processor:2.16"
|
kapt "com.google.dagger:dagger-android-processor:2.16"
|
||||||
|
|
||||||
implementation "androidx.room:room-runtime:2.1.0-alpha01"
|
implementation "androidx.room:room-runtime:2.1.0-alpha02"
|
||||||
implementation "androidx.room:room-rxjava2:2.1.0-alpha01"
|
implementation "androidx.room:room-rxjava2:2.1.0-alpha02"
|
||||||
kapt "androidx.room:room-compiler:2.1.0-alpha01"
|
kapt "androidx.room:room-compiler:2.1.0-alpha02"
|
||||||
|
|
||||||
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.2.0"
|
implementation "com.aurelhubert:ahbottomnavigation:2.2.0"
|
||||||
implementation 'com.ncapdevi:frag-nav:3.0.0-RC3'
|
implementation 'com.ncapdevi:frag-nav:3.0.0-RC3'
|
||||||
|
|
||||||
@ -120,9 +127,10 @@ dependencies {
|
|||||||
testImplementation "org.mockito:mockito-inline:2.23.0"
|
testImplementation "org.mockito:mockito-inline:2.23.0"
|
||||||
testImplementation 'org.threeten:threetenbp:1.3.7'
|
testImplementation 'org.threeten:threetenbp:1.3.7'
|
||||||
|
|
||||||
androidTestImplementation 'androidx.test:core:1.0.0-beta02'
|
androidTestImplementation 'androidx.test:core:1.0.0'
|
||||||
androidTestImplementation 'androidx.test:runner:1.1.0-beta02'
|
androidTestImplementation 'androidx.test:runner:1.1.0'
|
||||||
androidTestImplementation 'androidx.test.ext:junit:1.0.0-beta02'
|
androidTestImplementation 'androidx.test.ext:junit:1.0.0'
|
||||||
androidTestImplementation "org.mockito:mockito-android:2.23.0"
|
androidTestImplementation "org.mockito:mockito-android:2.23.0"
|
||||||
|
|
||||||
androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,14 @@
|
|||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
||||||
android:theme="@style/WulkanowyTheme.NoActionBar" />
|
android:theme="@style/WulkanowyTheme.NoActionBar" />
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name=".services.job.SyncWorker"
|
||||||
|
android:exported="false">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="com.firebase.jobdispatcher.ACTION_EXECUTE" />
|
||||||
|
</intent-filter>
|
||||||
|
</service>
|
||||||
|
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="io.fabric.ApiKey"
|
android:name="io.fabric.ApiKey"
|
||||||
android:value="${fabricApiKey}" />
|
android:value="${fabricApiKey}" />
|
||||||
|
@ -39,7 +39,7 @@ class WulkanowyApp : DaggerApplication() {
|
|||||||
private fun initializeFabric() {
|
private fun initializeFabric() {
|
||||||
Fabric.with(Fabric.Builder(this)
|
Fabric.with(Fabric.Builder(this)
|
||||||
.kits(Crashlytics.Builder()
|
.kits(Crashlytics.Builder()
|
||||||
.core(CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build())
|
.core(CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG || !BuildConfig.FABRIC_ENABLED).build())
|
||||||
.build(),
|
.build(),
|
||||||
Answers())
|
Answers())
|
||||||
.debuggable(BuildConfig.DEBUG)
|
.debuggable(BuildConfig.DEBUG)
|
||||||
|
@ -14,7 +14,7 @@ open class ErrorHandler @Inject constructor(private val resources: Resources) {
|
|||||||
var showErrorMessage: (String) -> Unit = {}
|
var showErrorMessage: (String) -> Unit = {}
|
||||||
|
|
||||||
open fun proceed(error: Throwable) {
|
open fun proceed(error: Throwable) {
|
||||||
Timber.i(error, "An exception occurred while the Wulkanowy was running")
|
Timber.e(error, "An exception occurred while the Wulkanowy was running")
|
||||||
|
|
||||||
showErrorMessage((when (error) {
|
showErrorMessage((when (error) {
|
||||||
is UnknownHostException -> resources.getString(R.string.all_no_internet)
|
is UnknownHostException -> resources.getString(R.string.all_no_internet)
|
||||||
|
@ -14,4 +14,12 @@ class SharedPrefHelper @Inject constructor(private val sharedPref: SharedPrefere
|
|||||||
fun getLong(key: String, defaultValue: Long): Long {
|
fun getLong(key: String, defaultValue: Long): Long {
|
||||||
return sharedPref.getLong(key, defaultValue)
|
return sharedPref.getLong(key, defaultValue)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
fun getBoolean(key: String, defaultValue: Boolean): Boolean {
|
||||||
|
return sharedPref.getBoolean(key, defaultValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getString(key: String, defaultValue: String): String {
|
||||||
|
return sharedPref.getString(key, defaultValue) ?: defaultValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -13,9 +13,15 @@ interface GradeDao {
|
|||||||
@Update
|
@Update
|
||||||
fun update(grade: Grade)
|
fun update(grade: Grade)
|
||||||
|
|
||||||
|
@Update
|
||||||
|
fun updateAll(grade: List<Grade>)
|
||||||
|
|
||||||
@Delete
|
@Delete
|
||||||
fun deleteAll(grades: List<Grade>)
|
fun deleteAll(grades: List<Grade>)
|
||||||
|
|
||||||
@Query("SELECT * FROM Grades WHERE semester_id = :semesterId AND student_id = :studentId")
|
@Query("SELECT * FROM Grades WHERE semester_id = :semesterId AND student_id = :studentId")
|
||||||
fun getGrades(semesterId: Int, studentId: Int): Maybe<List<Grade>>
|
fun getGrades(semesterId: Int, studentId: Int): Maybe<List<Grade>>
|
||||||
|
|
||||||
|
@Query("SELECT * FROM Grades WHERE is_read = 0 AND semester_id = :semesterId AND student_id = :studentId")
|
||||||
|
fun getNewGrades(semesterId: Int, studentId: Int): Maybe<List<Grade>>
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ import io.reactivex.Maybe
|
|||||||
@Dao
|
@Dao
|
||||||
interface GradeSummaryDao {
|
interface GradeSummaryDao {
|
||||||
|
|
||||||
@Insert(onConflict = REPLACE)
|
@Insert
|
||||||
fun insertAll(gradesSummary: List<GradeSummary>)
|
fun insertAll(gradesSummary: List<GradeSummary>)
|
||||||
|
|
||||||
@Delete
|
@Delete
|
||||||
|
@ -14,4 +14,10 @@ interface SemesterDao {
|
|||||||
|
|
||||||
@Query("SELECT * FROM Semesters WHERE student_id = :studentId")
|
@Query("SELECT * FROM Semesters WHERE student_id = :studentId")
|
||||||
fun getSemester(studentId: Int): Single<List<Semester>>
|
fun getSemester(studentId: Int): Single<List<Semester>>
|
||||||
|
|
||||||
|
@Query("UPDATE Semesters SET is_current = 0")
|
||||||
|
fun resetCurrentSemester()
|
||||||
|
|
||||||
|
@Query("UPDATE Semesters SET is_current = 1 WHERE semester_id = :semesterId")
|
||||||
|
fun setCurrentSemester(semesterId: Int)
|
||||||
}
|
}
|
||||||
|
@ -9,41 +9,44 @@ import java.io.Serializable
|
|||||||
@Entity(tableName = "Grades")
|
@Entity(tableName = "Grades")
|
||||||
data class Grade(
|
data class Grade(
|
||||||
|
|
||||||
@ColumnInfo(name = "semester_id")
|
@ColumnInfo(name = "semester_id")
|
||||||
var semesterId: Int,
|
var semesterId: Int,
|
||||||
|
|
||||||
@ColumnInfo(name = "student_id")
|
@ColumnInfo(name = "student_id")
|
||||||
var studentId: Int,
|
var studentId: Int,
|
||||||
|
|
||||||
var subject: String,
|
var subject: String,
|
||||||
|
|
||||||
var entry: String,
|
var entry: String,
|
||||||
|
|
||||||
var value: Int,
|
var value: Int,
|
||||||
|
|
||||||
var modifier: Double,
|
var modifier: Double,
|
||||||
|
|
||||||
var comment: String,
|
var comment: String,
|
||||||
|
|
||||||
var color: String,
|
var color: String,
|
||||||
|
|
||||||
@ColumnInfo(name = "grade_symbol")
|
@ColumnInfo(name = "grade_symbol")
|
||||||
var gradeSymbol: String,
|
var gradeSymbol: String,
|
||||||
|
|
||||||
var description: String,
|
var description: String,
|
||||||
|
|
||||||
var weight: String,
|
var weight: String,
|
||||||
|
|
||||||
var weightValue: Int,
|
var weightValue: Int,
|
||||||
|
|
||||||
var date: LocalDate,
|
var date: LocalDate,
|
||||||
|
|
||||||
var teacher: String
|
var teacher: String
|
||||||
) : Serializable {
|
) : Serializable {
|
||||||
|
|
||||||
@PrimaryKey(autoGenerate = true)
|
@PrimaryKey(autoGenerate = true)
|
||||||
var id: Long = 0
|
var id: Long = 0
|
||||||
|
|
||||||
@ColumnInfo(name = "is_new")
|
@ColumnInfo(name = "is_read")
|
||||||
var isNew: Boolean = false
|
var isRead: Boolean = true
|
||||||
|
|
||||||
|
@ColumnInfo(name = "is_notified")
|
||||||
|
var isNotified: Boolean = true
|
||||||
}
|
}
|
||||||
|
@ -14,29 +14,39 @@ import javax.inject.Singleton
|
|||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class GradeRepository @Inject constructor(
|
class GradeRepository @Inject constructor(
|
||||||
private val settings: InternetObservingSettings,
|
private val settings: InternetObservingSettings,
|
||||||
private val local: GradeLocal,
|
private val local: GradeLocal,
|
||||||
private val remote: GradeRemote
|
private val remote: GradeRemote
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun getGrades(semester: Semester, forceRefresh: Boolean = false): Single<List<Grade>> {
|
fun getGrades(semester: Semester, forceRefresh: Boolean = false, notify: Boolean = false): Single<List<Grade>> {
|
||||||
return local.getGrades(semester).filter { !forceRefresh }
|
return local.getGrades(semester).filter { !forceRefresh }
|
||||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||||
.flatMap {
|
.flatMap {
|
||||||
if (it) remote.getGrades(semester)
|
if (it) remote.getGrades(semester)
|
||||||
else Single.error(UnknownHostException())
|
else Single.error(UnknownHostException())
|
||||||
}.flatMap { newGrades ->
|
}.flatMap { newGrades ->
|
||||||
local.getGrades(semester).toSingle(emptyList())
|
local.getGrades(semester).toSingle(emptyList())
|
||||||
.doOnSuccess { oldGrades ->
|
.doOnSuccess { oldGrades ->
|
||||||
local.deleteGrades(oldGrades - newGrades)
|
local.deleteGrades(oldGrades - newGrades)
|
||||||
local.saveGrades((newGrades - oldGrades)
|
local.saveGrades((newGrades - oldGrades)
|
||||||
.onEach { if (oldGrades.isNotEmpty()) it.isNew = true })
|
.onEach {
|
||||||
}
|
if (oldGrades.isNotEmpty()) it.isRead = false
|
||||||
}.flatMap { local.getGrades(semester).toSingle(emptyList()) })
|
if (notify) it.isNotified = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}.flatMap { local.getGrades(semester).toSingle(emptyList()) })
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getNewGrades(semester: Semester): Single<List<Grade>> {
|
||||||
|
return local.getNewGrades(semester).toSingle(emptyList())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateGrade(grade: Grade): Completable {
|
fun updateGrade(grade: Grade): Completable {
|
||||||
return local.updateGrade(grade)
|
return local.updateGrade(grade)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun updateGrades(grades: List<Grade>): Completable {
|
||||||
|
return local.updateGrades(grades)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,39 @@
|
|||||||
package io.github.wulkanowy.data.repositories
|
package io.github.wulkanowy.data.repositories
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
|
import io.github.wulkanowy.R
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class PreferencesRepository @Inject constructor(private val sharedPref: SharedPreferences) {
|
class PreferencesRepository @Inject constructor(
|
||||||
|
private val sharedPref: SharedPreferences,
|
||||||
|
val context: Context
|
||||||
|
) {
|
||||||
|
|
||||||
val startMenuIndex: Int
|
val startMenuIndex: Int
|
||||||
get() = sharedPref.getString("start_menu", "0")?.toInt() ?: 0
|
get() = sharedPref.getString(context.getString(R.string.pref_key_start_menu), "0")?.toInt() ?: 0
|
||||||
|
|
||||||
val showPresent: Boolean
|
val showPresent: Boolean
|
||||||
get() = sharedPref.getBoolean("attendance_present", true)
|
get() = sharedPref.getBoolean(context.getString(R.string.pref_key_attendance_present), true)
|
||||||
|
|
||||||
|
val currentThemeKey: String = context.getString(R.string.pref_key_theme)
|
||||||
val currentTheme: Int
|
val currentTheme: Int
|
||||||
get() = sharedPref.getString("theme", "1")?.toInt() ?: 1
|
get() = sharedPref.getString(currentThemeKey, "1")?.toInt() ?: 1
|
||||||
}
|
|
||||||
|
|
||||||
|
val serviceEnablesKey: String = context.getString(R.string.pref_key_services_enable)
|
||||||
|
val serviceEnabled: Boolean
|
||||||
|
get() = sharedPref.getBoolean(serviceEnablesKey, true)
|
||||||
|
|
||||||
|
val servicesIntervalKey: String = context.getString(R.string.pref_key_services_interval)
|
||||||
|
val servicesInterval: Int
|
||||||
|
get() = sharedPref.getString(servicesIntervalKey, "60")?.toInt() ?: 60
|
||||||
|
|
||||||
|
val servicesOnlyWifiKey: String = context.getString(R.string.pref_key_services_wifi_only)
|
||||||
|
val servicesOnlyWifi: Boolean
|
||||||
|
get() = sharedPref.getBoolean(servicesOnlyWifiKey, true)
|
||||||
|
|
||||||
|
val notificationsEnable: Boolean
|
||||||
|
get() = sharedPref.getBoolean(context.getString(R.string.pref_key_notifications_enable), true)
|
||||||
|
}
|
||||||
|
@ -14,9 +14,10 @@ import javax.inject.Singleton
|
|||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class SessionRepository @Inject constructor(
|
class SessionRepository @Inject constructor(
|
||||||
private val local: SessionLocal,
|
private val local: SessionLocal,
|
||||||
private val remote: SessionRemote,
|
private val remote: SessionRemote,
|
||||||
private val settings: InternetObservingSettings) {
|
private val settings: InternetObservingSettings
|
||||||
|
) {
|
||||||
|
|
||||||
val isSessionSaved
|
val isSessionSaved
|
||||||
get() = local.isSessionSaved
|
get() = local.isSessionSaved
|
||||||
@ -26,24 +27,39 @@ class SessionRepository @Inject constructor(
|
|||||||
|
|
||||||
fun getConnectedStudents(email: String, password: String, symbol: String, endpoint: String): Single<List<Student>> {
|
fun getConnectedStudents(email: String, password: String, symbol: String, endpoint: String): Single<List<Student>> {
|
||||||
cachedStudents = ReactiveNetwork.checkInternetConnectivity(settings)
|
cachedStudents = ReactiveNetwork.checkInternetConnectivity(settings)
|
||||||
.flatMap { isConnected ->
|
.flatMap { isConnected ->
|
||||||
if (isConnected) remote.getConnectedStudents(email, password, symbol, endpoint)
|
if (isConnected) remote.getConnectedStudents(email, password, symbol, endpoint)
|
||||||
else Single.error<List<Student>>(UnknownHostException("No internet connection"))
|
else Single.error<List<Student>>(UnknownHostException("No internet connection"))
|
||||||
}.doOnSuccess { cachedStudents = Single.just(it) }
|
}.doOnSuccess { cachedStudents = Single.just(it) }
|
||||||
return cachedStudents
|
return cachedStudents
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getSemesters(): Single<List<Semester>> {
|
fun saveStudent(student: Student): Completable {
|
||||||
return local.getLastStudent()
|
return remote.getSemesters(student)
|
||||||
.flatMapSingle {
|
.flatMapCompletable { local.saveSemesters(it) }
|
||||||
remote.initApi(it, true)
|
.concatWith(local.saveStudent(student))
|
||||||
local.getSemesters(it)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun saveStudent(student: Student): Completable {
|
fun getSemesters(forceRefresh: Boolean = false): Single<List<Semester>> {
|
||||||
return remote.getSemesters(student).flatMapCompletable { local.saveSemesters(it) }
|
return local.getLastStudent()
|
||||||
.concatWith(local.saveStudent(student))
|
.flatMapSingle { student ->
|
||||||
|
remote.initApi(student)
|
||||||
|
local.getSemesters(student).filter { !forceRefresh }
|
||||||
|
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings).flatMap {
|
||||||
|
if (it) remote.getCurrentSemester(student)
|
||||||
|
else Single.error(UnknownHostException())
|
||||||
|
}.flatMap { current ->
|
||||||
|
local.getSemesters(student).doOnSuccess { semesters ->
|
||||||
|
if (semesters.single { it.current }.semesterId != current.semesterId) {
|
||||||
|
local.saveSemesters(listOf(current)).andThen {
|
||||||
|
local.setCurrentSemester(current.semesterId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.flatMap {
|
||||||
|
local.getSemesters(student)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun clearCache() {
|
fun clearCache() {
|
||||||
|
@ -15,6 +15,10 @@ class GradeLocal @Inject constructor(private val gradeDb: GradeDao) {
|
|||||||
return gradeDb.getGrades(semester.semesterId, semester.studentId).filter { !it.isEmpty() }
|
return gradeDb.getGrades(semester.semesterId, semester.studentId).filter { !it.isEmpty() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getNewGrades(semester: Semester): Maybe<List<Grade>> {
|
||||||
|
return gradeDb.getNewGrades(semester.semesterId, semester.studentId)
|
||||||
|
}
|
||||||
|
|
||||||
fun saveGrades(grades: List<Grade>) {
|
fun saveGrades(grades: List<Grade>) {
|
||||||
gradeDb.insertAll(grades)
|
gradeDb.insertAll(grades)
|
||||||
}
|
}
|
||||||
@ -23,6 +27,10 @@ class GradeLocal @Inject constructor(private val gradeDb: GradeDao) {
|
|||||||
return Completable.fromCallable { gradeDb.update(grade) }
|
return Completable.fromCallable { gradeDb.update(grade) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun updateGrades(grade: List<Grade>): Completable {
|
||||||
|
return Completable.fromCallable { gradeDb.updateAll(grade) }
|
||||||
|
}
|
||||||
|
|
||||||
fun deleteGrades(grades: List<Grade>) {
|
fun deleteGrades(grades: List<Grade>) {
|
||||||
gradeDb.deleteAll(grades)
|
gradeDb.deleteAll(grades)
|
||||||
}
|
}
|
||||||
|
@ -46,4 +46,10 @@ class SessionLocal @Inject constructor(
|
|||||||
fun getSemesters(student: Student): Single<List<Semester>> {
|
fun getSemesters(student: Student): Single<List<Semester>> {
|
||||||
return semesterDb.getSemester(student.studentId)
|
return semesterDb.getSemester(student.studentId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun setCurrentSemester(semesterId: Int): Completable {
|
||||||
|
return Single.fromCallable { semesterDb.resetCurrentSemester() }.ignoreElement().andThen {
|
||||||
|
semesterDb.setCurrentSemester(semesterId)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,37 +12,46 @@ import javax.inject.Singleton
|
|||||||
class SessionRemote @Inject constructor(private val api: Api) {
|
class SessionRemote @Inject constructor(private val api: Api) {
|
||||||
|
|
||||||
fun getConnectedStudents(email: String, password: String, symbol: String, endpoint: String): Single<List<Student>> {
|
fun getConnectedStudents(email: String, password: String, symbol: String, endpoint: String): Single<List<Student>> {
|
||||||
return Single.just(initApi(Student(email = email, password = password, symbol = symbol, endpoint = endpoint, loginType = "AUTO")))
|
return Single.just(
|
||||||
.flatMap { _ ->
|
initApi(
|
||||||
api.getPupils().map { students ->
|
Student(
|
||||||
students.map {
|
email = email,
|
||||||
Student(
|
password = password,
|
||||||
email = email,
|
symbol = symbol,
|
||||||
password = password,
|
endpoint = endpoint,
|
||||||
symbol = it.symbol,
|
loginType = "AUTO"
|
||||||
studentId = it.studentId,
|
), true
|
||||||
studentName = it.studentName,
|
)
|
||||||
schoolSymbol = it.schoolSymbol,
|
).flatMap {
|
||||||
schoolName = it.schoolName,
|
api.getPupils().map { students ->
|
||||||
endpoint = endpoint,
|
students.map { pupil ->
|
||||||
loginType = it.loginType.name
|
Student(
|
||||||
)
|
email = email,
|
||||||
}
|
password = password,
|
||||||
}
|
symbol = pupil.symbol,
|
||||||
|
studentId = pupil.studentId,
|
||||||
|
studentName = pupil.studentName,
|
||||||
|
schoolSymbol = pupil.schoolSymbol,
|
||||||
|
schoolName = pupil.schoolName,
|
||||||
|
endpoint = endpoint,
|
||||||
|
loginType = pupil.loginType.name
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getSemesters(student: Student): Single<List<Semester>> {
|
fun getSemesters(student: Student): Single<List<Semester>> {
|
||||||
return Single.just(initApi(student)).flatMap { _ ->
|
return Single.just(initApi(student)).flatMap {
|
||||||
api.getSemesters().map { semesters ->
|
api.getSemesters().map { semesters ->
|
||||||
semesters.map {
|
semesters.map { semester ->
|
||||||
Semester(
|
Semester(
|
||||||
studentId = student.studentId,
|
studentId = student.studentId,
|
||||||
diaryId = it.diaryId,
|
diaryId = semester.diaryId,
|
||||||
diaryName = it.diaryName,
|
diaryName = semester.diaryName,
|
||||||
semesterId = it.semesterId,
|
semesterId = semester.semesterId,
|
||||||
semesterName = it.semesterNumber,
|
semesterName = semester.semesterNumber,
|
||||||
current = it.current
|
current = semester.current
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,8 +59,21 @@ class SessionRemote @Inject constructor(private val api: Api) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun initApi(student: Student, checkInit: Boolean = false) {
|
fun getCurrentSemester(student: Student): Single<Semester> {
|
||||||
if (if (checkInit) 0 == api.studentId else true) {
|
return api.getCurrentSemester().map {
|
||||||
|
Semester(
|
||||||
|
studentId = student.studentId,
|
||||||
|
diaryId = it.diaryId,
|
||||||
|
diaryName = it.diaryName,
|
||||||
|
semesterId = it.semesterId,
|
||||||
|
semesterName = it.semesterNumber,
|
||||||
|
current = it.current
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun initApi(student: Student, reInitialize: Boolean = false) {
|
||||||
|
if (if (reInitialize) true else 0 == api.studentId) {
|
||||||
api.run {
|
api.run {
|
||||||
email = student.email
|
email = student.email
|
||||||
password = student.password
|
password = student.password
|
||||||
|
@ -14,6 +14,7 @@ import javax.inject.Singleton
|
|||||||
RepositoryModule::class,
|
RepositoryModule::class,
|
||||||
BuilderModule::class])
|
BuilderModule::class])
|
||||||
interface AppComponent : AndroidInjector<WulkanowyApp> {
|
interface AppComponent : AndroidInjector<WulkanowyApp> {
|
||||||
|
|
||||||
@Component.Builder
|
@Component.Builder
|
||||||
abstract class Builder : AndroidInjector.Builder<WulkanowyApp>()
|
abstract class Builder : AndroidInjector.Builder<WulkanowyApp>()
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package io.github.wulkanowy.di
|
package io.github.wulkanowy.di
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import com.firebase.jobdispatcher.FirebaseJobDispatcher
|
||||||
|
import com.firebase.jobdispatcher.GooglePlayDriver
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
@ -22,4 +24,10 @@ internal class AppModule {
|
|||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
fun provideFlexibleAdapter() = FlexibleAdapter<AbstractFlexibleItem<*>>(null, null, true)
|
fun provideFlexibleAdapter() = FlexibleAdapter<AbstractFlexibleItem<*>>(null, null, true)
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@Provides
|
||||||
|
fun provideJobDispatcher(context: Context): FirebaseJobDispatcher {
|
||||||
|
return FirebaseJobDispatcher(GooglePlayDriver(context))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package io.github.wulkanowy.di
|
|||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.android.ContributesAndroidInjector
|
import dagger.android.ContributesAndroidInjector
|
||||||
import io.github.wulkanowy.di.scopes.PerActivity
|
import io.github.wulkanowy.di.scopes.PerActivity
|
||||||
|
import io.github.wulkanowy.services.job.SyncWorker
|
||||||
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.main.MainActivity
|
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||||
@ -23,4 +24,7 @@ internal abstract class BuilderModule {
|
|||||||
@PerActivity
|
@PerActivity
|
||||||
@ContributesAndroidInjector(modules = [MainModule::class])
|
@ContributesAndroidInjector(modules = [MainModule::class])
|
||||||
abstract fun bindMainActivity(): MainActivity
|
abstract fun bindMainActivity(): MainActivity
|
||||||
|
|
||||||
|
@ContributesAndroidInjector
|
||||||
|
abstract fun bindSyncJob(): SyncWorker
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,57 @@
|
|||||||
|
package io.github.wulkanowy.services.job
|
||||||
|
|
||||||
|
import com.firebase.jobdispatcher.Constraint.ON_ANY_NETWORK
|
||||||
|
import com.firebase.jobdispatcher.Constraint.ON_UNMETERED_NETWORK
|
||||||
|
import com.firebase.jobdispatcher.FirebaseJobDispatcher
|
||||||
|
import com.firebase.jobdispatcher.Lifetime.FOREVER
|
||||||
|
import com.firebase.jobdispatcher.RetryStrategy.DEFAULT_EXPONENTIAL
|
||||||
|
import com.firebase.jobdispatcher.Trigger.executionWindow
|
||||||
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
|
import io.github.wulkanowy.utils.isHolidays
|
||||||
|
import org.threeten.bp.LocalDate
|
||||||
|
import timber.log.Timber
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class ServiceHelper @Inject constructor(
|
||||||
|
private val prefRepository: PreferencesRepository,
|
||||||
|
private val dispatcher: FirebaseJobDispatcher
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun reloadFullSyncService() {
|
||||||
|
startFullSyncService(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun startFullSyncService(replaceCurrent: Boolean = false) {
|
||||||
|
if (LocalDate.now().isHolidays || !prefRepository.serviceEnabled) {
|
||||||
|
Timber.d("Services disabled or it's holidays")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatcher.mustSchedule(
|
||||||
|
dispatcher.newJobBuilder()
|
||||||
|
.setLifetime(FOREVER)
|
||||||
|
.setRecurring(true)
|
||||||
|
.setService(SyncWorker::class.java)
|
||||||
|
.setTag(SyncWorker.WORK_TAG)
|
||||||
|
.setTrigger(
|
||||||
|
executionWindow(
|
||||||
|
prefRepository.servicesInterval * 60,
|
||||||
|
(prefRepository.servicesInterval + 10) * 60
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.setConstraints(if (prefRepository.servicesOnlyWifi) ON_UNMETERED_NETWORK else ON_ANY_NETWORK)
|
||||||
|
.setReplaceCurrent(replaceCurrent)
|
||||||
|
.setRetryStrategy(DEFAULT_EXPONENTIAL)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
|
||||||
|
Timber.d("Services started")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun stopFullSyncService() {
|
||||||
|
dispatcher.cancel(SyncWorker.WORK_TAG)
|
||||||
|
Timber.d("Services stopped")
|
||||||
|
}
|
||||||
|
}
|
110
app/src/main/java/io/github/wulkanowy/services/job/SyncWorker.kt
Normal file
110
app/src/main/java/io/github/wulkanowy/services/job/SyncWorker.kt
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
package io.github.wulkanowy.services.job
|
||||||
|
|
||||||
|
import com.firebase.jobdispatcher.JobParameters
|
||||||
|
import com.firebase.jobdispatcher.SimpleJobService
|
||||||
|
import dagger.android.AndroidInjection
|
||||||
|
import io.github.wulkanowy.data.repositories.AttendanceRepository
|
||||||
|
import io.github.wulkanowy.data.repositories.ExamRepository
|
||||||
|
import io.github.wulkanowy.data.repositories.GradeRepository
|
||||||
|
import io.github.wulkanowy.data.repositories.GradeSummaryRepository
|
||||||
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
|
import io.github.wulkanowy.data.repositories.SessionRepository
|
||||||
|
import io.github.wulkanowy.data.repositories.TimetableRepository
|
||||||
|
import io.github.wulkanowy.services.notification.GradeNotification
|
||||||
|
import io.github.wulkanowy.utils.friday
|
||||||
|
import io.github.wulkanowy.utils.isHolidays
|
||||||
|
import io.github.wulkanowy.utils.monday
|
||||||
|
import io.reactivex.Single
|
||||||
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
|
import org.threeten.bp.LocalDate
|
||||||
|
import timber.log.Timber
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class SyncWorker : SimpleJobService() {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var session: SessionRepository
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var gradesDetails: GradeRepository
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var gradesSummary: GradeSummaryRepository
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var attendance: AttendanceRepository
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var exam: ExamRepository
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var timetable: TimetableRepository
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var prefRepository: PreferencesRepository
|
||||||
|
|
||||||
|
private val disposable = CompositeDisposable()
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val WORK_TAG = "FULL_SYNC"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate() {
|
||||||
|
super.onCreate()
|
||||||
|
AndroidInjection.inject(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRunJob(job: JobParameters?): Int {
|
||||||
|
Timber.d("Synchronization started")
|
||||||
|
|
||||||
|
val start = LocalDate.now().monday
|
||||||
|
val end = LocalDate.now().friday
|
||||||
|
|
||||||
|
if (start.isHolidays) return RESULT_FAIL_NORETRY
|
||||||
|
|
||||||
|
var error: Throwable? = null
|
||||||
|
|
||||||
|
disposable.add(session.getSemesters(true)
|
||||||
|
.map { it.single { semester -> semester.current } }
|
||||||
|
.flatMapPublisher {
|
||||||
|
Single.merge(
|
||||||
|
listOf(
|
||||||
|
gradesDetails.getGrades(it, true, true),
|
||||||
|
gradesSummary.getGradesSummary(it, true),
|
||||||
|
attendance.getAttendance(it, start, end, true),
|
||||||
|
exam.getExams(it, start, end, true),
|
||||||
|
timetable.getTimetable(it, start, end, true)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.subscribe({}, { error = it }))
|
||||||
|
|
||||||
|
return if (null === error) {
|
||||||
|
if (prefRepository.notificationsEnable) sendNotifications()
|
||||||
|
Timber.d("Synchronization successful")
|
||||||
|
RESULT_SUCCESS
|
||||||
|
} else {
|
||||||
|
Timber.e(error, "Synchronization failed")
|
||||||
|
RESULT_FAIL_RETRY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun sendNotifications() {
|
||||||
|
disposable.add(session.getSemesters(true)
|
||||||
|
.map { it.single { semester -> semester.current } }
|
||||||
|
.flatMap { gradesDetails.getNewGrades(it) }
|
||||||
|
.map { it.filter { grade -> !grade.isNotified } }
|
||||||
|
.subscribe({
|
||||||
|
if (it.isNotEmpty()) {
|
||||||
|
Timber.d("Found ${it.size} unread grades")
|
||||||
|
GradeNotification(applicationContext).sendNotification(it)
|
||||||
|
gradesDetails.updateGrades(it.map { grade -> grade.apply { isNotified = true } }).subscribe()
|
||||||
|
}
|
||||||
|
}) { Timber.e("Notifications sending failed") })
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
disposable.clear()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
package io.github.wulkanowy.services.notification
|
||||||
|
|
||||||
|
import android.app.Notification
|
||||||
|
import android.app.NotificationManager
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Context.NOTIFICATION_SERVICE
|
||||||
|
import android.os.Build.VERSION.SDK_INT
|
||||||
|
import android.os.Build.VERSION_CODES.O
|
||||||
|
import androidx.core.app.NotificationCompat
|
||||||
|
import timber.log.Timber
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
abstract class BaseNotification(protected val context: Context) {
|
||||||
|
|
||||||
|
protected val notificationManager: NotificationManager by lazy {
|
||||||
|
context.getSystemService(NOTIFICATION_SERVICE) as NotificationManager
|
||||||
|
}
|
||||||
|
|
||||||
|
fun notify(notification: Notification) {
|
||||||
|
notificationManager.notify(Random.nextInt(1000), notification)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun notificationBuilder(channelId: String): NotificationCompat.Builder {
|
||||||
|
if (SDK_INT >= O) createChannel(channelId)
|
||||||
|
return NotificationCompat.Builder(context, channelId)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun cancelAll() {
|
||||||
|
notificationManager.cancelAll()
|
||||||
|
Timber.d("Notifications canceled")
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract fun createChannel(channelId: String)
|
||||||
|
}
|
@ -0,0 +1,60 @@
|
|||||||
|
package io.github.wulkanowy.services.notification
|
||||||
|
|
||||||
|
import android.annotation.TargetApi
|
||||||
|
import android.app.Notification.VISIBILITY_PUBLIC
|
||||||
|
import android.app.NotificationChannel
|
||||||
|
import android.app.NotificationManager.IMPORTANCE_HIGH
|
||||||
|
import android.app.PendingIntent
|
||||||
|
import android.app.PendingIntent.FLAG_UPDATE_CURRENT
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.core.app.NotificationCompat
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.data.db.entities.Grade
|
||||||
|
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||||
|
import io.github.wulkanowy.ui.modules.main.MainActivity.Companion.EXTRA_CARD_ID_KEY
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
class GradeNotification(context: Context) : BaseNotification(context) {
|
||||||
|
|
||||||
|
private val channelId = "Grade_Notify"
|
||||||
|
|
||||||
|
@TargetApi(26)
|
||||||
|
override fun createChannel(channelId: String) {
|
||||||
|
notificationManager.createNotificationChannel(NotificationChannel(
|
||||||
|
channelId, context.getString(R.string.notify_grade_channel), IMPORTANCE_HIGH
|
||||||
|
).apply {
|
||||||
|
enableLights(true)
|
||||||
|
enableVibration(true)
|
||||||
|
lockscreenVisibility = VISIBILITY_PUBLIC
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fun sendNotification(items: List<Grade>) {
|
||||||
|
notify(notificationBuilder(channelId)
|
||||||
|
.setContentTitle(context.resources.getQuantityString(R.plurals.grade_new_items, items.size, items.size))
|
||||||
|
.setContentText(context.resources.getQuantityString(R.plurals.notify_grade_new_items, items.size, items.size))
|
||||||
|
.setSmallIcon(R.drawable.ic_stat_notify_grade)
|
||||||
|
.setAutoCancel(true)
|
||||||
|
.setDefaults(NotificationCompat.DEFAULT_ALL)
|
||||||
|
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||||
|
.setColor(ContextCompat.getColor(context, R.color.colorPrimary))
|
||||||
|
.setContentIntent(
|
||||||
|
PendingIntent.getActivity(context, 0,
|
||||||
|
MainActivity.getStartIntent(context).putExtra(EXTRA_CARD_ID_KEY, 0),
|
||||||
|
FLAG_UPDATE_CURRENT
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.setStyle(NotificationCompat.InboxStyle().run {
|
||||||
|
setSummaryText(context.resources.getQuantityString(R.plurals.grade_number_item, items.size, items.size))
|
||||||
|
items.forEach {
|
||||||
|
addLine("${it.subject}: ${it.entry}")
|
||||||
|
}
|
||||||
|
this
|
||||||
|
})
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
|
||||||
|
Timber.d("Notification sent")
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package io.github.wulkanowy.ui.base
|
package io.github.wulkanowy.ui.base
|
||||||
|
|
||||||
import io.github.wulkanowy.data.ErrorHandler
|
import io.github.wulkanowy.data.ErrorHandler
|
||||||
|
import io.github.wulkanowy.ui.modules.main.MainView
|
||||||
import io.reactivex.disposables.CompositeDisposable
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
|
|
||||||
open class BasePresenter<T : BaseView>(private val errorHandler: ErrorHandler) {
|
open class BasePresenter<T : BaseView>(private val errorHandler: ErrorHandler) {
|
||||||
|
@ -12,4 +12,3 @@ class AboutModule {
|
|||||||
@Provides
|
@Provides
|
||||||
fun provideLibsFragmentCompat() = LibsFragmentCompat()
|
fun provideLibsFragmentCompat() = LibsFragmentCompat()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,4 +7,4 @@ interface AboutView : BaseView {
|
|||||||
fun openSourceWebView()
|
fun openSourceWebView()
|
||||||
|
|
||||||
fun openIssuesWebView()
|
fun openIssuesWebView()
|
||||||
}
|
}
|
||||||
|
@ -29,4 +29,3 @@ abstract class GradeModule {
|
|||||||
@ContributesAndroidInjector
|
@ContributesAndroidInjector
|
||||||
abstract fun binGradeSummaryFragment(): GradeSummaryFragment
|
abstract fun binGradeSummaryFragment(): GradeSummaryFragment
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,6 +75,4 @@ class GradeDetailsDialog : DialogFragment() {
|
|||||||
|
|
||||||
gradeDialogClose.setOnClickListener { dismiss() }
|
gradeDialogClose.setOnClickListener { dismiss() }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ class GradeDetailsItem(val grade: Grade, private val weightString: String, priva
|
|||||||
gradeItemDescription.text = if (grade.description.isNotBlank()) grade.description else grade.gradeSymbol
|
gradeItemDescription.text = if (grade.description.isNotBlank()) grade.description else grade.gradeSymbol
|
||||||
gradeItemDate.text = grade.date.toFormattedString()
|
gradeItemDate.text = grade.date.toFormattedString()
|
||||||
gradeItemWeight.text = "$weightString: ${grade.weight}"
|
gradeItemWeight.text = "$weightString: ${grade.weight}"
|
||||||
gradeItemNote.visibility = if (grade.isNew) VISIBLE else GONE
|
gradeItemNote.visibility = if (!grade.isRead) VISIBLE else GONE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ import io.github.wulkanowy.ui.base.BasePresenter
|
|||||||
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.valueColor
|
import io.github.wulkanowy.utils.valueColor
|
||||||
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class GradeDetailsPresenter @Inject constructor(
|
class GradeDetailsPresenter @Inject constructor(
|
||||||
@ -51,8 +52,8 @@ class GradeDetailsPresenter @Inject constructor(
|
|||||||
if (item is GradeDetailsItem) {
|
if (item is GradeDetailsItem) {
|
||||||
view?.apply {
|
view?.apply {
|
||||||
showGradeDialog(item.grade)
|
showGradeDialog(item.grade)
|
||||||
if (item.grade.isNew) {
|
if (!item.grade.isRead) {
|
||||||
item.grade.isNew = false
|
item.grade.isRead = true
|
||||||
updateItem(item)
|
updateItem(item)
|
||||||
getHeaderOfItem(item)?.let { header ->
|
getHeaderOfItem(item)?.let { header ->
|
||||||
if (header is GradeDetailsHeader) {
|
if (header is GradeDetailsHeader) {
|
||||||
@ -94,7 +95,7 @@ class GradeDetailsPresenter @Inject constructor(
|
|||||||
subject = it.key,
|
subject = it.key,
|
||||||
average = formatAverage(average),
|
average = formatAverage(average),
|
||||||
number = view?.getGradeNumberString(it.value.size).orEmpty(),
|
number = view?.getGradeNumberString(it.value.size).orEmpty(),
|
||||||
newGrades = it.value.filter { grade -> grade.isNew }.size
|
newGrades = it.value.filter { grade -> !grade.isRead }.size
|
||||||
).apply {
|
).apply {
|
||||||
subItems = it.value.map { item ->
|
subItems = it.value.map { item ->
|
||||||
GradeDetailsItem(
|
GradeDetailsItem(
|
||||||
@ -120,5 +121,6 @@ class GradeDetailsPresenter @Inject constructor(
|
|||||||
.subscribeOn(schedulers.backgroundThread)
|
.subscribeOn(schedulers.backgroundThread)
|
||||||
.observeOn(schedulers.mainThread)
|
.observeOn(schedulers.mainThread)
|
||||||
.subscribe({}) { error -> errorHandler.proceed(error) })
|
.subscribe({}) { error -> errorHandler.proceed(error) })
|
||||||
|
Timber.d("Grade ${grade.id} updated")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,4 +20,3 @@ class LoginErrorHandler(resources: Resources) : ErrorHandler(resources) {
|
|||||||
doOnBadCredentials = {}
|
doOnBadCredentials = {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,4 +3,4 @@ package io.github.wulkanowy.ui.modules.login
|
|||||||
interface LoginSwitchListener {
|
interface LoginSwitchListener {
|
||||||
|
|
||||||
fun switchFragment(position: Int)
|
fun switchFragment(position: Int)
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import com.aurelhubert.ahbottomnavigation.AHBottomNavigationItem
|
|||||||
import com.ncapdevi.fragnav.FragNavController
|
import com.ncapdevi.fragnav.FragNavController
|
||||||
import com.ncapdevi.fragnav.FragNavController.Companion.HIDE
|
import com.ncapdevi.fragnav.FragNavController.Companion.HIDE
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.services.notification.GradeNotification
|
||||||
import io.github.wulkanowy.ui.base.BaseActivity
|
import io.github.wulkanowy.ui.base.BaseActivity
|
||||||
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
|
||||||
@ -31,6 +32,7 @@ class MainActivity : BaseActivity(), MainView {
|
|||||||
lateinit var navController: FragNavController
|
lateinit var navController: FragNavController
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
const val EXTRA_CARD_ID_KEY = "cardId"
|
||||||
fun getStartIntent(context: Context) = Intent(context, MainActivity::class.java)
|
fun getStartIntent(context: Context) = Intent(context, MainActivity::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,7 +53,7 @@ class MainActivity : BaseActivity(), MainView {
|
|||||||
setSupportActionBar(mainToolbar)
|
setSupportActionBar(mainToolbar)
|
||||||
messageContainer = mainFragmentContainer
|
messageContainer = mainFragmentContainer
|
||||||
|
|
||||||
presenter.onAttachView(this)
|
presenter.onAttachView(this, intent.getIntExtra(EXTRA_CARD_ID_KEY, -1))
|
||||||
navController.initialize(startMenuIndex, savedInstanceState)
|
navController.initialize(startMenuIndex, savedInstanceState)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,13 +68,15 @@ class MainActivity : BaseActivity(), MainView {
|
|||||||
|
|
||||||
override fun initView() {
|
override fun initView() {
|
||||||
mainBottomNav.run {
|
mainBottomNav.run {
|
||||||
addItems(mutableListOf(
|
addItems(
|
||||||
|
mutableListOf(
|
||||||
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),
|
||||||
AHBottomNavigationItem(R.string.timetable_title, R.drawable.ic_menu_main_timetable_24dp, 0),
|
AHBottomNavigationItem(R.string.timetable_title, R.drawable.ic_menu_main_timetable_24dp, 0),
|
||||||
AHBottomNavigationItem(R.string.more_title, R.drawable.ic_menu_main_more_24dp, 0)
|
AHBottomNavigationItem(R.string.more_title, R.drawable.ic_menu_main_more_24dp, 0)
|
||||||
))
|
)
|
||||||
|
)
|
||||||
accentColor = ContextCompat.getColor(context, R.color.colorPrimary)
|
accentColor = ContextCompat.getColor(context, R.color.colorPrimary)
|
||||||
inactiveColor = getThemeAttrColor(android.R.attr.textColorSecondary)
|
inactiveColor = getThemeAttrColor(android.R.attr.textColorSecondary)
|
||||||
defaultBackgroundColor = getThemeAttrColor(R.attr.bottomNavBackground)
|
defaultBackgroundColor = getThemeAttrColor(R.attr.bottomNavBackground)
|
||||||
@ -89,11 +93,11 @@ class MainActivity : BaseActivity(), MainView {
|
|||||||
setOnViewChangeListener { presenter.onViewStart() }
|
setOnViewChangeListener { presenter.onViewStart() }
|
||||||
fragmentHideStrategy = HIDE
|
fragmentHideStrategy = HIDE
|
||||||
rootFragments = listOf(
|
rootFragments = listOf(
|
||||||
GradeFragment.newInstance(),
|
GradeFragment.newInstance(),
|
||||||
AttendanceFragment.newInstance(),
|
AttendanceFragment.newInstance(),
|
||||||
ExamFragment.newInstance(),
|
ExamFragment.newInstance(),
|
||||||
TimetableFragment.newInstance(),
|
TimetableFragment.newInstance(),
|
||||||
MoreFragment.newInstance()
|
MoreFragment.newInstance()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -126,6 +130,10 @@ class MainActivity : BaseActivity(), MainView {
|
|||||||
presenter.onBackPressed { super.onBackPressed() }
|
presenter.onBackPressed { super.onBackPressed() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun cancelNotifications() {
|
||||||
|
GradeNotification(applicationContext).cancelAll()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onSaveInstanceState(outState: Bundle?) {
|
override fun onSaveInstanceState(outState: Bundle?) {
|
||||||
super.onSaveInstanceState(outState)
|
super.onSaveInstanceState(outState)
|
||||||
navController.onSaveInstanceState(outState)
|
navController.onSaveInstanceState(outState)
|
||||||
|
@ -14,6 +14,7 @@ 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.grade.GradeModule
|
import io.github.wulkanowy.ui.modules.grade.GradeModule
|
||||||
import io.github.wulkanowy.ui.modules.more.MoreFragment
|
import io.github.wulkanowy.ui.modules.more.MoreFragment
|
||||||
|
import io.github.wulkanowy.ui.modules.settings.SettingsFragment
|
||||||
import io.github.wulkanowy.ui.modules.timetable.TimetableFragment
|
import io.github.wulkanowy.ui.modules.timetable.TimetableFragment
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
@ -53,4 +54,7 @@ abstract class MainModule {
|
|||||||
@PerFragment
|
@PerFragment
|
||||||
@ContributesAndroidInjector(modules = [AboutModule::class])
|
@ContributesAndroidInjector(modules = [AboutModule::class])
|
||||||
abstract fun bindAboutFragment(): AboutFragment
|
abstract fun bindAboutFragment(): AboutFragment
|
||||||
|
|
||||||
|
@ContributesAndroidInjector
|
||||||
|
abstract fun bindSettingsFragment(): SettingsFragment
|
||||||
}
|
}
|
||||||
|
@ -2,20 +2,26 @@ package io.github.wulkanowy.ui.modules.main
|
|||||||
|
|
||||||
import io.github.wulkanowy.data.ErrorHandler
|
import io.github.wulkanowy.data.ErrorHandler
|
||||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
|
import io.github.wulkanowy.services.job.ServiceHelper
|
||||||
import io.github.wulkanowy.ui.base.BasePresenter
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class MainPresenter @Inject constructor(
|
class MainPresenter @Inject constructor(
|
||||||
errorHandler: ErrorHandler,
|
errorHandler: ErrorHandler,
|
||||||
private val prefRepository: PreferencesRepository)
|
private val prefRepository: PreferencesRepository,
|
||||||
: BasePresenter<MainView>(errorHandler) {
|
private val serviceHelper: ServiceHelper
|
||||||
|
) : BasePresenter<MainView>(errorHandler) {
|
||||||
|
|
||||||
override fun onAttachView(view: MainView) {
|
fun onAttachView(view: MainView, init: Int) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
|
|
||||||
view.run {
|
view.run {
|
||||||
startMenuIndex = prefRepository.startMenuIndex
|
cancelNotifications()
|
||||||
|
startMenuIndex = if (init != -1) init else prefRepository.startMenuIndex
|
||||||
initView()
|
initView()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
serviceHelper.startFullSyncService()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onViewStart() {
|
fun onViewStart() {
|
||||||
@ -33,7 +39,6 @@ class MainPresenter @Inject constructor(
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun onBackPressed(default: () -> Unit) {
|
fun onBackPressed(default: () -> Unit) {
|
||||||
view?.run {
|
view?.run {
|
||||||
if (isRootView) default()
|
if (isRootView) default()
|
||||||
|
@ -24,6 +24,8 @@ interface MainView : BaseView {
|
|||||||
|
|
||||||
fun popView()
|
fun popView()
|
||||||
|
|
||||||
|
fun cancelNotifications()
|
||||||
|
|
||||||
interface MainChildView {
|
interface MainChildView {
|
||||||
|
|
||||||
fun onFragmentReselected()
|
fun onFragmentReselected()
|
||||||
|
@ -1,14 +1,21 @@
|
|||||||
package io.github.wulkanowy.ui.modules.settings
|
package io.github.wulkanowy.ui.modules.settings
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AppCompatDelegate
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
import com.takisoft.preferencex.PreferenceFragmentCompat
|
import com.takisoft.preferencex.PreferenceFragmentCompat
|
||||||
|
import dagger.android.support.AndroidSupportInjection
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.ui.modules.main.MainView
|
import io.github.wulkanowy.ui.modules.main.MainView
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
class SettingsFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedPreferenceChangeListener,
|
class SettingsFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedPreferenceChangeListener,
|
||||||
MainView.TitledView {
|
MainView.TitledView, SettingsView {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var presenter: SettingsPresenter
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun newInstance() = SettingsFragment()
|
fun newInstance() = SettingsFragment()
|
||||||
@ -17,19 +24,40 @@ class SettingsFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedP
|
|||||||
override val titleStringId: Int
|
override val titleStringId: Int
|
||||||
get() = R.string.settings_title
|
get() = R.string.settings_title
|
||||||
|
|
||||||
|
override fun onAttach(context: Context) {
|
||||||
|
AndroidSupportInjection.inject(this)
|
||||||
|
super.onAttach(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
|
super.onActivityCreated(savedInstanceState)
|
||||||
|
presenter.onAttachView(this)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreatePreferencesFix(savedInstanceState: Bundle?, rootKey: String?) {
|
override fun onCreatePreferencesFix(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
addPreferencesFromResource(R.xml.scheme_preferences)
|
addPreferencesFromResource(R.xml.scheme_preferences)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String) {
|
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
|
||||||
when(key) {
|
presenter.onSharedPreferenceChanged(key)
|
||||||
"theme" -> {
|
}
|
||||||
AppCompatDelegate.setDefaultNightMode(sharedPreferences?.getString("theme", "1")?.toInt() ?: 1)
|
|
||||||
activity?.recreate()
|
override fun setTheme(theme: Int) {
|
||||||
}
|
AppCompatDelegate.setDefaultNightMode(theme)
|
||||||
|
activity?.recreate()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setServicesSuspended(serviceEnablesKey: String, isHolidays: Boolean) {
|
||||||
|
findPreference(serviceEnablesKey).run {
|
||||||
|
summary = if (isHolidays) getString(R.string.pref_services_suspended) else ""
|
||||||
|
isEnabled = !isHolidays
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun showMessage(text: String) {
|
||||||
|
Toast.makeText(context, text, Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
preferenceScreen.sharedPreferences.registerOnSharedPreferenceChangeListener(this)
|
preferenceScreen.sharedPreferences.registerOnSharedPreferenceChangeListener(this)
|
||||||
|
@ -0,0 +1,40 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.settings
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.ErrorHandler
|
||||||
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
|
import io.github.wulkanowy.services.job.ServiceHelper
|
||||||
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
|
import io.github.wulkanowy.utils.isHolidays
|
||||||
|
import org.threeten.bp.LocalDate.now
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class SettingsPresenter @Inject constructor(
|
||||||
|
errorHandler: ErrorHandler,
|
||||||
|
private val preferencesRepository: PreferencesRepository,
|
||||||
|
private val serviceHelper: ServiceHelper
|
||||||
|
) : BasePresenter<SettingsView>(errorHandler) {
|
||||||
|
|
||||||
|
override fun onAttachView(view: SettingsView) {
|
||||||
|
super.onAttachView(view)
|
||||||
|
|
||||||
|
view.run {
|
||||||
|
setServicesSuspended(preferencesRepository.serviceEnablesKey, now().isHolidays)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onSharedPreferenceChanged(key: String) {
|
||||||
|
when (key) {
|
||||||
|
preferencesRepository.serviceEnablesKey -> {
|
||||||
|
if (preferencesRepository.serviceEnabled) serviceHelper.startFullSyncService()
|
||||||
|
else serviceHelper.stopFullSyncService()
|
||||||
|
}
|
||||||
|
preferencesRepository.servicesIntervalKey,
|
||||||
|
preferencesRepository.servicesOnlyWifiKey -> {
|
||||||
|
serviceHelper.reloadFullSyncService()
|
||||||
|
}
|
||||||
|
preferencesRepository.currentThemeKey -> {
|
||||||
|
view?.setTheme(preferencesRepository.currentTheme)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.settings
|
||||||
|
|
||||||
|
import io.github.wulkanowy.ui.base.BaseView
|
||||||
|
|
||||||
|
interface SettingsView : BaseView {
|
||||||
|
|
||||||
|
fun setTheme(theme: Int)
|
||||||
|
|
||||||
|
fun setServicesSuspended(serviceEnablesKey: String, isHolidays: Boolean)
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package io.github.wulkanowy.ui.modules.splash
|
package io.github.wulkanowy.ui.modules.splash
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import io.github.wulkanowy.services.notification.GradeNotification
|
||||||
import io.github.wulkanowy.ui.base.BaseActivity
|
import io.github.wulkanowy.ui.base.BaseActivity
|
||||||
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.ui.modules.main.MainActivity
|
||||||
|
@ -140,4 +140,3 @@ private fun generateKeyPair(context: Context) {
|
|||||||
}
|
}
|
||||||
Timber.i("A new KeyPair has been generated")
|
Timber.i("A new KeyPair has been generated")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,6 +62,16 @@
|
|||||||
</plurals>
|
</plurals>
|
||||||
|
|
||||||
|
|
||||||
|
<!--Grade notify-->
|
||||||
|
<string name="notify_grade_channel">Nowe oceny</string>
|
||||||
|
<plurals name="notify_grade_new_items">
|
||||||
|
<item quantity="one">Dostałeś %1$d ocenę</item>
|
||||||
|
<item quantity="few">"Dostałeś %1$d oceny</item>
|
||||||
|
<item quantity="many">Dostałeś %1$d ocen</item>
|
||||||
|
<item quantity="other">Dostałeś %1$d ocen</item>
|
||||||
|
</plurals>
|
||||||
|
|
||||||
|
|
||||||
<!--Timetable-->
|
<!--Timetable-->
|
||||||
<string name="timetable_lesson">Lekcja</string>
|
<string name="timetable_lesson">Lekcja</string>
|
||||||
<string name="timetable_room">Sala</string>
|
<string name="timetable_room">Sala</string>
|
||||||
@ -128,24 +138,12 @@
|
|||||||
<string name="pref_notify_header">Powiadomienia</string>
|
<string name="pref_notify_header">Powiadomienia</string>
|
||||||
<string name="pref_notify_switch">Pokazuj powiadomienia</string>
|
<string name="pref_notify_switch">Pokazuj powiadomienia</string>
|
||||||
|
|
||||||
<string name="pref_services_header">Usługi</string>
|
<string name="pref_services_header">Synchronizacja</string>
|
||||||
<string name="pref_services_switch">Automatyczna aktualizacja</string>
|
<string name="pref_services_switch">Automatyczna aktualizacja</string>
|
||||||
<string name="pref_services_suspended">Zawieszone na wakacjach</string>
|
<string name="pref_services_suspended">Zawieszona na wakacjach</string>
|
||||||
<string name="pref_services_interval">Interwał aktualizacji</string>
|
<string name="pref_services_interval">Interwał aktualizacji</string>
|
||||||
<string name="pref_services_wifi">Tylko WiFi</string>
|
<string name="pref_services_wifi">Tylko WiFi</string>
|
||||||
|
|
||||||
<string name="pref_restart">Wymagany restart</string>
|
|
||||||
|
|
||||||
|
|
||||||
<!--Grade notify-->
|
|
||||||
<string name="notify_grade_chanel">Nowe oceny</string>
|
|
||||||
<plurals name="notify_grade_new_items">
|
|
||||||
<item quantity="one">Dostałeś %1$d ocenę</item>
|
|
||||||
<item quantity="few">"Dostałeś %1$d oceny</item>
|
|
||||||
<item quantity="many">Dostałeś %1$d ocen</item>
|
|
||||||
<item quantity="other">Dostałeś %1$d ocen</item>
|
|
||||||
</plurals>
|
|
||||||
|
|
||||||
|
|
||||||
<!--Colors-->
|
<!--Colors-->
|
||||||
<string name="all_black">Czarny</string>
|
<string name="all_black">Czarny</string>
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string-array name="services_interval_entries">
|
<string-array name="services_interval_entries">
|
||||||
<item>10 minut</item>
|
<item>15 minut</item>
|
||||||
<item>30 minut</item>
|
<item>30 minut</item>
|
||||||
<item>1 godzinę</item>
|
<item>1 godzina</item>
|
||||||
<item>2 godziny</item>
|
<item>2 godziny</item>
|
||||||
<item>6 godzin</item>
|
<item>6 godzin</item>
|
||||||
<item>12 godzin</item>
|
<item>12 godzin</item>
|
||||||
|
10
app/src/main/res/values/preferences_keys.xml
Normal file
10
app/src/main/res/values/preferences_keys.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
|
||||||
|
<string name="pref_key_start_menu">start_menu</string>
|
||||||
|
<string name="pref_key_attendance_present">attendance_present</string>
|
||||||
|
<string name="pref_key_theme">theme</string>
|
||||||
|
<string name="pref_key_services_enable">services_enable</string>
|
||||||
|
<string name="pref_key_services_interval">services_interval</string>
|
||||||
|
<string name="pref_key_services_wifi_only">services_disable_wifi_only</string>
|
||||||
|
<string name="pref_key_notifications_enable">notifications_enable</string>
|
||||||
|
</resources>
|
@ -57,6 +57,13 @@
|
|||||||
<item quantity="other">New grades</item>
|
<item quantity="other">New grades</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
|
|
||||||
|
<!--Grade notify-->
|
||||||
|
<string name="notify_grade_channel">New grades</string>
|
||||||
|
<plurals name="notify_grade_new_items">
|
||||||
|
<item quantity="one">You received %1$d grade</item>
|
||||||
|
<item quantity="other">You received %1$d grades</item>
|
||||||
|
</plurals>
|
||||||
|
|
||||||
|
|
||||||
<!--Timetable-->
|
<!--Timetable-->
|
||||||
<string name="timetable_lesson">Lesson</string>
|
<string name="timetable_lesson">Lesson</string>
|
||||||
@ -124,22 +131,12 @@
|
|||||||
<string name="pref_notify_header">Notifications</string>
|
<string name="pref_notify_header">Notifications</string>
|
||||||
<string name="pref_notify_switch">Show notifications</string>
|
<string name="pref_notify_switch">Show notifications</string>
|
||||||
|
|
||||||
<string name="pref_services_header">Services</string>
|
<string name="pref_services_header">Synchronization</string>
|
||||||
<string name="pref_services_switch">Automatic update</string>
|
<string name="pref_services_switch">Automatic update</string>
|
||||||
<string name="pref_services_suspended">Suspended on holiday</string>
|
<string name="pref_services_suspended">Suspended on holiday</string>
|
||||||
<string name="pref_services_interval">Updates interval</string>
|
<string name="pref_services_interval">Updates interval</string>
|
||||||
<string name="pref_services_wifi">Only WiFi</string>
|
<string name="pref_services_wifi">Only WiFi</string>
|
||||||
|
|
||||||
<string name="pref_restart">Restart required</string>
|
|
||||||
|
|
||||||
|
|
||||||
<!--Grade notify-->
|
|
||||||
<string name="notify_grade_chanel">New grades</string>
|
|
||||||
<plurals name="notify_grade_new_items">
|
|
||||||
<item quantity="one">You received %1$d grade</item>
|
|
||||||
<item quantity="other">You received %1$d grades</item>
|
|
||||||
</plurals>
|
|
||||||
|
|
||||||
|
|
||||||
<!--Colors-->
|
<!--Colors-->
|
||||||
<string name="all_black">Black</string>
|
<string name="all_black">Black</string>
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
<string-array name="services_interval_entries">
|
<string-array name="services_interval_entries">
|
||||||
<item>10 minutes</item>
|
<item>15 minutes</item>
|
||||||
<item>30 minutes</item>
|
<item>30 minutes</item>
|
||||||
<item>1 hour</item>
|
<item>1 hour</item>
|
||||||
<item>2 hours</item>
|
<item>2 hours</item>
|
||||||
@ -36,7 +36,7 @@
|
|||||||
<item>24 hours</item>
|
<item>24 hours</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string-array name="services_interval_value" translatable="false">
|
<string-array name="services_interval_value" translatable="false">
|
||||||
<item>10</item>
|
<item>15</item>
|
||||||
<item>30</item>
|
<item>30</item>
|
||||||
<item>60</item>
|
<item>60</item>
|
||||||
<item>120</item>
|
<item>120</item>
|
||||||
|
@ -1,29 +1,63 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
android:title="@string/pref_view_header"
|
android:title="@string/pref_view_header"
|
||||||
app:iconSpaceReserved="false">
|
app:iconSpaceReserved="false">
|
||||||
<ListPreference
|
<ListPreference
|
||||||
android:defaultValue="0"
|
android:defaultValue="0"
|
||||||
android:entries="@array/startup_tab_entries"
|
android:entries="@array/startup_tab_entries"
|
||||||
android:entryValues="@array/startup_tab_value"
|
android:entryValues="@array/startup_tab_value"
|
||||||
android:key="start_menu"
|
android:key="@string/pref_key_start_menu"
|
||||||
android:summary="%s"
|
android:summary="%s"
|
||||||
android:title="@string/pref_view_list"
|
android:title="@string/pref_view_list"
|
||||||
app:iconSpaceReserved="false"/>
|
app:iconSpaceReserved="false" />
|
||||||
|
<ListPreference
|
||||||
|
android:defaultValue="1"
|
||||||
|
android:entries="@array/theme_entries"
|
||||||
|
android:entryValues="@array/theme_values"
|
||||||
|
android:key="theme"
|
||||||
|
android:summary="%s"
|
||||||
|
android:title="@string/pref_view_theme_dark"
|
||||||
|
app:iconSpaceReserved="false" />
|
||||||
<SwitchPreference
|
<SwitchPreference
|
||||||
android:defaultValue="true"
|
android:defaultValue="true"
|
||||||
android:key="attendance_present"
|
android:key="@string/pref_key_attendance_present"
|
||||||
android:title="@string/pref_view_present"
|
android:title="@string/pref_view_present"
|
||||||
app:iconSpaceReserved="false"/>
|
app:iconSpaceReserved="false" />
|
||||||
|
</PreferenceCategory>
|
||||||
|
<PreferenceCategory
|
||||||
|
android:title="@string/pref_services_header"
|
||||||
|
app:iconSpaceReserved="false">
|
||||||
|
<SwitchPreference
|
||||||
|
android:defaultValue="true"
|
||||||
|
android:key="@string/pref_key_services_enable"
|
||||||
|
android:title="@string/pref_services_switch"
|
||||||
|
app:iconSpaceReserved="false" />
|
||||||
<ListPreference
|
<ListPreference
|
||||||
android:defaultValue="1"
|
android:defaultValue="60"
|
||||||
android:entries="@array/theme_entries"
|
android:dependency="services_enable"
|
||||||
android:entryValues="@array/theme_values"
|
android:entries="@array/services_interval_entries"
|
||||||
android:key="theme"
|
android:entryValues="@array/services_interval_value"
|
||||||
android:summary="%s"
|
android:key="@string/pref_key_services_interval"
|
||||||
android:title="@string/pref_view_theme_dark"
|
android:summary="%s"
|
||||||
app:iconSpaceReserved="false"/>
|
android:title="@string/pref_services_interval"
|
||||||
|
app:iconSpaceReserved="false" />
|
||||||
|
<SwitchPreference
|
||||||
|
android:defaultValue="false"
|
||||||
|
android:dependency="services_enable"
|
||||||
|
android:key="@string/pref_key_services_wifi_only"
|
||||||
|
android:title="@string/pref_services_wifi"
|
||||||
|
app:iconSpaceReserved="false" />
|
||||||
|
</PreferenceCategory>
|
||||||
|
<PreferenceCategory
|
||||||
|
android:title="@string/pref_notify_header"
|
||||||
|
app:iconSpaceReserved="false">
|
||||||
|
<SwitchPreference
|
||||||
|
android:defaultValue="true"
|
||||||
|
android:dependency="services_enable"
|
||||||
|
android:key="@string/pref_key_notifications_enable"
|
||||||
|
android:title="@string/pref_notify_switch"
|
||||||
|
app:iconSpaceReserved="false" />
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
@ -2,6 +2,7 @@ package io.github.wulkanowy.ui.modules.main
|
|||||||
|
|
||||||
import io.github.wulkanowy.data.ErrorHandler
|
import io.github.wulkanowy.data.ErrorHandler
|
||||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
|
import io.github.wulkanowy.services.job.ServiceHelper
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.mockito.Mock
|
import org.mockito.Mock
|
||||||
@ -17,6 +18,9 @@ class MainPresenterTest {
|
|||||||
@Mock
|
@Mock
|
||||||
lateinit var prefRepository: PreferencesRepository
|
lateinit var prefRepository: PreferencesRepository
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
lateinit var serviceHelper: ServiceHelper
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
lateinit var mainView: MainView
|
lateinit var mainView: MainView
|
||||||
|
|
||||||
@ -27,8 +31,8 @@ class MainPresenterTest {
|
|||||||
MockitoAnnotations.initMocks(this)
|
MockitoAnnotations.initMocks(this)
|
||||||
clearInvocations(mainView)
|
clearInvocations(mainView)
|
||||||
|
|
||||||
presenter = MainPresenter(errorHandler, prefRepository)
|
presenter = MainPresenter(errorHandler, prefRepository, serviceHelper)
|
||||||
presenter.onAttachView(mainView)
|
presenter.onAttachView(mainView, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
buildscript {
|
buildscript {
|
||||||
ext.kotlin_version = '1.2.71'
|
ext.kotlin_version = '1.3.0'
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
google()
|
google()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user