forked from github/wulkanowy-mirror
Add sending messages (#232)
This commit is contained in:

committed by
Rafał Borcz

parent
5ba12cf8c6
commit
c72c301039
@ -121,4 +121,12 @@ internal class RepositoryModule {
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideCompletedLessonsDao(database: AppDatabase) = database.completedLessonsDao
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideReportingUnitDao(database: AppDatabase) = database.reportingUnitDao
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideRecipientDao(database: AppDatabase) = database.recipientDao
|
||||
}
|
||||
|
@ -16,6 +16,8 @@ import io.github.wulkanowy.data.db.dao.HomeworkDao
|
||||
import io.github.wulkanowy.data.db.dao.LuckyNumberDao
|
||||
import io.github.wulkanowy.data.db.dao.MessagesDao
|
||||
import io.github.wulkanowy.data.db.dao.NoteDao
|
||||
import io.github.wulkanowy.data.db.dao.RecipientDao
|
||||
import io.github.wulkanowy.data.db.dao.ReportingUnitDao
|
||||
import io.github.wulkanowy.data.db.dao.SemesterDao
|
||||
import io.github.wulkanowy.data.db.dao.StudentDao
|
||||
import io.github.wulkanowy.data.db.dao.SubjectDao
|
||||
@ -30,6 +32,8 @@ import io.github.wulkanowy.data.db.entities.Homework
|
||||
import io.github.wulkanowy.data.db.entities.LuckyNumber
|
||||
import io.github.wulkanowy.data.db.entities.Message
|
||||
import io.github.wulkanowy.data.db.entities.Note
|
||||
import io.github.wulkanowy.data.db.entities.Recipient
|
||||
import io.github.wulkanowy.data.db.entities.ReportingUnit
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.db.entities.Subject
|
||||
@ -38,6 +42,7 @@ import io.github.wulkanowy.data.db.migrations.Migration2
|
||||
import io.github.wulkanowy.data.db.migrations.Migration3
|
||||
import io.github.wulkanowy.data.db.migrations.Migration4
|
||||
import io.github.wulkanowy.data.db.migrations.Migration5
|
||||
import io.github.wulkanowy.data.db.migrations.Migration6
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
@ -56,7 +61,9 @@ import javax.inject.Singleton
|
||||
Homework::class,
|
||||
Subject::class,
|
||||
LuckyNumber::class,
|
||||
CompletedLesson::class
|
||||
CompletedLesson::class,
|
||||
ReportingUnit::class,
|
||||
Recipient::class
|
||||
],
|
||||
version = AppDatabase.VERSION_SCHEMA,
|
||||
exportSchema = false
|
||||
@ -65,7 +72,7 @@ import javax.inject.Singleton
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
|
||||
companion object {
|
||||
const val VERSION_SCHEMA = 5
|
||||
const val VERSION_SCHEMA = 6
|
||||
|
||||
fun newInstance(context: Context): AppDatabase {
|
||||
return Room.databaseBuilder(context, AppDatabase::class.java, "wulkanowy_database")
|
||||
@ -76,7 +83,8 @@ abstract class AppDatabase : RoomDatabase() {
|
||||
Migration2(),
|
||||
Migration3(),
|
||||
Migration4(),
|
||||
Migration5()
|
||||
Migration5(),
|
||||
Migration6()
|
||||
)
|
||||
.build()
|
||||
}
|
||||
@ -109,4 +117,8 @@ abstract class AppDatabase : RoomDatabase() {
|
||||
abstract val luckyNumberDao: LuckyNumberDao
|
||||
|
||||
abstract val completedLessonsDao: CompletedLessonsDao
|
||||
|
||||
abstract val reportingUnitDao: ReportingUnitDao
|
||||
|
||||
abstract val recipientDao: RecipientDao
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ import org.threeten.bp.LocalDateTime
|
||||
import org.threeten.bp.Month
|
||||
import org.threeten.bp.ZoneOffset
|
||||
import java.util.Date
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
|
||||
class Converters {
|
||||
|
||||
@ -36,4 +38,14 @@ class Converters {
|
||||
|
||||
@TypeConverter
|
||||
fun intToMonth(value: Int?) = value?.let { Month.of(it) }
|
||||
|
||||
@TypeConverter
|
||||
fun intListToGson(list: List<Int>): String {
|
||||
return Gson().toJson(list)
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun gsonToIntList(value: String): List<Int> {
|
||||
return Gson().fromJson(value, object : TypeToken<List<Int>>() {}.type)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,23 @@
|
||||
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.Recipient
|
||||
import io.reactivex.Maybe
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
@Dao
|
||||
interface RecipientDao {
|
||||
|
||||
@Insert
|
||||
fun insertAll(messages: List<Recipient>)
|
||||
|
||||
@Delete
|
||||
fun deleteAll(messages: List<Recipient>)
|
||||
|
||||
@Query("SELECT * FROM Recipients WHERE student_id = :studentId AND role = :role AND unit_id = :unitId")
|
||||
fun load(studentId: Int, role: Int, unitId: Int): Maybe<List<Recipient>>
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
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.ReportingUnit
|
||||
import io.reactivex.Maybe
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
@Dao
|
||||
interface ReportingUnitDao {
|
||||
|
||||
@Insert
|
||||
fun insertAll(reportingUnits: List<ReportingUnit>)
|
||||
|
||||
@Delete
|
||||
fun deleteAll(reportingUnits: List<ReportingUnit>)
|
||||
|
||||
@Query("SELECT * FROM ReportingUnits WHERE student_id = :studentId")
|
||||
fun load(studentId: Int): Maybe<List<ReportingUnit>>
|
||||
|
||||
@Query("SELECT * FROM ReportingUnits WHERE student_id = :studentId AND real_id = :unitId")
|
||||
fun loadOne(studentId: Int, unitId: Int): Maybe<ReportingUnit>
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package io.github.wulkanowy.data.db.entities
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import java.io.Serializable
|
||||
|
||||
@Entity(tableName = "Recipients")
|
||||
data class Recipient(
|
||||
|
||||
@ColumnInfo(name = "student_id")
|
||||
val studentId: Int,
|
||||
|
||||
@ColumnInfo(name = "real_id")
|
||||
val realId: String,
|
||||
|
||||
val name: String,
|
||||
|
||||
@ColumnInfo(name = "real_name")
|
||||
val realName: String,
|
||||
|
||||
@ColumnInfo(name = "login_id")
|
||||
val loginId: Int,
|
||||
|
||||
@ColumnInfo(name = "unit_id")
|
||||
val unitId: Int,
|
||||
|
||||
val role: Int,
|
||||
|
||||
val hash: String
|
||||
|
||||
) : Serializable {
|
||||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Long = 0
|
||||
|
||||
override fun toString() = name
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package io.github.wulkanowy.data.db.entities
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import java.io.Serializable
|
||||
|
||||
@Entity(tableName = "ReportingUnits")
|
||||
data class ReportingUnit(
|
||||
|
||||
@ColumnInfo(name = "student_id")
|
||||
val studentId: Int,
|
||||
|
||||
@ColumnInfo(name = "real_id")
|
||||
val realId: Int,
|
||||
|
||||
@ColumnInfo(name = "short")
|
||||
val shortName: String,
|
||||
|
||||
@ColumnInfo(name = "sender_id")
|
||||
val senderId: Int,
|
||||
|
||||
@ColumnInfo(name = "sender_name")
|
||||
val senderName: String,
|
||||
|
||||
val roles: List<Int>
|
||||
|
||||
) : Serializable {
|
||||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Long = 0
|
||||
}
|
@ -24,7 +24,13 @@ data class Semester(
|
||||
val semesterName: Int,
|
||||
|
||||
@ColumnInfo(name = "is_current")
|
||||
val isCurrent: Boolean
|
||||
val isCurrent: Boolean,
|
||||
|
||||
@ColumnInfo(name = "class_id")
|
||||
val classId: Int,
|
||||
|
||||
@ColumnInfo(name = "unit_id")
|
||||
val unitId: Int
|
||||
) {
|
||||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
|
@ -0,0 +1,33 @@
|
||||
package io.github.wulkanowy.data.db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
class Migration6 : Migration(5, 6) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("CREATE TABLE ReportingUnits (" +
|
||||
"id INTEGER NOT NULL PRIMARY KEY," +
|
||||
"student_id INTEGER NOT NULL," +
|
||||
"real_id INTEGER NOT NULL," +
|
||||
"short TEXT NOT NULL," +
|
||||
"sender_id INTEGER NOT NULL," +
|
||||
"sender_name TEXT NOT NULL," +
|
||||
"roles TEXT NOT NULL)")
|
||||
|
||||
database.execSQL("CREATE TABLE Recipients (" +
|
||||
"id INTEGER NOT NULL PRIMARY KEY," +
|
||||
"student_id INTEGER NOT NULL," +
|
||||
"real_id TEXT NOT NULL," +
|
||||
"name TEXT NOT NULL," +
|
||||
"real_name TEXT NOT NULL," +
|
||||
"login_id INTEGER NOT NULL," +
|
||||
"unit_id INTEGER NOT NULL," +
|
||||
"role INTEGER NOT NULL," +
|
||||
"hash TEXT NOT NULL)")
|
||||
|
||||
database.execSQL("DELETE FROM Semesters WHERE 1")
|
||||
database.execSQL("ALTER TABLE Semesters ADD COLUMN class_id INTEGER DEFAULT 0 NOT NULL")
|
||||
database.execSQL("ALTER TABLE Semesters ADD COLUMN unit_id INTEGER DEFAULT 0 NOT NULL")
|
||||
}
|
||||
}
|
@ -2,13 +2,16 @@ package io.github.wulkanowy.data.repositories.message
|
||||
|
||||
import io.github.wulkanowy.api.Api
|
||||
import io.github.wulkanowy.api.messages.Folder
|
||||
import io.github.wulkanowy.api.messages.SentMessage
|
||||
import io.github.wulkanowy.data.db.entities.Message
|
||||
import io.github.wulkanowy.data.db.entities.Recipient
|
||||
import io.github.wulkanowy.utils.toLocalDateTime
|
||||
import io.reactivex.Single
|
||||
import org.threeten.bp.LocalDateTime.now
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import io.github.wulkanowy.api.messages.Message as ApiMessage
|
||||
import io.github.wulkanowy.api.messages.Recipient as ApiRecipient
|
||||
|
||||
@Singleton
|
||||
class MessageRemote @Inject constructor(private val api: Api) {
|
||||
@ -39,4 +42,21 @@ class MessageRemote @Inject constructor(private val api: Api) {
|
||||
fun getMessagesContent(message: Message, markAsRead: Boolean = false): Single<String> {
|
||||
return api.getMessageContent(message.messageId, message.folderId, markAsRead, message.realId)
|
||||
}
|
||||
|
||||
fun sendMessage(subject: String, content: String, recipients: List<Recipient>): Single<SentMessage> {
|
||||
return api.sendMessage(
|
||||
subject = subject,
|
||||
content = content,
|
||||
recipients = recipients.map {
|
||||
ApiRecipient(
|
||||
id = it.realId,
|
||||
realName = it.realName,
|
||||
loginId = it.loginId,
|
||||
reportingUnitId = it.unitId,
|
||||
role = it.role,
|
||||
hash = it.hash
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,10 @@ package io.github.wulkanowy.data.repositories.message
|
||||
|
||||
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
|
||||
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
||||
import io.github.wulkanowy.api.messages.SentMessage
|
||||
import io.github.wulkanowy.data.ApiHelper
|
||||
import io.github.wulkanowy.data.db.entities.Message
|
||||
import io.github.wulkanowy.data.db.entities.Recipient
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.Single
|
||||
@ -82,4 +84,8 @@ class MessageRepository @Inject constructor(
|
||||
fun updateMessages(messages: List<Message>): Completable {
|
||||
return Completable.fromCallable { local.updateMessages(messages) }
|
||||
}
|
||||
|
||||
fun sendMessage(subject: String, content: String, recipients: List<Recipient>): Single<SentMessage> {
|
||||
return remote.sendMessage(subject, content, recipients)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,25 @@
|
||||
package io.github.wulkanowy.data.repositories.recipient
|
||||
|
||||
import io.github.wulkanowy.data.db.dao.RecipientDao
|
||||
import io.github.wulkanowy.data.db.entities.Recipient
|
||||
import io.github.wulkanowy.data.db.entities.ReportingUnit
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.reactivex.Maybe
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class RecipientLocal @Inject constructor(private val recipientDb: RecipientDao) {
|
||||
|
||||
fun getRecipients(student: Student, role: Int, unit: ReportingUnit): Maybe<List<Recipient>> {
|
||||
return recipientDb.load(student.studentId, role, unit.realId).filter { !it.isEmpty() }
|
||||
}
|
||||
|
||||
fun saveRecipients(recipients: List<Recipient>) {
|
||||
return recipientDb.insertAll(recipients)
|
||||
}
|
||||
|
||||
fun deleteRecipients(recipients: List<Recipient>) {
|
||||
recipientDb.deleteAll(recipients)
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package io.github.wulkanowy.data.repositories.recipient
|
||||
|
||||
import io.github.wulkanowy.api.Api
|
||||
import io.github.wulkanowy.data.db.entities.Recipient
|
||||
import io.github.wulkanowy.data.db.entities.ReportingUnit
|
||||
import io.reactivex.Single
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class RecipientRemote @Inject constructor(private val api: Api) {
|
||||
|
||||
fun getRecipients(role: Int, unit: ReportingUnit): Single<List<Recipient>> {
|
||||
return api.getRecipients(role, unit.realId)
|
||||
.map { recipients ->
|
||||
recipients.map {
|
||||
Recipient(
|
||||
studentId = api.studentId,
|
||||
name = it.name,
|
||||
realName = it.realName,
|
||||
realId = it.id,
|
||||
hash = it.hash,
|
||||
loginId = it.loginId,
|
||||
role = it.role,
|
||||
unitId = it.reportingUnitId
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package io.github.wulkanowy.data.repositories.recipient
|
||||
|
||||
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
|
||||
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
||||
import io.github.wulkanowy.data.ApiHelper
|
||||
import io.github.wulkanowy.data.db.entities.Recipient
|
||||
import io.github.wulkanowy.data.db.entities.ReportingUnit
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.reactivex.Single
|
||||
import java.net.UnknownHostException
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class RecipientRepository @Inject constructor(
|
||||
private val settings: InternetObservingSettings,
|
||||
private val local: RecipientLocal,
|
||||
private val remote: RecipientRemote,
|
||||
private val apiHelper: ApiHelper
|
||||
) {
|
||||
|
||||
fun getRecipients(student: Student, role: Int, unit: ReportingUnit, forceRefresh: Boolean = false): Single<List<Recipient>> {
|
||||
return Single.just(apiHelper.initApi(student))
|
||||
.flatMap { _ ->
|
||||
local.getRecipients(student, role, unit).filter { !forceRefresh }
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) remote.getRecipients(role, unit)
|
||||
else Single.error(UnknownHostException())
|
||||
}.flatMap { new ->
|
||||
local.getRecipients(student, role, unit).toSingle(emptyList())
|
||||
.doOnSuccess { old ->
|
||||
local.deleteRecipients(old - new)
|
||||
local.saveRecipients(new - old)
|
||||
}
|
||||
}.flatMap {
|
||||
local.getRecipients(student, role, unit).toSingle(emptyList())
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package io.github.wulkanowy.data.repositories.reportingunit
|
||||
|
||||
import io.github.wulkanowy.data.db.dao.ReportingUnitDao
|
||||
import io.github.wulkanowy.data.db.entities.ReportingUnit
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.reactivex.Maybe
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class ReportingUnitLocal @Inject constructor(private val reportingUnitDb: ReportingUnitDao) {
|
||||
|
||||
fun getReportingUnits(student: Student): Maybe<List<ReportingUnit>> {
|
||||
return reportingUnitDb.load(student.studentId).filter { !it.isEmpty() }
|
||||
}
|
||||
|
||||
fun getReportingUnit(student: Student, unitId: Int): Maybe<ReportingUnit> {
|
||||
return reportingUnitDb.loadOne(student.studentId, unitId)
|
||||
}
|
||||
|
||||
fun saveReportingUnits(reportingUnits: List<ReportingUnit>) {
|
||||
return reportingUnitDb.insertAll(reportingUnits)
|
||||
}
|
||||
|
||||
fun deleteReportingUnits(reportingUnits: List<ReportingUnit>) {
|
||||
reportingUnitDb.deleteAll(reportingUnits)
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package io.github.wulkanowy.data.repositories.reportingunit
|
||||
|
||||
import io.github.wulkanowy.api.Api
|
||||
import io.github.wulkanowy.data.db.entities.ReportingUnit
|
||||
import io.reactivex.Single
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class ReportingUnitRemote @Inject constructor(private val api: Api) {
|
||||
|
||||
fun getReportingUnits(): Single<List<ReportingUnit>> {
|
||||
return api.getReportingUnits().map {
|
||||
it.map { unit ->
|
||||
ReportingUnit(
|
||||
studentId = api.studentId,
|
||||
realId = unit.id,
|
||||
roles = unit.roles,
|
||||
senderId = unit.senderId,
|
||||
senderName = unit.senderName,
|
||||
shortName = unit.short
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package io.github.wulkanowy.data.repositories.reportingunit
|
||||
|
||||
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
|
||||
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
||||
import io.github.wulkanowy.data.ApiHelper
|
||||
import io.github.wulkanowy.data.db.entities.ReportingUnit
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.reactivex.Maybe
|
||||
import io.reactivex.Single
|
||||
import java.net.UnknownHostException
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class ReportingUnitRepository @Inject constructor(
|
||||
private val settings: InternetObservingSettings,
|
||||
private val local: ReportingUnitLocal,
|
||||
private val remote: ReportingUnitRemote,
|
||||
private val apiHelper: ApiHelper
|
||||
) {
|
||||
|
||||
fun getReportingUnits(student: Student, forceRefresh: Boolean = false): Single<List<ReportingUnit>> {
|
||||
return Single.just(apiHelper.initApi(student))
|
||||
.flatMap { _ ->
|
||||
local.getReportingUnits(student).filter { !forceRefresh }
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) remote.getReportingUnits()
|
||||
else Single.error(UnknownHostException())
|
||||
}.flatMap { new ->
|
||||
local.getReportingUnits(student).toSingle(emptyList())
|
||||
.doOnSuccess { old ->
|
||||
local.deleteReportingUnits(old - new)
|
||||
local.saveReportingUnits(new - old)
|
||||
}
|
||||
}.flatMap { local.getReportingUnits(student).toSingle(emptyList()) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun getReportingUnit(student: Student, unitId: Int): Maybe<ReportingUnit> {
|
||||
return Maybe.just(apiHelper.initApi(student))
|
||||
.flatMap { _ ->
|
||||
local.getReportingUnit(student, unitId)
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) getReportingUnits(student, true)
|
||||
else Single.error(UnknownHostException())
|
||||
}.flatMapMaybe {
|
||||
local.getReportingUnit(student, unitId)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -19,7 +19,9 @@ class SemesterRemote @Inject constructor(private val api: Api) {
|
||||
diaryName = semester.diaryName,
|
||||
semesterId = semester.semesterId,
|
||||
semesterName = semester.semesterNumber,
|
||||
isCurrent = semester.current
|
||||
isCurrent = semester.current,
|
||||
classId = semester.classId,
|
||||
unitId = semester.unitId
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,8 @@ import io.github.wulkanowy.data.repositories.message.MessageRepository
|
||||
import io.github.wulkanowy.data.repositories.message.MessageRepository.MessageFolder.RECEIVED
|
||||
import io.github.wulkanowy.data.repositories.note.NoteRepository
|
||||
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
|
||||
import io.github.wulkanowy.data.repositories.recipient.RecipientRepository
|
||||
import io.github.wulkanowy.data.repositories.reportingunit.ReportingUnitRepository
|
||||
import io.github.wulkanowy.data.repositories.semester.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||
import io.github.wulkanowy.data.repositories.timetable.TimetableRepository
|
||||
@ -26,6 +28,7 @@ import io.github.wulkanowy.utils.isHolidays
|
||||
import io.github.wulkanowy.utils.monday
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.Maybe
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import org.threeten.bp.LocalDate
|
||||
import timber.log.Timber
|
||||
@ -69,6 +72,12 @@ class SyncWorker : SimpleJobService() {
|
||||
@Inject
|
||||
lateinit var completedLessons: CompletedLessonsRepository
|
||||
|
||||
@Inject
|
||||
lateinit var reportingUnitRepository: ReportingUnitRepository
|
||||
|
||||
@Inject
|
||||
lateinit var recipientRepository: RecipientRepository
|
||||
|
||||
@Inject
|
||||
lateinit var prefRepository: PreferencesRepository
|
||||
|
||||
@ -98,21 +107,24 @@ class SyncWorker : SimpleJobService() {
|
||||
disposable.add(student.isStudentSaved()
|
||||
.flatMapMaybe { if (it) student.getCurrentStudent().toMaybe() else Maybe.empty() }
|
||||
.flatMap { semester.getCurrentSemester(it, true).map { semester -> semester to it }.toMaybe() }
|
||||
.flatMapCompletable {
|
||||
.flatMapCompletable { c ->
|
||||
Completable.merge(
|
||||
listOf(
|
||||
gradesDetails.getGrades(it.second, it.first, true, notify).ignoreElement(),
|
||||
gradesSummary.getGradesSummary(it.first, true).ignoreElement(),
|
||||
attendance.getAttendance(it.first, start, end, true).ignoreElement(),
|
||||
exam.getExams(it.first, start, end, true).ignoreElement(),
|
||||
timetable.getTimetable(it.first, start, end, true).ignoreElement(),
|
||||
message.getMessages(it.second, RECEIVED, true, notify).ignoreElement(),
|
||||
note.getNotes(it.second, it.first, true, notify).ignoreElement(),
|
||||
homework.getHomework(it.first, LocalDate.now(), true).ignoreElement(),
|
||||
homework.getHomework(it.first, LocalDate.now().plusDays(1), true).ignoreElement(),
|
||||
luckyNumber.getLuckyNumber(it.first, true, notify).ignoreElement(),
|
||||
completedLessons.getCompletedLessons(it.first, start, end, true).ignoreElement()
|
||||
)
|
||||
gradesDetails.getGrades(c.second, c.first, true, notify).ignoreElement(),
|
||||
gradesSummary.getGradesSummary(c.first, true).ignoreElement(),
|
||||
attendance.getAttendance(c.first, start, end, true).ignoreElement(),
|
||||
exam.getExams(c.first, start, end, true).ignoreElement(),
|
||||
timetable.getTimetable(c.first, start, end, true).ignoreElement(),
|
||||
message.getMessages(c.second, RECEIVED, true, notify).ignoreElement(),
|
||||
note.getNotes(c.second, c.first, true, notify).ignoreElement(),
|
||||
homework.getHomework(c.first, LocalDate.now(), true).ignoreElement(),
|
||||
homework.getHomework(c.first, LocalDate.now().plusDays(1), true).ignoreElement(),
|
||||
luckyNumber.getLuckyNumber(c.first, true, notify).ignoreElement(),
|
||||
completedLessons.getCompletedLessons(c.first, start, end, true).ignoreElement()
|
||||
) + reportingUnitRepository.getReportingUnits(c.second, true)
|
||||
.flatMapPublisher { reportingUnits ->
|
||||
Single.merge(reportingUnits.map { recipientRepository.getRecipients(c.second, 2, it, true) })
|
||||
}.ignoreElements()
|
||||
)
|
||||
}
|
||||
.subscribe({}, { error = it }))
|
||||
|
@ -20,6 +20,7 @@ import io.github.wulkanowy.ui.modules.luckynumber.LuckyNumberFragment
|
||||
import io.github.wulkanowy.ui.modules.message.MessageFragment
|
||||
import io.github.wulkanowy.ui.modules.message.MessageModule
|
||||
import io.github.wulkanowy.ui.modules.message.preview.MessagePreviewFragment
|
||||
import io.github.wulkanowy.ui.modules.message.send.SendMessageFragment
|
||||
import io.github.wulkanowy.ui.modules.more.MoreFragment
|
||||
import io.github.wulkanowy.ui.modules.note.NoteFragment
|
||||
import io.github.wulkanowy.ui.modules.settings.SettingsFragment
|
||||
@ -94,9 +95,13 @@ abstract class MainModule {
|
||||
|
||||
@PerFragment
|
||||
@ContributesAndroidInjector
|
||||
abstract fun bindAccountDialog(): AccountDialog
|
||||
abstract fun bindCompletedLessonsFragment(): CompletedLessonsFragment
|
||||
|
||||
@PerFragment
|
||||
@ContributesAndroidInjector
|
||||
abstract fun bindCompletedLessonsFragment(): CompletedLessonsFragment
|
||||
abstract fun bindSendMessageFragment(): SendMessageFragment
|
||||
|
||||
@PerFragment
|
||||
@ContributesAndroidInjector
|
||||
abstract fun bindAccountDialog(): AccountDialog
|
||||
}
|
||||
|
@ -12,7 +12,9 @@ import io.github.wulkanowy.data.repositories.message.MessageRepository.MessageFo
|
||||
import io.github.wulkanowy.data.repositories.message.MessageRepository.MessageFolder.TRASHED
|
||||
import io.github.wulkanowy.ui.base.BaseFragment
|
||||
import io.github.wulkanowy.ui.base.BaseFragmentPagerAdapter
|
||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||
import io.github.wulkanowy.ui.modules.main.MainView
|
||||
import io.github.wulkanowy.ui.modules.message.send.SendMessageFragment
|
||||
import io.github.wulkanowy.ui.modules.message.tab.MessageTabFragment
|
||||
import io.github.wulkanowy.utils.setOnSelectPageListener
|
||||
import kotlinx.android.synthetic.main.fragment_message.*
|
||||
@ -61,6 +63,8 @@ class MessageFragment : BaseFragment(), MessageView, MainView.TitledView {
|
||||
setOnSelectPageListener { presenter.onPageSelected(it) }
|
||||
}
|
||||
messageTabLayout.setupWithViewPager(messageViewPager)
|
||||
|
||||
openSendMessageButton.setOnClickListener { presenter.onSendMessageButtonClicked() }
|
||||
}
|
||||
|
||||
override fun showContent(show: Boolean) {
|
||||
@ -80,6 +84,10 @@ class MessageFragment : BaseFragment(), MessageView, MainView.TitledView {
|
||||
(pagerAdapter.getFragmentInstance(index) as? MessageView.MessageChildView)?.onParentLoadData(forceRefresh)
|
||||
}
|
||||
|
||||
override fun openSendMessage() {
|
||||
(activity as? MainActivity)?.pushView(SendMessageFragment.newInstance())
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
presenter.onDetachView()
|
||||
super.onDestroyView()
|
||||
|
@ -42,4 +42,8 @@ class MessagePresenter @Inject constructor(
|
||||
showProgress(false)
|
||||
}
|
||||
}
|
||||
|
||||
fun onSendMessageButtonClicked() {
|
||||
view?.openSendMessage()
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,8 @@ interface MessageView : BaseView {
|
||||
|
||||
fun notifyChildLoadData(index: Int, forceRefresh: Boolean)
|
||||
|
||||
fun openSendMessage()
|
||||
|
||||
interface MessageChildView {
|
||||
|
||||
fun onParentLoadData(forceRefresh: Boolean)
|
||||
|
@ -0,0 +1,154 @@
|
||||
package io.github.wulkanowy.ui.modules.message.send
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.Toast
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.hootsuite.nachos.ChipConfiguration
|
||||
import com.hootsuite.nachos.chip.ChipSpan
|
||||
import com.hootsuite.nachos.chip.ChipSpanChipCreator
|
||||
import com.hootsuite.nachos.tokenizer.SpanChipTokenizer
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.Recipient
|
||||
import io.github.wulkanowy.data.db.entities.ReportingUnit
|
||||
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.hideSoftInput
|
||||
import io.github.wulkanowy.utils.setOnTextChangedListener
|
||||
import kotlinx.android.synthetic.main.activity_main.*
|
||||
import kotlinx.android.synthetic.main.fragment_send_message.*
|
||||
import javax.inject.Inject
|
||||
|
||||
class SendMessageFragment : BaseSessionFragment(), SendMessageView, MainView.TitledView {
|
||||
|
||||
@Inject
|
||||
lateinit var presenter: SendMessagePresenter
|
||||
|
||||
private var recipients: List<Recipient> = emptyList()
|
||||
|
||||
private lateinit var recipientsAdapter: ArrayAdapter<Recipient>
|
||||
|
||||
companion object {
|
||||
fun newInstance() = SendMessageFragment()
|
||||
}
|
||||
|
||||
override val titleStringId: Int
|
||||
get() = R.string.send_message_title
|
||||
|
||||
override val formRecipientsData: List<Recipient>
|
||||
get() = sendMessageRecipientInput.allChips.map { it.data as Recipient }
|
||||
|
||||
override val formSubjectValue: String
|
||||
get() = sendMessageSubjectInput.text.toString()
|
||||
|
||||
override val formContentValue: String
|
||||
get() = sendMessageContentInput.text.toString()
|
||||
|
||||
override val messageRequiredRecipients: String
|
||||
get() = getString(R.string.send_message_required_recipients)
|
||||
|
||||
override val messageContentMinLength: String
|
||||
get() = getString(R.string.send_message_content_min_length)
|
||||
|
||||
override val messageSuccess: String
|
||||
get() = getString(R.string.send_message_successful)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setHasOptionsMenu(true)
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.fragment_send_message, container, false)
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
presenter.onAttachView(this)
|
||||
}
|
||||
|
||||
override fun initView() {
|
||||
context?.let {
|
||||
sendMessageRecipientInput.chipTokenizer = SpanChipTokenizer<ChipSpan>(it, object : ChipSpanChipCreator() {
|
||||
override fun createChip(context: Context, text: CharSequence, data: Any?): ChipSpan {
|
||||
return ChipSpan(context, text, ContextCompat.getDrawable(context, R.drawable.ic_all_account_24dp), data)
|
||||
}
|
||||
|
||||
override fun configureChip(chip: ChipSpan, chipConfiguration: ChipConfiguration) {
|
||||
super.configureChip(chip, chipConfiguration)
|
||||
chip.setShowIconOnLeft(true)
|
||||
}
|
||||
}, ChipSpan::class.java)
|
||||
recipientsAdapter = ArrayAdapter(it, android.R.layout.simple_dropdown_item_1line)
|
||||
}
|
||||
|
||||
sendMessageRecipientInput.setAdapter(recipientsAdapter)
|
||||
sendMessageRecipientInput.setOnTextChangedListener { presenter.onTypingRecipients() }
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
|
||||
inflater?.inflate(R.menu.action_menu_send_message, menu)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
|
||||
return if (item?.itemId == R.id.sendMessageMenuSend) presenter.onSend()
|
||||
else false
|
||||
}
|
||||
|
||||
override fun setReportingUnit(unit: ReportingUnit) {
|
||||
sendMessageFromTextView.setText(unit.senderName)
|
||||
}
|
||||
|
||||
override fun setRecipients(recipients: List<Recipient>) {
|
||||
this.recipients = recipients
|
||||
}
|
||||
|
||||
override fun refreshRecipientsAdapter() {
|
||||
recipientsAdapter.run {
|
||||
clear()
|
||||
addAll(recipients - sendMessageRecipientInput.allChips.map { it.data as Recipient })
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
override fun showProgress(show: Boolean) {
|
||||
sendMessageProgress.visibility = if (show) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
override fun showContent(show: Boolean) {
|
||||
sendMessageContent.visibility = if (show) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
override fun showEmpty(show: Boolean) {
|
||||
sendMessageEmpty.visibility = if (show) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
override fun popView() {
|
||||
(activity as? MainActivity)?.popView()
|
||||
}
|
||||
|
||||
override fun hideSoftInput() {
|
||||
activity?.hideSoftInput()
|
||||
}
|
||||
|
||||
override fun showBottomNav(show: Boolean) {
|
||||
(activity as? MainActivity)?.mainBottomNav?.visibility = if (show) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
override fun showMessage(text: String) {
|
||||
Toast.makeText(context, text, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
presenter.onDetachView()
|
||||
}
|
||||
}
|
@ -0,0 +1,137 @@
|
||||
package io.github.wulkanowy.ui.modules.message.send
|
||||
|
||||
import io.github.wulkanowy.data.db.entities.Recipient
|
||||
import io.github.wulkanowy.data.db.entities.ReportingUnit
|
||||
import io.github.wulkanowy.data.repositories.message.MessageRepository
|
||||
import io.github.wulkanowy.data.repositories.recipient.RecipientRepository
|
||||
import io.github.wulkanowy.data.repositories.reportingunit.ReportingUnitRepository
|
||||
import io.github.wulkanowy.data.repositories.semester.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.session.BaseSessionPresenter
|
||||
import io.github.wulkanowy.ui.base.session.SessionErrorHandler
|
||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||
import io.github.wulkanowy.utils.SchedulersProvider
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
class SendMessagePresenter @Inject constructor(
|
||||
private val errorHandler: SessionErrorHandler,
|
||||
private val schedulers: SchedulersProvider,
|
||||
private val studentRepository: StudentRepository,
|
||||
private val semesterRepository: SemesterRepository,
|
||||
private val messageRepository: MessageRepository,
|
||||
private val reportingUnitRepository: ReportingUnitRepository,
|
||||
private val recipientRepository: RecipientRepository,
|
||||
private val analytics: FirebaseAnalyticsHelper
|
||||
) : BaseSessionPresenter<SendMessageView>(errorHandler) {
|
||||
|
||||
private lateinit var reportingUnit: ReportingUnit
|
||||
|
||||
override fun onAttachView(view: SendMessageView) {
|
||||
Timber.i("Send message view is attached")
|
||||
super.onAttachView(view)
|
||||
view.run {
|
||||
initView()
|
||||
showBottomNav(false)
|
||||
}
|
||||
loadRecipients()
|
||||
}
|
||||
|
||||
private fun loadRecipients() {
|
||||
Timber.i("Loading recipients started")
|
||||
disposable.add(studentRepository.getCurrentStudent()
|
||||
.flatMapMaybe { student ->
|
||||
semesterRepository.getCurrentSemester(student)
|
||||
.flatMapMaybe { reportingUnitRepository.getReportingUnit(student, it.unitId) }
|
||||
.doOnSuccess { reportingUnit = it }
|
||||
.flatMap { recipientRepository.getRecipients(student, 2, it).toMaybe() }
|
||||
}
|
||||
.subscribeOn(schedulers.backgroundThread)
|
||||
.observeOn(schedulers.mainThread)
|
||||
.doOnSubscribe {
|
||||
view?.run {
|
||||
showProgress(true)
|
||||
showContent(false)
|
||||
}
|
||||
}
|
||||
.doFinally {
|
||||
view?.run {
|
||||
showProgress(false)
|
||||
}
|
||||
}
|
||||
.subscribe({
|
||||
view?.apply {
|
||||
setReportingUnit(reportingUnit)
|
||||
setRecipients(it)
|
||||
refreshRecipientsAdapter()
|
||||
showContent(true)
|
||||
}
|
||||
Timber.i("Loading recipients result: Success, fetched %s recipients", it.size.toString())
|
||||
}, {
|
||||
Timber.i("Loading recipients result: An exception occurred")
|
||||
view?.showContent(true)
|
||||
errorHandler.dispatch(it)
|
||||
}, {
|
||||
Timber.i("Loading recipients result: Can't find the reporting unit")
|
||||
view?.showEmpty(true)
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
private fun sendMessage(subject: String, content: String, recipients: List<Recipient>) {
|
||||
Timber.i("Sending message started")
|
||||
disposable.add(messageRepository.sendMessage(subject, content, recipients)
|
||||
.subscribeOn(schedulers.backgroundThread)
|
||||
.observeOn(schedulers.mainThread)
|
||||
.doOnSubscribe {
|
||||
view?.run {
|
||||
hideSoftInput()
|
||||
showContent(false)
|
||||
showProgress(true)
|
||||
}
|
||||
}
|
||||
.doFinally {
|
||||
view?.showProgress(false)
|
||||
}
|
||||
.subscribe({
|
||||
Timber.i("Sending message result: Success")
|
||||
analytics.logEvent("send_message", "recipients" to recipients.size)
|
||||
view?.run {
|
||||
showMessage(messageSuccess)
|
||||
popView()
|
||||
}
|
||||
}, {
|
||||
Timber.i("Sending message result: An exception occurred")
|
||||
view?.showContent(true)
|
||||
errorHandler.dispatch(it)
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
fun onTypingRecipients() {
|
||||
view?.refreshRecipientsAdapter()
|
||||
}
|
||||
|
||||
fun onSend(): Boolean {
|
||||
view?.run {
|
||||
when {
|
||||
formRecipientsData.isEmpty() -> showMessage(messageRequiredRecipients)
|
||||
formContentValue.length < 3 -> showMessage(messageContentMinLength)
|
||||
else -> {
|
||||
sendMessage(
|
||||
subject = formSubjectValue,
|
||||
content = formContentValue,
|
||||
recipients = formRecipientsData
|
||||
)
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onDetachView() {
|
||||
view?.showBottomNav(true)
|
||||
super.onDetachView()
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package io.github.wulkanowy.ui.modules.message.send
|
||||
|
||||
import io.github.wulkanowy.data.db.entities.Recipient
|
||||
import io.github.wulkanowy.data.db.entities.ReportingUnit
|
||||
import io.github.wulkanowy.ui.base.session.BaseSessionView
|
||||
|
||||
interface SendMessageView : BaseSessionView {
|
||||
|
||||
val formRecipientsData: List<Recipient>
|
||||
|
||||
val formSubjectValue: String
|
||||
|
||||
val formContentValue: String
|
||||
|
||||
val messageRequiredRecipients: String
|
||||
|
||||
val messageContentMinLength: String
|
||||
|
||||
val messageSuccess: String
|
||||
|
||||
fun initView()
|
||||
|
||||
fun setReportingUnit(unit: ReportingUnit)
|
||||
|
||||
fun setRecipients(recipients: List<Recipient>)
|
||||
|
||||
fun refreshRecipientsAdapter()
|
||||
|
||||
fun showProgress(show: Boolean)
|
||||
|
||||
fun showContent(show: Boolean)
|
||||
|
||||
fun showEmpty(show: Boolean)
|
||||
|
||||
fun popView()
|
||||
|
||||
fun hideSoftInput()
|
||||
|
||||
fun showBottomNav(show: Boolean)
|
||||
}
|
Reference in New Issue
Block a user