1
0

Compare commits

...

21 Commits
0.7.0 ... 0.7.3

Author SHA1 Message Date
c2ab53cfeb Version 0.7.3 2019-03-26 19:46:59 +01:00
87268b3ef6 Fix rejected execution in sync worker (#305) 2019-03-26 16:47:14 +01:00
b3cd7e8ac1 Fix undeliverable network exceptions (#306)
* Remove unnecessary this
2019-03-26 14:32:23 +01:00
5a997dacb7 Version 0.7.2 2019-03-24 22:42:09 +01:00
ed9458d9a5 Fix more than one current semester in database (#304) 2019-03-24 20:21:05 +01:00
3656d3161f Fix crash on duplicate items (#303) 2019-03-24 17:31:39 +01:00
d178c15d2f Update dependencies (#302) 2019-03-24 16:03:51 +01:00
1f65b8465e Add logging to sync worker (#300) 2019-03-23 18:35:56 +01:00
6bb03b3be8 Fix day navigation unevenition (#301) 2019-03-23 17:29:34 +01:00
68b9847927 Fix reselecting root fragments (#299) 2019-03-23 16:35:33 +01:00
e1a83927c4 Fix reset button in timetable widget (#298) 2019-03-23 14:44:52 +01:00
fc9981aa5d Fix issues when loading lucky number (#297) 2019-03-23 13:01:01 +01:00
2d6610e05c Set max concurrency in sync worker (#296) 2019-03-23 01:12:17 +01:00
316cd2f7f9 Add checking current student in background services (#295) 2019-03-23 00:37:13 +01:00
36785f019a Fix restoring the grade fragment (#293) 2019-03-22 23:54:58 +01:00
4b78862486 Remove retry sync work when completed lessons is disabled (#294) 2019-03-22 23:41:41 +01:00
20d0abba29 Fix empty container id in grade fragemnt adapter (#289) 2019-03-21 22:34:41 +01:00
5add95ece1 Version 0.7.1 2019-03-20 21:02:09 +01:00
575e244b3a Add swipe refresh to grade fragment (#287) 2019-03-20 20:45:26 +01:00
8db73e9459 Fix the application finish after selecting an account (#286) 2019-03-19 18:14:55 +01:00
040857ba20 Change grade weightValue type to double (#285) 2019-03-19 13:23:52 +01:00
58 changed files with 430 additions and 266 deletions

View File

@ -14,6 +14,7 @@ cache:
#branches: #branches:
# only: # only:
# - master # - master
# - 0.7.x
android: android:
licenses: licenses:

View File

@ -16,8 +16,8 @@ android {
testApplicationId "io.github.tests.wulkanowy" testApplicationId "io.github.tests.wulkanowy"
minSdkVersion 15 minSdkVersion 15
targetSdkVersion 28 targetSdkVersion 28
versionCode 26 versionCode 29
versionName "0.7.0" versionName "0.7.3"
multiDexEnabled true multiDexEnabled true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true vectorDrawables.useSupportLibrary = true
@ -77,7 +77,7 @@ play {
dependencies { dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation('io.github.wulkanowy:api:0.7.0') { exclude module: "threetenbp" } implementation('io.github.wulkanowy:api:0.7.3') { exclude module: "threetenbp" }
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"
@ -86,10 +86,14 @@ dependencies {
implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.multidex:multidex:2.0.1' implementation 'androidx.multidex:multidex:2.0.1'
implementation 'com.takisoft.preferencex:preferencex:1.0.0' implementation "androidx.work:work-runtime:2.0.0"
implementation "androidx.work:work-rxjava2:2.0.0"
implementation "android.arch.work:work-rxjava2:1.0.0" implementation "androidx.room:room-runtime:2.1.0-alpha06"
implementation "android.arch.work:work-runtime:1.0.0" implementation "androidx.room:room-rxjava2:2.1.0-alpha06"
kapt "androidx.room:room-compiler:2.1.0-alpha06"
implementation 'com.takisoft.preferencex:preferencex:1.0.0'
implementation 'com.squareup.inject:assisted-inject-annotations-dagger2:0.3.3' implementation 'com.squareup.inject:assisted-inject-annotations-dagger2:0.3.3'
kapt 'com.squareup.inject:assisted-inject-processor-dagger2:0.3.3' kapt 'com.squareup.inject:assisted-inject-processor-dagger2:0.3.3'
@ -98,17 +102,13 @@ dependencies {
kapt "com.google.dagger:dagger-compiler:2.21" kapt "com.google.dagger:dagger-compiler:2.21"
kapt "com.google.dagger:dagger-android-processor:2.21" kapt "com.google.dagger:dagger-android-processor:2.21"
implementation "androidx.room:room-runtime:2.1.0-alpha05"
implementation "androidx.room:room-rxjava2:2.1.0-alpha05"
kapt "androidx.room:room-compiler:2.1.0-alpha05"
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.1.0' implementation 'com.ncapdevi:frag-nav:3.2.0'
implementation 'com.github.wulkanowy:MaterialChipsInput:b72fd0ee6f' implementation 'com.github.wulkanowy:MaterialChipsInput:b72fd0ee6f'
implementation 'com.github.PhilJay:MPAndroidChart:971640b29d' 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'
@ -128,15 +128,15 @@ dependencies {
debugImplementation "com.amitshekhar.android:debug-db:1.0.6" debugImplementation "com.amitshekhar.android:debug-db:1.0.6"
testImplementation "junit:junit:4.12" testImplementation "junit:junit:4.12"
testImplementation "io.mockk:mockk:1.9.1" testImplementation "io.mockk:mockk:1.9.2"
testImplementation "org.mockito:mockito-inline:2.25.0" testImplementation "org.mockito:mockito-inline:2.25.1"
testImplementation 'org.threeten:threetenbp:1.3.8' testImplementation 'org.threeten:threetenbp:1.3.8'
androidTestImplementation "io.mockk:mockk-android:1.9.1"
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 'org.mockito:mockito-android:2.25.0' androidTestImplementation "io.mockk:mockk-android:1.9.2"
androidTestImplementation 'org.mockito:mockito-android:2.25.1'
androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version" androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
} }

View File

@ -34,9 +34,9 @@ class GradeLocalTest {
@Test @Test
fun saveAndReadTest() { fun saveAndReadTest() {
gradeLocal.saveGrades(listOf( gradeLocal.saveGrades(listOf(
createGradeLocal(5, 3, LocalDate.of(2018, 9, 10), "", 1), createGradeLocal(5, 3.0, LocalDate.of(2018, 9, 10), "", 1),
createGradeLocal(4, 4, LocalDate.of(2019, 2, 27), "", 2), createGradeLocal(4, 4.0, LocalDate.of(2019, 2, 27), "", 2),
createGradeLocal(3, 5, LocalDate.of(2019, 2, 28), "", 2) createGradeLocal(3, 5.0, LocalDate.of(2019, 2, 28), "", 2)
)) ))
val grades = gradeLocal val grades = gradeLocal

View File

@ -71,10 +71,10 @@ class GradeRepositoryTest {
@Test @Test
fun markOlderThanRegisterDateAsRead() { fun markOlderThanRegisterDateAsRead() {
every { mockApi.getGrades(1) } returns Single.just(listOf( every { mockApi.getGrades(1) } returns Single.just(listOf(
createGradeApi(5, 4, of(2019, 2, 25), "Ocena pojawiła się"), createGradeApi(5, 4.0, of(2019, 2, 25), "Ocena pojawiła się"),
createGradeApi(5, 4, of(2019, 2, 26), "przed zalogowanie w aplikacji"), createGradeApi(5, 4.0, of(2019, 2, 26), "przed zalogowanie w aplikacji"),
createGradeApi(5, 4, of(2019, 2, 27), "Ocena z dnia logowania"), createGradeApi(5, 4.0, of(2019, 2, 27), "Ocena z dnia logowania"),
createGradeApi(5, 4, of(2019, 2, 28), "Ocena jeszcze nowsza") createGradeApi(5, 4.0, of(2019, 2, 28), "Ocena jeszcze nowsza")
)) ))
val grades = GradeRepository(settings, gradeLocal, gradeRemote) val grades = GradeRepository(settings, gradeLocal, gradeRemote)
@ -89,16 +89,16 @@ class GradeRepositoryTest {
@Test @Test
fun mitigateOldGradesNotifications() { fun mitigateOldGradesNotifications() {
gradeLocal.saveGrades(listOf( gradeLocal.saveGrades(listOf(
createGradeLocal(5, 3, of(2019, 2, 25), "Jedna ocena"), createGradeLocal(5, 3.0, of(2019, 2, 25), "Jedna ocena"),
createGradeLocal(4, 4, of(2019, 2, 26), "Druga"), createGradeLocal(4, 4.0, of(2019, 2, 26), "Druga"),
createGradeLocal(3, 5, of(2019, 2, 27), "Trzecia") createGradeLocal(3, 5.0, of(2019, 2, 27), "Trzecia")
)) ))
every { mockApi.getGrades(1) } returns Single.just(listOf( every { mockApi.getGrades(1) } returns Single.just(listOf(
createGradeApi(5, 2, of(2019, 2, 25), "Ocena ma datę, jest inna, ale nie zostanie powiadomiona"), createGradeApi(5, 2.0, of(2019, 2, 25), "Ocena ma datę, jest inna, ale nie zostanie powiadomiona"),
createGradeApi(4, 3, of(2019, 2, 26), "starszą niż ostatnia lokalnie"), createGradeApi(4, 3.0, of(2019, 2, 26), "starszą niż ostatnia lokalnie"),
createGradeApi(3, 4, of(2019, 2, 27), "Ta jest z tego samego dnia co ostatnia lokalnie"), createGradeApi(3, 4.0, of(2019, 2, 27), "Ta jest z tego samego dnia co ostatnia lokalnie"),
createGradeApi(2, 5, of(2019, 2, 28), "Ta jest już w ogóle nowa") createGradeApi(2, 5.0, of(2019, 2, 28), "Ta jest już w ogóle nowa")
)) ))
val grades = GradeRepository(settings, gradeLocal, gradeRemote) val grades = GradeRepository(settings, gradeLocal, gradeRemote)

View File

@ -5,7 +5,7 @@ import org.threeten.bp.LocalDate
import io.github.wulkanowy.api.grades.Grade as GradeRemote import io.github.wulkanowy.api.grades.Grade as GradeRemote
import io.github.wulkanowy.data.db.entities.Grade as GradeLocal import io.github.wulkanowy.data.db.entities.Grade as GradeLocal
fun createGradeLocal(value: Int, weight: Int, date: LocalDate, desc: String, semesterId: Int = 1): GradeLocal { fun createGradeLocal(value: Int, weight: Double, date: LocalDate, desc: String, semesterId: Int = 1): GradeLocal {
return GradeLocal( return GradeLocal(
semesterId = semesterId, semesterId = semesterId,
studentId = 1, studentId = 1,
@ -24,7 +24,7 @@ fun createGradeLocal(value: Int, weight: Int, date: LocalDate, desc: String, sem
) )
} }
fun createGradeApi(value: Int, weight: Int, date: LocalDate, desc: String): GradeRemote { fun createGradeApi(value: Int, weight: Double, date: LocalDate, desc: String): GradeRemote {
return GradeRemote().apply { return GradeRemote().apply {
this.value = value this.value = value
this.weightValue = weight this.weightValue = weight

View File

@ -39,18 +39,12 @@
android:name=".ui.modules.main.MainActivity" android:name=".ui.modules.main.MainActivity"
android:configChanges="orientation|screenSize" android:configChanges="orientation|screenSize"
android:label="@string/main_title" android:label="@string/main_title"
android:launchMode="singleTop"
android:theme="@style/WulkanowyTheme.NoActionBar" /> android:theme="@style/WulkanowyTheme.NoActionBar" />
<activity <activity
android:name=".ui.modules.message.send.SendMessageActivity" android:name=".ui.modules.message.send.SendMessageActivity"
android:configChanges="orientation|screenSize" android:configChanges="orientation|screenSize"
android:label="@string/send_message_title" android:label="@string/send_message_title"
android:parentActivityName=".ui.modules.main.MainActivity" android:theme="@style/WulkanowyTheme.NoActionBar" />
android:theme="@style/WulkanowyTheme.NoActionBar">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".ui.modules.main.MainActivity" />
</activity>
<service <service
android:name=".services.widgets.TimetableWidgetService" android:name=".services.widgets.TimetableWidgetService"
@ -58,6 +52,7 @@
<receiver <receiver
android:name=".ui.widgets.timetable.TimetableWidgetProvider" android:name=".ui.widgets.timetable.TimetableWidgetProvider"
android:exported="true"
android:label="@string/timetable_title"> android:label="@string/timetable_title">
<intent-filter> <intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />

View File

@ -19,7 +19,11 @@ 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.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.plugins.RxJavaPlugins
import timber.log.Timber import timber.log.Timber
import java.io.IOException
import java.lang.Exception
import javax.inject.Inject import javax.inject.Inject
class WulkanowyApp : DaggerApplication() { class WulkanowyApp : DaggerApplication() {
@ -42,6 +46,7 @@ class WulkanowyApp : DaggerApplication() {
if (DEBUG) enableDebugLog() if (DEBUG) enableDebugLog()
AppCompatDelegate.setDefaultNightMode(prefRepository.currentTheme) AppCompatDelegate.setDefaultNightMode(prefRepository.currentTheme)
WorkManager.initialize(this, Configuration.Builder().setWorkerFactory(workerFactory).build()) WorkManager.initialize(this, Configuration.Builder().setWorkerFactory(workerFactory).build())
RxJavaPlugins.setErrorHandler(::onError)
} }
private fun enableDebugLog() { private fun enableDebugLog() {
@ -56,6 +61,12 @@ class WulkanowyApp : DaggerApplication() {
Timber.plant(CrashlyticsTree()) Timber.plant(CrashlyticsTree())
} }
private fun onError(t: Throwable) {
if (t is UndeliverableException && t.cause is IOException || t.cause is InterruptedException) {
Timber.e(t.cause, "An undeliverable error occurred")
} else throw t
}
override fun applicationInjector(): AndroidInjector<out DaggerApplication> { override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
return DaggerAppComponent.builder().create(this) return DaggerAppComponent.builder().create(this)
} }

View File

@ -41,6 +41,7 @@ import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.Subject import io.github.wulkanowy.data.db.entities.Subject
import io.github.wulkanowy.data.db.entities.Timetable import io.github.wulkanowy.data.db.entities.Timetable
import io.github.wulkanowy.data.db.migrations.Migration10 import io.github.wulkanowy.data.db.migrations.Migration10
import io.github.wulkanowy.data.db.migrations.Migration11
import io.github.wulkanowy.data.db.migrations.Migration2 import io.github.wulkanowy.data.db.migrations.Migration2
import io.github.wulkanowy.data.db.migrations.Migration3 import io.github.wulkanowy.data.db.migrations.Migration3
import io.github.wulkanowy.data.db.migrations.Migration4 import io.github.wulkanowy.data.db.migrations.Migration4
@ -79,7 +80,7 @@ import javax.inject.Singleton
abstract class AppDatabase : RoomDatabase() { abstract class AppDatabase : RoomDatabase() {
companion object { companion object {
const val VERSION_SCHEMA = 10 const val VERSION_SCHEMA = 11
fun newInstance(context: Context): AppDatabase { fun newInstance(context: Context): AppDatabase {
return Room.databaseBuilder(context, AppDatabase::class.java, "wulkanowy_database") return Room.databaseBuilder(context, AppDatabase::class.java, "wulkanowy_database")
@ -95,7 +96,8 @@ abstract class AppDatabase : RoomDatabase() {
Migration7(), Migration7(),
Migration8(), Migration8(),
Migration9(), Migration9(),
Migration10() Migration10(),
Migration11()
) )
.build() .build()
} }

View File

@ -1,8 +1,8 @@
package io.github.wulkanowy.data.db.dao package io.github.wulkanowy.data.db.dao
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert import androidx.room.Insert
import androidx.room.OnConflictStrategy.IGNORE
import androidx.room.Query import androidx.room.Query
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.reactivex.Maybe import io.reactivex.Maybe
@ -12,15 +12,12 @@ import javax.inject.Singleton
@Dao @Dao
interface SemesterDao { interface SemesterDao {
@Insert(onConflict = IGNORE) @Insert
fun insertAll(semester: List<Semester>) fun insertAll(semester: List<Semester>)
@Delete
fun deleteAll(semester: List<Semester>)
@Query("SELECT * FROM Semesters WHERE student_id = :studentId") @Query("SELECT * FROM Semesters WHERE student_id = :studentId")
fun loadAll(studentId: Int): Maybe<List<Semester>> fun loadAll(studentId: Int): Maybe<List<Semester>>
@Query("UPDATE Semesters SET is_current = 1 WHERE semester_id = :semesterId AND diary_id = :diaryId")
fun updateCurrent(semesterId: Int, diaryId: Int)
@Query("UPDATE Semesters SET is_current = 0 WHERE student_id = :studentId")
fun resetCurrent(studentId: Int)
} }

View File

@ -34,7 +34,7 @@ data class Grade(
val weight: String, val weight: String,
val weightValue: Int, val weightValue: Double,
val date: LocalDate, val date: LocalDate,

View File

@ -0,0 +1,34 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration11 : Migration(10, 11) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("""
CREATE TABLE IF NOT EXISTS Grades_temp (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
is_read INTEGER NOT NULL,
is_notified INTEGER NOT NULL,
semester_id INTEGER NOT NULL,
student_id INTEGER NOT NULL,
subject TEXT NOT NULL,
entry TEXT NOT NULL,
value INTEGER NOT NULL,
modifier REAL NOT NULL,
comment TEXT NOT NULL,
color TEXT NOT NULL,
grade_symbol TEXT NOT NULL,
description TEXT NOT NULL,
weight TEXT NOT NULL,
weightValue REAL NOT NULL,
date INTEGER NOT NULL,
teacher TEXT NOT NULL
)
""")
database.execSQL("INSERT INTO Grades_temp SELECT * FROM Grades")
database.execSQL("DROP TABLE Grades")
database.execSQL("ALTER TABLE Grades_temp RENAME TO Grades")
}
}

View File

@ -11,17 +11,14 @@ import javax.inject.Singleton
class SemesterLocal @Inject constructor(private val semesterDb: SemesterDao) { class SemesterLocal @Inject constructor(private val semesterDb: SemesterDao) {
fun saveSemesters(semesters: List<Semester>) { fun saveSemesters(semesters: List<Semester>) {
return semesterDb.insertAll(semesters) semesterDb.insertAll(semesters)
}
fun deleteSemesters(semesters: List<Semester>) {
semesterDb.deleteAll(semesters)
} }
fun getSemesters(student: Student): Maybe<List<Semester>> { fun getSemesters(student: Student): Maybe<List<Semester>> {
return semesterDb.loadAll(student.studentId).filter { !it.isEmpty() } return semesterDb.loadAll(student.studentId).filter { !it.isEmpty() }
} }
fun setCurrentSemester(semester: Semester) {
semesterDb.run {
resetCurrent(semester.studentId)
updateCurrent(semester.semesterId, semester.diaryId)
}
}
} }

View File

@ -7,6 +7,7 @@ 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.reactivex.Maybe import io.reactivex.Maybe
import io.reactivex.Single import io.reactivex.Single
import timber.log.Timber
import java.net.UnknownHostException import java.net.UnknownHostException
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -25,10 +26,17 @@ class SemesterRepository @Inject constructor(
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap { .flatMap {
if (it) remote.getSemesters(student) else Single.error(UnknownHostException()) if (it) remote.getSemesters(student) else Single.error(UnknownHostException())
}.map { newSemesters -> }.flatMap { new ->
local.apply { val currentSemesters = new.filter { it.isCurrent }
saveSemesters(newSemesters) if (currentSemesters.size == 1) {
setCurrentSemester(newSemesters.single { it.isCurrent }) local.getSemesters(student).toSingle(emptyList())
.doOnSuccess { old ->
local.deleteSemesters(old - new)
local.saveSemesters(new - old)
}
} else {
Timber.i("Current semesters list:\n${currentSemesters.joinToString(separator = "\n")}")
throw IllegalArgumentException("Current semester can be only one.")
} }
}.flatMap { local.getSemesters(student).toSingle(emptyList()) }) }.flatMap { local.getSemesters(student).toSingle(emptyList()) })
} }

View File

@ -3,7 +3,6 @@ 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.widgets.TimetableWidgetService
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
@ -30,9 +29,6 @@ internal abstract class BuilderModule {
@ContributesAndroidInjector @ContributesAndroidInjector
abstract fun bindMessageSendActivity(): SendMessageActivity abstract fun bindMessageSendActivity(): SendMessageActivity
@ContributesAndroidInjector
abstract fun bindTimetableWidgetService(): TimetableWidgetService
@ContributesAndroidInjector @ContributesAndroidInjector
abstract fun bindTimetableWidgetProvider(): TimetableWidgetProvider abstract fun bindTimetableWidgetProvider(): TimetableWidgetProvider
} }

View File

@ -9,6 +9,7 @@ import com.squareup.inject.assisted.dagger2.AssistedModule
import dagger.Binds import dagger.Binds
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import dagger.android.ContributesAndroidInjector
import dagger.multibindings.IntoSet import dagger.multibindings.IntoSet
import io.github.wulkanowy.services.sync.works.AttendanceSummaryWork import io.github.wulkanowy.services.sync.works.AttendanceSummaryWork
import io.github.wulkanowy.services.sync.works.AttendanceWork import io.github.wulkanowy.services.sync.works.AttendanceWork
@ -24,6 +25,7 @@ import io.github.wulkanowy.services.sync.works.NoteWork
import io.github.wulkanowy.services.sync.works.RecipientWork import io.github.wulkanowy.services.sync.works.RecipientWork
import io.github.wulkanowy.services.sync.works.TimetableWork import io.github.wulkanowy.services.sync.works.TimetableWork
import io.github.wulkanowy.services.sync.works.Work import io.github.wulkanowy.services.sync.works.Work
import io.github.wulkanowy.services.widgets.TimetableWidgetService
import javax.inject.Singleton import javax.inject.Singleton
@AssistedModule @AssistedModule
@ -48,6 +50,9 @@ abstract class ServicesModule {
fun provideNotificationManager(context: Context) = context.getSystemService(NOTIFICATION_SERVICE) as NotificationManager fun provideNotificationManager(context: Context) = context.getSystemService(NOTIFICATION_SERVICE) as NotificationManager
} }
@ContributesAndroidInjector
abstract fun bindTimetableWidgetService(): TimetableWidgetService
@Binds @Binds
@IntoSet @IntoSet
abstract fun provideGradeWork(work: GradeWork): Work abstract fun provideGradeWork(work: GradeWork): Work

View File

@ -11,6 +11,7 @@ import androidx.work.WorkerParameters
import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.Assisted
import com.squareup.inject.assisted.AssistedInject import com.squareup.inject.assisted.AssistedInject
import io.github.wulkanowy.R import io.github.wulkanowy.R
import io.github.wulkanowy.api.interceptor.FeatureDisabledException
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository 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
@ -33,19 +34,31 @@ class SyncWorker @AssistedInject constructor(
) : RxWorker(appContext, workerParameters) { ) : RxWorker(appContext, workerParameters) {
override fun createWork(): Single<Result> { override fun createWork(): Single<Result> {
return studentRepository.getCurrentStudent() Timber.i("SyncWorker is starting")
return studentRepository.isStudentSaved()
.filter { true }
.flatMap { studentRepository.getCurrentStudent().toMaybe() }
.flatMapCompletable { student -> .flatMapCompletable { student ->
semesterRepository.getCurrentSemester(student, true) semesterRepository.getCurrentSemester(student, true)
.flatMapCompletable { semester -> .flatMapCompletable { semester ->
Completable.mergeDelayError(works.map { it.create(student, semester) }) Completable.mergeDelayError(works.map { work ->
work.create(student, semester)
.doOnSubscribe { Timber.i("${work::class.java.simpleName} is starting") }
.doOnError { Timber.i("${work::class.java.simpleName} result: An exception occurred") }
.doOnComplete { Timber.i("${work::class.java.simpleName} result: Success") }
})
} }
} }
.toSingleDefault(Result.success()) .toSingleDefault(Result.success())
.onErrorReturn { .onErrorReturn {
Timber.e(it, "There was an error during synchronization") Timber.e(it, "There was an error during synchronization")
Result.retry() if (it is FeatureDisabledException) Result.success()
else Result.retry()
}
.doOnSuccess {
if (preferencesRepository.isDebugNotificationEnable) notify(it)
Timber.i("SyncWorker result: $it")
} }
.doOnSuccess { if (preferencesRepository.isDebugNotificationEnable) notify(it) }
} }
private fun notify(result: Result) { private fun notify(result: Result) {

View File

@ -13,10 +13,10 @@ class RecipientWork @Inject constructor(
) : Work { ) : Work {
override fun create(student: Student, semester: Semester): Completable { override fun create(student: Student, semester: Semester): Completable {
return reportingUnitRepository.getReportingUnits(student) return reportingUnitRepository.getReportingUnits(student, true)
.flatMapCompletable { units -> .flatMapCompletable { units ->
Completable.mergeDelayError(units.map { Completable.mergeDelayError(units.map {
recipientRepository.getRecipients(student, 2, it).ignoreElement() recipientRepository.getRecipients(student, 2, it, true).ignoreElement()
}) })
} }
} }

View File

@ -43,7 +43,8 @@ class AboutFragment : BaseFragment(), AboutView, MainView.TitledView {
.withAboutSpecial3(getString(R.string.about_feedback)) .withAboutSpecial3(getString(R.string.about_feedback))
.withFields(R.string::class.java.fields) .withFields(R.string::class.java.fields)
.withCheckCachedDetection(false) .withCheckCachedDetection(false)
.withExcludedLibraries("fastadapter", "AndroidIconics", "gson", "Jsoup", "Retrofit", "okio", "OkHttp") .withExcludedLibraries("fastadapter", "AndroidIconics", "Jsoup", "Retrofit", "okio",
"OkHttp", "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)
@ -68,7 +69,7 @@ class AboutFragment : BaseFragment(), AboutView, MainView.TitledView {
data = Uri.parse("mailto:") data = Uri.parse("mailto:")
putExtra(Intent.EXTRA_EMAIL, Array(1) { "wulkanowyinc@gmail.com" }) putExtra(Intent.EXTRA_EMAIL, Array(1) { "wulkanowyinc@gmail.com" })
putExtra(Intent.EXTRA_SUBJECT, "Zgłoszenie błędu") putExtra(Intent.EXTRA_SUBJECT, "Zgłoszenie błędu")
putExtra(Intent.EXTRA_TEXT,"Tu umieść treść zgłoszenia\n\n" + "-".repeat(40) + "\n" + """ putExtra(Intent.EXTRA_TEXT, "Tu umieść treść zgłoszenia\n\n" + "-".repeat(40) + "\n" + """
Build: ${BuildConfig.VERSION_CODE} Build: ${BuildConfig.VERSION_CODE}
SDK: ${android.os.Build.VERSION.SDK_INT} SDK: ${android.os.Build.VERSION.SDK_INT}
Device: ${android.os.Build.MANUFACTURER} ${android.os.Build.MODEL} Device: ${android.os.Build.MANUFACTURER} ${android.os.Build.MODEL}

View File

@ -14,12 +14,12 @@ class AccountItem(val student: Student) : AbstractFlexibleItem<AccountItem.ViewH
override fun getLayoutRes() = R.layout.item_account override fun getLayoutRes() = R.layout.item_account
override fun createViewHolder(view: View?, adapter: FlexibleAdapter<IFlexible<*>>?): ViewHolder { override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<*>>): ViewHolder {
return ViewHolder(view, adapter) return ViewHolder(view, adapter)
} }
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>?, holder: ViewHolder?, position: Int, payloads: MutableList<Any>?) { override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder, position: Int, payloads: MutableList<Any>?) {
holder?.apply { holder.apply {
accountItemName.text = student.studentName accountItemName.text = student.studentName
accountItemSchool.text = student.schoolName accountItemSchool.text = student.schoolName
accountItemImage.setBackgroundResource(if (student.isCurrent) R.drawable.ic_account_circular_border else 0) accountItemImage.setBackgroundResource(if (student.isCurrent) R.drawable.ic_account_circular_border else 0)
@ -38,14 +38,13 @@ class AccountItem(val student: Student) : AbstractFlexibleItem<AccountItem.ViewH
} }
override fun hashCode(): Int { override fun hashCode(): Int {
return student.hashCode() var result = student.hashCode()
result = 31 * result + student.id.toInt()
return result
} }
class ViewHolder(view: View?, adapter: FlexibleAdapter<IFlexible<*>>?) : FlexibleViewHolder(view, adapter), class ViewHolder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer {
LayoutContainer { override val containerView: View
override val containerView: View?
get() = contentView get() = contentView
} }
} }

View File

@ -14,14 +14,13 @@ import kotlinx.android.synthetic.main.item_attendance.*
class AttendanceItem(val attendance: Attendance) : AbstractFlexibleItem<AttendanceItem.ViewHolder>() { class AttendanceItem(val attendance: Attendance) : AbstractFlexibleItem<AttendanceItem.ViewHolder>() {
override fun getLayoutRes() = R.layout.item_attendance
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<*>>): ViewHolder { override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<*>>): ViewHolder {
return ViewHolder(view, adapter) return ViewHolder(view, adapter)
} }
override fun getLayoutRes(): Int = R.layout.item_attendance override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder, position: Int, payloads: MutableList<Any>?) {
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder,
position: Int, payloads: MutableList<Any>?) {
holder.apply { holder.apply {
attendanceItemNumber.text = attendance.number.toString() attendanceItemNumber.text = attendance.number.toString()
attendanceItemSubject.text = attendance.subject attendanceItemSubject.text = attendance.subject
@ -37,16 +36,17 @@ class AttendanceItem(val attendance: Attendance) : AbstractFlexibleItem<Attendan
other as AttendanceItem other as AttendanceItem
if (attendance != other.attendance) return false if (attendance != other.attendance) return false
return true return true
} }
override fun hashCode(): Int { override fun hashCode(): Int {
return attendance.hashCode() var result = attendance.hashCode()
result = 31 * result + attendance.id.toInt()
return result
} }
class ViewHolder(val view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), class ViewHolder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer {
LayoutContainer {
override val containerView: View override val containerView: View
get() = contentView get() = contentView
} }

View File

@ -135,7 +135,7 @@ class AttendancePresenter @Inject constructor(
clearData() clearData()
showNextButton(!currentDate.plusDays(1).isHolidays) showNextButton(!currentDate.plusDays(1).isHolidays)
showPreButton(!currentDate.minusDays(1).isHolidays) showPreButton(!currentDate.minusDays(1).isHolidays)
updateNavigationDay(currentDate.toFormattedString("EEEE \n dd.MM.YYYY").capitalize()) updateNavigationDay(currentDate.toFormattedString("EEEE\ndd.MM.YYYY").capitalize())
} }
} }
} }

View File

@ -23,12 +23,12 @@ class AttendanceSummaryItem(
override fun getLayoutRes() = R.layout.item_attendance_summary override fun getLayoutRes() = R.layout.item_attendance_summary
override fun createViewHolder(view: View?, adapter: FlexibleAdapter<IFlexible<*>>?): ViewHolder { override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<*>>): ViewHolder {
return ViewHolder(view, adapter) return ViewHolder(view, adapter)
} }
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>?, holder: ViewHolder?, position: Int, payloads: MutableList<Any>?) { override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder, position: Int, payloads: MutableList<Any>?) {
holder?.apply { holder.apply {
attendanceSummaryMonth.text = month attendanceSummaryMonth.text = month
attendanceSummaryPercentage.text = percentage attendanceSummaryPercentage.text = percentage
attendanceSummaryPresent.text = present attendanceSummaryPresent.text = present
@ -73,10 +73,8 @@ class AttendanceSummaryItem(
return result return result
} }
class ViewHolder(view: View?, adapter: FlexibleAdapter<IFlexible<*>>?) : FlexibleViewHolder(view, adapter), class ViewHolder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer {
LayoutContainer { override val containerView: View
override val containerView: View?
get() = contentView get() = contentView
} }
} }

View File

@ -18,8 +18,7 @@ class ExamItem(header: ExamHeader, val exam: Exam) : AbstractSectionableItem<Exa
return ViewHolder(view, adapter) return ViewHolder(view, adapter)
} }
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder, override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder, position: Int, payloads: MutableList<Any>?) {
position: Int, payloads: MutableList<Any>?) {
holder.run { holder.run {
examItemSubject.text = exam.subject examItemSubject.text = exam.subject
examItemTeacher.text = exam.teacher examItemTeacher.text = exam.teacher
@ -39,12 +38,12 @@ class ExamItem(header: ExamHeader, val exam: Exam) : AbstractSectionableItem<Exa
} }
override fun hashCode(): Int { override fun hashCode(): Int {
return exam.hashCode() var result = exam.hashCode()
result = 31 * result + exam.id.toInt()
return result
} }
class ViewHolder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), class ViewHolder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer {
LayoutContainer {
override val containerView: View override val containerView: View
get() = contentView get() = contentView
} }

View File

@ -29,6 +29,8 @@ class GradeFragment : BaseSessionFragment(), GradeView, MainView.MainChildView,
@Inject @Inject
lateinit var pagerAdapter: BaseFragmentPagerAdapter lateinit var pagerAdapter: BaseFragmentPagerAdapter
private var semesterSwitchMenu: MenuItem? = null
companion object { companion object {
private const val SAVED_SEMESTER_KEY = "CURRENT_SEMESTER" private const val SAVED_SEMESTER_KEY = "CURRENT_SEMESTER"
@ -57,6 +59,8 @@ class GradeFragment : BaseSessionFragment(), GradeView, MainView.MainChildView,
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)
presenter.onCreateMenu()
} }
override fun initView() { override fun initView() {
@ -75,6 +79,7 @@ class GradeFragment : BaseSessionFragment(), GradeView, MainView.MainChildView,
setOnSelectPageListener { presenter.onPageSelected(it) } setOnSelectPageListener { presenter.onPageSelected(it) }
} }
gradeTabLayout.setupWithViewPager(gradeViewPager) gradeTabLayout.setupWithViewPager(gradeViewPager)
gradeSwipe.setOnRefreshListener { presenter.onSwipeRefresh() }
} }
override fun onOptionsItemSelected(item: MenuItem?): Boolean { override fun onOptionsItemSelected(item: MenuItem?): Boolean {
@ -95,8 +100,20 @@ class GradeFragment : BaseSessionFragment(), GradeView, MainView.MainChildView,
gradeProgress.visibility = if (show) VISIBLE else INVISIBLE gradeProgress.visibility = if (show) VISIBLE else INVISIBLE
} }
override fun showEmpty() { override fun showEmpty(show: Boolean) {
gradeEmpty.visibility = VISIBLE gradeEmpty.visibility = if (show) VISIBLE else INVISIBLE
}
override fun showRefresh(show: Boolean) {
gradeSwipe.isRefreshing = show
}
override fun showSemesterSwitch(show: Boolean) {
semesterSwitchMenu?.isVisible = show
}
override fun enableSwipe(enable: Boolean) {
gradeSwipe.isEnabled = enable
} }
override fun showSemesterDialog(selectedIndex: Int) { override fun showSemesterDialog(selectedIndex: Int) {

View File

@ -7,9 +7,7 @@ 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.utils.FirebaseAnalyticsHelper import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
import io.github.wulkanowy.utils.SchedulersProvider import io.github.wulkanowy.utils.SchedulersProvider
import io.reactivex.Completable
import timber.log.Timber import timber.log.Timber
import java.util.concurrent.TimeUnit.MILLISECONDS
import javax.inject.Inject import javax.inject.Inject
class GradePresenter @Inject constructor( class GradePresenter @Inject constructor(
@ -30,12 +28,16 @@ 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") Timber.i("Grade view is attached")
disposable.add(Completable.timer(150, MILLISECONDS, schedulers.mainThread)
.subscribe {
selectedIndex = savedIndex ?: 0 selectedIndex = savedIndex ?: 0
view.initView() view.run {
initView()
enableSwipe(false)
}
loadData() loadData()
}) }
fun onCreateMenu() {
if (semesters.isEmpty()) view?.showSemesterSwitch(false)
} }
fun onViewReselected() { fun onViewReselected() {
@ -69,12 +71,17 @@ class GradePresenter @Inject constructor(
view?.apply { view?.apply {
showContent(true) showContent(true)
showProgress(false) showProgress(false)
showEmpty(false)
loadedSemesterId[currentPageIndex] = semesterId loadedSemesterId[currentPageIndex] = semesterId
} }
} }
fun onPageSelected(index: Int) { fun onPageSelected(index: Int) {
loadChild(index) if (semesters.isNotEmpty()) loadChild(index)
}
fun onSwipeRefresh() {
loadData()
} }
private fun loadData() { private fun loadData() {
@ -89,17 +96,21 @@ class GradePresenter @Inject constructor(
} }
.subscribeOn(schedulers.backgroundThread) .subscribeOn(schedulers.backgroundThread)
.observeOn(schedulers.mainThread) .observeOn(schedulers.mainThread)
.doFinally { view?.showRefresh(false) }
.subscribe({ .subscribe({
view?.run { view?.run {
Timber.i("Loading grade result: Attempt load index $currentPageIndex") Timber.i("Loading grade result: Attempt load index $currentPageIndex")
loadChild(currentPageIndex) loadChild(currentPageIndex)
enableSwipe(false)
showSemesterSwitch(true)
} }
}) { }) {
Timber.i("Loading grade result: An exception occurred") Timber.i("Loading grade result: An exception occurred")
errorHandler.dispatch(it) errorHandler.dispatch(it)
view?.run { view?.run {
showProgress(false) showProgress(false)
showEmpty() showEmpty(true)
enableSwipe(true)
} }
}) })
} }

View File

@ -12,10 +12,16 @@ interface GradeView : BaseSessionView {
fun showProgress(show: Boolean) fun showProgress(show: Boolean)
fun showEmpty() fun showEmpty(show: Boolean)
fun showRefresh(show: Boolean)
fun showSemesterSwitch(show: Boolean)
fun showSemesterDialog(selectedIndex: Int) fun showSemesterDialog(selectedIndex: Int)
fun enableSwipe(enable: Boolean)
fun notifyChildLoadData(index: Int, semesterId: Int, forceRefresh: Boolean) fun notifyChildLoadData(index: Int, semesterId: Int, forceRefresh: Boolean)
fun notifyChildParentReselected(index: Int) fun notifyChildParentReselected(index: Int)

View File

@ -28,10 +28,7 @@ class GradeDetailsItem(
} }
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
override fun bindViewHolder( override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder, position: Int, payloads: MutableList<Any>?) {
adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder,
position: Int, payloads: MutableList<Any>?
) {
holder.run { holder.run {
gradeItemValue.run { gradeItemValue.run {
text = grade.entry text = grade.entry
@ -70,9 +67,7 @@ class GradeDetailsItem(
return result return result
} }
class ViewHolder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), class ViewHolder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer {
LayoutContainer {
override val containerView: View override val containerView: View
get() = contentView get() = contentView
} }

View File

@ -63,7 +63,7 @@ class GradeStatisticsPresenter @Inject constructor(
} }
fun onSubjectSelected(name: String) { fun onSubjectSelected(name: String) {
Timber.i("Select attendance stats subject $name") Timber.i("Select grade stats subject $name")
view?.run { view?.run {
showContent(false) showContent(false)
showProgress(true) showProgress(true)
@ -77,7 +77,7 @@ class GradeStatisticsPresenter @Inject constructor(
} }
fun onTypeChange(isSemester: Boolean) { fun onTypeChange(isSemester: Boolean) {
Timber.i("Select attendance stats semester: $isSemester") Timber.i("Select grade stats semester: $isSemester")
disposable.clear() disposable.clear()
view?.run { view?.run {
showContent(false) showContent(false)

View File

@ -18,15 +18,12 @@ class GradeSummaryItem(
override fun getLayoutRes() = R.layout.item_grade_summary override fun getLayoutRes() = R.layout.item_grade_summary
override fun createViewHolder(view: View?, adapter: FlexibleAdapter<IFlexible<*>>?): ViewHolder { override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<*>>): ViewHolder {
return ViewHolder(view, adapter) return ViewHolder(view, adapter)
} }
override fun bindViewHolder( override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder, position: Int, payloads: MutableList<Any>?) {
adapter: FlexibleAdapter<IFlexible<*>>?, holder: ViewHolder?, holder.run {
position: Int, payloads: MutableList<Any>?
) {
holder?.run {
gradeSummaryItemTitle.text = title gradeSummaryItemTitle.text = title
gradeSummaryItemAverage.text = average gradeSummaryItemAverage.text = average
gradeSummaryItemPredicted.text = predictedGrade gradeSummaryItemPredicted.text = predictedGrade
@ -56,10 +53,8 @@ class GradeSummaryItem(
return result return result
} }
class ViewHolder(view: View?, adapter: FlexibleAdapter<IFlexible<*>>?) : FlexibleViewHolder(view, adapter), class ViewHolder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer {
LayoutContainer { override val containerView: View
override val containerView: View?
get() = contentView get() = contentView
} }
} }

View File

@ -10,9 +10,8 @@ import io.github.wulkanowy.data.db.entities.Homework
import kotlinx.android.extensions.LayoutContainer import kotlinx.android.extensions.LayoutContainer
import kotlinx.android.synthetic.main.item_homework.* import kotlinx.android.synthetic.main.item_homework.*
class HomeworkItem( class HomeworkItem(header: HomeworkHeader, val homework: Homework) :
header: HomeworkHeader, val homework: Homework AbstractSectionableItem<HomeworkItem.ViewHolder, HomeworkHeader>(header) {
) : AbstractSectionableItem<HomeworkItem.ViewHolder, HomeworkHeader>(header) {
override fun getLayoutRes() = R.layout.item_homework override fun getLayoutRes() = R.layout.item_homework
@ -20,10 +19,7 @@ class HomeworkItem(
return ViewHolder(view, adapter) return ViewHolder(view, adapter)
} }
override fun bindViewHolder( override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder, position: Int, payloads: MutableList<Any>?) {
adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder,
position: Int, payloads: MutableList<Any>?
) {
holder.apply { holder.apply {
homeworkItemSubject.text = homework.subject homeworkItemSubject.text = homework.subject
homeworkItemTeacher.text = homework.teacher homeworkItemTeacher.text = homework.teacher
@ -42,12 +38,12 @@ class HomeworkItem(
} }
override fun hashCode(): Int { override fun hashCode(): Int {
return homework.hashCode() var result = homework.hashCode()
result = 31 * result + homework.id.toInt()
return result
} }
class ViewHolder(val view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), class ViewHolder(val view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer {
LayoutContainer {
override val containerView: View override val containerView: View
get() = contentView get() = contentView
} }

View File

@ -8,19 +8,21 @@ import eu.davidea.viewholders.FlexibleViewHolder
import io.github.wulkanowy.R import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import kotlinx.android.extensions.LayoutContainer import kotlinx.android.extensions.LayoutContainer
import kotlinx.android.synthetic.main.item_login_student_select.view.* 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(): Int = 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)
} }
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>?, holder: ItemViewHolder?, override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ItemViewHolder, position: Int, payloads: MutableList<Any>?) {
position: Int, payloads: MutableList<Any>?) { holder.run {
holder?.bind(student) loginItemName.text = student.studentName
loginItemSchool.text = student.schoolName
}
} }
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
@ -38,17 +40,8 @@ class LoginStudentSelectItem(val student: Student) : AbstractFlexibleItem<LoginS
return student.hashCode() return student.hashCode()
} }
class ItemViewHolder(view: View?, adapter: FlexibleAdapter<*>?) class ItemViewHolder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer {
: FlexibleViewHolder(view, adapter), LayoutContainer { override val containerView: View
override val containerView: View?
get() = itemView get() = itemView
fun bind(item: Student) {
itemView.run {
loginItemName.text = item.studentName
loginItemSchool.text = item.schoolName
}
}
} }
} }

View File

@ -22,7 +22,11 @@ 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") Timber.i("Lucky number view is attached")
view.initView() view.run {
initView()
showContent(false)
enableSwipe(false)
}
loadData() loadData()
} }
@ -35,12 +39,6 @@ class LuckyNumberPresenter @Inject constructor(
.flatMapMaybe { luckyNumberRepository.getLuckyNumber(it, forceRefresh) } .flatMapMaybe { luckyNumberRepository.getLuckyNumber(it, forceRefresh) }
.subscribeOn(schedulers.backgroundThread) .subscribeOn(schedulers.backgroundThread)
.observeOn(schedulers.mainThread) .observeOn(schedulers.mainThread)
.doOnSubscribe {
view?.run {
showContent(false)
enableSwipe(false)
}
}
.doFinally { .doFinally {
view?.run { view?.run {
hideRefresh() hideRefresh()

View File

@ -2,7 +2,10 @@ package io.github.wulkanowy.ui.modules.main
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.os.Bundle import android.os.Bundle
import android.os.Handler
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
@ -68,11 +71,6 @@ class MainActivity : BaseActivity(), MainView {
return true return true
} }
override fun onStart() {
super.onStart()
presenter.onViewChange()
}
override fun initView() { override fun initView() {
mainBottomNav.run { mainBottomNav.run {
addItems( addItems(
@ -144,7 +142,9 @@ class MainActivity : BaseActivity(), MainView {
} }
override fun notifyMenuViewReselected() { override fun notifyMenuViewReselected() {
Handler().postDelayed({
(navController.currentStack?.get(0) as? MainView.MainChildView)?.onFragmentReselected() (navController.currentStack?.get(0) as? MainView.MainChildView)?.onFragmentReselected()
}, 250)
} }
fun showDialogFragment(dialog: DialogFragment) { fun showDialogFragment(dialog: DialogFragment) {
@ -165,7 +165,7 @@ class MainActivity : BaseActivity(), MainView {
override fun openLoginView() { override fun openLoginView() {
startActivity(LoginActivity.getStartIntent(this) startActivity(LoginActivity.getStartIntent(this)
.apply { addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.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?) {

View File

@ -5,7 +5,6 @@ import dagger.Module
import dagger.Provides import dagger.Provides
import dagger.android.ContributesAndroidInjector import dagger.android.ContributesAndroidInjector
import io.github.wulkanowy.R import io.github.wulkanowy.R
import io.github.wulkanowy.di.scopes.PerActivity
import io.github.wulkanowy.di.scopes.PerFragment import io.github.wulkanowy.di.scopes.PerFragment
import io.github.wulkanowy.ui.modules.about.AboutFragment import io.github.wulkanowy.ui.modules.about.AboutFragment
import io.github.wulkanowy.ui.modules.about.AboutModule import io.github.wulkanowy.ui.modules.about.AboutModule
@ -33,7 +32,6 @@ abstract class MainModule {
companion object { companion object {
@JvmStatic @JvmStatic
@PerActivity
@Provides @Provides
fun provideFragNavController(activity: MainActivity): FragNavController { fun provideFragNavController(activity: MainActivity): FragNavController {
return FragNavController(activity.supportFragmentManager, R.id.mainFragmentContainer) return FragNavController(activity.supportFragmentManager, R.id.mainFragmentContainer)

View File

@ -24,9 +24,9 @@ class MainPresenter @Inject constructor(
fun onAttachView(view: MainView, initMenuIndex: Int) { fun onAttachView(view: MainView, initMenuIndex: Int) {
super.onAttachView(view) super.onAttachView(view)
Timber.i("Main view is attached with $initMenuIndex menu index")
view.run { view.run {
startMenuIndex = if (initMenuIndex != -1) initMenuIndex else prefRepository.startMenuIndex startMenuIndex = if (initMenuIndex != -1) initMenuIndex else prefRepository.startMenuIndex
Timber.i("Main view is attached with $startMenuIndex menu index")
initView() initView()
} }

View File

@ -20,12 +20,9 @@ class MessageItem(val message: Message, private val noSubjectString: String) :
return ViewHolder(view, adapter) return ViewHolder(view, adapter)
} }
override fun getLayoutRes(): Int = R.layout.item_message override fun getLayoutRes() = R.layout.item_message
override fun bindViewHolder( override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder, position: Int, payloads: MutableList<Any>?) {
adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder,
position: Int, payloads: MutableList<Any>?
) {
holder.apply { holder.apply {
val style = if (message.unread) BOLD else NORMAL val style = if (message.unread) BOLD else NORMAL
@ -58,9 +55,7 @@ class MessageItem(val message: Message, private val noSubjectString: String) :
return message.hashCode() return message.hashCode()
} }
class ViewHolder(val view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), class ViewHolder(val view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer {
LayoutContainer {
override val containerView: View override val containerView: View
get() = contentView get() = contentView
} }

View File

@ -72,6 +72,10 @@ class SendMessageActivity : BaseActivity(), SendMessageView {
else false else false
} }
override fun onSupportNavigateUp(): Boolean {
return presenter.onUpNavigate()
}
override fun setReportingUnit(unit: ReportingUnit) { override fun setReportingUnit(unit: ReportingUnit) {
sendMessageFromTextView.setText(unit.senderName) sendMessageFromTextView.setText(unit.senderName)
} }

View File

@ -47,6 +47,11 @@ class SendMessagePresenter @Inject constructor(
} }
} }
fun onUpNavigate(): Boolean {
view?.popView()
return true
}
private fun loadData(message: Message?) { private fun loadData(message: Message?) {
var reportingUnit: ReportingUnit? = null var reportingUnit: ReportingUnit? = null
var recipients: List<Recipient> = emptyList() var recipients: List<Recipient> = emptyList()

View File

@ -14,12 +14,12 @@ class MoreItem(val title: String, private val drawable: Drawable?) : AbstractFle
override fun getLayoutRes() = R.layout.item_more override fun getLayoutRes() = R.layout.item_more
override fun createViewHolder(view: View?, adapter: FlexibleAdapter<IFlexible<*>>?): ViewHolder { override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<*>>): ViewHolder {
return ViewHolder(view, adapter) return ViewHolder(view, adapter)
} }
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>?, holder: ViewHolder?, position: Int, payloads: MutableList<Any>?) { override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder, position: Int, payloads: MutableList<Any>?) {
holder?.apply { holder.apply {
moreItemTitle.text = title moreItemTitle.text = title
moreItemImage.setImageDrawable(drawable) moreItemImage.setImageDrawable(drawable)
} }
@ -40,9 +40,8 @@ class MoreItem(val title: String, private val drawable: Drawable?) : AbstractFle
return title.hashCode() return title.hashCode()
} }
class ViewHolder(view: View?, adapter: FlexibleAdapter<*>?) : FlexibleViewHolder(view, adapter), LayoutContainer { class ViewHolder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer {
override val containerView: View
override val containerView: View?
get() = contentView get() = contentView
} }
} }

View File

@ -15,16 +15,13 @@ import kotlinx.android.synthetic.main.item_note.*
class NoteItem(val note: Note) : AbstractFlexibleItem<NoteItem.ViewHolder>() { class NoteItem(val note: Note) : AbstractFlexibleItem<NoteItem.ViewHolder>() {
override fun getLayoutRes() = R.layout.item_note
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<*>>): NoteItem.ViewHolder { override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<*>>): NoteItem.ViewHolder {
return NoteItem.ViewHolder(view, adapter) return NoteItem.ViewHolder(view, adapter)
} }
override fun getLayoutRes(): Int = R.layout.item_note override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: NoteItem.ViewHolder, position: Int, payloads: MutableList<Any>?) {
override fun bindViewHolder(
adapter: FlexibleAdapter<IFlexible<*>>,
holder: NoteItem.ViewHolder, position: Int, payloads: MutableList<Any>?
) {
holder.apply { holder.apply {
noteItemDate.apply { noteItemDate.apply {
text = note.date.toFormattedString() text = note.date.toFormattedString()
@ -57,7 +54,6 @@ class NoteItem(val note: Note) : AbstractFlexibleItem<NoteItem.ViewHolder>() {
} }
class ViewHolder(val view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer { class ViewHolder(val view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer {
override val containerView: View override val containerView: View
get() = contentView get() = contentView
} }

View File

@ -15,18 +15,17 @@ import io.github.wulkanowy.utils.toFormattedString
import kotlinx.android.extensions.LayoutContainer import kotlinx.android.extensions.LayoutContainer
import kotlinx.android.synthetic.main.item_timetable.* import kotlinx.android.synthetic.main.item_timetable.*
class TimetableItem(val lesson: Timetable, private val roomText: String) class TimetableItem(val lesson: Timetable, private val roomText: String) :
: AbstractFlexibleItem<TimetableItem.ViewHolder>() { AbstractFlexibleItem<TimetableItem.ViewHolder>() {
override fun getLayoutRes(): Int = R.layout.item_timetable override fun getLayoutRes() = R.layout.item_timetable
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<*>>): ViewHolder { override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<*>>): ViewHolder {
return ViewHolder(view, adapter) return ViewHolder(view, adapter)
} }
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder, override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder, position: Int, payloads: MutableList<Any>?) {
position: Int, payloads: MutableList<Any>?) {
holder.apply { holder.apply {
timetableItemNumber.text = lesson.number.toString() timetableItemNumber.text = lesson.number.toString()
timetableItemSubject.text = lesson.subject timetableItemSubject.text = lesson.subject
@ -50,12 +49,12 @@ class TimetableItem(val lesson: Timetable, private val roomText: String)
} }
override fun hashCode(): Int { override fun hashCode(): Int {
return lesson.hashCode() var result = lesson.hashCode()
result = 31 * result + lesson.id.toInt()
return result
} }
class ViewHolder(val view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), class ViewHolder(val view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer {
LayoutContainer {
override val containerView: View override val containerView: View
get() = contentView get() = contentView
} }

View File

@ -128,7 +128,7 @@ class TimetablePresenter @Inject constructor(
clearData() clearData()
showNextButton(!currentDate.plusDays(1).isHolidays) showNextButton(!currentDate.plusDays(1).isHolidays)
showPreButton(!currentDate.minusDays(1).isHolidays) showPreButton(!currentDate.minusDays(1).isHolidays)
updateNavigationDay(currentDate.toFormattedString("EEEE \n dd.MM.YYYY").capitalize()) updateNavigationDay(currentDate.toFormattedString("EEEE\ndd.MM.YYYY").capitalize())
} }
} }
} }

View File

@ -112,7 +112,7 @@ class CompletedLessonsPresenter @Inject constructor(
clearData() clearData()
showNextButton(!currentDate.plusDays(1).isHolidays) showNextButton(!currentDate.plusDays(1).isHolidays)
showPreButton(!currentDate.minusDays(1).isHolidays) showPreButton(!currentDate.minusDays(1).isHolidays)
updateNavigationDay(currentDate.toFormattedString("EEEE \n dd.MM.YYYY").capitalize()) updateNavigationDay(currentDate.toFormattedString("EEEE\ndd.MM.YYYY").capitalize())
} }
} }
} }

View File

@ -17,6 +17,7 @@ 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.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 org.threeten.bp.LocalDate import org.threeten.bp.LocalDate
import timber.log.Timber import timber.log.Timber
@ -51,9 +52,13 @@ class TimetableWidgetFactory(
?.let { date -> ?.let { date ->
try { try {
lessons = studentRepository.isStudentSaved() lessons = studentRepository.isStudentSaved()
.flatMap { studentRepository.getCurrentStudent() } .flatMap { isSaved ->
if (isSaved) {
studentRepository.getCurrentStudent()
.flatMap { semesterRepository.getCurrentSemester(it) } .flatMap { semesterRepository.getCurrentSemester(it) }
.flatMap { timetableRepository.getTimetable(it, date, date) } .flatMap { timetableRepository.getTimetable(it, date, date) }
} else Single.just(emptyList())
}
.map { item -> item.sortedBy { it.number } } .map { item -> item.sortedBy { it.number } }
.subscribeOn(schedulers.backgroundThread) .subscribeOn(schedulers.backgroundThread)
.blockingGet() .blockingGet()

View File

@ -62,7 +62,7 @@ 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) updateWidget(context, appWidgetId, now().nextOrSameSchoolDay)
} }
} else { } else {
@ -95,7 +95,7 @@ class TimetableWidgetProvider : BroadcastReceiver() {
.apply { action = createWidgetKey(appWidgetId) }) .apply { action = createWidgetKey(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, BUTTON_RESET).also { createNavIntent(context, Int.MAX_VALUE - appWidgetId, appWidgetId, BUTTON_RESET).also {
setOnClickPendingIntent(R.id.timetableWidgetDate, it) setOnClickPendingIntent(R.id.timetableWidgetDate, it)
setOnClickPendingIntent(R.id.timetableWidgetDay, it) setOnClickPendingIntent(R.id.timetableWidgetDay, it)
} }

View File

@ -1,20 +1,6 @@
Wersja 0.7.0 Wersja 0.7.3
Dodaliśmy:
- szczęśliwy numerek
- lekcje zrealizowane
- wysyłanie wiadomości
- ucznia na tle klasy
- opcję zmiany kolorów ocen
Zmieniliśmy:
- wygląd ekranu logowania
- sposób wyświetlania zastępstw
- widok zadań domowych na tygodniowy
Naprawiliśmy: Naprawiliśmy:
- automatyczne przełączanie widżetu na nowy dzień - naprawiono problemy ze stabilnością podczas odświeżania danych
- wyświetlanie powiadomień o starych ocenach
- znikające numery sal w planie lekcji
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases/tag/0.7.0 Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases/tag/0.7.3

View File

@ -17,13 +17,19 @@
app:tabTextColor="@android:color/white" app:tabTextColor="@android:color/white"
tools:visibility="visible" /> tools:visibility="visible" />
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/gradeSwipe"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="48dp">
<androidx.viewpager.widget.ViewPager <androidx.viewpager.widget.ViewPager
android:id="@+id/gradeViewPager" android:id="@+id/gradeViewPager"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginTop="48dp"
android:visibility="invisible" android:visibility="invisible"
tools:visibility="visible" /> tools:visibility="visible" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<ProgressBar <ProgressBar
android:id="@+id/gradeProgress" android:id="@+id/gradeProgress"

View File

@ -0,0 +1,19 @@
package io.github.wulkanowy.data.repositories
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingStrategy
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.error.ErrorHandler
import io.reactivex.Observable
import io.reactivex.Single
class UnitTestInternetObservingStrategy : InternetObservingStrategy {
override fun checkInternetConnectivity(host: String?, port: Int, timeoutInMs: Int, httpResponse: Int, errorHandler: ErrorHandler?): Single<Boolean> {
return Single.just(true)
}
override fun observeInternetConnectivity(initialIntervalInMs: Int, intervalInMs: Int, host: String?, port: Int, timeoutInMs: Int, httpResponse: Int, errorHandler: ErrorHandler?): Observable<Boolean> {
return Observable.just(true)
}
override fun getDefaultPingHost() = "localhost"
}

View File

@ -1,9 +1,8 @@
package io.github.wulkanowy.data.repositories.remote package io.github.wulkanowy.data.repositories.attendance
import io.github.wulkanowy.api.Api import io.github.wulkanowy.api.Api
import io.github.wulkanowy.api.attendance.Attendance import io.github.wulkanowy.api.attendance.Attendance
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.repositories.attendance.AttendanceRemote
import io.mockk.MockKAnnotations import io.mockk.MockKAnnotations
import io.mockk.every import io.mockk.every
import io.mockk.impl.annotations.MockK import io.mockk.impl.annotations.MockK

View File

@ -1,9 +1,8 @@
package io.github.wulkanowy.data.repositories.remote package io.github.wulkanowy.data.repositories.completedlessons
import io.github.wulkanowy.api.Api import io.github.wulkanowy.api.Api
import io.github.wulkanowy.api.timetable.CompletedLesson import io.github.wulkanowy.api.timetable.CompletedLesson
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.repositories.completedlessons.CompletedLessonsRemote
import io.mockk.MockKAnnotations import io.mockk.MockKAnnotations
import io.mockk.every import io.mockk.every
import io.mockk.impl.annotations.MockK import io.mockk.impl.annotations.MockK

View File

@ -1,9 +1,8 @@
package io.github.wulkanowy.data.repositories.remote package io.github.wulkanowy.data.repositories.exam
import io.github.wulkanowy.api.Api import io.github.wulkanowy.api.Api
import io.github.wulkanowy.api.exams.Exam import io.github.wulkanowy.api.exams.Exam
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.repositories.exam.ExamRemote
import io.mockk.MockKAnnotations import io.mockk.MockKAnnotations
import io.mockk.every import io.mockk.every
import io.mockk.impl.annotations.MockK import io.mockk.impl.annotations.MockK

View File

@ -1,9 +1,8 @@
package io.github.wulkanowy.data.repositories.remote package io.github.wulkanowy.data.repositories.gradestatistics
import io.github.wulkanowy.api.Api import io.github.wulkanowy.api.Api
import io.github.wulkanowy.api.grades.GradeStatistics import io.github.wulkanowy.api.grades.GradeStatistics
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.repositories.gradestatistics.GradeStatisticsRemote
import io.mockk.MockKAnnotations import io.mockk.MockKAnnotations
import io.mockk.every import io.mockk.every
import io.mockk.impl.annotations.MockK import io.mockk.impl.annotations.MockK

View File

@ -1,4 +1,4 @@
package io.github.wulkanowy.data.repositories.remote package io.github.wulkanowy.data.repositories.luckynumber
import io.github.wulkanowy.api.Api import io.github.wulkanowy.api.Api
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester

View File

@ -0,0 +1,74 @@
package io.github.wulkanowy.data.repositories.semester
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import io.github.wulkanowy.data.ApiHelper
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.UnitTestInternetObservingStrategy
import io.reactivex.Maybe
import io.reactivex.Single
import org.junit.Before
import org.junit.Test
import org.mockito.Mock
import org.mockito.Mockito.doNothing
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
class SemesterRepositoryTest {
@Mock
private lateinit var semesterRemote: SemesterRemote
@Mock
private lateinit var semesterLocal: SemesterLocal
@Mock
private lateinit var apiHelper: ApiHelper
@Mock
private lateinit var student: Student
private lateinit var semesterRepository: SemesterRepository
private val settings = InternetObservingSettings.builder()
.strategy(UnitTestInternetObservingStrategy())
.build()
@Before
fun initTest() {
MockitoAnnotations.initMocks(this)
semesterRepository = SemesterRepository(semesterRemote, semesterLocal, settings, apiHelper)
}
@Test
fun singleCurrentSemesterTest() {
val semesters = listOf(
createSemesterEntity(false),
createSemesterEntity(true)
)
doNothing().`when`(apiHelper).initApi(student)
doReturn(Maybe.empty<Semester>()).`when`(semesterLocal).getSemesters(student)
doReturn(Single.just(semesters)).`when`(semesterRemote).getSemesters(student)
semesterRepository.getSemesters(student).blockingGet()
verify(semesterLocal).deleteSemesters(emptyList())
verify(semesterLocal).saveSemesters(semesters)
}
@Test(expected = IllegalArgumentException::class)
fun twoCurrentSemesterTest() {
val semesters = listOf(
createSemesterEntity(true),
createSemesterEntity(true)
)
doNothing().`when`(apiHelper).initApi(student)
doReturn(Maybe.empty<Semester>()).`when`(semesterLocal).getSemesters(student)
doReturn(Single.just(semesters)).`when`(semesterRemote).getSemesters(student)
semesterRepository.getSemesters(student).blockingGet()
}
}

View File

@ -0,0 +1,16 @@
package io.github.wulkanowy.data.repositories.semester
import io.github.wulkanowy.data.db.entities.Semester
fun createSemesterEntity(current: Boolean): Semester {
return Semester(
studentId = 0,
diaryId = 0,
semesterId = 0,
diaryName = "",
classId = 0,
isCurrent = current,
semesterName = 0,
unitId = 0
)
}

View File

@ -1,8 +1,7 @@
package io.github.wulkanowy.data.repositories.remote package io.github.wulkanowy.data.repositories.student
import io.github.wulkanowy.api.Api import io.github.wulkanowy.api.Api
import io.github.wulkanowy.api.register.Student import io.github.wulkanowy.api.register.Student
import io.github.wulkanowy.data.repositories.student.StudentRemote
import io.reactivex.Single import io.reactivex.Single
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Before import org.junit.Before

View File

@ -1,4 +1,4 @@
package io.github.wulkanowy.data.repositories.remote package io.github.wulkanowy.data.repositories.timetable
import io.github.wulkanowy.api.Api import io.github.wulkanowy.api.Api
import io.github.wulkanowy.api.timetable.Timetable import io.github.wulkanowy.api.timetable.Timetable

View File

@ -22,11 +22,11 @@ class GradeExtensionTest {
@Test @Test
fun calcWeightedAverage() { fun calcWeightedAverage() {
assertEquals(3.47, listOf( assertEquals(3.47, listOf(
createGrade(5, 6, 0.33), createGrade(5, 6.0, 0.33),
createGrade(5, 5, -0.33), createGrade(5, 5.0, -0.33),
createGrade(4, 1, 0.0), createGrade(4, 1.0, 0.0),
createGrade(1, 9, 0.5), createGrade(1, 9.0, 0.5),
createGrade(0, 0, 0.0) createGrade(0, .0, 0.0)
).calcAverage(), 0.005) ).calcAverage(), 0.005)
} }
@ -42,23 +42,23 @@ class GradeExtensionTest {
@Test @Test
fun changeModifier_default() { fun changeModifier_default() {
assertEquals(.33, createGrade(5, 0, .33).changeModifier(.0, .0).modifier, .0) assertEquals(.33, createGrade(5, .0, .33).changeModifier(.0, .0).modifier, .0)
assertEquals(-.33, createGrade(5, 0, -.33).changeModifier(.0, .0).modifier, .0) assertEquals(-.33, createGrade(5, .0, -.33).changeModifier(.0, .0).modifier, .0)
} }
@Test @Test
fun changeModifier_plus() { fun changeModifier_plus() {
assertEquals(.33, createGrade(5, 0, .25).changeModifier(.33, .50).modifier, .0) assertEquals(.33, createGrade(5, .0, .25).changeModifier(.33, .50).modifier, .0)
assertEquals(.25, createGrade(5, 0, .33).changeModifier(.25, .0).modifier, .0) assertEquals(.25, createGrade(5, .0, .33).changeModifier(.25, .0).modifier, .0)
} }
@Test @Test
fun changeModifier_minus() { fun changeModifier_minus() {
assertEquals(-.33, createGrade(5, 0, -.25).changeModifier(.25, .33).modifier, .0) assertEquals(-.33, createGrade(5, .0, -.25).changeModifier(.25, .33).modifier, .0)
assertEquals(-.25, createGrade(5, 0, -.33).changeModifier(.0, .25).modifier, .0) assertEquals(-.25, createGrade(5, .0, -.33).changeModifier(.0, .25).modifier, .0)
} }
private fun createGrade(value: Int, weightValue: Int = 0, modifier: Double = 0.25): Grade { private fun createGrade(value: Int, weightValue: Double = .0, modifier: Double = 0.25): Grade {
return Grade( return Grade(
semesterId = 1, semesterId = 1,
studentId = 1, studentId = 1,