Block app timezone to polish timezone (#1598)

This commit is contained in:
Michael 2021-12-31 11:53:09 +01:00 committed by GitHub
parent bfd7f688ab
commit e6b2acabd5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
61 changed files with 2870 additions and 400 deletions

View File

@ -174,7 +174,7 @@ ext {
} }
dependencies { dependencies {
implementation "io.github.wulkanowy:sdk:1.4.4" implementation "io.github.wulkanowy:sdk:42bce37748"
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5' coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'

File diff suppressed because it is too large Load Diff

View File

@ -67,49 +67,7 @@ import io.github.wulkanowy.data.db.entities.Teacher
import io.github.wulkanowy.data.db.entities.Timetable import io.github.wulkanowy.data.db.entities.Timetable
import io.github.wulkanowy.data.db.entities.TimetableAdditional import io.github.wulkanowy.data.db.entities.TimetableAdditional
import io.github.wulkanowy.data.db.entities.TimetableHeader import io.github.wulkanowy.data.db.entities.TimetableHeader
import io.github.wulkanowy.data.db.migrations.Migration10 import io.github.wulkanowy.data.db.migrations.*
import io.github.wulkanowy.data.db.migrations.Migration11
import io.github.wulkanowy.data.db.migrations.Migration12
import io.github.wulkanowy.data.db.migrations.Migration13
import io.github.wulkanowy.data.db.migrations.Migration14
import io.github.wulkanowy.data.db.migrations.Migration15
import io.github.wulkanowy.data.db.migrations.Migration16
import io.github.wulkanowy.data.db.migrations.Migration17
import io.github.wulkanowy.data.db.migrations.Migration18
import io.github.wulkanowy.data.db.migrations.Migration19
import io.github.wulkanowy.data.db.migrations.Migration2
import io.github.wulkanowy.data.db.migrations.Migration20
import io.github.wulkanowy.data.db.migrations.Migration21
import io.github.wulkanowy.data.db.migrations.Migration22
import io.github.wulkanowy.data.db.migrations.Migration23
import io.github.wulkanowy.data.db.migrations.Migration24
import io.github.wulkanowy.data.db.migrations.Migration25
import io.github.wulkanowy.data.db.migrations.Migration26
import io.github.wulkanowy.data.db.migrations.Migration27
import io.github.wulkanowy.data.db.migrations.Migration28
import io.github.wulkanowy.data.db.migrations.Migration29
import io.github.wulkanowy.data.db.migrations.Migration3
import io.github.wulkanowy.data.db.migrations.Migration30
import io.github.wulkanowy.data.db.migrations.Migration31
import io.github.wulkanowy.data.db.migrations.Migration32
import io.github.wulkanowy.data.db.migrations.Migration33
import io.github.wulkanowy.data.db.migrations.Migration34
import io.github.wulkanowy.data.db.migrations.Migration35
import io.github.wulkanowy.data.db.migrations.Migration36
import io.github.wulkanowy.data.db.migrations.Migration37
import io.github.wulkanowy.data.db.migrations.Migration38
import io.github.wulkanowy.data.db.migrations.Migration39
import io.github.wulkanowy.data.db.migrations.Migration4
import io.github.wulkanowy.data.db.migrations.Migration40
import io.github.wulkanowy.data.db.migrations.Migration41
import io.github.wulkanowy.data.db.migrations.Migration42
import io.github.wulkanowy.data.db.migrations.Migration43
import io.github.wulkanowy.data.db.migrations.Migration44
import io.github.wulkanowy.data.db.migrations.Migration5
import io.github.wulkanowy.data.db.migrations.Migration6
import io.github.wulkanowy.data.db.migrations.Migration7
import io.github.wulkanowy.data.db.migrations.Migration8
import io.github.wulkanowy.data.db.migrations.Migration9
import io.github.wulkanowy.utils.AppInfo import io.github.wulkanowy.utils.AppInfo
import javax.inject.Singleton import javax.inject.Singleton
@ -157,7 +115,7 @@ import javax.inject.Singleton
abstract class AppDatabase : RoomDatabase() { abstract class AppDatabase : RoomDatabase() {
companion object { companion object {
const val VERSION_SCHEMA = 45 const val VERSION_SCHEMA = 46
fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf( fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf(
Migration2(), Migration2(),
@ -203,6 +161,7 @@ abstract class AppDatabase : RoomDatabase() {
Migration42(), Migration42(),
Migration43(), Migration43(),
Migration44(), Migration44(),
Migration46(),
) )
fun newInstance( fun newInstance(

View File

@ -1,40 +1,33 @@
package io.github.wulkanowy.data.db package io.github.wulkanowy.data.db
import androidx.room.TypeConverter import androidx.room.TypeConverter
import io.github.wulkanowy.utils.toTimestamp
import kotlinx.serialization.SerializationException import kotlinx.serialization.SerializationException
import kotlinx.serialization.decodeFromString import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import java.time.Instant import java.time.Instant
import java.time.LocalDate import java.time.LocalDate
import java.time.LocalDateTime
import java.time.Month import java.time.Month
import java.time.ZoneOffset import java.time.ZoneOffset
import java.util.Date import java.util.*
class Converters { class Converters {
private val json = Json private val json = Json
@TypeConverter @TypeConverter
fun timestampToDate(value: Long?): LocalDate? = value?.run { fun timestampToLocalDate(value: Long?): LocalDate? =
Date(value).toInstant().atZone(ZoneOffset.UTC).toLocalDate() value?.let(::Date)?.toInstant()?.atZone(ZoneOffset.UTC)?.toLocalDate()
}
@TypeConverter @TypeConverter
fun dateToTimestamp(date: LocalDate?): Long? { fun dateToTimestamp(date: LocalDate?): Long? = date?.toTimestamp()
return date?.atStartOfDay()?.toInstant(ZoneOffset.UTC)?.toEpochMilli()
}
@TypeConverter @TypeConverter
fun timestampToTime(value: Long?): LocalDateTime? = value?.let { fun instantToTimestamp(instant: Instant?): Long? = instant?.toEpochMilli()
LocalDateTime.ofInstant(Instant.ofEpochMilli(value), ZoneOffset.UTC)
}
@TypeConverter @TypeConverter
fun timeToTimestamp(date: LocalDateTime?): Long? { fun timestampToInstant(timestamp: Long?): Instant? = timestamp?.let(Instant::ofEpochMilli)
return date?.atZone(ZoneOffset.UTC)?.toInstant()?.toEpochMilli()
}
@TypeConverter @TypeConverter
fun monthToInt(month: Month?) = month?.value fun monthToInt(month: Month?) = month?.value

View File

@ -4,7 +4,7 @@ import androidx.room.Dao
import androidx.room.Query import androidx.room.Query
import io.github.wulkanowy.data.db.entities.Conference import io.github.wulkanowy.data.db.entities.Conference
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import java.time.LocalDateTime import java.time.Instant
import javax.inject.Singleton import javax.inject.Singleton
@Dao @Dao
@ -12,5 +12,5 @@ import javax.inject.Singleton
interface ConferenceDao : BaseDao<Conference> { interface ConferenceDao : BaseDao<Conference> {
@Query("SELECT * FROM Conferences WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :startDate") @Query("SELECT * FROM Conferences WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :startDate")
fun loadAll(diaryId: Int, studentId: Int, startDate: LocalDateTime): Flow<List<Conference>> fun loadAll(diaryId: Int, studentId: Int, startDate: Instant): Flow<List<Conference>>
} }

View File

@ -4,7 +4,7 @@ import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import java.io.Serializable import java.io.Serializable
import java.time.LocalDateTime import java.time.Instant
@Entity(tableName = "Conferences") @Entity(tableName = "Conferences")
data class Conference( data class Conference(
@ -27,7 +27,7 @@ data class Conference(
@ColumnInfo(name = "conference_id") @ColumnInfo(name = "conference_id")
val conferenceId: Int, val conferenceId: Int,
val date: LocalDateTime val date: Instant,
) : Serializable { ) : Serializable {
@PrimaryKey(autoGenerate = true) @PrimaryKey(autoGenerate = true)

View File

@ -3,7 +3,7 @@ package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import java.time.LocalDateTime import java.time.Instant
@Entity(tableName = "GradesSummary") @Entity(tableName = "GradesSummary")
data class GradeSummary( data class GradeSummary(
@ -45,8 +45,8 @@ data class GradeSummary(
var isFinalGradeNotified: Boolean = true var isFinalGradeNotified: Boolean = true
@ColumnInfo(name = "predicted_grade_last_change") @ColumnInfo(name = "predicted_grade_last_change")
var predictedGradeLastChange: LocalDateTime = LocalDateTime.now() var predictedGradeLastChange: Instant = Instant.now()
@ColumnInfo(name = "final_grade_last_change") @ColumnInfo(name = "final_grade_last_change")
var finalGradeLastChange: LocalDateTime = LocalDateTime.now() var finalGradeLastChange: Instant = Instant.now()
} }

View File

@ -4,7 +4,7 @@ import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import java.io.Serializable import java.io.Serializable
import java.time.LocalDateTime import java.time.Instant
@Entity(tableName = "Messages") @Entity(tableName = "Messages")
data class Message( data class Message(
@ -29,7 +29,7 @@ data class Message(
val subject: String, val subject: String,
val date: LocalDateTime, val date: Instant,
@ColumnInfo(name = "folder_id") @ColumnInfo(name = "folder_id")
val folderId: Int, val folderId: Int,

View File

@ -4,7 +4,7 @@ import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import java.io.Serializable import java.io.Serializable
import java.time.LocalDateTime import java.time.Instant
@Entity(tableName = "MobileDevices") @Entity(tableName = "MobileDevices")
data class MobileDevice( data class MobileDevice(
@ -17,7 +17,7 @@ data class MobileDevice(
val name: String, val name: String,
val date: LocalDateTime val date: Instant,
) : Serializable { ) : Serializable {
@PrimaryKey(autoGenerate = true) @PrimaryKey(autoGenerate = true)

View File

@ -4,7 +4,7 @@ import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import io.github.wulkanowy.services.sync.notifications.NotificationType import io.github.wulkanowy.services.sync.notifications.NotificationType
import java.time.LocalDateTime import java.time.Instant
@Entity(tableName = "Notifications") @Entity(tableName = "Notifications")
data class Notification( data class Notification(
@ -18,7 +18,7 @@ data class Notification(
val type: NotificationType, val type: NotificationType,
val date: LocalDateTime, val date: Instant,
val data: String? = null val data: String? = null
) { ) {

View File

@ -5,7 +5,7 @@ import androidx.room.Entity
import androidx.room.Index import androidx.room.Index
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import java.io.Serializable import java.io.Serializable
import java.time.LocalDateTime import java.time.Instant
@Entity( @Entity(
tableName = "Students", tableName = "Students",
@ -74,7 +74,7 @@ data class Student(
val isCurrent: Boolean, val isCurrent: Boolean,
@ColumnInfo(name = "registration_date") @ColumnInfo(name = "registration_date")
val registrationDate: LocalDateTime val registrationDate: Instant,
) : Serializable { ) : Serializable {
@PrimaryKey(autoGenerate = true) @PrimaryKey(autoGenerate = true)

View File

@ -4,8 +4,8 @@ import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import java.io.Serializable import java.io.Serializable
import java.time.Instant
import java.time.LocalDate import java.time.LocalDate
import java.time.LocalDateTime
@Entity(tableName = "Timetable") @Entity(tableName = "Timetable")
data class Timetable( data class Timetable(
@ -18,9 +18,9 @@ data class Timetable(
val number: Int, val number: Int,
val start: LocalDateTime, val start: Instant,
val end: LocalDateTime, val end: Instant,
val date: LocalDate, val date: LocalDate,

View File

@ -4,9 +4,9 @@ import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import java.io.Serializable import java.io.Serializable
import java.time.Instant
import java.time.LocalDate import java.time.LocalDate
import java.time.LocalDateTime import java.util.*
import java.util.UUID
@Entity(tableName = "TimetableAdditional") @Entity(tableName = "TimetableAdditional")
data class TimetableAdditional( data class TimetableAdditional(
@ -17,9 +17,9 @@ data class TimetableAdditional(
@ColumnInfo(name = "diary_id") @ColumnInfo(name = "diary_id")
val diaryId: Int, val diaryId: Int,
val start: LocalDateTime, val start: Instant,
val end: LocalDateTime, val end: Instant,
val date: LocalDate, val date: LocalDate,

View File

@ -43,12 +43,14 @@ class Migration12 : Migration(11, 12) {
private fun getStudentsIds(database: SupportSQLiteDatabase): List<Int> { private fun getStudentsIds(database: SupportSQLiteDatabase): List<Int> {
val students = mutableListOf<Int>() val students = mutableListOf<Int>()
val studentsCursor = database.query("SELECT student_id FROM Students") database.query("SELECT student_id FROM Students").use {
if (studentsCursor.moveToFirst()) { if (it.moveToFirst()) {
do { do {
students.add(studentsCursor.getInt(0)) students.add(it.getInt(0))
} while (studentsCursor.moveToNext()) } while (it.moveToNext())
}
} }
return students return students
} }

View File

@ -25,12 +25,14 @@ class Migration13 : Migration(12, 13) {
private fun getStudentsIds(database: SupportSQLiteDatabase): MutableList<Pair<Int, String>> { private fun getStudentsIds(database: SupportSQLiteDatabase): MutableList<Pair<Int, String>> {
val students = mutableListOf<Pair<Int, String>>() val students = mutableListOf<Pair<Int, String>>()
val studentsCursor = database.query("SELECT id, school_name FROM Students") database.query("SELECT id, school_name FROM Students").use {
if (studentsCursor.moveToFirst()) { if (it.moveToFirst()) {
do { do {
students.add(studentsCursor.getInt(0) to studentsCursor.getString(1)) students.add(it.getInt(0) to it.getString(1))
} while (studentsCursor.moveToNext()) } while (it.moveToNext())
}
} }
return students return students
} }
@ -42,12 +44,14 @@ class Migration13 : Migration(12, 13) {
private fun getStudentsAndClassIds(database: SupportSQLiteDatabase): List<Pair<Int, Int>> { private fun getStudentsAndClassIds(database: SupportSQLiteDatabase): List<Pair<Int, Int>> {
val students = mutableListOf<Pair<Int, Int>>() val students = mutableListOf<Pair<Int, Int>>()
val studentsCursor = database.query("SELECT student_id, class_id FROM Students") database.query("SELECT student_id, class_id FROM Students").use {
if (studentsCursor.moveToFirst()) { if (it.moveToFirst()) {
do { do {
students.add(studentsCursor.getInt(0) to studentsCursor.getInt(1)) students.add(it.getInt(0) to it.getInt(1))
} while (studentsCursor.moveToNext()) } while (it.moveToNext())
}
} }
return students return students
} }

View File

@ -22,24 +22,28 @@ class Migration27 : Migration(26, 27) {
private fun getStudentsIdsAndNames(database: SupportSQLiteDatabase): MutableList<Triple<Long, Int, String>> { private fun getStudentsIdsAndNames(database: SupportSQLiteDatabase): MutableList<Triple<Long, Int, String>> {
val students = mutableListOf<Triple<Long, Int, String>>() val students = mutableListOf<Triple<Long, Int, String>>()
val studentsCursor = database.query("SELECT id, user_login_id, student_name FROM Students") database.query("SELECT id, user_login_id, student_name FROM Students").use {
if (studentsCursor.moveToFirst()) { if (it.moveToFirst()) {
do { do {
students.add(Triple(studentsCursor.getLong(0), studentsCursor.getInt(1), studentsCursor.getString(2))) students.add(Triple(it.getLong(0), it.getInt(1), it.getString(2)))
} while (studentsCursor.moveToNext()) } while (it.moveToNext())
}
} }
return students return students
} }
private fun getReportingUnits(database: SupportSQLiteDatabase): MutableList<Pair<Int, String>> { private fun getReportingUnits(database: SupportSQLiteDatabase): MutableList<Pair<Int, String>> {
val units = mutableListOf<Pair<Int, String>>() val units = mutableListOf<Pair<Int, String>>()
val unitsCursor = database.query("SELECT sender_id, sender_name FROM ReportingUnits") database.query("SELECT sender_id, sender_name FROM ReportingUnits").use {
if (unitsCursor.moveToFirst()) { if (it.moveToFirst()) {
do { do {
units.add(unitsCursor.getInt(0) to unitsCursor.getString(1)) units.add(it.getInt(0) to it.getString(1))
} while (unitsCursor.moveToNext()) } while (it.moveToNext())
}
} }
return units return units
} }
} }

View File

@ -10,15 +10,17 @@ class Migration35(private val appInfo: AppInfo) : Migration(34, 35) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Students ADD COLUMN `avatar_color` INTEGER NOT NULL DEFAULT 0") database.execSQL("ALTER TABLE Students ADD COLUMN `avatar_color` INTEGER NOT NULL DEFAULT 0")
val studentsCursor = database.query("SELECT * FROM Students") database.query("SELECT * FROM Students").use {
while (it.moveToNext()) {
while (studentsCursor.moveToNext()) { val studentId = it.getLongOrNull(0)
val studentId = studentsCursor.getLongOrNull(0) database.execSQL(
database.execSQL( """
"""UPDATE Students UPDATE Students
SET avatar_color = ${appInfo.defaultColorsForAvatar.random()} SET avatar_color = ${appInfo.defaultColorsForAvatar.random()}
WHERE id = $studentId""" WHERE id = $studentId
) """
)
}
} }
} }
} }

View File

@ -0,0 +1,102 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import java.time.Instant
import java.time.ZoneId
import java.time.ZoneOffset
class Migration46 : Migration(45, 46) {
override fun migrate(database: SupportSQLiteDatabase) {
migrateConferences(database)
migrateMessages(database)
migrateMobileDevices(database)
migrateNotifications(database)
migrateTimetable(database)
migrateTimetableAdditional(database)
}
private fun migrateConferences(database: SupportSQLiteDatabase) {
database.query("SELECT * FROM Conferences").use {
while (it.moveToNext()) {
val id = it.getLong(it.getColumnIndexOrThrow("id"))
val timestampLocal = it.getLong(it.getColumnIndexOrThrow("date"))
val timestampUtc = timestampLocal.timestampLocalToUTC()
database.execSQL("UPDATE Conferences SET date = $timestampUtc WHERE id = $id")
}
}
}
private fun migrateMessages(database: SupportSQLiteDatabase) {
database.query("SELECT * FROM Messages").use {
while (it.moveToNext()) {
val id = it.getLong(it.getColumnIndexOrThrow("id"))
val timestampLocal = it.getLong(it.getColumnIndexOrThrow("date"))
val timestampUtc = timestampLocal.timestampLocalToUTC()
database.execSQL("UPDATE Messages SET date = $timestampUtc WHERE id = $id")
}
}
}
private fun migrateMobileDevices(database: SupportSQLiteDatabase) {
database.query("SELECT * FROM MobileDevices").use {
while (it.moveToNext()) {
val id = it.getLong(it.getColumnIndexOrThrow("id"))
val timestampLocal = it.getLong(it.getColumnIndexOrThrow("date"))
val timestampUtc = timestampLocal.timestampLocalToUTC()
database.execSQL("UPDATE MobileDevices SET date = $timestampUtc WHERE id = $id")
}
}
}
private fun migrateNotifications(database: SupportSQLiteDatabase) {
database.query("SELECT * FROM Notifications").use {
while (it.moveToNext()) {
val id = it.getLong(it.getColumnIndexOrThrow("id"))
val timestampLocal = it.getLong(it.getColumnIndexOrThrow("date"))
val timestampUtc = timestampLocal.timestampLocalToUTC()
database.execSQL("UPDATE Notifications SET date = $timestampUtc WHERE id = $id")
}
}
}
private fun migrateTimetable(database: SupportSQLiteDatabase) {
database.query("SELECT * FROM Timetable").use {
while (it.moveToNext()) {
val id = it.getLong(it.getColumnIndexOrThrow("id"))
val timestampLocalStart = it.getLong(it.getColumnIndexOrThrow("start"))
val timestampLocalEnd = it.getLong(it.getColumnIndexOrThrow("end"))
val timestampUtcStart = timestampLocalStart.timestampLocalToUTC()
val timestampUtcEnd = timestampLocalEnd.timestampLocalToUTC()
database.execSQL("UPDATE Timetable SET start = $timestampUtcStart, end = $timestampUtcEnd WHERE id = $id")
}
}
}
private fun migrateTimetableAdditional(database: SupportSQLiteDatabase) {
database.query("SELECT * FROM TimetableAdditional").use {
while (it.moveToNext()) {
val id = it.getLong(it.getColumnIndexOrThrow("id"))
val timestampLocalStart = it.getLong(it.getColumnIndexOrThrow("start"))
val timestampLocalEnd = it.getLong(it.getColumnIndexOrThrow("end"))
val timestampUtcStart = timestampLocalStart.timestampLocalToUTC()
val timestampUtcEnd = timestampLocalEnd.timestampLocalToUTC()
database.execSQL("UPDATE TimetableAdditional SET start = $timestampUtcStart, end = $timestampUtcEnd WHERE id = $id")
}
}
}
private fun Long.timestampLocalToUTC(): Long = Instant.ofEpochMilli(this)
.atZone(ZoneOffset.UTC)
.withZoneSameLocal(ZoneId.of("Europe/Warsaw"))
.withZoneSameInstant(ZoneId.systemDefault())
.toInstant()
.toEpochMilli()
}

View File

@ -10,7 +10,7 @@ fun List<SdkConference>.mapToEntities(semester: Semester) = map {
diaryId = semester.diaryId, diaryId = semester.diaryId,
agenda = it.agenda, agenda = it.agenda,
conferenceId = it.id, conferenceId = it.id,
date = it.date, date = it.dateZoned.toInstant(),
presentOnConference = it.presentOnConference, presentOnConference = it.presentOnConference,
subject = it.subject, subject = it.subject,
title = it.title title = it.title

View File

@ -4,7 +4,7 @@ import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.db.entities.MessageAttachment import io.github.wulkanowy.data.db.entities.MessageAttachment
import io.github.wulkanowy.data.db.entities.Recipient import io.github.wulkanowy.data.db.entities.Recipient
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import java.time.LocalDateTime import java.time.Instant
import io.github.wulkanowy.sdk.pojo.Message as SdkMessage import io.github.wulkanowy.sdk.pojo.Message as SdkMessage
import io.github.wulkanowy.sdk.pojo.MessageAttachment as SdkMessageAttachment import io.github.wulkanowy.sdk.pojo.MessageAttachment as SdkMessageAttachment
import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient
@ -18,7 +18,7 @@ fun List<SdkMessage>.mapToEntities(student: Student) = map {
senderId = it.sender?.loginId ?: 0, senderId = it.sender?.loginId ?: 0,
recipient = it.recipients.singleOrNull()?.name ?: "Wielu adresatów", recipient = it.recipients.singleOrNull()?.name ?: "Wielu adresatów",
subject = it.subject.trim(), subject = it.subject.trim(),
date = it.date ?: LocalDateTime.now(), date = it.dateZoned?.toInstant() ?: Instant.now(),
folderId = it.folderId, folderId = it.folderId,
unread = it.unread ?: false, unread = it.unread ?: false,
removed = it.removed, removed = it.removed,

View File

@ -3,13 +3,13 @@ package io.github.wulkanowy.data.mappers
import io.github.wulkanowy.data.db.entities.MobileDevice import io.github.wulkanowy.data.db.entities.MobileDevice
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.pojos.MobileDeviceToken import io.github.wulkanowy.data.pojos.MobileDeviceToken
import io.github.wulkanowy.sdk.pojo.Token as SdkToken
import io.github.wulkanowy.sdk.pojo.Device as SdkDevice import io.github.wulkanowy.sdk.pojo.Device as SdkDevice
import io.github.wulkanowy.sdk.pojo.Token as SdkToken
fun List<SdkDevice>.mapToEntities(semester: Semester) = map { fun List<SdkDevice>.mapToEntities(semester: Semester) = map {
MobileDevice( MobileDevice(
userLoginId = semester.studentId, userLoginId = semester.studentId,
date = it.createDate, date = it.createDateZoned.toInstant(),
deviceId = it.id, deviceId = it.id,
name = it.name name = it.name
) )

View File

@ -2,7 +2,7 @@ package io.github.wulkanowy.data.mappers
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.StudentWithSemesters import io.github.wulkanowy.data.db.entities.StudentWithSemesters
import java.time.LocalDateTime import java.time.Instant
import io.github.wulkanowy.sdk.pojo.Student as SdkStudent import io.github.wulkanowy.sdk.pojo.Student as SdkStudent
fun List<SdkStudent>.mapToEntities(password: String = "", colors: List<Long>) = map { fun List<SdkStudent>.mapToEntities(password: String = "", colors: List<Long>) = map {
@ -24,7 +24,7 @@ fun List<SdkStudent>.mapToEntities(password: String = "", colors: List<Long>) =
scrapperBaseUrl = it.scrapperBaseUrl, scrapperBaseUrl = it.scrapperBaseUrl,
loginType = it.loginType.name, loginType = it.loginType.name,
isCurrent = false, isCurrent = false,
registrationDate = LocalDateTime.now(), registrationDate = Instant.now(),
mobileBaseUrl = it.mobileBaseUrl, mobileBaseUrl = it.mobileBaseUrl,
privateKey = it.privateKey, privateKey = it.privateKey,
certificateKey = it.certificateKey, certificateKey = it.certificateKey,

View File

@ -21,8 +21,8 @@ fun List<SdkTimetable>.mapToEntities(semester: Semester) = map {
studentId = semester.studentId, studentId = semester.studentId,
diaryId = semester.diaryId, diaryId = semester.diaryId,
number = it.number, number = it.number,
start = it.start, start = it.startZoned.toInstant(),
end = it.end, end = it.endZoned.toInstant(),
date = it.date, date = it.date,
subject = it.subject, subject = it.subject,
subjectOld = it.subjectOld, subjectOld = it.subjectOld,
@ -45,8 +45,8 @@ fun List<SdkTimetableAdditional>.mapToEntities(semester: Semester) = map {
diaryId = semester.diaryId, diaryId = semester.diaryId,
subject = it.subject, subject = it.subject,
date = it.date, date = it.date,
start = it.start, start = it.startZoned.toInstant(),
end = it.end end = it.endZoned.toInstant(),
) )
} }

View File

@ -6,16 +6,10 @@ 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.mappers.mapToEntities import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AutoRefreshHelper import io.github.wulkanowy.utils.*
import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.uniqueSubtract
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
import java.time.Instant import java.time.Instant
import java.time.LocalDateTime
import java.time.ZoneOffset
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -35,7 +29,7 @@ class ConferenceRepository @Inject constructor(
semester: Semester, semester: Semester,
forceRefresh: Boolean, forceRefresh: Boolean,
notify: Boolean = false, notify: Boolean = false,
startDate: LocalDateTime = LocalDateTime.ofInstant(Instant.EPOCH, ZoneOffset.UTC), startDate: Instant = Instant.EPOCH,
) = networkBoundResource( ) = networkBoundResource(
mutex = saveFetchResultMutex, mutex = saveFetchResultMutex,
shouldFetch = { shouldFetch = {
@ -66,7 +60,7 @@ class ConferenceRepository @Inject constructor(
conferenceDb.loadAll( conferenceDb.loadAll(
diaryId = semester.diaryId, diaryId = semester.diaryId,
studentId = semester.studentId, studentId = semester.studentId,
startDate = LocalDateTime.ofInstant(Instant.EPOCH, ZoneOffset.UTC) startDate = Instant.EPOCH,
) )
suspend fun updateConference(conference: List<Conference>) = conferenceDb.updateAll(conference) suspend fun updateConference(conference: List<Conference>) = conferenceDb.updateAll(conference)

View File

@ -8,16 +8,12 @@ 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.mappers.mapToEntities import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AutoRefreshHelper import io.github.wulkanowy.utils.*
import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.uniqueSubtract
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
import java.time.LocalDateTime import java.time.Instant
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -70,8 +66,8 @@ class GradeRepository @Inject constructor(
newDetails: List<Grade>, newDetails: List<Grade>,
notify: Boolean notify: Boolean
) { ) {
val notifyBreakDate = oldGrades.maxByOrNull {it.date } val notifyBreakDate = oldGrades.maxByOrNull { it.date }?.date
?.date ?: student.registrationDate.toLocalDate() ?: student.registrationDate.toLocalDate()
gradeDb.deleteAll(oldGrades uniqueSubtract newDetails) gradeDb.deleteAll(oldGrades uniqueSubtract newDetails)
gradeDb.insertAll((newDetails uniqueSubtract oldGrades).onEach { gradeDb.insertAll((newDetails uniqueSubtract oldGrades).onEach {
if (it.date >= notifyBreakDate) it.apply { if (it.date >= notifyBreakDate) it.apply {
@ -101,13 +97,13 @@ class GradeRepository @Inject constructor(
} }
summary.predictedGradeLastChange = when { summary.predictedGradeLastChange = when {
oldSummary == null -> LocalDateTime.now() oldSummary == null -> Instant.now()
summary.predictedGrade != oldSummary.predictedGrade -> LocalDateTime.now() summary.predictedGrade != oldSummary.predictedGrade -> Instant.now()
else -> oldSummary.predictedGradeLastChange else -> oldSummary.predictedGradeLastChange
} }
summary.finalGradeLastChange = when { summary.finalGradeLastChange = when {
oldSummary == null -> LocalDateTime.now() oldSummary == null -> Instant.now()
summary.finalGrade != oldSummary.finalGrade -> LocalDateTime.now() summary.finalGrade != oldSummary.finalGrade -> Instant.now()
else -> oldSummary.finalGradeLastChange else -> oldSummary.finalGradeLastChange
} }
}) })

View File

@ -6,11 +6,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.github.wulkanowy.data.mappers.mapToEntities import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AutoRefreshHelper import io.github.wulkanowy.utils.*
import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.uniqueSubtract
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
import javax.inject.Inject import javax.inject.Inject

View File

@ -7,24 +7,16 @@ import com.fredporciuncula.flow.preferences.FlowSharedPreferences
import com.fredporciuncula.flow.preferences.Preference import com.fredporciuncula.flow.preferences.Preference
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import io.github.wulkanowy.R import io.github.wulkanowy.R
import io.github.wulkanowy.data.enums.AppTheme import io.github.wulkanowy.data.enums.*
import io.github.wulkanowy.data.enums.GradeColorTheme
import io.github.wulkanowy.data.enums.GradeExpandMode
import io.github.wulkanowy.data.enums.GradeSortingMode
import io.github.wulkanowy.data.enums.TimetableMode
import io.github.wulkanowy.sdk.toLocalDate
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
import io.github.wulkanowy.ui.modules.grade.GradeAverageMode import io.github.wulkanowy.ui.modules.grade.GradeAverageMode
import io.github.wulkanowy.utils.toLocalDateTime
import io.github.wulkanowy.utils.toTimestamp
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.serialization.decodeFromString import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import java.time.LocalDate import java.time.Instant
import java.time.LocalDateTime
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -208,10 +200,10 @@ class PreferencesRepository @Inject constructor(
R.bool.pref_default_optional_arithmetic_average R.bool.pref_default_optional_arithmetic_average
) )
var lasSyncDate: LocalDateTime var lasSyncDate: Instant?
get() = getLong(R.string.pref_key_last_sync_date, R.string.pref_default_last_sync_date) get() = getLong(R.string.pref_key_last_sync_date, R.string.pref_default_last_sync_date)
.toLocalDateTime() .takeIf { it != 0L }?.let(Instant::ofEpochMilli)
set(value) = sharedPref.edit().putLong("last_sync_date", value.toTimestamp()).apply() set(value) = sharedPref.edit().putLong("last_sync_date", value?.toEpochMilli() ?: 0).apply()
var dashboardItemsPosition: Map<DashboardItem.Type, Int>? var dashboardItemsPosition: Map<DashboardItem.Type, Int>?
get() { get() {
@ -270,11 +262,12 @@ class PreferencesRepository @Inject constructor(
get() = sharedPref.getInt(PREF_KEY_IN_APP_REVIEW_COUNT, 0) get() = sharedPref.getInt(PREF_KEY_IN_APP_REVIEW_COUNT, 0)
set(value) = sharedPref.edit().putInt(PREF_KEY_IN_APP_REVIEW_COUNT, value).apply() set(value) = sharedPref.edit().putInt(PREF_KEY_IN_APP_REVIEW_COUNT, value).apply()
var inAppReviewDate: LocalDate? var inAppReviewDate: Instant?
get() = sharedPref.getLong(PREF_KEY_IN_APP_REVIEW_DATE, 0).takeIf { it != 0L } get() = sharedPref.getLong(PREF_KEY_IN_APP_REVIEW_DATE, 0).takeIf { it != 0L }
?.toLocalDate() ?.let(Instant::ofEpochMilli)
set(value) = sharedPref.edit().putLong(PREF_KEY_IN_APP_REVIEW_DATE, value!!.toTimestamp()) set(value) = sharedPref.edit {
.apply() putLong(PREF_KEY_IN_APP_REVIEW_DATE, value?.toEpochMilli() ?: 0)
}
var isAppReviewDone: Boolean var isAppReviewDone: Boolean
get() = sharedPref.getBoolean(PREF_KEY_IN_APP_REVIEW_DONE, false) get() = sharedPref.getBoolean(PREF_KEY_IN_APP_REVIEW_DONE, false)

View File

@ -19,7 +19,6 @@ import io.github.wulkanowy.ui.modules.splash.SplashActivity
import io.github.wulkanowy.utils.PendingIntentCompat import io.github.wulkanowy.utils.PendingIntentCompat
import io.github.wulkanowy.utils.flowWithResource import io.github.wulkanowy.utils.flowWithResource
import io.github.wulkanowy.utils.getCompatColor import io.github.wulkanowy.utils.getCompatColor
import io.github.wulkanowy.utils.toLocalDateTime
import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
@ -95,7 +94,7 @@ class TimetableNotificationReceiver : BroadcastReceiver() {
val nextSubject = intent.getStringExtra(LESSON_NEXT_TITLE) val nextSubject = intent.getStringExtra(LESSON_NEXT_TITLE)
val nextRoom = intent.getStringExtra(LESSON_NEXT_ROOM) val nextRoom = intent.getStringExtra(LESSON_NEXT_ROOM)
Timber.d("TimetableNotification receive: type: $type, subject: $subject, start: ${start.toLocalDateTime()}, student: $studentId") Timber.d("TimetableNotification receive: type: $type, subject: $subject, start: $start, student: $studentId")
val notificationTitleResId = val notificationTitleResId =
if (type == NOTIFICATION_TYPE_CURRENT) R.string.timetable_now else R.string.timetable_next if (type == NOTIFICATION_TYPE_CURRENT) R.string.timetable_now else R.string.timetable_next

View File

@ -28,12 +28,12 @@ import io.github.wulkanowy.services.alarm.TimetableNotificationReceiver.Companio
import io.github.wulkanowy.utils.DispatchersProvider import io.github.wulkanowy.utils.DispatchersProvider
import io.github.wulkanowy.utils.PendingIntentCompat import io.github.wulkanowy.utils.PendingIntentCompat
import io.github.wulkanowy.utils.nickOrName import io.github.wulkanowy.utils.nickOrName
import io.github.wulkanowy.utils.toTimestamp
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import timber.log.Timber import timber.log.Timber
import java.time.Duration.ofMinutes
import java.time.Instant
import java.time.Instant.now
import java.time.LocalDate import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalDateTime.now
import javax.inject.Inject import javax.inject.Inject
class TimetableNotificationSchedulerHelper @Inject constructor( class TimetableNotificationSchedulerHelper @Inject constructor(
@ -43,14 +43,14 @@ class TimetableNotificationSchedulerHelper @Inject constructor(
private val dispatchersProvider: DispatchersProvider, private val dispatchersProvider: DispatchersProvider,
) { ) {
private fun getRequestCode(time: LocalDateTime, studentId: Int) = private fun getRequestCode(time: Instant, studentId: Int): Int =
(time.toTimestamp() * studentId).toInt() (time.toEpochMilli() * studentId).toInt()
private fun getUpcomingLessonTime( private fun getUpcomingLessonTime(
index: Int, index: Int,
day: List<Timetable>, day: List<Timetable>,
lesson: Timetable lesson: Timetable
) = day.getOrNull(index - 1)?.end ?: lesson.start.minusMinutes(30) ): Instant = day.getOrNull(index - 1)?.end ?: lesson.start.minus(ofMinutes(30))
suspend fun cancelScheduled(lessons: List<Timetable>, student: Student) { suspend fun cancelScheduled(lessons: List<Timetable>, student: Student) {
val studentId = student.studentId val studentId = student.studentId
@ -71,7 +71,7 @@ class TimetableNotificationSchedulerHelper @Inject constructor(
} }
} }
private fun cancelScheduledTo(range: ClosedRange<LocalDateTime>, requestCode: Int) { private fun cancelScheduledTo(range: ClosedRange<Instant>, requestCode: Int) {
if (now() in range) cancelNotification() if (now() in range) cancelNotification()
alarmManager.cancel( alarmManager.cancel(
@ -150,8 +150,8 @@ class TimetableNotificationSchedulerHelper @Inject constructor(
putExtra(STUDENT_ID, student.studentId) putExtra(STUDENT_ID, student.studentId)
putExtra(STUDENT_NAME, student.nickOrName) putExtra(STUDENT_NAME, student.nickOrName)
putExtra(LESSON_ROOM, lesson.room) putExtra(LESSON_ROOM, lesson.room)
putExtra(LESSON_START, lesson.start.toTimestamp()) putExtra(LESSON_START, lesson.start.toEpochMilli())
putExtra(LESSON_END, lesson.end.toTimestamp()) putExtra(LESSON_END, lesson.end.toEpochMilli())
putExtra(LESSON_TITLE, lesson.subject) putExtra(LESSON_TITLE, lesson.subject)
putExtra(LESSON_NEXT_TITLE, nextLesson?.subject) putExtra(LESSON_NEXT_TITLE, nextLesson?.subject)
putExtra(LESSON_NEXT_ROOM, nextLesson?.room) putExtra(LESSON_NEXT_ROOM, nextLesson?.room)
@ -162,11 +162,11 @@ class TimetableNotificationSchedulerHelper @Inject constructor(
intent: Intent, intent: Intent,
studentId: Int, studentId: Int,
notificationType: Int, notificationType: Int,
time: LocalDateTime time: Instant
) { ) {
try { try {
AlarmManagerCompat.setExactAndAllowWhileIdle( AlarmManagerCompat.setExactAndAllowWhileIdle(
alarmManager, RTC_WAKEUP, time.toTimestamp(), alarmManager, RTC_WAKEUP, time.toEpochMilli(),
PendingIntent.getBroadcast(context, getRequestCode(time, studentId), intent.also { PendingIntent.getBroadcast(context, getRequestCode(time, studentId), intent.also {
it.putExtra(LESSON_TYPE, notificationType) it.putExtra(LESSON_TYPE, notificationType)
}, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE) }, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE)

View File

@ -23,7 +23,7 @@ import io.github.wulkanowy.utils.DispatchersProvider
import io.github.wulkanowy.utils.getCompatColor import io.github.wulkanowy.utils.getCompatColor
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import timber.log.Timber import timber.log.Timber
import java.time.LocalDateTime import java.time.Instant
import kotlin.random.Random import kotlin.random.Random
@HiltWorker @HiltWorker
@ -91,7 +91,7 @@ class SyncWorker @AssistedInject constructor(
} }
errors.isNotEmpty() -> Result.retry() errors.isNotEmpty() -> Result.retry()
else -> { else -> {
preferencesRepository.lasSyncDate = LocalDateTime.now() preferencesRepository.lasSyncDate = Instant.now()
Result.success() Result.success()
} }
} }

View File

@ -18,7 +18,7 @@ import io.github.wulkanowy.utils.PendingIntentCompat
import io.github.wulkanowy.utils.getCompatBitmap import io.github.wulkanowy.utils.getCompatBitmap
import io.github.wulkanowy.utils.getCompatColor import io.github.wulkanowy.utils.getCompatColor
import io.github.wulkanowy.utils.nickOrName import io.github.wulkanowy.utils.nickOrName
import java.time.LocalDateTime import java.time.Instant
import javax.inject.Inject import javax.inject.Inject
import kotlin.random.Random import kotlin.random.Random
@ -169,7 +169,7 @@ class AppNotificationManager @Inject constructor(
title = notificationData.title, title = notificationData.title,
content = notificationData.content, content = notificationData.content,
type = notificationType, type = notificationType,
date = LocalDateTime.now() date = Instant.now(),
) )
notificationRepository.saveNotification(notificationEntity) notificationRepository.saveNotification(notificationEntity)

View File

@ -11,8 +11,8 @@ import io.github.wulkanowy.ui.modules.Destination
import io.github.wulkanowy.ui.modules.splash.SplashActivity import io.github.wulkanowy.ui.modules.splash.SplashActivity
import io.github.wulkanowy.utils.getPlural import io.github.wulkanowy.utils.getPlural
import io.github.wulkanowy.utils.toFormattedString import io.github.wulkanowy.utils.toFormattedString
import java.time.Instant
import java.time.LocalDate import java.time.LocalDate
import java.time.LocalDateTime
import javax.inject.Inject import javax.inject.Inject
class ChangeTimetableNotification @Inject constructor( class ChangeTimetableNotification @Inject constructor(
@ -21,7 +21,7 @@ class ChangeTimetableNotification @Inject constructor(
) { ) {
suspend fun notify(items: List<Timetable>, student: Student) { suspend fun notify(items: List<Timetable>, student: Student) {
val currentTime = LocalDateTime.now() val currentTime = Instant.now()
val changedLessons = items.filter { (it.canceled || it.changes) && it.start > currentTime } val changedLessons = items.filter { (it.canceled || it.changes) && it.start > currentTime }
val notificationDataList = changedLessons.groupBy { it.date } val notificationDataList = changedLessons.groupBy { it.date }
.map { (date, lessons) -> .map { (date, lessons) ->

View File

@ -11,7 +11,7 @@ import io.github.wulkanowy.ui.modules.Destination
import io.github.wulkanowy.ui.modules.splash.SplashActivity import io.github.wulkanowy.ui.modules.splash.SplashActivity
import io.github.wulkanowy.utils.getPlural import io.github.wulkanowy.utils.getPlural
import io.github.wulkanowy.utils.toFormattedString import io.github.wulkanowy.utils.toFormattedString
import java.time.LocalDateTime import java.time.Instant
import javax.inject.Inject import javax.inject.Inject
class NewConferenceNotification @Inject constructor( class NewConferenceNotification @Inject constructor(
@ -20,7 +20,7 @@ class NewConferenceNotification @Inject constructor(
) { ) {
suspend fun notify(items: List<Conference>, student: Student) { suspend fun notify(items: List<Conference>, student: Student) {
val today = LocalDateTime.now() val today = Instant.now()
val lines = items.filter { !it.date.isBefore(today) } val lines = items.filter { !it.date.isBefore(today) }
.map { .map {
"${it.date.toFormattedString("dd.MM")} - ${it.title}: ${it.subject}" "${it.date.toFormattedString("dd.MM")} - ${it.title}: ${it.subject}"

View File

@ -13,13 +13,8 @@ import io.github.wulkanowy.ui.modules.about.license.LicenseFragment
import io.github.wulkanowy.ui.modules.debug.DebugFragment import io.github.wulkanowy.ui.modules.debug.DebugFragment
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.utils.AppInfo import io.github.wulkanowy.utils.*
import io.github.wulkanowy.utils.getCompatDrawable import java.time.Instant
import io.github.wulkanowy.utils.openAppInMarket
import io.github.wulkanowy.utils.openEmailClient
import io.github.wulkanowy.utils.openInternetBrowser
import io.github.wulkanowy.utils.toFormattedString
import io.github.wulkanowy.utils.toLocalDateTime
import javax.inject.Inject import javax.inject.Inject
@AndroidEntryPoint @AndroidEntryPoint
@ -38,7 +33,7 @@ class AboutFragment : BaseFragment<FragmentAboutBinding>(R.layout.fragment_about
override val versionRes: Triple<String, String, Drawable?>? override val versionRes: Triple<String, String, Drawable?>?
get() = context?.run { get() = context?.run {
val buildTimestamp = val buildTimestamp =
appInfo.buildTimestamp.toLocalDateTime().toFormattedString("yyyy-MM-dd") Instant.ofEpochMilli(appInfo.buildTimestamp).toFormattedString("yyyy-MM-dd")
val versionSignature = val versionSignature =
"${appInfo.versionName}-${appInfo.buildFlavor} (${appInfo.versionCode}), $buildTimestamp" "${appInfo.versionName}-${appInfo.buildFlavor} (${appInfo.versionCode}), $buildTimestamp"
Triple( Triple(

View File

@ -37,9 +37,7 @@ import io.github.wulkanowy.utils.left
import io.github.wulkanowy.utils.nickOrName import io.github.wulkanowy.utils.nickOrName
import io.github.wulkanowy.utils.toFormattedString import io.github.wulkanowy.utils.toFormattedString
import timber.log.Timber import timber.log.Timber
import java.time.Duration import java.time.*
import java.time.LocalDate
import java.time.LocalDateTime
import java.util.Timer import java.util.Timer
import javax.inject.Inject import javax.inject.Inject
import kotlin.concurrent.timer import kotlin.concurrent.timer
@ -291,7 +289,7 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
var dateToNavigate = LocalDate.now() var dateToNavigate = LocalDate.now()
fun updateLessonState() { fun updateLessonState() {
val currentDateTime = LocalDateTime.now() val currentDateTime = Instant.now()
val currentDate = LocalDate.now() val currentDate = LocalDate.now()
val tomorrowDate = currentDate.plusDays(1) val tomorrowDate = currentDate.plusDays(1)
@ -361,7 +359,7 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
binding: ItemDashboardLessonsBinding, binding: ItemDashboardLessonsBinding,
header: TimetableHeader? = null, header: TimetableHeader? = null,
) { ) {
val currentDateTime = LocalDateTime.now() val currentDateTime = Instant.now()
val nextLessons = timetableToShow.filter { it.end.isAfter(currentDateTime) } val nextLessons = timetableToShow.filter { it.end.isAfter(currentDateTime) }
.sortedBy { it.start } .sortedBy { it.start }
@ -386,7 +384,7 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
private fun updateFirstLessonView( private fun updateFirstLessonView(
binding: ItemDashboardLessonsBinding, binding: ItemDashboardLessonsBinding,
firstLesson: Timetable?, firstLesson: Timetable?,
currentDateTime: LocalDateTime currentDateTime: Instant
) { ) {
val context = binding.root.context val context = binding.root.context
val sansSerifFont = Typeface.create("sans-serif", Typeface.NORMAL) val sansSerifFont = Typeface.create("sans-serif", Typeface.NORMAL)

View File

@ -15,8 +15,8 @@ import io.github.wulkanowy.utils.nextOrSameSchoolDay
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import timber.log.Timber import timber.log.Timber
import java.time.Instant
import java.time.LocalDate import java.time.LocalDate
import java.time.LocalDateTime
import javax.inject.Inject import javax.inject.Inject
class DashboardPresenter @Inject constructor( class DashboardPresenter @Inject constructor(
@ -532,7 +532,7 @@ class DashboardPresenter @Inject constructor(
student = student, student = student,
semester = semester, semester = semester,
forceRefresh = forceRefresh, forceRefresh = forceRefresh,
startDate = LocalDateTime.now() startDate = Instant.now(),
) )
}.onEach { }.onEach {
when (it.status) { when (it.status) {

View File

@ -1,7 +1,8 @@
package io.github.wulkanowy.ui.modules.debug.notification.mock package io.github.wulkanowy.ui.modules.debug.notification.mock
import io.github.wulkanowy.data.db.entities.Conference import io.github.wulkanowy.data.db.entities.Conference
import java.time.LocalDateTime import java.time.Duration
import java.time.Instant
val debugConferenceItems = listOf( val debugConferenceItems = listOf(
generateConference( generateConference(
@ -53,6 +54,6 @@ private fun generateConference(title: String, subject: String) = Conference(
diaryId = 0, diaryId = 0,
agenda = "", agenda = "",
conferenceId = 0, conferenceId = 0,
date = LocalDateTime.now().plusMinutes(10), date = Instant.now().plus(Duration.ofMinutes(10)),
presentOnConference = "", presentOnConference = "",
) )

View File

@ -1,7 +1,7 @@
package io.github.wulkanowy.ui.modules.debug.notification.mock package io.github.wulkanowy.ui.modules.debug.notification.mock
import io.github.wulkanowy.data.db.entities.Message import io.github.wulkanowy.data.db.entities.Message
import java.time.LocalDateTime import java.time.Instant
val debugMessageItems = listOf( val debugMessageItems = listOf(
generateMessage("Kowalski Jan", "Tytuł"), generateMessage("Kowalski Jan", "Tytuł"),
@ -24,7 +24,7 @@ private fun generateMessage(sender: String, subject: String) = Message(
messageId = 0, messageId = 0,
senderId = 0, senderId = 0,
recipient = "", recipient = "",
date = LocalDateTime.now(), date = Instant.now(),
folderId = 0, folderId = 0,
unread = true, unread = true,
removed = false, removed = false,

View File

@ -1,8 +1,9 @@
package io.github.wulkanowy.ui.modules.debug.notification.mock package io.github.wulkanowy.ui.modules.debug.notification.mock
import io.github.wulkanowy.data.db.entities.Timetable import io.github.wulkanowy.data.db.entities.Timetable
import java.time.Duration
import java.time.Instant
import java.time.LocalDate import java.time.LocalDate
import java.time.LocalDateTime
import kotlin.random.Random import kotlin.random.Random
val debugTimetableItems = listOf( val debugTimetableItems = listOf(
@ -24,8 +25,8 @@ private fun generateTimetable(subject: String, room: String, roomOld: String) =
diaryId = 0, diaryId = 0,
date = LocalDate.now().minusDays(Random.nextLong(0, 8)), date = LocalDate.now().minusDays(Random.nextLong(0, 8)),
number = 1, number = 1,
start = LocalDateTime.now().plusHours(1), start = Instant.now(),
end = LocalDateTime.now(), end = Instant.now().plus(Duration.ofHours(1)),
subjectOld = "", subjectOld = "",
group = "", group = "",
room = room, room = room,

View File

@ -19,7 +19,8 @@ import io.github.wulkanowy.utils.AnalyticsHelper
import io.github.wulkanowy.utils.flowWithResource import io.github.wulkanowy.utils.flowWithResource
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import timber.log.Timber import timber.log.Timber
import java.time.LocalDate import java.time.Duration
import java.time.Instant
import javax.inject.Inject import javax.inject.Inject
class MainPresenter @Inject constructor( class MainPresenter @Inject constructor(
@ -158,11 +159,11 @@ class MainPresenter @Inject constructor(
prefRepository.inAppReviewCount++ prefRepository.inAppReviewCount++
if (prefRepository.inAppReviewDate == null) { if (prefRepository.inAppReviewDate == null) {
prefRepository.inAppReviewDate = LocalDate.now() prefRepository.inAppReviewDate = Instant.now()
} }
if (!prefRepository.isAppReviewDone && prefRepository.inAppReviewCount >= 50 && if (!prefRepository.isAppReviewDone && prefRepository.inAppReviewCount >= 50 &&
LocalDate.now().minusDays(14).isAfter(prefRepository.inAppReviewDate) Instant.now().minus(Duration.ofDays(14)).isAfter(prefRepository.inAppReviewDate)
) { ) {
view?.showInAppReview() view?.showInAppReview()
prefRepository.isAppReviewDone = true prefRepository.isAppReviewDone = true

View File

@ -79,9 +79,7 @@ class SyncPresenter @Inject constructor(
} }
private fun setSyncDateInView() { private fun setSyncDateInView() {
val lastSyncDate = preferencesRepository.lasSyncDate val lastSyncDate = preferencesRepository.lasSyncDate ?: return
if (lastSyncDate.year == 1970) return
view?.setLastSyncDate(lastSyncDate.toFormattedString("dd.MM.yyyy HH:mm:ss")) view?.setLastSyncDate(lastSyncDate.toFormattedString("dd.MM.yyyy HH:mm:ss"))
} }

View File

@ -15,15 +15,10 @@ import io.github.wulkanowy.data.db.entities.Timetable
import io.github.wulkanowy.data.enums.TimetableMode import io.github.wulkanowy.data.enums.TimetableMode
import io.github.wulkanowy.databinding.ItemTimetableBinding import io.github.wulkanowy.databinding.ItemTimetableBinding
import io.github.wulkanowy.databinding.ItemTimetableSmallBinding import io.github.wulkanowy.databinding.ItemTimetableSmallBinding
import io.github.wulkanowy.utils.getThemeAttrColor import io.github.wulkanowy.utils.*
import io.github.wulkanowy.utils.isJustFinished
import io.github.wulkanowy.utils.isShowTimeUntil
import io.github.wulkanowy.utils.left
import io.github.wulkanowy.utils.toFormattedString
import io.github.wulkanowy.utils.until
import timber.log.Timber import timber.log.Timber
import java.time.LocalDateTime import java.time.Instant
import java.util.Timer import java.util.*
import javax.inject.Inject import javax.inject.Inject
import kotlin.concurrent.timer import kotlin.concurrent.timer
@ -167,7 +162,7 @@ class TimetableAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
} }
} }
private fun getPreviousLesson(position: Int): LocalDateTime? { private fun getPreviousLesson(position: Int): Instant? {
return items.filter { it.isStudentPlan } return items.filter { it.isStudentPlan }
.getOrNull(position - 1 - items.filterIndexed { i, item -> i < position && !item.isStudentPlan }.size) .getOrNull(position - 1 - items.filterIndexed { i, item -> i < position && !item.isStudentPlan }.size)
?.let { ?.let {

View File

@ -16,7 +16,7 @@ import io.github.wulkanowy.utils.capitalise
import io.github.wulkanowy.utils.getThemeAttrColor import io.github.wulkanowy.utils.getThemeAttrColor
import io.github.wulkanowy.utils.lifecycleAwareVariable import io.github.wulkanowy.utils.lifecycleAwareVariable
import io.github.wulkanowy.utils.toFormattedString import io.github.wulkanowy.utils.toFormattedString
import java.time.LocalDateTime import java.time.Instant
class TimetableDialog : DialogFragment() { class TimetableDialog : DialogFragment() {
@ -192,7 +192,7 @@ class TimetableDialog : DialogFragment() {
} }
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
private fun setTime(start: LocalDateTime, end: LocalDateTime) { private fun setTime(start: Instant, end: Instant) {
binding.timetableDialogTimeValue.text = binding.timetableDialogTimeValue.text =
"${start.toFormattedString("HH:mm")} - ${end.toFormattedString("HH:mm")}" "${start.toFormattedString("HH:mm")} - ${end.toFormattedString("HH:mm")}"
} }

View File

@ -10,11 +10,9 @@ import io.github.wulkanowy.utils.lastSchoolDayInSchoolYear
import io.github.wulkanowy.utils.toLocalDate import io.github.wulkanowy.utils.toLocalDate
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import timber.log.Timber import timber.log.Timber
import java.time.LocalDate import java.time.*
import java.time.LocalDateTime
import java.time.LocalTime
import java.time.temporal.ChronoUnit import java.time.temporal.ChronoUnit
import java.util.UUID import java.util.*
import javax.inject.Inject import javax.inject.Inject
class AdditionalLessonAddPresenter @Inject constructor( class AdditionalLessonAddPresenter @Inject constructor(
@ -138,8 +136,8 @@ class AdditionalLessonAddPresenter @Inject constructor(
TimetableAdditional( TimetableAdditional(
studentId = semester.studentId, studentId = semester.studentId,
diaryId = semester.diaryId, diaryId = semester.diaryId,
start = LocalDateTime.of(date, start), start = ZonedDateTime.of(date, start, ZoneId.systemDefault()).toInstant(),
end = LocalDateTime.of(date, end), end = ZonedDateTime.of(date, end, ZoneId.systemDefault()).toInstant(),
date = date.plusWeeks(it), date = date.plusWeeks(it),
subject = subject subject = subject
).apply { ).apply {

View File

@ -29,7 +29,6 @@ import io.github.wulkanowy.utils.toFormattedString
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import timber.log.Timber import timber.log.Timber
import java.time.LocalDate import java.time.LocalDate
import java.time.ZoneOffset
class TimetableWidgetFactory( class TimetableWidgetFactory(
private val timetableRepository: TimetableRepository, private val timetableRepository: TimetableRepository,
@ -77,7 +76,7 @@ class TimetableWidgetFactory(
if (date == LocalDate.now() && todayLastLessonEndTimestamp != null) { if (date == LocalDate.now() && todayLastLessonEndTimestamp != null) {
sharedPref.putLong( sharedPref.putLong(
key = getTodayLastLessonEndDateTimeWidgetKey(appWidgetId), key = getTodayLastLessonEndDateTimeWidgetKey(appWidgetId),
value = todayLastLessonEndTimestamp.toEpochSecond(ZoneOffset.UTC), value = todayLastLessonEndTimestamp.epochSecond,
sync = true sync = true
) )
} }

View File

@ -5,7 +5,6 @@ import com.google.android.material.datepicker.CalendarConstraints
import com.google.android.material.datepicker.MaterialDatePicker import com.google.android.material.datepicker.MaterialDatePicker
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
import java.time.LocalDate import java.time.LocalDate
import java.time.ZoneOffset
import java.time.temporal.ChronoUnit import java.time.temporal.ChronoUnit
fun Fragment.openMaterialDatePicker( fun Fragment.openMaterialDatePicker(
@ -16,17 +15,17 @@ fun Fragment.openMaterialDatePicker(
) { ) {
val constraintsBuilder = CalendarConstraints.Builder().apply { val constraintsBuilder = CalendarConstraints.Builder().apply {
setValidator(CalendarDayRangeValidator(rangeStart, rangeEnd)) setValidator(CalendarDayRangeValidator(rangeStart, rangeEnd))
setStart(rangeStart.toTimestamp(ZoneOffset.UTC)) setStart(rangeStart.toTimestamp())
setEnd(rangeEnd.toTimestamp(ZoneOffset.UTC)) setEnd(rangeEnd.toTimestamp())
} }
val datePicker = MaterialDatePicker.Builder.datePicker() val datePicker = MaterialDatePicker.Builder.datePicker()
.setCalendarConstraints(constraintsBuilder.build()) .setCalendarConstraints(constraintsBuilder.build())
.setSelection(selected.toTimestamp(ZoneOffset.UTC)) .setSelection(selected.toTimestamp())
.build() .build()
datePicker.addOnPositiveButtonClickListener { datePicker.addOnPositiveButtonClickListener {
val date = it.toLocalDateTime(ZoneOffset.UTC).toLocalDate() val date = it.toLocalDateTime().toLocalDate()
onDateSelected(date) onDateSelected(date)
} }

View File

@ -8,8 +8,9 @@ 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.enums.MessageFolder import io.github.wulkanowy.data.enums.MessageFolder
import timber.log.Timber import timber.log.Timber
import java.time.Duration.ofMinutes
import java.time.Instant
import java.time.LocalDate import java.time.LocalDate
import java.time.LocalDateTime
import javax.inject.Inject import javax.inject.Inject
fun getRefreshKey(name: String, semester: Semester, start: LocalDate, end: LocalDate): String { fun getRefreshKey(name: String, semester: Semester, start: LocalDate, end: LocalDate): String {
@ -34,10 +35,10 @@ class AutoRefreshHelper @Inject constructor(
) { ) {
fun shouldBeRefreshed(key: String): Boolean { fun shouldBeRefreshed(key: String): Boolean {
val timestamp = sharedPref.getLong(key, 0).toLocalDateTime() val timestamp = sharedPref.getLong(key, 0).let(Instant::ofEpochMilli)
val servicesInterval = sharedPref.getString(context.getString(R.string.pref_key_services_interval), context.getString(R.string.pref_default_services_interval)).toLong() val servicesInterval = sharedPref.getString(context.getString(R.string.pref_key_services_interval), context.getString(R.string.pref_default_services_interval)).toLong()
val shouldBeRefreshed = timestamp < LocalDateTime.now().minusMinutes(servicesInterval) val shouldBeRefreshed = timestamp < Instant.now().minus(ofMinutes(servicesInterval))
Timber.d("Check if $key need to be refreshed: $shouldBeRefreshed (last refresh: $timestamp, interval: $servicesInterval min)") Timber.d("Check if $key need to be refreshed: $shouldBeRefreshed (last refresh: $timestamp, interval: $servicesInterval min)")
@ -45,6 +46,6 @@ class AutoRefreshHelper @Inject constructor(
} }
fun updateLastRefreshTimestamp(key: String) { fun updateLastRefreshTimestamp(key: String) {
sharedPref.putLong(key, LocalDateTime.now().toTimestamp()) sharedPref.putLong(key, Instant.now().toEpochMilli())
} }
} }

View File

@ -12,12 +12,17 @@ import io.github.wulkanowy.sdk.scrapper.login.PasswordChangeRequiredException
import okhttp3.internal.http2.StreamResetException import okhttp3.internal.http2.StreamResetException
import java.io.InterruptedIOException import java.io.InterruptedIOException
import java.net.ConnectException import java.net.ConnectException
import java.net.SocketException
import java.net.SocketTimeoutException import java.net.SocketTimeoutException
import java.net.UnknownHostException import java.net.UnknownHostException
fun Resources.getString(error: Throwable) = when (error) { fun Resources.getString(error: Throwable) = when (error) {
is UnknownHostException -> getString(R.string.error_no_internet) is UnknownHostException -> getString(R.string.error_no_internet)
is SocketTimeoutException, is InterruptedIOException, is ConnectException, is StreamResetException -> getString(R.string.error_timeout) is SocketException,
is SocketTimeoutException,
is InterruptedIOException,
is ConnectException,
is StreamResetException -> getString(R.string.error_timeout)
is NotLoggedInException -> getString(R.string.error_login_failed) is NotLoggedInException -> getString(R.string.error_login_failed)
is PasswordChangeRequiredException -> getString(R.string.error_password_change_required) is PasswordChangeRequiredException -> getString(R.string.error_password_change_required)
is ServiceUnavailableException -> getString(R.string.error_service_unavailable) is ServiceUnavailableException -> getString(R.string.error_service_unavailable)

View File

@ -1,40 +1,34 @@
package io.github.wulkanowy.utils package io.github.wulkanowy.utils
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.time.DayOfWeek.FRIDAY import java.time.*
import java.time.DayOfWeek.MONDAY import java.time.DayOfWeek.*
import java.time.DayOfWeek.SATURDAY
import java.time.DayOfWeek.SUNDAY
import java.time.Instant
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.Month
import java.time.ZoneId
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
import java.time.temporal.TemporalAdjusters.firstInMonth import java.time.temporal.TemporalAdjusters.*
import java.time.temporal.TemporalAdjusters.next import java.util.*
import java.time.temporal.TemporalAdjusters.previous
import java.util.Locale
private const val DEFAULT_DATE_PATTERN = "dd.MM.yyyy" private const val DEFAULT_DATE_PATTERN = "dd.MM.yyyy"
fun LocalDate.toTimestamp(): Long = atStartOfDay()
.toInstant(ZoneOffset.UTC)
.toEpochMilli()
fun Long.toLocalDateTime(): LocalDateTime = LocalDateTime.ofInstant(
Instant.ofEpochMilli(this), ZoneOffset.UTC
)
fun Instant.toLocalDate(): LocalDate = atZone(ZoneOffset.UTC).toLocalDate()
fun String.toLocalDate(format: String = DEFAULT_DATE_PATTERN): LocalDate = fun String.toLocalDate(format: String = DEFAULT_DATE_PATTERN): LocalDate =
LocalDate.parse(this, DateTimeFormatter.ofPattern(format)) LocalDate.parse(this, DateTimeFormatter.ofPattern(format))
fun LocalDateTime.toTimestamp(tz: ZoneId = ZoneId.systemDefault()) =
atZone(tz).withZoneSameInstant(ZoneOffset.UTC).toInstant().toEpochMilli()
fun Long.toLocalDateTime(tz: ZoneId = ZoneId.systemDefault()): LocalDateTime =
LocalDateTime.ofInstant(Instant.ofEpochMilli(this), tz)
fun LocalDate.toTimestamp(tz: ZoneId = ZoneId.systemDefault()) = atStartOfDay().toTimestamp(tz)
fun LocalDate.toFormattedString(pattern: String = DEFAULT_DATE_PATTERN): String = fun LocalDate.toFormattedString(pattern: String = DEFAULT_DATE_PATTERN): String =
format(DateTimeFormatter.ofPattern(pattern)) format(DateTimeFormatter.ofPattern(pattern))
fun LocalDateTime.toFormattedString(pattern: String = DEFAULT_DATE_PATTERN): String = fun Instant.toFormattedString(
format(DateTimeFormatter.ofPattern(pattern)) pattern: String = DEFAULT_DATE_PATTERN,
tz: ZoneId = ZoneId.systemDefault()
): String = atZone(tz).format(DateTimeFormatter.ofPattern(pattern))
fun Month.getFormattedName(): String { fun Month.getFormattedName(): String {
val formatter = SimpleDateFormat("LLLL", Locale.getDefault()) val formatter = SimpleDateFormat("LLLL", Locale.getDefault())

View File

@ -3,10 +3,10 @@ package io.github.wulkanowy.utils
import io.github.wulkanowy.data.db.entities.Timetable import io.github.wulkanowy.data.db.entities.Timetable
import java.time.Duration import java.time.Duration
import java.time.Duration.between import java.time.Duration.between
import java.time.LocalDateTime import java.time.Instant
import java.time.LocalDateTime.now import java.time.Instant.now
fun Timetable.isShowTimeUntil(previousLessonEnd: LocalDateTime?) = when { fun Timetable.isShowTimeUntil(previousLessonEnd: Instant?) = when {
!isStudentPlan -> false !isStudentPlan -> false
canceled -> false canceled -> false
now().isAfter(start) -> false now().isAfter(start) -> false

View File

@ -4,7 +4,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.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import java.time.LocalDate import java.time.LocalDate
import java.time.LocalDateTime.now import java.time.Instant.now
import io.github.wulkanowy.sdk.pojo.Semester as SdkSemester import io.github.wulkanowy.sdk.pojo.Semester as SdkSemester
fun getSemesterEntity(diaryId: Int = 1, semesterId: Int = 1, start: LocalDate = LocalDate.now(), end: LocalDate = LocalDate.now(), semesterName: Int = 1) = Semester( fun getSemesterEntity(diaryId: Int = 1, semesterId: Int = 1, start: LocalDate = LocalDate.now(), end: LocalDate = LocalDate.now(), semesterName: Int = 1) = Semester(

View File

@ -153,23 +153,25 @@ class Migration13Test : AbstractMigrationTest() {
private fun getSemesters(db: SupportSQLiteDatabase, query: String): List<Pair<Semester, Boolean>> { private fun getSemesters(db: SupportSQLiteDatabase, query: String): List<Pair<Semester, Boolean>> {
val semesters = mutableListOf<Pair<Semester, Boolean>>() val semesters = mutableListOf<Pair<Semester, Boolean>>()
val cursor = db.query(query) db.query(query).use {
if (cursor.moveToFirst()) { if (it.moveToFirst()) {
do { do {
semesters.add(Semester( semesters.add(Semester(
studentId = cursor.getInt(1), studentId = it.getInt(1),
diaryId = cursor.getInt(2), diaryId = it.getInt(2),
diaryName = cursor.getString(3), diaryName = it.getString(3),
semesterId = cursor.getInt(4), semesterId = it.getInt(4),
semesterName = cursor.getInt(5), semesterName = it.getInt(5),
classId = cursor.getInt(7), classId = it.getInt(7),
unitId = cursor.getInt(8), unitId = it.getInt(8),
schoolYear = cursor.getInt(9), schoolYear = it.getInt(9),
start = Converters().timestampToDate(cursor.getLong(10))!!, start = Converters().timestampToLocalDate(it.getLong(10))!!,
end = Converters().timestampToDate(cursor.getLong(11))!! end = Converters().timestampToLocalDate(it.getLong(11))!!
) to (cursor.getInt(6) == 1)) ) to (it.getInt(6) == 1))
} while (cursor.moveToNext()) } while (it.moveToNext())
}
} }
return semesters.toList() return semesters.toList()
} }

View File

@ -8,23 +8,17 @@ import io.github.wulkanowy.getStudentEntity
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AutoRefreshHelper import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.toFirstResult import io.github.wulkanowy.utils.toFirstResult
import io.mockk.MockKAnnotations import io.mockk.*
import io.mockk.Runs
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.every
import io.mockk.impl.annotations.MockK import io.mockk.impl.annotations.MockK
import io.mockk.impl.annotations.SpyK import io.mockk.impl.annotations.SpyK
import io.mockk.just
import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals import org.junit.Assert.*
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import java.time.LocalDate import java.time.LocalDate
import java.time.LocalDate.of import java.time.LocalDate.of
import java.time.ZoneOffset
import io.github.wulkanowy.sdk.pojo.Grade as SdkGrade import io.github.wulkanowy.sdk.pojo.Grade as SdkGrade
class GradeRepositoryTest { class GradeRepositoryTest {
@ -57,7 +51,11 @@ class GradeRepositoryTest {
coEvery { gradeDb.deleteAll(any()) } just Runs coEvery { gradeDb.deleteAll(any()) } just Runs
coEvery { gradeDb.insertAll(any()) } returns listOf() coEvery { gradeDb.insertAll(any()) } returns listOf()
coEvery { gradeSummaryDb.loadAll(1, 1) } returnsMany listOf(flowOf(listOf()), flowOf(listOf()), flowOf(listOf())) coEvery { gradeSummaryDb.loadAll(1, 1) } returnsMany listOf(
flowOf(listOf()),
flowOf(listOf()),
flowOf(listOf())
)
coEvery { gradeSummaryDb.deleteAll(any()) } just Runs coEvery { gradeSummaryDb.deleteAll(any()) } just Runs
coEvery { gradeSummaryDb.insertAll(any()) } returns listOf() coEvery { gradeSummaryDb.insertAll(any()) } returns listOf()
} }
@ -65,7 +63,7 @@ class GradeRepositoryTest {
@Test @Test
fun `mark grades older than registration date as read`() { fun `mark grades older than registration date as read`() {
// prepare // prepare
val boundaryDate = of(2019, 2, 27).atStartOfDay() val boundaryDate = of(2019, 2, 27).atStartOfDay().toInstant(ZoneOffset.UTC)
val remoteList = listOf( val remoteList = listOf(
createGradeApi(5, 4.0, of(2019, 2, 25), "Ocena pojawiła się"), createGradeApi(5, 4.0, of(2019, 2, 25), "Ocena pojawiła się"),
createGradeApi(5, 4.0, of(2019, 2, 26), "przed zalogowanie w aplikacji"), createGradeApi(5, 4.0, of(2019, 2, 26), "przed zalogowanie w aplikacji"),
@ -81,7 +79,13 @@ class GradeRepositoryTest {
) )
// execute // execute
val res = runBlocking { gradeRepository.getGrades(student.copy(registrationDate = boundaryDate), semester, true).toFirstResult() } val res = runBlocking {
gradeRepository.getGrades(
student = student.copy(registrationDate = boundaryDate),
semester = semester,
forceRefresh = true
).toFirstResult()
}
// verify // verify
assertEquals(null, res.error) assertEquals(null, res.error)
@ -101,9 +105,19 @@ class GradeRepositoryTest {
fun `mitigate mark grades as unread when old grades changed`() { fun `mitigate mark grades as unread when old grades changed`() {
// prepare // prepare
val remoteList = listOf( val remoteList = listOf(
createGradeApi(5, 2.0, of(2019, 2, 25), "Ocena ma datę, jest inna, ale nie zostanie powiadomiona"), createGradeApi(
5,
2.0,
of(2019, 2, 25),
"Ocena ma datę, jest inna, ale nie zostanie powiadomiona"
),
createGradeApi(4, 3.0, of(2019, 2, 26), "starszą niż ostatnia lokalnie"), createGradeApi(4, 3.0, of(2019, 2, 26), "starszą niż ostatnia lokalnie"),
createGradeApi(3, 4.0, of(2019, 2, 27), "Ta jest z tego samego dnia co ostatnia lokalnie"), createGradeApi(
3,
4.0,
of(2019, 2, 27),
"Ta jest z tego samego dnia co ostatnia lokalnie"
),
createGradeApi(2, 5.0, of(2019, 2, 28), "Ta jest już w ogóle nowa") createGradeApi(2, 5.0, of(2019, 2, 28), "Ta jest już w ogóle nowa")
) )
coEvery { sdk.getGrades(1) } returns (remoteList to emptyList()) coEvery { sdk.getGrades(1) } returns (remoteList to emptyList())
@ -111,7 +125,12 @@ class GradeRepositoryTest {
val localList = listOf( val localList = listOf(
createGradeApi(5, 3.0, of(2019, 2, 25), "Jedna ocena"), createGradeApi(5, 3.0, of(2019, 2, 25), "Jedna ocena"),
createGradeApi(4, 4.0, of(2019, 2, 26), "Druga"), createGradeApi(4, 4.0, of(2019, 2, 26), "Druga"),
createGradeApi(3, 4.0, of(2019, 2, 27), "Ta jest z tego samego dnia co ostatnia lokalnie") createGradeApi(
3,
4.0,
of(2019, 2, 27),
"Ta jest z tego samego dnia co ostatnia lokalnie"
)
) )
coEvery { gradeDb.loadAll(1, 1) } returnsMany listOf( coEvery { gradeDb.loadAll(1, 1) } returnsMany listOf(
flowOf(localList.mapToEntities(semester)), flowOf(localList.mapToEntities(semester)),
@ -248,18 +267,19 @@ class GradeRepositoryTest {
assertEquals(0, res.data?.first?.size) assertEquals(0, res.data?.first?.size)
} }
private fun createGradeApi(value: Int, weight: Double, date: LocalDate, desc: String) = SdkGrade( private fun createGradeApi(value: Int, weight: Double, date: LocalDate, desc: String) =
subject = "", SdkGrade(
color = "", subject = "",
comment = "", color = "",
date = date, comment = "",
description = desc, date = date,
entry = "", description = desc,
modifier = .0, entry = "",
symbol = "", modifier = .0,
teacher = "", symbol = "",
value = value.toDouble(), teacher = "",
weight = weight.toString(), value = value.toDouble(),
weightValue = weight weight = weight.toString(),
) weightValue = weight
)
} }

View File

@ -16,27 +16,25 @@ import io.github.wulkanowy.sdk.pojo.MessageDetails
import io.github.wulkanowy.sdk.pojo.Sender import io.github.wulkanowy.sdk.pojo.Sender
import io.github.wulkanowy.utils.AutoRefreshHelper import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.toFirstResult import io.github.wulkanowy.utils.toFirstResult
import io.mockk.MockKAnnotations import io.mockk.*
import io.mockk.Runs
import io.mockk.checkEquals
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.every
import io.mockk.impl.annotations.MockK import io.mockk.impl.annotations.MockK
import io.mockk.impl.annotations.SpyK import io.mockk.impl.annotations.SpyK
import io.mockk.just import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.toList import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.runTest
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import java.net.UnknownHostException import java.net.UnknownHostException
import java.time.LocalDateTime import java.time.Instant
import java.time.ZoneOffset
import kotlin.test.assertTrue import kotlin.test.assertTrue
@OptIn(ExperimentalCoroutinesApi::class)
class MessageRepositoryTest { class MessageRepositoryTest {
@SpyK @SpyK
@ -80,7 +78,7 @@ class MessageRepositoryTest {
} }
@Test @Test
fun `get messages when read by values was changed on already read message`() = runBlocking { fun `get messages when read by values was changed on already read message`() = runTest {
every { messageDb.loadAll(any(), any()) } returns flow { every { messageDb.loadAll(any(), any()) } returns flow {
val dbMessage = getMessageEntity(3, "", false).apply { val dbMessage = getMessageEntity(3, "", false).apply {
unreadBy = 10 unreadBy = 10
@ -239,7 +237,7 @@ class MessageRepositoryTest {
senderId = 0, senderId = 0,
recipient = "Wielu adresatów", recipient = "Wielu adresatów",
subject = "", subject = "",
date = LocalDateTime.MAX, date = Instant.EPOCH,
folderId = 1, folderId = 1,
unread = unread, unread = unread,
removed = false, removed = false,
@ -261,7 +259,8 @@ class MessageRepositoryTest {
recipients = listOf(), recipients = listOf(),
subject = "", subject = "",
content = content, content = content,
date = LocalDateTime.MAX, date = Instant.EPOCH.atZone(ZoneOffset.UTC).toLocalDateTime(),
dateZoned = Instant.EPOCH.atZone(ZoneOffset.UTC),
folderId = 1, folderId = 1,
unread = unread, unread = unread,
unreadBy = 0, unreadBy = 0,

View File

@ -22,6 +22,7 @@ import org.junit.Assert
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import java.time.LocalDateTime.of import java.time.LocalDateTime.of
import java.time.ZoneId
class MobileDeviceRepositoryTest { class MobileDeviceRepositoryTest {
@ -137,6 +138,8 @@ class MobileDeviceRepositoryTest {
name = "", name = "",
deviceId = "", deviceId = "",
createDate = of(2019, 5, day, 0, 0, 0), createDate = of(2019, 5, day, 0, 0, 0),
modificationDate = of(2019, 5, day, 0, 0, 0) modificationDate = of(2019, 5, day, 0, 0, 0),
createDateZoned = of(2019, 5, day, 0, 0, 0).atZone(ZoneId.systemDefault()),
modificationDateZoned = of(2019, 5, day, 0, 0, 0).atZone(ZoneId.systemDefault())
) )
} }

View File

@ -27,6 +27,7 @@ import org.junit.Test
import java.time.LocalDate import java.time.LocalDate
import java.time.LocalDateTime import java.time.LocalDateTime
import java.time.LocalDateTime.of import java.time.LocalDateTime.of
import java.time.ZoneId
import io.github.wulkanowy.sdk.pojo.Timetable as SdkTimetable import io.github.wulkanowy.sdk.pojo.Timetable as SdkTimetable
class TimetableRepositoryTest { class TimetableRepositoryTest {
@ -107,6 +108,8 @@ class TimetableRepositoryTest {
number = number, number = number,
start = start, start = start,
end = start.plusMinutes(45), end = start.plusMinutes(45),
startZoned = start.atZone(ZoneId.systemDefault()),
endZoned = start.plusMinutes(45).atZone(ZoneId.systemDefault()),
date = start.toLocalDate(), date = start.toLocalDate(),
subject = subject, subject = subject,
group = "", group = "",

View File

@ -23,9 +23,9 @@ import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import java.time.Instant
import java.time.LocalDate.now import java.time.LocalDate.now
import java.time.LocalDate.of import java.time.LocalDate.of
import java.time.LocalDateTime
class GradeAverageProviderTest { class GradeAverageProviderTest {
@ -63,7 +63,7 @@ class GradeAverageProviderTest {
className = "", className = "",
classId = 1, classId = 1,
isCurrent = true, isCurrent = true,
registrationDate = LocalDateTime.now() registrationDate = Instant.now()
) )
private val semesters = mutableListOf( private val semesters = mutableListOf(

View File

@ -6,18 +6,13 @@ import io.github.wulkanowy.data.db.entities.StudentWithSemesters
import io.github.wulkanowy.data.repositories.StudentRepository import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
import io.github.wulkanowy.utils.AnalyticsHelper import io.github.wulkanowy.utils.AnalyticsHelper
import io.mockk.MockKAnnotations import io.mockk.*
import io.mockk.Runs
import io.mockk.coEvery
import io.mockk.every
import io.mockk.impl.annotations.MockK import io.mockk.impl.annotations.MockK
import io.mockk.just
import io.mockk.verify
import org.junit.Before import org.junit.Before
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import java.io.IOException import java.io.IOException
import java.time.LocalDateTime.now import java.time.Instant
class LoginFormPresenterTest { class LoginFormPresenterTest {
@ -121,7 +116,7 @@ class LoginFormPresenterTest {
classId = 1, classId = 1,
isCurrent = false, isCurrent = false,
symbol = "", symbol = "",
registrationDate = now(), registrationDate = Instant.now(),
className = "", className = "",
mobileBaseUrl = "", mobileBaseUrl = "",
privateKey = "", privateKey = "",

View File

@ -7,18 +7,12 @@ import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.services.sync.SyncManager import io.github.wulkanowy.services.sync.SyncManager
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
import io.github.wulkanowy.utils.AnalyticsHelper import io.github.wulkanowy.utils.AnalyticsHelper
import io.mockk.MockKAnnotations import io.mockk.*
import io.mockk.Runs
import io.mockk.clearMocks
import io.mockk.coEvery
import io.mockk.every
import io.mockk.impl.annotations.MockK import io.mockk.impl.annotations.MockK
import io.mockk.just
import io.mockk.verify
import org.junit.Before import org.junit.Before
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import java.time.LocalDateTime.now import java.time.Instant
class LoginStudentSelectPresenterTest { class LoginStudentSelectPresenterTest {
@ -55,7 +49,7 @@ class LoginStudentSelectPresenterTest {
schoolSymbol = "", schoolSymbol = "",
classId = 1, classId = 1,
studentName = "", studentName = "",
registrationDate = now(), registrationDate = Instant.now(),
className = "", className = "",
loginMode = "", loginMode = "",
certificateKey = "", certificateKey = "",

View File

@ -1,14 +1,13 @@
package io.github.wulkanowy.utils package io.github.wulkanowy.utils
import org.junit.Assert.assertEquals import org.junit.Assert.*
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test import org.junit.Test
import java.time.Instant
import java.time.LocalDate.of import java.time.LocalDate.of
import java.time.LocalDateTime import java.time.LocalDateTime
import java.time.Month.JANUARY import java.time.Month.JANUARY
import java.time.ZoneOffset import java.time.ZoneOffset
import java.util.Locale import java.util.*
class TimeExtensionTest { class TimeExtensionTest {
@ -24,11 +23,15 @@ class TimeExtensionTest {
} }
@Test @Test
fun toFormattedStringLocalDateTimeTest() { fun toFormattedStringFromInstantTest() {
assertEquals("01.10.2018", LocalDateTime.of(2018, 10, 1, 10, 0, 0).toFormattedString()) assertEquals(
"01.10.2018",
LocalDateTime.of(2018, 10, 1, 10, 0, 0).toInstant(ZoneOffset.UTC).toFormattedString()
)
assertEquals( assertEquals(
"2018-10-01 10:00:00", "2018-10-01 10:00:00",
LocalDateTime.of(2018, 10, 1, 10, 0, 0).toFormattedString("uuuu-MM-dd HH:mm:ss") LocalDateTime.of(2018, 10, 1, 10, 0, 0).toInstant(ZoneOffset.UTC)
.toFormattedString("uuuu-MM-dd HH:mm:ss", ZoneOffset.UTC)
) )
} }
@ -228,16 +231,23 @@ class TimeExtensionTest {
} }
@Test @Test
fun getLocalDateToTimestampUTC() { fun getLocalDateToTimestamp() {
assertEquals(0L, of(1970, 1, 1).toTimestamp(ZoneOffset.UTC)) assertEquals(0L, of(1970, 1, 1).toTimestamp())
assertEquals(946684800000L, of(2000, 1, 1).toTimestamp(ZoneOffset.UTC)) assertEquals(946684800000L, of(2000, 1, 1).toTimestamp())
assertEquals(1640131200000L, of(2021, 12, 22).toTimestamp(ZoneOffset.UTC)) assertEquals(1640131200000L, of(2021, 12, 22).toTimestamp())
} }
@Test @Test
fun getLocalDateTimeToUtcTimestamp() { fun getLocalDateFromInstant() {
assertEquals(0L, LocalDateTime.of(1970, 1, 1, 0, 0, 0).toTimestamp(ZoneOffset.UTC)) assertEquals(of(1970, 1, 1), Instant.ofEpochMilli(0).toLocalDate())
assertEquals(946684800000L, LocalDateTime.of(2000, 1, 1, 0, 0, 0).toTimestamp(ZoneOffset.UTC)) assertEquals(of(2000, 1, 1), Instant.ofEpochMilli(946684800000).toLocalDate())
assertEquals(1640131200000L, LocalDateTime.of(2021, 12, 22, 0, 0, 0).toTimestamp(ZoneOffset.UTC)) assertEquals(of(2021, 12, 22), Instant.ofEpochMilli(1640131200000L).toLocalDate())
}
@Test
fun timestampToLocalDateTime() {
assertEquals(LocalDateTime.of(1970, 1, 1, 0, 0, 0), 0L.toLocalDateTime())
assertEquals(LocalDateTime.of(2000, 1, 1, 0, 0, 0), 946684800000.toLocalDateTime())
assertEquals(LocalDateTime.of(2021, 12, 22, 0, 0, 0), 1640131200000L.toLocalDateTime())
} }
} }

View File

@ -6,9 +6,8 @@ import org.junit.Assert.assertFalse
import org.junit.Assert.assertNotEquals import org.junit.Assert.assertNotEquals
import org.junit.Assert.assertTrue import org.junit.Assert.assertTrue
import org.junit.Test import org.junit.Test
import java.time.LocalDate import java.time.*
import java.time.LocalDateTime import java.time.Duration.ofMinutes
import java.time.LocalDateTime.now
class TimetableExtensionTest { class TimetableExtensionTest {
@ -17,52 +16,38 @@ class TimetableExtensionTest {
assertFalse(getTimetableEntity().isShowTimeUntil(null)) assertFalse(getTimetableEntity().isShowTimeUntil(null))
assertFalse(getTimetableEntity(isStudentPlan = false).isShowTimeUntil(null)) assertFalse(getTimetableEntity(isStudentPlan = false).isShowTimeUntil(null))
assertFalse(getTimetableEntity(isStudentPlan = true, canceled = true).isShowTimeUntil(null)) assertFalse(getTimetableEntity(isStudentPlan = true, canceled = true).isShowTimeUntil(null))
assertFalse(getTimetableEntity(isStudentPlan = true, canceled = false, start = now().minusSeconds(1)).isShowTimeUntil(null)) assertFalse(getTimetableEntity(isStudentPlan = true, canceled = false, start = Instant.now().minusSeconds(1)).isShowTimeUntil(null))
assertFalse(getTimetableEntity(isStudentPlan = true, canceled = false, start = now().plusMinutes(5)).isShowTimeUntil(now().plusMinutes(5))) assertFalse(getTimetableEntity(isStudentPlan = true, canceled = false, start = Instant.now().plus(ofMinutes(5))).isShowTimeUntil(Instant.now().plus(ofMinutes(5))))
assertFalse(getTimetableEntity(isStudentPlan = true, canceled = false, start = now().plusMinutes(61)).isShowTimeUntil(now().minusMinutes(5))) assertFalse(getTimetableEntity(isStudentPlan = true, canceled = false, start = Instant.now().plus(ofMinutes(61))).isShowTimeUntil(Instant.now().minus(ofMinutes(5))))
assertTrue(getTimetableEntity(isStudentPlan = true, canceled = false, start = now().plusMinutes(60)).isShowTimeUntil(now().minusMinutes(5))) assertTrue(getTimetableEntity(isStudentPlan = true, canceled = false, start = Instant.now().plus(ofMinutes(60))).isShowTimeUntil(Instant.now().minus(ofMinutes(5))))
assertTrue(getTimetableEntity(isStudentPlan = true, canceled = false, start = now().plusMinutes(60)).isShowTimeUntil(null)) assertTrue(getTimetableEntity(isStudentPlan = true, canceled = false, start = Instant.now().plus(ofMinutes(60))).isShowTimeUntil(null))
assertFalse(getTimetableEntity(isStudentPlan = true, canceled = false, start = now().minusSeconds(1)).isShowTimeUntil(null)) assertFalse(getTimetableEntity(isStudentPlan = true, canceled = false, start = Instant.now().minusSeconds(1)).isShowTimeUntil(null))
} }
@Test @Test
fun getLeft() { fun getLeft() {
assertEquals(null, getTimetableEntity(canceled = true).left) assertEquals(null, getTimetableEntity(canceled = true).left)
assertEquals(null, getTimetableEntity(start = now().plusMinutes(5), end = now().plusMinutes(50)).left) assertEquals(null, getTimetableEntity(start = Instant.now().plus(ofMinutes(5)), end = Instant.now().plus(ofMinutes(50))).left)
assertEquals(null, getTimetableEntity(start = now().minusMinutes(1), end = now().plusMinutes(44), isStudentPlan = false).left) assertEquals(null, getTimetableEntity(start = Instant.now().minus(ofMinutes(1)), end = Instant.now().plus(ofMinutes(44)), isStudentPlan = false).left)
assertNotEquals( assertNotEquals(null, getTimetableEntity(start = Instant.now().minus(ofMinutes(1)), end = Instant.now().plus(ofMinutes(44)), isStudentPlan = true).left)
null, assertNotEquals(null, getTimetableEntity(start = Instant.now(), end = Instant.now().plus(ofMinutes(45)), isStudentPlan = true).left)
getTimetableEntity(
start = now().minusMinutes(1),
end = now().plusMinutes(44),
isStudentPlan = true
).left
)
assertNotEquals(
null,
getTimetableEntity(
start = now(),
end = now().plusMinutes(45),
isStudentPlan = true
).left
)
} }
@Test @Test
fun isJustFinished() { fun isJustFinished() {
assertFalse(getTimetableEntity(end = now().minusSeconds(16)).isJustFinished) assertFalse(getTimetableEntity(end = Instant.now().minusSeconds(16)).isJustFinished)
assertTrue(getTimetableEntity(end = now().minusSeconds(14)).isJustFinished) assertTrue(getTimetableEntity(end = Instant.now().minusSeconds(14)).isJustFinished)
assertTrue(getTimetableEntity(end = now().minusSeconds(1)).isJustFinished) assertTrue(getTimetableEntity(end = Instant.now().minusSeconds(1)).isJustFinished)
assertFalse(getTimetableEntity(end = now().plusSeconds(1)).isJustFinished) assertFalse(getTimetableEntity(end = Instant.now().plusSeconds(1)).isJustFinished)
} }
private fun getTimetableEntity( private fun getTimetableEntity(
isStudentPlan: Boolean = false, isStudentPlan: Boolean = false,
canceled: Boolean = false, canceled: Boolean = false,
start: LocalDateTime = now(), start: Instant = Instant.now(),
end: LocalDateTime = now() end: Instant = Instant.now()
) = Timetable( ) = Timetable(
studentId = 0, studentId = 0,
subject = "", subject = "",