Fix no current student (#243)

This commit is contained in:
Rafał Borcz 2019-02-13 20:49:19 +01:00 committed by Mikołaj Pich
parent 297502056c
commit ad9b6d42f0
11 changed files with 45 additions and 49 deletions

View File

@ -73,7 +73,7 @@ play {
dependencies { dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
implementation('com.github.wulkanowy:api:0bbd246778') { exclude module: "threetenbp" } implementation('com.github.wulkanowy:api:0a4317f651') { 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"

View File

@ -28,7 +28,7 @@ class StudentLocalTest {
testDb = Room.inMemoryDatabaseBuilder(context, AppDatabase::class.java) testDb = Room.inMemoryDatabaseBuilder(context, AppDatabase::class.java)
.build() .build()
sharedHelper = SharedPrefHelper(context.getSharedPreferences("TEST", Context.MODE_PRIVATE)) sharedHelper = SharedPrefHelper(context.getSharedPreferences("TEST", Context.MODE_PRIVATE))
studentLocal = StudentLocal(testDb.studentDao, sharedHelper, context) studentLocal = StudentLocal(testDb.studentDao, context)
} }
@After @After
@ -40,7 +40,6 @@ class StudentLocalTest {
fun saveAndReadTest() { fun saveAndReadTest() {
studentLocal.saveStudent(Student(email = "test", password = "test123", schoolSymbol = "23", endpoint = "fakelog.cf", loginType = "AUTO", isCurrent = true)) studentLocal.saveStudent(Student(email = "test", password = "test123", schoolSymbol = "23", endpoint = "fakelog.cf", loginType = "AUTO", isCurrent = true))
.blockingGet() .blockingGet()
assert(studentLocal.isStudentSaved)
val student = studentLocal.getCurrentStudent(true).blockingGet() val student = studentLocal.getCurrentStudent(true).blockingGet()
assertEquals("23", student.schoolSymbol) assertEquals("23", student.schoolSymbol)

View File

@ -19,14 +19,6 @@ class SharedPrefHelper @Inject constructor(private val sharedPref: SharedPrefere
return sharedPref.getLong(key, defaultValue) return sharedPref.getLong(key, defaultValue)
} }
fun putBoolean(key: String, value: Boolean) {
sharedPref.edit().putBoolean(key, value).apply()
}
fun getBoolean(key: String, defaultValue: Boolean): Boolean {
return sharedPref.getBoolean(key, defaultValue)
}
fun delete(key: String) { fun delete(key: String) {
sharedPref.edit().remove(key).apply() sharedPref.edit().remove(key).apply()
} }

View File

@ -3,7 +3,7 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Delete import androidx.room.Delete
import androidx.room.Insert import androidx.room.Insert
import androidx.room.OnConflictStrategy.FAIL import androidx.room.OnConflictStrategy.ABORT
import androidx.room.Query import androidx.room.Query
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.reactivex.Maybe import io.reactivex.Maybe
@ -13,7 +13,7 @@ import javax.inject.Singleton
@Dao @Dao
interface StudentDao { interface StudentDao {
@Insert(onConflict = FAIL) @Insert(onConflict = ABORT)
fun insert(student: Student): Long fun insert(student: Student): Long
@Delete @Delete

View File

@ -21,8 +21,7 @@ class StudentRepository @Inject constructor(
private val apiHelper: ApiHelper private val apiHelper: ApiHelper
) { ) {
val isStudentSaved fun isStudentSaved(): Single<Boolean> = local.getStudents(false).isEmpty.map { !it }
get() = local.isStudentSaved
fun getStudents(email: String, password: String, endpoint: String, symbol: String = ""): Single<List<Student>> { fun getStudents(email: String, password: String, endpoint: String, symbol: String = ""): Single<List<Student>> {
return ReactiveNetwork.checkInternetConnectivity(settings) return ReactiveNetwork.checkInternetConnectivity(settings)

View File

@ -1,7 +1,6 @@
package io.github.wulkanowy.data.repositories.local package io.github.wulkanowy.data.repositories.local
import android.content.Context import android.content.Context
import io.github.wulkanowy.data.db.SharedPrefHelper
import io.github.wulkanowy.data.db.dao.StudentDao import io.github.wulkanowy.data.db.dao.StudentDao
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.utils.security.decrypt import io.github.wulkanowy.utils.security.decrypt
@ -15,25 +14,17 @@ import javax.inject.Singleton
@Singleton @Singleton
class StudentLocal @Inject constructor( class StudentLocal @Inject constructor(
private val studentDb: StudentDao, private val studentDb: StudentDao,
private val sharedPref: SharedPrefHelper,
private val context: Context private val context: Context
) { ) {
companion object {
const val STUDENT_SAVED_KEY: String = "is_student_saved"
}
val isStudentSaved
get() = sharedPref.getBoolean(STUDENT_SAVED_KEY, false)
fun saveStudent(student: Student): Single<Long> { fun saveStudent(student: Student): Single<Long> {
return Single.fromCallable { studentDb.insert(student.copy(password = encrypt(student.password, context))) } return Single.fromCallable { studentDb.insert(student.copy(password = encrypt(student.password, context))) }
.doOnSuccess { sharedPref.putBoolean(STUDENT_SAVED_KEY, true) }
} }
fun getStudents(decryptPass: Boolean): Maybe<List<Student>> { fun getStudents(decryptPass: Boolean): Maybe<List<Student>> {
return studentDb.loadAll() return studentDb.loadAll()
.map { list -> list.map { it.apply { if (decryptPass) password = decrypt(password) } } } .map { list -> list.map { it.apply { if (decryptPass) password = decrypt(password) } } }
.filter { !it.isEmpty() }
} }
fun getCurrentStudent(decryptPass: Boolean): Maybe<Student> { fun getCurrentStudent(decryptPass: Boolean): Maybe<Student> {
@ -46,13 +37,10 @@ class StudentLocal @Inject constructor(
resetCurrent() resetCurrent()
updateCurrent(student.studentId) updateCurrent(student.studentId)
} }
}.doOnComplete { sharedPref.putBoolean(STUDENT_SAVED_KEY, true) } }
} }
fun logoutStudent(student: Student): Completable { fun logoutStudent(student: Student): Completable {
return Completable.fromCallable { return Completable.fromCallable { studentDb.delete(student) }
studentDb.delete(student)
if (student.isCurrent) sharedPref.putBoolean(STUDENT_SAVED_KEY, false)
}
} }
} }

View File

@ -25,6 +25,7 @@ import io.github.wulkanowy.utils.friday
import io.github.wulkanowy.utils.isHolidays import io.github.wulkanowy.utils.isHolidays
import io.github.wulkanowy.utils.monday import io.github.wulkanowy.utils.monday
import io.reactivex.Completable import io.reactivex.Completable
import io.reactivex.Maybe
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import org.threeten.bp.LocalDate import org.threeten.bp.LocalDate
import timber.log.Timber import timber.log.Timber
@ -89,14 +90,14 @@ class SyncWorker : SimpleJobService() {
val end = LocalDate.now().friday val end = LocalDate.now().friday
if (start.isHolidays) return RESULT_FAIL_NORETRY if (start.isHolidays) return RESULT_FAIL_NORETRY
if (!student.isStudentSaved) return RESULT_FAIL_RETRY
var error: Throwable? = null var error: Throwable? = null
val notify = prefRepository.isNotificationsEnable val notify = prefRepository.isNotificationsEnable
disposable.add(student.getCurrentStudent() disposable.add(student.isStudentSaved()
.flatMap { semester.getCurrentSemester(it, true).map { semester -> semester to it } } .flatMapMaybe { if (it) student.getCurrentStudent().toMaybe() else Maybe.empty() }
.flatMap { semester.getCurrentSemester(it, true).map { semester -> semester to it }.toMaybe() }
.flatMapCompletable { .flatMapCompletable {
Completable.merge( Completable.merge(
listOf( listOf(

View File

@ -1,6 +1,8 @@
package io.github.wulkanowy.ui.modules.splash package io.github.wulkanowy.ui.modules.splash
import android.os.Bundle import android.os.Bundle
import android.widget.Toast
import android.widget.Toast.LENGTH_LONG
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
@ -26,6 +28,10 @@ class SplashActivity : BaseActivity(), SplashView {
finish() finish()
} }
override fun showError(text: String, error: Throwable) {
Toast.makeText(this, text, LENGTH_LONG).show()
}
override fun onDestroy() { override fun onDestroy() {
presenter.onDetachView() presenter.onDetachView()
super.onDestroy() super.onDestroy()

View File

@ -3,18 +3,25 @@ package io.github.wulkanowy.ui.modules.splash
import io.github.wulkanowy.data.repositories.StudentRepository import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.ui.base.BasePresenter
import io.github.wulkanowy.ui.base.ErrorHandler import io.github.wulkanowy.ui.base.ErrorHandler
import io.github.wulkanowy.utils.SchedulersProvider
import javax.inject.Inject import javax.inject.Inject
class SplashPresenter @Inject constructor( class SplashPresenter @Inject constructor(
private val studentRepository: StudentRepository, private val studentRepository: StudentRepository,
errorHandler: ErrorHandler private val errorHandler: ErrorHandler,
private val schedulers: SchedulersProvider
) : BasePresenter<SplashView>(errorHandler) { ) : BasePresenter<SplashView>(errorHandler) {
override fun onAttachView(view: SplashView) { override fun onAttachView(view: SplashView) {
super.onAttachView(view) super.onAttachView(view)
view.run { disposable.add(studentRepository.isStudentSaved()
if (studentRepository.isStudentSaved) openMainView() .subscribeOn(schedulers.backgroundThread)
.observeOn(schedulers.mainThread)
.subscribe({
view.apply {
if (it) openMainView()
else openLoginView() else openLoginView()
} }
}, { errorHandler.dispatch(it) }))
} }
} }

View File

@ -16,6 +16,7 @@ import io.github.wulkanowy.data.repositories.SemesterRepository
import io.github.wulkanowy.data.repositories.StudentRepository import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.data.repositories.TimetableRepository import io.github.wulkanowy.data.repositories.TimetableRepository
import io.github.wulkanowy.utils.toFormattedString import io.github.wulkanowy.utils.toFormattedString
import io.reactivex.Single
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import org.threeten.bp.LocalDate import org.threeten.bp.LocalDate
import timber.log.Timber import timber.log.Timber
@ -48,16 +49,17 @@ class TimetableWidgetFactory(
override fun onDataSetChanged() { override fun onDataSetChanged() {
intent?.action?.let { LocalDate.ofEpochDay(sharedPref.getLong(it, 0)) } intent?.action?.let { LocalDate.ofEpochDay(sharedPref.getLong(it, 0)) }
?.let { date -> ?.let { date ->
if (studentRepository.isStudentSaved) { disposable.add(studentRepository.isStudentSaved()
disposable.add(studentRepository.getCurrentStudent() .flatMap {
.flatMap { semesterRepository.getCurrentSemester(it) } if (it) studentRepository.getCurrentStudent()
else Single.error(IllegalArgumentException("No saved students"))
}.flatMap { semesterRepository.getCurrentSemester(it) }
.flatMap { timetableRepository.getTimetable(it, date, date) } .flatMap { timetableRepository.getTimetable(it, date, date) }
.map { item -> item.sortedBy { it.number } } .map { item -> item.sortedBy { it.number } }
.subscribe({ lessons = it }) .subscribe({ lessons = it })
{ Timber.e(it, "An error has occurred while downloading data for the widget") }) { Timber.e(it, "An error has occurred while downloading data for the widget") })
} }
} }
}
override fun getViewAt(position: Int): RemoteViews? { override fun getViewAt(position: Int): RemoteViews? {
if (position == INVALID_POSITION) return null if (position == INVALID_POSITION) return null

View File

@ -1,7 +1,9 @@
package io.github.wulkanowy.ui.modules.splash package io.github.wulkanowy.ui.modules.splash
import io.github.wulkanowy.TestSchedulersProvider
import io.github.wulkanowy.data.repositories.StudentRepository import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.ui.base.ErrorHandler import io.github.wulkanowy.ui.base.ErrorHandler
import io.reactivex.Single
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.mockito.Mock import org.mockito.Mock
@ -25,19 +27,19 @@ class SplashPresenterTest {
@Before @Before
fun initPresenter() { fun initPresenter() {
MockitoAnnotations.initMocks(this) MockitoAnnotations.initMocks(this)
presenter = SplashPresenter(studentRepository, errorHandler) presenter = SplashPresenter(studentRepository, errorHandler, TestSchedulersProvider())
} }
@Test @Test
fun testOpenLoginView() { fun testOpenLoginView() {
doReturn(false).`when`(studentRepository).isStudentSaved doReturn(Single.just(false)).`when`(studentRepository).isStudentSaved()
presenter.onAttachView(splashView) presenter.onAttachView(splashView)
verify(splashView).openLoginView() verify(splashView).openLoginView()
} }
@Test @Test
fun testMainMainView() { fun testMainMainView() {
doReturn(true).`when`(studentRepository).isStudentSaved doReturn(Single.just(true)).`when`(studentRepository).isStudentSaved()
presenter.onAttachView(splashView) presenter.onAttachView(splashView)
verify(splashView).openMainView() verify(splashView).openMainView()
} }