forked from github/wulkanowy-mirror
Add completed lessons (#236)
This commit is contained in:
parent
52ed7dcb6c
commit
297502056c
@ -11,9 +11,9 @@ cache:
|
|||||||
- $HOME/.gradle/caches/
|
- $HOME/.gradle/caches/
|
||||||
- $HOME/.gradle/wrapper/
|
- $HOME/.gradle/wrapper/
|
||||||
|
|
||||||
#branches:
|
branches:
|
||||||
# only:
|
only:
|
||||||
# - master
|
- master
|
||||||
|
|
||||||
android:
|
android:
|
||||||
licenses:
|
licenses:
|
||||||
|
@ -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:f941c4b1c7') { exclude module: "threetenbp" }
|
implementation('com.github.wulkanowy:api:0bbd246778') { 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"
|
||||||
|
@ -0,0 +1,57 @@
|
|||||||
|
package io.github.wulkanowy.data.repositories.local
|
||||||
|
|
||||||
|
import androidx.room.Room
|
||||||
|
import androidx.test.core.app.ApplicationProvider
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
import io.github.wulkanowy.data.db.AppDatabase
|
||||||
|
import io.github.wulkanowy.data.db.entities.CompletedLesson
|
||||||
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
|
import org.junit.After
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.threeten.bp.LocalDate
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
class CompletedLessonsLocalTest {
|
||||||
|
|
||||||
|
private lateinit var completedLessonsLocal: CompletedLessonsLocal
|
||||||
|
|
||||||
|
private lateinit var testDb: AppDatabase
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun createDb() {
|
||||||
|
testDb = Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java)
|
||||||
|
.build()
|
||||||
|
completedLessonsLocal = CompletedLessonsLocal(testDb.completedLessonsDao)
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
fun closeDb() {
|
||||||
|
testDb.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun saveAndReadTest() {
|
||||||
|
completedLessonsLocal.saveCompletedLessons(listOf(
|
||||||
|
getCompletedLesson(LocalDate.of(2018, 9, 10), 1),
|
||||||
|
getCompletedLesson(LocalDate.of(2018, 9, 14), 2),
|
||||||
|
getCompletedLesson(LocalDate.of(2018, 9, 17), 3)
|
||||||
|
))
|
||||||
|
|
||||||
|
val completed = completedLessonsLocal
|
||||||
|
.getCompletedLessons(Semester(1, 1, 2, "", 3, 1),
|
||||||
|
LocalDate.of(2018, 9, 10),
|
||||||
|
LocalDate.of(2018, 9, 14)
|
||||||
|
)
|
||||||
|
.blockingGet()
|
||||||
|
assertEquals(2, completed.size)
|
||||||
|
assertEquals(completed[0].date, LocalDate.of(2018, 9, 10))
|
||||||
|
assertEquals(completed[1].date, LocalDate.of(2018, 9, 14))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getCompletedLesson(date: LocalDate, number: Int): CompletedLesson {
|
||||||
|
return CompletedLesson(1, 2, date, number, "", "", "", "", "", "", "")
|
||||||
|
}
|
||||||
|
}
|
@ -117,4 +117,8 @@ internal class RepositoryModule {
|
|||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
fun provideLuckyNumberDao(database: AppDatabase) = database.luckyNumberDao
|
fun provideLuckyNumberDao(database: AppDatabase) = database.luckyNumberDao
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@Provides
|
||||||
|
fun provideCompletedLessonsDao(database: AppDatabase) = database.completedLessonsDao
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ import io.github.wulkanowy.data.db.dao.HomeworkDao
|
|||||||
import io.github.wulkanowy.data.db.dao.LuckyNumberDao
|
import io.github.wulkanowy.data.db.dao.LuckyNumberDao
|
||||||
import io.github.wulkanowy.data.db.dao.MessagesDao
|
import io.github.wulkanowy.data.db.dao.MessagesDao
|
||||||
import io.github.wulkanowy.data.db.dao.NoteDao
|
import io.github.wulkanowy.data.db.dao.NoteDao
|
||||||
|
import io.github.wulkanowy.data.db.dao.CompletedLessonsDao
|
||||||
import io.github.wulkanowy.data.db.dao.SemesterDao
|
import io.github.wulkanowy.data.db.dao.SemesterDao
|
||||||
import io.github.wulkanowy.data.db.dao.StudentDao
|
import io.github.wulkanowy.data.db.dao.StudentDao
|
||||||
import io.github.wulkanowy.data.db.dao.SubjectDao
|
import io.github.wulkanowy.data.db.dao.SubjectDao
|
||||||
@ -28,11 +29,13 @@ import io.github.wulkanowy.data.db.entities.Homework
|
|||||||
import io.github.wulkanowy.data.db.entities.LuckyNumber
|
import io.github.wulkanowy.data.db.entities.LuckyNumber
|
||||||
import io.github.wulkanowy.data.db.entities.Message
|
import io.github.wulkanowy.data.db.entities.Message
|
||||||
import io.github.wulkanowy.data.db.entities.Note
|
import io.github.wulkanowy.data.db.entities.Note
|
||||||
|
import io.github.wulkanowy.data.db.entities.CompletedLesson
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
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.Migration2
|
import io.github.wulkanowy.data.db.migrations.Migration2
|
||||||
|
import io.github.wulkanowy.data.db.migrations.Migration3
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@ -50,9 +53,10 @@ import javax.inject.Singleton
|
|||||||
Note::class,
|
Note::class,
|
||||||
Homework::class,
|
Homework::class,
|
||||||
Subject::class,
|
Subject::class,
|
||||||
LuckyNumber::class
|
LuckyNumber::class,
|
||||||
|
CompletedLesson::class
|
||||||
],
|
],
|
||||||
version = 2,
|
version = 3,
|
||||||
exportSchema = false
|
exportSchema = false
|
||||||
)
|
)
|
||||||
@TypeConverters(Converters::class)
|
@TypeConverters(Converters::class)
|
||||||
@ -63,7 +67,8 @@ abstract class AppDatabase : RoomDatabase() {
|
|||||||
return Room.databaseBuilder(context, AppDatabase::class.java, "wulkanowy_database")
|
return Room.databaseBuilder(context, AppDatabase::class.java, "wulkanowy_database")
|
||||||
.setJournalMode(TRUNCATE)
|
.setJournalMode(TRUNCATE)
|
||||||
.addMigrations(
|
.addMigrations(
|
||||||
Migration2()
|
Migration2(),
|
||||||
|
Migration3()
|
||||||
)
|
)
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
@ -94,4 +99,6 @@ abstract class AppDatabase : RoomDatabase() {
|
|||||||
abstract val subjectDao: SubjectDao
|
abstract val subjectDao: SubjectDao
|
||||||
|
|
||||||
abstract val luckyNumberDao: LuckyNumberDao
|
abstract val luckyNumberDao: LuckyNumberDao
|
||||||
|
|
||||||
|
abstract val completedLessonsDao: CompletedLessonsDao
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,24 @@
|
|||||||
|
package io.github.wulkanowy.data.db.dao
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Delete
|
||||||
|
import androidx.room.Insert
|
||||||
|
import androidx.room.Query
|
||||||
|
import io.github.wulkanowy.data.db.entities.CompletedLesson
|
||||||
|
import io.reactivex.Maybe
|
||||||
|
import org.threeten.bp.LocalDate
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@Dao
|
||||||
|
interface CompletedLessonsDao {
|
||||||
|
|
||||||
|
@Insert
|
||||||
|
fun insertAll(exams: List<CompletedLesson>): List<Long>
|
||||||
|
|
||||||
|
@Delete
|
||||||
|
fun deleteAll(exams: List<CompletedLesson>)
|
||||||
|
|
||||||
|
@Query("SELECT * FROM CompletedLesson WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :from AND date <= :end")
|
||||||
|
fun loadAll(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): Maybe<List<CompletedLesson>>
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
package io.github.wulkanowy.data.db.entities
|
||||||
|
|
||||||
|
import androidx.room.ColumnInfo
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
import org.threeten.bp.LocalDate
|
||||||
|
import java.io.Serializable
|
||||||
|
|
||||||
|
@Entity(tableName = "CompletedLesson")
|
||||||
|
data class CompletedLesson(
|
||||||
|
|
||||||
|
@ColumnInfo(name = "student_id")
|
||||||
|
var studentId: Int,
|
||||||
|
|
||||||
|
@ColumnInfo(name = "diary_id")
|
||||||
|
var diaryId: Int,
|
||||||
|
|
||||||
|
var date: LocalDate,
|
||||||
|
|
||||||
|
var number: Int,
|
||||||
|
|
||||||
|
var subject: String,
|
||||||
|
|
||||||
|
var topic: String,
|
||||||
|
|
||||||
|
var teacher: String,
|
||||||
|
|
||||||
|
@ColumnInfo(name = "teacher_symbol")
|
||||||
|
var teacherSymbol: String,
|
||||||
|
|
||||||
|
var substitution: String,
|
||||||
|
|
||||||
|
var absence: String,
|
||||||
|
|
||||||
|
var resources: String
|
||||||
|
) : Serializable {
|
||||||
|
|
||||||
|
@PrimaryKey(autoGenerate = true)
|
||||||
|
var id: Long = 0
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package io.github.wulkanowy.data.db.migrations
|
||||||
|
|
||||||
|
import androidx.room.migration.Migration
|
||||||
|
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||||
|
|
||||||
|
class Migration3 : Migration(2, 3) {
|
||||||
|
|
||||||
|
override fun migrate(database: SupportSQLiteDatabase) {
|
||||||
|
database.execSQL("CREATE TABLE CompletedLesson (" +
|
||||||
|
"id INTEGER NOT NULL PRIMARY KEY, " +
|
||||||
|
"student_id INTEGER NOT NULL, " +
|
||||||
|
"diary_id INTEGER NOT NULL, " +
|
||||||
|
"date INTEGER NOT NULL, " +
|
||||||
|
"number INTEGER NOT NULL, " +
|
||||||
|
"subject TEXT NOT NULL, " +
|
||||||
|
"topic TEXT NOT NULL, " +
|
||||||
|
"teacher TEXT NOT NULL, " +
|
||||||
|
"teacher_symbol TEXT NOT NULL, " +
|
||||||
|
"substitution TEXT NOT NULL, " +
|
||||||
|
"absence TEXT NOT NULL, " +
|
||||||
|
"resources TEXT NOT NULL)")
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
package io.github.wulkanowy.data.repositories
|
||||||
|
|
||||||
|
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
|
||||||
|
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
||||||
|
import io.github.wulkanowy.data.db.entities.CompletedLesson
|
||||||
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
|
import io.github.wulkanowy.data.repositories.local.CompletedLessonsLocal
|
||||||
|
import io.github.wulkanowy.data.repositories.remote.CompletedLessonsRemote
|
||||||
|
import io.github.wulkanowy.utils.friday
|
||||||
|
import io.github.wulkanowy.utils.monday
|
||||||
|
import io.reactivex.Single
|
||||||
|
import org.threeten.bp.LocalDate
|
||||||
|
import java.net.UnknownHostException
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class CompletedLessonsRepository @Inject constructor(
|
||||||
|
private val settings: InternetObservingSettings,
|
||||||
|
private val local: CompletedLessonsLocal,
|
||||||
|
private val remote: CompletedLessonsRemote
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun getCompletedLessons(semester: Semester, startDate: LocalDate, endDate: LocalDate, forceRefresh: Boolean = false): Single<List<CompletedLesson>> {
|
||||||
|
return Single.fromCallable { startDate.monday to endDate.friday }
|
||||||
|
.flatMap { dates ->
|
||||||
|
local.getCompletedLessons(semester, dates.first, dates.second).filter { !forceRefresh }
|
||||||
|
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||||
|
.flatMap {
|
||||||
|
if (it) remote.getCompletedLessons(semester, dates.first, dates.second)
|
||||||
|
else Single.error(UnknownHostException())
|
||||||
|
}.flatMap { new ->
|
||||||
|
local.getCompletedLessons(semester, dates.first, dates.second)
|
||||||
|
.toSingle(emptyList())
|
||||||
|
.doOnSuccess { old ->
|
||||||
|
local.deleteCompleteLessons(old - new)
|
||||||
|
local.saveCompletedLessons(new - old)
|
||||||
|
}
|
||||||
|
}.flatMap {
|
||||||
|
local.getCompletedLessons(semester, dates.first, dates.second)
|
||||||
|
.toSingle(emptyList())
|
||||||
|
}).map { list -> list.filter { it.date in startDate..endDate } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package io.github.wulkanowy.data.repositories.local
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.db.dao.CompletedLessonsDao
|
||||||
|
import io.github.wulkanowy.data.db.entities.CompletedLesson
|
||||||
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
|
import io.reactivex.Maybe
|
||||||
|
import org.threeten.bp.LocalDate
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class CompletedLessonsLocal @Inject constructor(private val completedLessonsDb: CompletedLessonsDao) {
|
||||||
|
|
||||||
|
fun getCompletedLessons(semester: Semester, start: LocalDate, end: LocalDate): Maybe<List<CompletedLesson>> {
|
||||||
|
return completedLessonsDb.loadAll(semester.diaryId, semester.studentId, start, end).filter { !it.isEmpty() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveCompletedLessons(completedLessons: List<CompletedLesson>) {
|
||||||
|
completedLessonsDb.insertAll(completedLessons)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deleteCompleteLessons(completedLessons: List<CompletedLesson>) {
|
||||||
|
completedLessonsDb.deleteAll(completedLessons)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
package io.github.wulkanowy.data.repositories.remote
|
||||||
|
|
||||||
|
import io.github.wulkanowy.api.Api
|
||||||
|
import io.github.wulkanowy.api.toLocalDate
|
||||||
|
import io.github.wulkanowy.data.db.entities.CompletedLesson
|
||||||
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
|
import io.reactivex.Single
|
||||||
|
import org.threeten.bp.LocalDate
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class CompletedLessonsRemote @Inject constructor(private val api: Api) {
|
||||||
|
|
||||||
|
fun getCompletedLessons(semester: Semester, startDate: LocalDate, endDate: LocalDate): Single<List<CompletedLesson>> {
|
||||||
|
return Single.just(api.apply { diaryId = semester.diaryId })
|
||||||
|
.flatMap { it.getCompletedLessons(startDate, endDate) }
|
||||||
|
.map { lessons ->
|
||||||
|
lessons.map {
|
||||||
|
it.absence
|
||||||
|
CompletedLesson(
|
||||||
|
studentId = semester.studentId,
|
||||||
|
diaryId = semester.diaryId,
|
||||||
|
date = it.date.toLocalDate(),
|
||||||
|
number = it.number,
|
||||||
|
subject = it.subject,
|
||||||
|
topic = it.topic,
|
||||||
|
teacher = it.teacher,
|
||||||
|
teacherSymbol = it.teacherSymbol,
|
||||||
|
substitution = it.substitution,
|
||||||
|
absence = it.absence,
|
||||||
|
resources = it.resources
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@ import com.firebase.jobdispatcher.JobParameters
|
|||||||
import com.firebase.jobdispatcher.SimpleJobService
|
import com.firebase.jobdispatcher.SimpleJobService
|
||||||
import dagger.android.AndroidInjection
|
import dagger.android.AndroidInjection
|
||||||
import io.github.wulkanowy.data.repositories.AttendanceRepository
|
import io.github.wulkanowy.data.repositories.AttendanceRepository
|
||||||
|
import io.github.wulkanowy.data.repositories.CompletedLessonsRepository
|
||||||
import io.github.wulkanowy.data.repositories.ExamRepository
|
import io.github.wulkanowy.data.repositories.ExamRepository
|
||||||
import io.github.wulkanowy.data.repositories.GradeRepository
|
import io.github.wulkanowy.data.repositories.GradeRepository
|
||||||
import io.github.wulkanowy.data.repositories.GradeSummaryRepository
|
import io.github.wulkanowy.data.repositories.GradeSummaryRepository
|
||||||
@ -64,6 +65,9 @@ class SyncWorker : SimpleJobService() {
|
|||||||
@Inject
|
@Inject
|
||||||
lateinit var luckyNumber: LuckyNumberRepository
|
lateinit var luckyNumber: LuckyNumberRepository
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var completedLessons: CompletedLessonsRepository
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var prefRepository: PreferencesRepository
|
lateinit var prefRepository: PreferencesRepository
|
||||||
|
|
||||||
@ -105,7 +109,8 @@ class SyncWorker : SimpleJobService() {
|
|||||||
note.getNotes(it.first, true, notify).ignoreElement(),
|
note.getNotes(it.first, true, notify).ignoreElement(),
|
||||||
homework.getHomework(it.first, LocalDate.now(), true).ignoreElement(),
|
homework.getHomework(it.first, LocalDate.now(), true).ignoreElement(),
|
||||||
homework.getHomework(it.first, LocalDate.now().plusDays(1), true).ignoreElement(),
|
homework.getHomework(it.first, LocalDate.now().plusDays(1), true).ignoreElement(),
|
||||||
luckyNumber.getLuckyNumber(it.first, true, notify).ignoreElement()
|
luckyNumber.getLuckyNumber(it.first, true, notify).ignoreElement(),
|
||||||
|
completedLessons.getCompletedLessons(it.first, start, end, true).ignoreElement()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package io.github.wulkanowy.ui.base
|
|||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import com.readystatesoftware.chuck.api.ChuckCollector
|
import com.readystatesoftware.chuck.api.ChuckCollector
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.api.interceptor.FeatureDisabledException
|
||||||
import io.github.wulkanowy.api.interceptor.ServiceUnavailableException
|
import io.github.wulkanowy.api.interceptor.ServiceUnavailableException
|
||||||
import io.github.wulkanowy.api.login.NotLoggedInException
|
import io.github.wulkanowy.api.login.NotLoggedInException
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
@ -26,6 +27,7 @@ open class ErrorHandler @Inject constructor(protected val resources: Resources,
|
|||||||
is SocketTimeoutException -> resources.getString(R.string.error_timeout)
|
is SocketTimeoutException -> resources.getString(R.string.error_timeout)
|
||||||
is NotLoggedInException -> resources.getString(R.string.error_login_failed)
|
is NotLoggedInException -> resources.getString(R.string.error_login_failed)
|
||||||
is ServiceUnavailableException -> resources.getString(R.string.error_service_unavailable)
|
is ServiceUnavailableException -> resources.getString(R.string.error_service_unavailable)
|
||||||
|
is FeatureDisabledException -> resources.getString(R.string.error_feature_disabled)
|
||||||
else -> resources.getString(R.string.error_unknown)
|
else -> resources.getString(R.string.error_unknown)
|
||||||
}), error)
|
}), error)
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,10 @@ import io.github.wulkanowy.ui.base.ErrorHandler
|
|||||||
import io.github.wulkanowy.utils.security.ScramblerException
|
import io.github.wulkanowy.utils.security.ScramblerException
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class SessionErrorHandler @Inject constructor(resources: Resources, chuckCollector: ChuckCollector) : ErrorHandler(resources, chuckCollector) {
|
open class SessionErrorHandler @Inject constructor(
|
||||||
|
resources: Resources,
|
||||||
|
chuckCollector: ChuckCollector
|
||||||
|
) : ErrorHandler(resources, chuckCollector) {
|
||||||
|
|
||||||
var onDecryptionFail: () -> Unit = {}
|
var onDecryptionFail: () -> Unit = {}
|
||||||
|
|
||||||
|
@ -8,7 +8,10 @@ import io.github.wulkanowy.api.login.BadCredentialsException
|
|||||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class LoginErrorHandler @Inject constructor(resources: Resources, chuckCollector: ChuckCollector) : ErrorHandler(resources, chuckCollector) {
|
class LoginErrorHandler @Inject constructor(
|
||||||
|
resources: Resources,
|
||||||
|
chuckCollector: ChuckCollector
|
||||||
|
) : ErrorHandler(resources, chuckCollector) {
|
||||||
|
|
||||||
var onBadCredentials: () -> Unit = {}
|
var onBadCredentials: () -> Unit = {}
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ import io.github.wulkanowy.ui.modules.more.MoreFragment
|
|||||||
import io.github.wulkanowy.ui.modules.note.NoteFragment
|
import io.github.wulkanowy.ui.modules.note.NoteFragment
|
||||||
import io.github.wulkanowy.ui.modules.settings.SettingsFragment
|
import io.github.wulkanowy.ui.modules.settings.SettingsFragment
|
||||||
import io.github.wulkanowy.ui.modules.timetable.TimetableFragment
|
import io.github.wulkanowy.ui.modules.timetable.TimetableFragment
|
||||||
|
import io.github.wulkanowy.ui.modules.timetable.completed.CompletedLessonsFragment
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
abstract class MainModule {
|
abstract class MainModule {
|
||||||
@ -93,5 +94,9 @@ abstract class MainModule {
|
|||||||
|
|
||||||
@PerFragment
|
@PerFragment
|
||||||
@ContributesAndroidInjector
|
@ContributesAndroidInjector
|
||||||
abstract fun bindsAccountDialog(): AccountDialog
|
abstract fun bindAccountDialog(): AccountDialog
|
||||||
|
|
||||||
|
@PerFragment
|
||||||
|
@ContributesAndroidInjector
|
||||||
|
abstract fun bindCompletedLessonsFragment(): CompletedLessonsFragment
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,9 @@ package io.github.wulkanowy.ui.modules.timetable
|
|||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
import android.view.Menu
|
||||||
|
import android.view.MenuInflater
|
||||||
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
@ -12,6 +15,7 @@ import io.github.wulkanowy.data.db.entities.Timetable
|
|||||||
import io.github.wulkanowy.ui.base.session.BaseSessionFragment
|
import io.github.wulkanowy.ui.base.session.BaseSessionFragment
|
||||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||||
import io.github.wulkanowy.ui.modules.main.MainView
|
import io.github.wulkanowy.ui.modules.main.MainView
|
||||||
|
import io.github.wulkanowy.ui.modules.timetable.completed.CompletedLessonsFragment
|
||||||
import io.github.wulkanowy.utils.setOnItemClickListener
|
import io.github.wulkanowy.utils.setOnItemClickListener
|
||||||
import kotlinx.android.synthetic.main.fragment_timetable.*
|
import kotlinx.android.synthetic.main.fragment_timetable.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -39,6 +43,14 @@ class TimetableFragment : BaseSessionFragment(), TimetableView, MainView.MainChi
|
|||||||
override val isViewEmpty: Boolean
|
override val isViewEmpty: Boolean
|
||||||
get() = timetableAdapter.isEmpty
|
get() = timetableAdapter.isEmpty
|
||||||
|
|
||||||
|
override val currentStackSize: Int?
|
||||||
|
get() = (activity as? MainActivity)?.currentStackSize
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setHasOptionsMenu(true)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
return inflater.inflate(R.layout.fragment_timetable, container, false)
|
return inflater.inflate(R.layout.fragment_timetable, container, false)
|
||||||
}
|
}
|
||||||
@ -63,6 +75,15 @@ class TimetableFragment : BaseSessionFragment(), TimetableView, MainView.MainChi
|
|||||||
timetableNextButton.setOnClickListener { presenter.onNextDay() }
|
timetableNextButton.setOnClickListener { presenter.onNextDay() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
|
||||||
|
inflater?.inflate(R.menu.action_menu_timetable, menu)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
|
||||||
|
return if (item?.itemId == R.id.timetableMenuCompletedLessons) presenter.onCompletedLessonsSwitchSelected()
|
||||||
|
else false
|
||||||
|
}
|
||||||
|
|
||||||
override fun updateData(data: List<TimetableItem>) {
|
override fun updateData(data: List<TimetableItem>) {
|
||||||
timetableAdapter.updateDataSet(data, true)
|
timetableAdapter.updateDataSet(data, true)
|
||||||
}
|
}
|
||||||
@ -87,6 +108,10 @@ class TimetableFragment : BaseSessionFragment(), TimetableView, MainView.MainChi
|
|||||||
presenter.onViewReselected()
|
presenter.onViewReselected()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun popView() {
|
||||||
|
(activity as? MainActivity)?.popView()
|
||||||
|
}
|
||||||
|
|
||||||
override fun showEmpty(show: Boolean) {
|
override fun showEmpty(show: Boolean) {
|
||||||
timetableEmpty.visibility = if (show) View.VISIBLE else View.GONE
|
timetableEmpty.visibility = if (show) View.VISIBLE else View.GONE
|
||||||
}
|
}
|
||||||
@ -111,6 +136,10 @@ class TimetableFragment : BaseSessionFragment(), TimetableView, MainView.MainChi
|
|||||||
(activity as? MainActivity)?.showDialogFragment(TimetableDialog.newInstance(lesson))
|
(activity as? MainActivity)?.showDialogFragment(TimetableDialog.newInstance(lesson))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun openCompletedLessonsView() {
|
||||||
|
(activity as? MainActivity)?.pushView(CompletedLessonsFragment.newInstance())
|
||||||
|
}
|
||||||
|
|
||||||
override fun onSaveInstanceState(outState: Bundle) {
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
super.onSaveInstanceState(outState)
|
super.onSaveInstanceState(outState)
|
||||||
outState.putLong(SAVED_DATE_KEY, presenter.currentDate.toEpochDay())
|
outState.putLong(SAVED_DATE_KEY, presenter.currentDate.toEpochDay())
|
||||||
|
@ -57,12 +57,16 @@ class TimetablePresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun onViewReselected() {
|
fun onViewReselected() {
|
||||||
Timber.i("Exam view is reselected")
|
Timber.i("Timetable view is reselected")
|
||||||
now().nextOrSameSchoolDay.also {
|
view?.also { view ->
|
||||||
if (currentDate != it) {
|
if (view.currentStackSize == 1) {
|
||||||
loadData(it)
|
now().nextOrSameSchoolDay.also {
|
||||||
reloadView()
|
if (currentDate != it) {
|
||||||
} else if (view?.isViewEmpty == false) view?.resetView()
|
loadData(it)
|
||||||
|
reloadView()
|
||||||
|
} else if (!view.isViewEmpty) view.resetView()
|
||||||
|
}
|
||||||
|
} else view.popView()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,6 +77,11 @@ class TimetablePresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onCompletedLessonsSwitchSelected(): Boolean {
|
||||||
|
view?.openCompletedLessonsView()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
private fun loadData(date: LocalDate, forceRefresh: Boolean = false) {
|
private fun loadData(date: LocalDate, forceRefresh: Boolean = false) {
|
||||||
Timber.i("Loading timetable data started")
|
Timber.i("Loading timetable data started")
|
||||||
currentDate = date
|
currentDate = date
|
||||||
|
@ -9,6 +9,8 @@ interface TimetableView : BaseSessionView {
|
|||||||
|
|
||||||
val isViewEmpty: Boolean
|
val isViewEmpty: Boolean
|
||||||
|
|
||||||
|
val currentStackSize: Int?
|
||||||
|
|
||||||
fun initView()
|
fun initView()
|
||||||
|
|
||||||
fun updateData(data: List<TimetableItem>)
|
fun updateData(data: List<TimetableItem>)
|
||||||
@ -32,4 +34,8 @@ interface TimetableView : BaseSessionView {
|
|||||||
fun showNextButton(show: Boolean)
|
fun showNextButton(show: Boolean)
|
||||||
|
|
||||||
fun showTimetableDialog(lesson: Timetable)
|
fun showTimetableDialog(lesson: Timetable)
|
||||||
|
|
||||||
|
fun popView()
|
||||||
|
|
||||||
|
fun openCompletedLessonsView()
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,73 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.timetable.completed
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.fragment.app.DialogFragment
|
||||||
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.data.db.entities.CompletedLesson
|
||||||
|
import kotlinx.android.synthetic.main.dialog_lesson_completed.*
|
||||||
|
|
||||||
|
class CompletedLessonDialog : DialogFragment() {
|
||||||
|
|
||||||
|
private lateinit var completedLesson: CompletedLesson
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val ARGUMENT_KEY = "Item"
|
||||||
|
|
||||||
|
fun newInstance(exam: CompletedLesson): CompletedLessonDialog {
|
||||||
|
return CompletedLessonDialog().apply {
|
||||||
|
arguments = Bundle().apply { putSerializable(ARGUMENT_KEY, exam) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setStyle(STYLE_NO_TITLE, 0)
|
||||||
|
arguments?.run {
|
||||||
|
completedLesson = getSerializable(CompletedLessonDialog.ARGUMENT_KEY) as CompletedLesson
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
|
return inflater.inflate(R.layout.dialog_lesson_completed, container, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("SetTextI18n")
|
||||||
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
|
super.onActivityCreated(savedInstanceState)
|
||||||
|
|
||||||
|
completedLessonDialogSubject.text = completedLesson.subject
|
||||||
|
completedLessonDialogTopic.text = completedLesson.topic
|
||||||
|
completedLessonDialogTeacher.text = completedLesson.teacher
|
||||||
|
completedLessonDialogAbsence.text = completedLesson.absence
|
||||||
|
completedLessonDialogChanges.text = completedLesson.substitution
|
||||||
|
completedLessonDialogResources.text = completedLesson.resources
|
||||||
|
|
||||||
|
completedLesson.substitution.let {
|
||||||
|
if (it.isBlank()) {
|
||||||
|
completedLessonDialogChangesTitle.visibility = View.GONE
|
||||||
|
completedLessonDialogChanges.visibility = View.GONE
|
||||||
|
} else completedLessonDialogChanges.text = it
|
||||||
|
}
|
||||||
|
|
||||||
|
completedLesson.absence.let {
|
||||||
|
if (it.isBlank()) {
|
||||||
|
completedLessonDialogAbsenceTitle.visibility = View.GONE
|
||||||
|
completedLessonDialogAbsence.visibility = View.GONE
|
||||||
|
} else completedLessonDialogAbsence.text = it
|
||||||
|
}
|
||||||
|
|
||||||
|
completedLesson.resources.let {
|
||||||
|
if (it.isBlank()) {
|
||||||
|
completedLessonDialogResourcesTitle.visibility = View.GONE
|
||||||
|
completedLessonDialogResources.visibility = View.GONE
|
||||||
|
} else completedLessonDialogResources.text = it
|
||||||
|
}
|
||||||
|
|
||||||
|
completedLessonDialogClose.setOnClickListener { dismiss() }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.timetable.completed
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import android.view.View.GONE
|
||||||
|
import android.view.View.VISIBLE
|
||||||
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||||
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
|
import eu.davidea.viewholders.FlexibleViewHolder
|
||||||
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.data.db.entities.CompletedLesson
|
||||||
|
import kotlinx.android.extensions.LayoutContainer
|
||||||
|
import kotlinx.android.synthetic.main.item_completed_lesson.*
|
||||||
|
|
||||||
|
class CompletedLessonItem(val completedLesson: CompletedLesson) : AbstractFlexibleItem<CompletedLessonItem.ViewHolder>() {
|
||||||
|
|
||||||
|
override fun getLayoutRes() = R.layout.item_completed_lesson
|
||||||
|
|
||||||
|
override fun createViewHolder(view: View?, adapter: FlexibleAdapter<IFlexible<*>>?): CompletedLessonItem.ViewHolder {
|
||||||
|
return CompletedLessonItem.ViewHolder(view, adapter)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>?, holder: CompletedLessonItem.ViewHolder?, position: Int, payloads: MutableList<Any>?) {
|
||||||
|
holder?.apply {
|
||||||
|
completedLessonItemNumber.text = completedLesson.number.toString()
|
||||||
|
completedLessonItemSubject.text = completedLesson.subject
|
||||||
|
completedLessonItemTopic.text = completedLesson.topic
|
||||||
|
completedLessonItemAlert.visibility = if (completedLesson.substitution.isNotEmpty()) VISIBLE else GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
|
||||||
|
other as CompletedLessonItem
|
||||||
|
|
||||||
|
if (completedLesson != other.completedLesson) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return completedLesson.hashCode()
|
||||||
|
}
|
||||||
|
|
||||||
|
class ViewHolder(view: View?, adapter: FlexibleAdapter<IFlexible<*>>?) : FlexibleViewHolder(view, adapter),
|
||||||
|
LayoutContainer {
|
||||||
|
|
||||||
|
override val containerView: View?
|
||||||
|
get() = contentView
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.timetable.completed
|
||||||
|
|
||||||
|
import android.content.res.Resources
|
||||||
|
import com.readystatesoftware.chuck.api.ChuckCollector
|
||||||
|
import io.github.wulkanowy.api.interceptor.FeatureDisabledException
|
||||||
|
import io.github.wulkanowy.ui.base.session.SessionErrorHandler
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class CompletedLessonsErrorHandler @Inject constructor(
|
||||||
|
resources: Resources,
|
||||||
|
chuckCollector: ChuckCollector
|
||||||
|
) : SessionErrorHandler(resources, chuckCollector) {
|
||||||
|
|
||||||
|
var onFeatureDisabled: () -> Unit = {}
|
||||||
|
|
||||||
|
override fun proceed(error: Throwable) {
|
||||||
|
when (error) {
|
||||||
|
is FeatureDisabledException -> onFeatureDisabled()
|
||||||
|
else -> super.proceed(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clear() {
|
||||||
|
super.clear()
|
||||||
|
onFeatureDisabled = {}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,120 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.timetable.completed
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
|
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
|
||||||
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||||
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.data.db.entities.CompletedLesson
|
||||||
|
import io.github.wulkanowy.ui.base.session.BaseSessionFragment
|
||||||
|
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||||
|
import io.github.wulkanowy.ui.modules.main.MainView
|
||||||
|
import io.github.wulkanowy.utils.setOnItemClickListener
|
||||||
|
import kotlinx.android.synthetic.main.fragment_timetable_completed.*
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class CompletedLessonsFragment : BaseSessionFragment(), CompletedLessonsView, MainView.TitledView {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var presenter: CompletedLessonsPresenter
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var completedLessonsAdapter: FlexibleAdapter<AbstractFlexibleItem<*>>
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val SAVED_DATE_KEY = "CURRENT_DATE"
|
||||||
|
|
||||||
|
fun newInstance() = CompletedLessonsFragment()
|
||||||
|
}
|
||||||
|
|
||||||
|
override val titleStringId: Int
|
||||||
|
get() = R.string.completed_lessons_title
|
||||||
|
|
||||||
|
override val isViewEmpty
|
||||||
|
get() = completedLessonsAdapter.isEmpty
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
|
return inflater.inflate(R.layout.fragment_timetable_completed, container, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
|
super.onActivityCreated(savedInstanceState)
|
||||||
|
messageContainer = completedLessonsRecycler
|
||||||
|
presenter.onAttachView(this, savedInstanceState?.getLong(SAVED_DATE_KEY))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun initView() {
|
||||||
|
completedLessonsAdapter.run {
|
||||||
|
setOnItemClickListener { presenter.onCompletedLessonsItemSelected(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
completedLessonsRecycler.run {
|
||||||
|
layoutManager = SmoothScrollLinearLayoutManager(context)
|
||||||
|
adapter = completedLessonsAdapter
|
||||||
|
}
|
||||||
|
completedLessonsSwipe.setOnRefreshListener { presenter.onSwipeRefresh() }
|
||||||
|
completedLessonsPreviousButton.setOnClickListener { presenter.onPreviousDay() }
|
||||||
|
completedLessonsNextButton.setOnClickListener { presenter.onNextDay() }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateData(data: List<CompletedLessonItem>) {
|
||||||
|
completedLessonsAdapter.updateDataSet(data, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clearData() {
|
||||||
|
completedLessonsAdapter.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateNavigationDay(date: String) {
|
||||||
|
completedLessonsNavDate.text = date
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hideRefresh() {
|
||||||
|
completedLessonsSwipe.isRefreshing = false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showEmpty(show: Boolean) {
|
||||||
|
completedLessonsEmpty.visibility = if (show) View.VISIBLE else View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showFeatureDisabled() {
|
||||||
|
context?.let {
|
||||||
|
completedLessonsInfo.text = getString(R.string.error_feature_disabled)
|
||||||
|
completedLessonsInfoImage.setImageDrawable(ContextCompat.getDrawable(it, R.drawable.ic_all_close_circle_24dp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showProgress(show: Boolean) {
|
||||||
|
completedLessonsProgress.visibility = if (show) View.VISIBLE else View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showContent(show: Boolean) {
|
||||||
|
completedLessonsRecycler.visibility = if (show) View.VISIBLE else View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showPreButton(show: Boolean) {
|
||||||
|
completedLessonsPreviousButton.visibility = if (show) View.VISIBLE else View.INVISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showNextButton(show: Boolean) {
|
||||||
|
completedLessonsNextButton.visibility = if (show) View.VISIBLE else View.INVISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showCompletedLessonDialog(completedLesson: CompletedLesson) {
|
||||||
|
(activity as? MainActivity)?.showDialogFragment(CompletedLessonDialog.newInstance(completedLesson))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
|
super.onSaveInstanceState(outState)
|
||||||
|
outState.putLong(CompletedLessonsFragment.SAVED_DATE_KEY, presenter.currentDate.toEpochDay())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
presenter.onDetachView()
|
||||||
|
super.onDestroyView()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,116 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.timetable.completed
|
||||||
|
|
||||||
|
import com.google.firebase.analytics.FirebaseAnalytics.Param.START_DATE
|
||||||
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||||
|
import io.github.wulkanowy.data.repositories.CompletedLessonsRepository
|
||||||
|
import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||||
|
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||||
|
import io.github.wulkanowy.ui.base.session.BaseSessionPresenter
|
||||||
|
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||||
|
import io.github.wulkanowy.utils.SchedulersProvider
|
||||||
|
import io.github.wulkanowy.utils.isHolidays
|
||||||
|
import io.github.wulkanowy.utils.nextOrSameSchoolDay
|
||||||
|
import io.github.wulkanowy.utils.nextSchoolDay
|
||||||
|
import io.github.wulkanowy.utils.previousSchoolDay
|
||||||
|
import io.github.wulkanowy.utils.toFormattedString
|
||||||
|
import org.threeten.bp.LocalDate
|
||||||
|
import org.threeten.bp.LocalDate.now
|
||||||
|
import org.threeten.bp.LocalDate.ofEpochDay
|
||||||
|
import timber.log.Timber
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class CompletedLessonsPresenter @Inject constructor(
|
||||||
|
private val schedulers: SchedulersProvider,
|
||||||
|
private val errorHandler: CompletedLessonsErrorHandler,
|
||||||
|
private val studentRepository: StudentRepository,
|
||||||
|
private val semesterRepository: SemesterRepository,
|
||||||
|
private val completedLessonsRepository: CompletedLessonsRepository,
|
||||||
|
private val analytics: FirebaseAnalyticsHelper
|
||||||
|
) : BaseSessionPresenter<CompletedLessonsView>(errorHandler) {
|
||||||
|
|
||||||
|
lateinit var currentDate: LocalDate
|
||||||
|
private set
|
||||||
|
|
||||||
|
fun onAttachView(view: CompletedLessonsView, date: Long?) {
|
||||||
|
super.onAttachView(view)
|
||||||
|
Timber.i("Completed lessons is attached")
|
||||||
|
view.initView()
|
||||||
|
loadData(ofEpochDay(date ?: now().nextOrSameSchoolDay.toEpochDay()))
|
||||||
|
reloadView()
|
||||||
|
errorHandler.onFeatureDisabled = {
|
||||||
|
this.view?.showFeatureDisabled()
|
||||||
|
Timber.i("Completed lessons feature disabled by school")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onPreviousDay() {
|
||||||
|
loadData(currentDate.previousSchoolDay)
|
||||||
|
reloadView()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onNextDay() {
|
||||||
|
loadData(currentDate.nextSchoolDay)
|
||||||
|
reloadView()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onSwipeRefresh() {
|
||||||
|
Timber.i("Force refreshing the completed lessons")
|
||||||
|
loadData(currentDate, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onCompletedLessonsItemSelected(item: AbstractFlexibleItem<*>?) {
|
||||||
|
if (item is CompletedLessonItem) {
|
||||||
|
Timber.i("Select completed lessons item ${item.completedLesson.id}")
|
||||||
|
view?.showCompletedLessonDialog(item.completedLesson)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadData(date: LocalDate, forceRefresh: Boolean = false) {
|
||||||
|
Timber.i("Loading completed lessons data started")
|
||||||
|
currentDate = date
|
||||||
|
disposable.apply {
|
||||||
|
clear()
|
||||||
|
add(studentRepository.getCurrentStudent()
|
||||||
|
.flatMap { semesterRepository.getCurrentSemester(it) }
|
||||||
|
.delay(200, TimeUnit.MILLISECONDS)
|
||||||
|
.flatMap { completedLessonsRepository.getCompletedLessons(it, currentDate, currentDate, forceRefresh) }
|
||||||
|
.map { items -> items.map { CompletedLessonItem(it) } }
|
||||||
|
.map { items -> items.sortedBy { it.completedLesson.number } }
|
||||||
|
.subscribeOn(schedulers.backgroundThread)
|
||||||
|
.observeOn(schedulers.mainThread)
|
||||||
|
.doFinally {
|
||||||
|
view?.run {
|
||||||
|
hideRefresh()
|
||||||
|
showProgress(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.subscribe({
|
||||||
|
Timber.i("Loading completed lessons lessons result: Success")
|
||||||
|
view?.apply {
|
||||||
|
updateData(it)
|
||||||
|
showEmpty(it.isEmpty())
|
||||||
|
showContent(it.isNotEmpty())
|
||||||
|
}
|
||||||
|
analytics.logEvent("load_completed_lessons", "items" to it.size, "force_refresh" to forceRefresh, START_DATE to currentDate.toFormattedString("yyyy-MM-dd"))
|
||||||
|
}) {
|
||||||
|
Timber.i("Loading completed lessons result: An exception occurred")
|
||||||
|
view?.run { showEmpty(isViewEmpty) }
|
||||||
|
errorHandler.dispatch(it)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun reloadView() {
|
||||||
|
Timber.i("Reload completed lessons view with the date ${currentDate.toFormattedString()}")
|
||||||
|
view?.apply {
|
||||||
|
showProgress(true)
|
||||||
|
showContent(false)
|
||||||
|
showEmpty(false)
|
||||||
|
clearData()
|
||||||
|
showNextButton(!currentDate.plusDays(1).isHolidays)
|
||||||
|
showPreButton(!currentDate.minusDays(1).isHolidays)
|
||||||
|
updateNavigationDay(currentDate.toFormattedString("EEEE \n dd.MM.YYYY").capitalize())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.timetable.completed
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.db.entities.CompletedLesson
|
||||||
|
import io.github.wulkanowy.ui.base.session.BaseSessionView
|
||||||
|
|
||||||
|
interface CompletedLessonsView : BaseSessionView {
|
||||||
|
|
||||||
|
val isViewEmpty: Boolean
|
||||||
|
|
||||||
|
fun initView()
|
||||||
|
|
||||||
|
fun updateData(data: List<CompletedLessonItem>)
|
||||||
|
|
||||||
|
fun clearData()
|
||||||
|
|
||||||
|
fun updateNavigationDay(date: String)
|
||||||
|
|
||||||
|
fun hideRefresh()
|
||||||
|
|
||||||
|
fun showEmpty(show: Boolean)
|
||||||
|
|
||||||
|
fun showFeatureDisabled()
|
||||||
|
|
||||||
|
fun showProgress(show: Boolean)
|
||||||
|
|
||||||
|
fun showContent(show: Boolean)
|
||||||
|
|
||||||
|
fun showPreButton(show: Boolean)
|
||||||
|
|
||||||
|
fun showNextButton(show: Boolean)
|
||||||
|
|
||||||
|
fun showCompletedLessonDialog(completedLesson: CompletedLesson)
|
||||||
|
}
|
9
app/src/main/res/drawable/ic_all_close_circle_24dp.xml
Normal file
9
app/src/main/res/drawable/ic_all_close_circle_24dp.xml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFFFF"
|
||||||
|
android:pathData="M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2C6.47,2 2,6.47 2,12C2,17.53 6.47,22 12,22C17.53,22 22,17.53 22,12C22,6.47 17.53,2 12,2M14.59,8L12,10.59L9.41,8L8,9.41L10.59,12L8,14.59L9.41,16L12,13.41L14.59,16L16,14.59L13.41,12L16,9.41L14.59,8Z" />
|
||||||
|
</vector>
|
@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFFFF"
|
||||||
|
android:pathData="M19,19H5V8H19M19,3H18V1H16V3H8V1H6V3H5C3.89,3 3,3.9 3,5V19A2,2 0,0 0,5 21H19A2,2 0,0 0,21 19V5A2,2 0,0 0,19 3M16.53,11.06L15.47,10L10.59,14.88L8.47,12.76L7.41,13.82L10.59,17L16.53,11.06Z" />
|
||||||
|
</vector>
|
138
app/src/main/res/layout/dialog_lesson_completed.xml
Normal file
138
app/src/main/res/layout/dialog_lesson_completed.xml
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:context=".ui.modules.timetable.completed.CompletedLessonDialog">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="300dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="20dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:layout_marginBottom="20dp"
|
||||||
|
android:text="@string/all_details"
|
||||||
|
android:textSize="20sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/timetable_lesson"
|
||||||
|
android:textSize="17sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/completedLessonDialogSubject"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="3dp"
|
||||||
|
android:text="@string/all_no_data"
|
||||||
|
android:textIsSelectable="true"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:text="@string/completed_lessons_topic"
|
||||||
|
android:textSize="17sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/completedLessonDialogTopic"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="3dp"
|
||||||
|
android:text="@string/all_no_data"
|
||||||
|
android:textIsSelectable="true"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/completedLessonDialogTeacherTitle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:text="@string/all_teacher"
|
||||||
|
android:textSize="17sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/completedLessonDialogTeacher"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="3dp"
|
||||||
|
android:text="@string/all_no_data"
|
||||||
|
android:textIsSelectable="true"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/completedLessonDialogChangesTitle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:text="@string/timetable_changes"
|
||||||
|
android:textColor="@color/colorPrimary"
|
||||||
|
android:textSize="17sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/completedLessonDialogChanges"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="3dp"
|
||||||
|
android:text="@string/all_no_data"
|
||||||
|
android:textColor="@color/colorPrimary"
|
||||||
|
android:textIsSelectable="true"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/completedLessonDialogAbsenceTitle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:text="@string/completed_lessons_absence"
|
||||||
|
android:textColor="@color/colorPrimary"
|
||||||
|
android:textSize="17sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/completedLessonDialogAbsence"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="3dp"
|
||||||
|
android:text="@string/all_no_data"
|
||||||
|
android:textColor="@color/colorPrimary"
|
||||||
|
android:textIsSelectable="true"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/completedLessonDialogResourcesTitle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:text="@string/completed_lessons_resources"
|
||||||
|
android:textSize="17sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/completedLessonDialogResources"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="3dp"
|
||||||
|
android:autoLink="web"
|
||||||
|
android:text="@string/all_no_data"
|
||||||
|
android:textIsSelectable="true"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/completedLessonDialogClose"
|
||||||
|
style="@style/Widget.AppCompat.Button.Borderless"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:layout_marginTop="15dp"
|
||||||
|
android:text="@string/all_close"
|
||||||
|
android:textAllCaps="true"
|
||||||
|
android:textSize="15sp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
99
app/src/main/res/layout/fragment_timetable_completed.xml
Normal file
99
app/src/main/res/layout/fragment_timetable_completed.xml
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:context=".ui.modules.timetable.completed.CompletedLessonsFragment">
|
||||||
|
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginBottom="50dp">
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/completedLessonsProgress"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:indeterminate="true" />
|
||||||
|
|
||||||
|
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||||
|
android:id="@+id/completedLessonsSwipe"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/completedLessonsRecycler"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/completedLessonsEmpty"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="10dp"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minWidth="100dp"
|
||||||
|
android:minHeight="100dp"
|
||||||
|
android:id="@+id/completedLessonsInfoImage"
|
||||||
|
app:srcCompat="@drawable/ic_menu_main_lessons_completed_24dp"
|
||||||
|
app:tint="?android:attr/textColorPrimary"
|
||||||
|
tools:ignore="contentDescription" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/completedLessonsInfo"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/completed_lessons_no_items"
|
||||||
|
android:textSize="20sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
android:background="?android:attr/windowBackground"
|
||||||
|
android:elevation="10dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/completedLessonsPreviousButton"
|
||||||
|
style="@style/Widget.AppCompat.Button.Borderless"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:drawablePadding="4dp"
|
||||||
|
android:gravity="start|center"
|
||||||
|
android:text="@string/all_prev"
|
||||||
|
android:textAlignment="gravity" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/completedLessonsNavDate"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/app_name" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/completedLessonsNextButton"
|
||||||
|
style="@style/Widget.AppCompat.Button.Borderless"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:drawablePadding="4dp"
|
||||||
|
android:gravity="end|center"
|
||||||
|
android:text="@string/all_next"
|
||||||
|
android:textAlignment="gravity" />
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
72
app/src/main/res/layout/item_completed_lesson.xml
Normal file
72
app/src/main/res/layout/item_completed_lesson.xml
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/completedLesson_subitem_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/ic_all_divider"
|
||||||
|
android:foreground="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:paddingStart="12dp"
|
||||||
|
android:paddingLeft="12dp"
|
||||||
|
android:paddingTop="7dp"
|
||||||
|
android:paddingEnd="12dp"
|
||||||
|
android:paddingRight="12dp"
|
||||||
|
android:paddingBottom="7dp"
|
||||||
|
tools:context=".ui.modules.timetable.completed.CompletedLessonItem">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/completedLessonItemNumber"
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:gravity="center"
|
||||||
|
android:maxLength="2"
|
||||||
|
android:textSize="32sp"
|
||||||
|
tools:ignore="all"
|
||||||
|
tools:text="1" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/completedLessonItemSubject"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
android:layout_marginLeft="10dp"
|
||||||
|
android:layout_marginEnd="40dp"
|
||||||
|
android:layout_marginRight="40dp"
|
||||||
|
android:layout_toEndOf="@+id/completedLessonItemNumber"
|
||||||
|
android:layout_toRightOf="@+id/completedLessonItemNumber"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textSize="17sp"
|
||||||
|
tools:ignore="RelativeOverlap"
|
||||||
|
tools:text="@tools:sample/lorem" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/completedLessonItemTopic"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignStart="@id/completedLessonItemSubject"
|
||||||
|
android:layout_alignLeft="@id/completedLessonItemSubject"
|
||||||
|
android:layout_alignEnd="@+id/completedLessonItemAlert"
|
||||||
|
android:layout_alignRight="@+id/completedLessonItemAlert"
|
||||||
|
android:layout_alignBottom="@+id/completedLessonItemNumber"
|
||||||
|
android:layout_marginEnd="40dp"
|
||||||
|
android:layout_marginRight="40dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColor="?android:attr/android:textColorSecondary"
|
||||||
|
android:textSize="12sp"
|
||||||
|
tools:text="@tools:sample/lorem" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/completedLessonItemAlert"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
app:srcCompat="@drawable/ic_timetable_swap_30dp"
|
||||||
|
tools:ignore="contentDescription" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
10
app/src/main/res/menu/action_menu_timetable.xml
Normal file
10
app/src/main/res/menu/action_menu_timetable.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
<item
|
||||||
|
android:id="@+id/timetableMenuCompletedLessons"
|
||||||
|
android:icon="@drawable/ic_menu_main_lessons_completed_24dp"
|
||||||
|
android:orderInCategory="1"
|
||||||
|
android:title="@string/completed_lessons_button"
|
||||||
|
app:showAsAction="ifRoom" />
|
||||||
|
</menu>
|
@ -102,6 +102,13 @@
|
|||||||
<string name="timetable_changes">Zmiany</string>
|
<string name="timetable_changes">Zmiany</string>
|
||||||
<string name="timetable_no_items">Brak lekcji w tym dniu</string>
|
<string name="timetable_no_items">Brak lekcji w tym dniu</string>
|
||||||
|
|
||||||
|
<!--CompletedLesson-->
|
||||||
|
<string name="completed_lessons_title">Lekcje zrealizowane</string>
|
||||||
|
<string name="completed_lessons_button">Zobacz lekcje zrealizowane</string>
|
||||||
|
<string name="completed_lessons_no_items">Brak informacji o lekcjach zrealizowanych</string>
|
||||||
|
<string name="completed_lessons_topic">Temat</string>
|
||||||
|
<string name="completed_lessons_absence">Nieobecność</string>
|
||||||
|
<string name="completed_lessons_resources">Zasoby</string>
|
||||||
|
|
||||||
<!--Attendance-->
|
<!--Attendance-->
|
||||||
<string name="attendance_summary_button">Podsumowanie frekwencji</string>
|
<string name="attendance_summary_button">Podsumowanie frekwencji</string>
|
||||||
@ -263,4 +270,5 @@
|
|||||||
<string name="error_login_failed">Logowanie nie powiodło się. Spróbuj ponownie lub zrestartuj aplikację</string>
|
<string name="error_login_failed">Logowanie nie powiodło się. Spróbuj ponownie lub zrestartuj aplikację</string>
|
||||||
<string name="error_service_unavailable">Dziennik jest niedostępny. Spróbuj ponownie później</string>
|
<string name="error_service_unavailable">Dziennik jest niedostępny. Spróbuj ponownie później</string>
|
||||||
<string name="error_unknown">Wystąpił nieoczekiwany błąd</string>
|
<string name="error_unknown">Wystąpił nieoczekiwany błąd</string>
|
||||||
|
<string name="error_feature_disabled">Funkcja wyłączona przez szkołę</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -93,6 +93,13 @@
|
|||||||
<string name="timetable_changes">Changes</string>
|
<string name="timetable_changes">Changes</string>
|
||||||
<string name="timetable_no_items">No lessons this day</string>
|
<string name="timetable_no_items">No lessons this day</string>
|
||||||
|
|
||||||
|
<!--Completed lessons-->
|
||||||
|
<string name="completed_lessons_title">Completed lessons</string>
|
||||||
|
<string name="completed_lessons_button">Show completed lessons</string>
|
||||||
|
<string name="completed_lessons_no_items">No info about completed lessons</string>
|
||||||
|
<string name="completed_lessons_topic">Topic</string>
|
||||||
|
<string name="completed_lessons_absence">Absence</string>
|
||||||
|
<string name="completed_lessons_resources">Resources</string>
|
||||||
|
|
||||||
<!--Attendance-->
|
<!--Attendance-->
|
||||||
<string name="attendance_summary_button">Attendance summary</string>
|
<string name="attendance_summary_button">Attendance summary</string>
|
||||||
@ -246,4 +253,5 @@
|
|||||||
<string name="error_login_failed">Login is failed. Try again or restart the app</string>
|
<string name="error_login_failed">Login is failed. Try again or restart the app</string>
|
||||||
<string name="error_service_unavailable">The log is not available. Try again later</string>
|
<string name="error_service_unavailable">The log is not available. Try again later</string>
|
||||||
<string name="error_unknown">An unexpected error occurred</string>
|
<string name="error_unknown">An unexpected error occurred</string>
|
||||||
|
<string name="error_feature_disabled">Feature disabled by your school</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -0,0 +1,56 @@
|
|||||||
|
package io.github.wulkanowy.data.repositories.remote
|
||||||
|
|
||||||
|
import io.github.wulkanowy.api.Api
|
||||||
|
import io.github.wulkanowy.api.timetable.CompletedLesson
|
||||||
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
|
import io.mockk.MockKAnnotations
|
||||||
|
import io.mockk.every
|
||||||
|
import io.mockk.impl.annotations.MockK
|
||||||
|
import io.mockk.impl.annotations.SpyK
|
||||||
|
import io.reactivex.Single
|
||||||
|
import org.junit.Assert
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.threeten.bp.LocalDate
|
||||||
|
import java.sql.Date
|
||||||
|
|
||||||
|
class CompletedLessonsRemoteTest {
|
||||||
|
|
||||||
|
@SpyK
|
||||||
|
private var mockApi = Api()
|
||||||
|
|
||||||
|
@MockK
|
||||||
|
private lateinit var semesterMock: Semester
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun initApi() {
|
||||||
|
MockKAnnotations.init(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun getCompletedLessonsTest() {
|
||||||
|
every {
|
||||||
|
mockApi.getCompletedLessons(
|
||||||
|
LocalDate.of(2018, 9, 10),
|
||||||
|
LocalDate.of(2018, 9, 15)
|
||||||
|
)
|
||||||
|
} returns Single.just(listOf(
|
||||||
|
getCompletedLesson("2018-09-10"),
|
||||||
|
getCompletedLesson("2018-09-17")
|
||||||
|
))
|
||||||
|
|
||||||
|
every { mockApi.diaryId } returns 1
|
||||||
|
every { semesterMock.studentId } returns 1
|
||||||
|
every { semesterMock.diaryId } returns 1
|
||||||
|
|
||||||
|
val completed = CompletedLessonsRemote(mockApi).getCompletedLessons(semesterMock,
|
||||||
|
LocalDate.of(2018, 9, 10),
|
||||||
|
LocalDate.of(2018, 9, 15)
|
||||||
|
).blockingGet()
|
||||||
|
Assert.assertEquals(2, completed.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getCompletedLesson(dateString: String): CompletedLesson {
|
||||||
|
return CompletedLesson().apply { date = Date.valueOf(dateString) }
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user