Merge branch '0.7.x'

This commit is contained in:
Mikołaj Pich 2019-03-24 23:08:50 +01:00
commit a2a18e5652
No known key found for this signature in database
GPG Key ID: F62B26E36D4C4BAA
45 changed files with 296 additions and 225 deletions

View File

@ -11,10 +11,10 @@ cache:
- $HOME/.gradle/caches/ - $HOME/.gradle/caches/
- $HOME/.gradle/wrapper/ - $HOME/.gradle/wrapper/
#branches: branches:
# only: only:
# - master - master
# - 0.7.x - 0.7.x
android: android:
licenses: licenses:

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 27 versionCode 28
versionName "0.7.1" versionName "0.7.2"
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.1') { exclude module: "threetenbp" } implementation('com.github.wulkanowy:api:master-SNAPSHOT') { 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

@ -52,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

@ -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

@ -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
@ -18,6 +19,7 @@ import io.github.wulkanowy.services.sync.channels.DebugChannel
import io.github.wulkanowy.services.sync.works.Work import io.github.wulkanowy.services.sync.works.Work
import io.github.wulkanowy.utils.getCompatColor import io.github.wulkanowy.utils.getCompatColor
import io.reactivex.Completable import io.reactivex.Completable
import io.reactivex.Flowable
import io.reactivex.Single import io.reactivex.Single
import timber.log.Timber import timber.log.Timber
import kotlin.random.Random import kotlin.random.Random
@ -33,19 +35,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(Flowable.fromIterable(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") }
}), 3)
} }
} }
.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)

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

@ -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

@ -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,15 +28,12 @@ class GradePresenter @Inject constructor(
fun onAttachView(view: GradeView, savedIndex: Int?) { fun onAttachView(view: GradeView, savedIndex: Int?) {
super.onAttachView(view) super.onAttachView(view)
Timber.i("Grade view is attached") Timber.i("Grade view is attached")
disposable.add(Completable.timer(150, MILLISECONDS, schedulers.mainThread)
.subscribe {
selectedIndex = savedIndex ?: 0 selectedIndex = savedIndex ?: 0
view.run { view.run {
initView() initView()
enableSwipe(false) enableSwipe(false)
} }
loadData() loadData()
})
} }
fun onCreateMenu() { fun onCreateMenu() {
@ -82,7 +77,7 @@ class GradePresenter @Inject constructor(
} }
fun onPageSelected(index: Int) { fun onPageSelected(index: Int) {
loadChild(index) if (semesters.isNotEmpty()) loadChild(index)
} }
fun onSwipeRefresh() { fun onSwipeRefresh() {

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

@ -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

@ -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,18 +1,6 @@
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ń - problemy ze stabilnością podczas przełączania zakładek
- wyświetlanie powiadomień o starych ocenach - nierówność w nawigacji między dniami w planie lekcji i frekwencji
- znikające numery sal w planie lekcji - zły wygląd odświeżania w szczęśliwym numerku
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.2

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