forked from github/wulkanowy-mirror
Add lucky numbers (#216)
This commit is contained in:
parent
d3c13b8fc3
commit
4da812af39
@ -41,7 +41,7 @@ before_script:
|
||||
- "curl -H 'Cache-Control: no-cache' https://raw.githubusercontent.com/fossas/fossa-cli/master/install.sh | sudo bash"
|
||||
|
||||
script:
|
||||
- ./gradlew build -x test -x lint -x fabricGenerateResourcesRelease -x packageRelease --stacktrace --daemon
|
||||
- ./gradlew dependencies --stacktrace --daemon
|
||||
- fossa --no-ansi || true
|
||||
- ./gradlew lint -x fabricGenerateResourcesRelease --stacktrace --daemon
|
||||
- ./gradlew test -x fabricGenerateResourcesRelease --stacktrace --daemon
|
||||
|
@ -0,0 +1,47 @@
|
||||
package io.github.wulkanowy.data.repositories.local
|
||||
|
||||
import androidx.room.Room
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import io.github.wulkanowy.data.db.AppDatabase
|
||||
import io.github.wulkanowy.data.db.entities.LuckyNumber
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.threeten.bp.LocalDate
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class LuckyNumberLocalTest {
|
||||
|
||||
private lateinit var luckyNumberLocal: LuckyNumberLocal
|
||||
|
||||
private lateinit var testDb: AppDatabase
|
||||
|
||||
@Before
|
||||
fun createDb() {
|
||||
testDb = Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java)
|
||||
.build()
|
||||
luckyNumberLocal = LuckyNumberLocal(testDb.luckyNumberDao)
|
||||
}
|
||||
|
||||
@After
|
||||
fun closeDb() {
|
||||
testDb.close()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun saveAndReadTest() {
|
||||
luckyNumberLocal.saveLuckyNumber(LuckyNumber(1, LocalDate.of(2019, 1, 20), 14))
|
||||
|
||||
val luckyNumber = luckyNumberLocal.getLuckyNumber(Semester(1, 1, 2, "", 3, 1),
|
||||
LocalDate.of(2019, 1, 20)
|
||||
).blockingGet()
|
||||
|
||||
assertEquals(1, luckyNumber.studentId)
|
||||
assertEquals(LocalDate.of(2019, 1, 20), luckyNumber.date)
|
||||
assertEquals(14, luckyNumber.luckyNumber)
|
||||
}
|
||||
}
|
@ -113,4 +113,8 @@ internal class RepositoryModule {
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideSubjectDao(database: AppDatabase) = database.subjectDao
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideLuckyNumberDao(database: AppDatabase) = database.luckyNumberDao
|
||||
}
|
||||
|
@ -6,6 +6,8 @@ import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
import androidx.room.RoomDatabase.JournalMode.TRUNCATE
|
||||
import androidx.room.TypeConverters
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import io.github.wulkanowy.data.db.dao.AttendanceDao
|
||||
import io.github.wulkanowy.data.db.dao.AttendanceSummaryDao
|
||||
import io.github.wulkanowy.data.db.dao.ExamDao
|
||||
@ -13,6 +15,7 @@ import io.github.wulkanowy.data.db.dao.GradeDao
|
||||
import io.github.wulkanowy.data.db.dao.GradeSummaryDao
|
||||
import io.github.wulkanowy.data.db.dao.MessagesDao
|
||||
import io.github.wulkanowy.data.db.dao.HomeworkDao
|
||||
import io.github.wulkanowy.data.db.dao.LuckyNumberDao
|
||||
import io.github.wulkanowy.data.db.dao.NoteDao
|
||||
import io.github.wulkanowy.data.db.dao.SemesterDao
|
||||
import io.github.wulkanowy.data.db.dao.StudentDao
|
||||
@ -25,11 +28,13 @@ import io.github.wulkanowy.data.db.entities.Grade
|
||||
import io.github.wulkanowy.data.db.entities.GradeSummary
|
||||
import io.github.wulkanowy.data.db.entities.Message
|
||||
import io.github.wulkanowy.data.db.entities.Homework
|
||||
import io.github.wulkanowy.data.db.entities.LuckyNumber
|
||||
import io.github.wulkanowy.data.db.entities.Note
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.db.entities.Subject
|
||||
import io.github.wulkanowy.data.db.entities.Timetable
|
||||
import io.github.wulkanowy.data.db.migrations.Migration2
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
@ -46,9 +51,10 @@ import javax.inject.Singleton
|
||||
Message::class,
|
||||
Note::class,
|
||||
Homework::class,
|
||||
Subject::class
|
||||
Subject::class,
|
||||
LuckyNumber::class
|
||||
],
|
||||
version = 1,
|
||||
version = 2,
|
||||
exportSchema = false
|
||||
)
|
||||
@TypeConverters(Converters::class)
|
||||
@ -58,6 +64,9 @@ abstract class AppDatabase : RoomDatabase() {
|
||||
fun newInstance(context: Context): AppDatabase {
|
||||
return Room.databaseBuilder(context, AppDatabase::class.java, "wulkanowy_database")
|
||||
.setJournalMode(TRUNCATE)
|
||||
.addMigrations(
|
||||
Migration2()
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
@ -85,4 +94,6 @@ abstract class AppDatabase : RoomDatabase() {
|
||||
abstract val homeworkDao: HomeworkDao
|
||||
|
||||
abstract val subjectDao: SubjectDao
|
||||
|
||||
abstract val luckyNumberDao: LuckyNumberDao
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
package io.github.wulkanowy.data.db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import androidx.room.Update
|
||||
import io.github.wulkanowy.data.db.entities.LuckyNumber
|
||||
import io.reactivex.Maybe
|
||||
import org.threeten.bp.LocalDate
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
@Dao
|
||||
interface LuckyNumberDao {
|
||||
|
||||
@Insert
|
||||
fun insert(luckyNumber: LuckyNumber)
|
||||
|
||||
@Update
|
||||
fun update(luckyNumber: LuckyNumber)
|
||||
|
||||
@Delete
|
||||
fun delete(luckyNumber: LuckyNumber)
|
||||
|
||||
@Query("SELECT * FROM LuckyNumbers WHERE student_id = :studentId AND date = :date")
|
||||
fun loadFromDate(studentId: Int, date: LocalDate): Maybe<LuckyNumber>
|
||||
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package io.github.wulkanowy.data.db.entities
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import org.threeten.bp.LocalDate
|
||||
import java.io.Serializable
|
||||
|
||||
@Entity(tableName = "LuckyNumbers")
|
||||
data class LuckyNumber (
|
||||
|
||||
@ColumnInfo(name = "student_id")
|
||||
var studentId: Int,
|
||||
|
||||
var date: LocalDate,
|
||||
|
||||
@ColumnInfo(name = "lucky_number")
|
||||
var luckyNumber: Int
|
||||
|
||||
) : Serializable {
|
||||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Long = 0
|
||||
|
||||
@ColumnInfo(name = "is_notified")
|
||||
var isNotified: Boolean = true
|
||||
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package io.github.wulkanowy.data.db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
class Migration2 : Migration(1, 2) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("CREATE TABLE LuckyNumbers (" +
|
||||
"id INTEGER NOT NULL PRIMARY KEY, " +
|
||||
"is_notified INTEGER NOT NULL, " +
|
||||
"student_id INTEGER NOT NULL, " +
|
||||
"date INTEGER NOT NULL, " +
|
||||
"lucky_number INTEGER NOT NULL)")
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package io.github.wulkanowy.data.repositories
|
||||
|
||||
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
|
||||
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
||||
import io.github.wulkanowy.data.db.entities.LuckyNumber
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.repositories.local.LuckyNumberLocal
|
||||
import io.github.wulkanowy.data.repositories.remote.LuckyNumberRemote
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.Maybe
|
||||
import org.threeten.bp.LocalDate
|
||||
import java.net.UnknownHostException
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class LuckyNumberRepository @Inject constructor(
|
||||
private val settings: InternetObservingSettings,
|
||||
private val local: LuckyNumberLocal,
|
||||
private val remote: LuckyNumberRemote
|
||||
) {
|
||||
|
||||
fun getLuckyNumber(semester: Semester, forceRefresh: Boolean = false, notify: Boolean = false): Maybe<LuckyNumber> {
|
||||
return local.getLuckyNumber(semester, LocalDate.now()).filter { !forceRefresh }
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMapMaybe {
|
||||
if (it) remote.getLuckyNumber(semester)
|
||||
else Maybe.error(UnknownHostException())
|
||||
}.flatMap { new ->
|
||||
local.getLuckyNumber(semester, LocalDate.now())
|
||||
.doOnSuccess { old ->
|
||||
if (new != old) {
|
||||
local.deleteLuckyNumber(old)
|
||||
local.saveLuckyNumber(new.apply {
|
||||
if (notify) isNotified = false
|
||||
})
|
||||
}
|
||||
}
|
||||
.doOnComplete {
|
||||
local.saveLuckyNumber(new.apply {
|
||||
if (notify) isNotified = false
|
||||
})
|
||||
}
|
||||
}.flatMap({ local.getLuckyNumber(semester, LocalDate.now()) }, { Maybe.error(it) },
|
||||
{ local.getLuckyNumber(semester, LocalDate.now()) })
|
||||
)
|
||||
}
|
||||
|
||||
fun updateLuckyNumber(luckyNumber: LuckyNumber): Completable {
|
||||
return local.updateLuckyNumber(luckyNumber)
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package io.github.wulkanowy.data.repositories.local
|
||||
|
||||
import io.github.wulkanowy.data.db.dao.LuckyNumberDao
|
||||
import io.github.wulkanowy.data.db.entities.LuckyNumber
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.Maybe
|
||||
import org.threeten.bp.LocalDate
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class LuckyNumberLocal @Inject constructor(private val luckyNumberDb: LuckyNumberDao) {
|
||||
|
||||
fun getLuckyNumber(semester: Semester, date: LocalDate): Maybe<LuckyNumber> {
|
||||
return luckyNumberDb.loadFromDate(semester.studentId, date)
|
||||
}
|
||||
|
||||
fun saveLuckyNumber(luckyNumber: LuckyNumber) {
|
||||
luckyNumberDb.insert(luckyNumber)
|
||||
}
|
||||
|
||||
fun updateLuckyNumber(luckyNumber: LuckyNumber): Completable {
|
||||
return Completable.fromCallable { luckyNumberDb.update(luckyNumber) }
|
||||
}
|
||||
|
||||
fun deleteLuckyNumber(luckyNumber: LuckyNumber) {
|
||||
luckyNumberDb.delete(luckyNumber)
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package io.github.wulkanowy.data.repositories.remote
|
||||
|
||||
import io.github.wulkanowy.api.Api
|
||||
import io.github.wulkanowy.data.db.entities.LuckyNumber
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.reactivex.Maybe
|
||||
import io.reactivex.Single
|
||||
import org.threeten.bp.LocalDate
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class LuckyNumberRemote @Inject constructor(private val api: Api) {
|
||||
|
||||
fun getLuckyNumber(semester: Semester): Maybe<LuckyNumber> {
|
||||
return Single.just(api.apply { diaryId = semester.diaryId })
|
||||
.flatMapMaybe { it.getLuckyNumber() }
|
||||
.map {
|
||||
LuckyNumber(
|
||||
studentId = semester.studentId,
|
||||
date = LocalDate.now(),
|
||||
luckyNumber = it
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -8,6 +8,7 @@ import io.github.wulkanowy.data.repositories.ExamRepository
|
||||
import io.github.wulkanowy.data.repositories.GradeRepository
|
||||
import io.github.wulkanowy.data.repositories.GradeSummaryRepository
|
||||
import io.github.wulkanowy.data.repositories.HomeworkRepository
|
||||
import io.github.wulkanowy.data.repositories.LuckyNumberRepository
|
||||
import io.github.wulkanowy.data.repositories.MessagesRepository
|
||||
import io.github.wulkanowy.data.repositories.MessagesRepository.MessageFolder.RECEIVED
|
||||
import io.github.wulkanowy.data.repositories.NoteRepository
|
||||
@ -16,12 +17,13 @@ import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.data.repositories.TimetableRepository
|
||||
import io.github.wulkanowy.services.notification.GradeNotification
|
||||
import io.github.wulkanowy.services.notification.LuckyNumberNotification
|
||||
import io.github.wulkanowy.services.notification.MessageNotification
|
||||
import io.github.wulkanowy.services.notification.NoteNotification
|
||||
import io.github.wulkanowy.utils.friday
|
||||
import io.github.wulkanowy.utils.isHolidays
|
||||
import io.github.wulkanowy.utils.monday
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import org.threeten.bp.LocalDate
|
||||
import timber.log.Timber
|
||||
@ -59,6 +61,9 @@ class SyncWorker : SimpleJobService() {
|
||||
@Inject
|
||||
lateinit var homework: HomeworkRepository
|
||||
|
||||
@Inject
|
||||
lateinit var luckyNumber: LuckyNumberRepository
|
||||
|
||||
@Inject
|
||||
lateinit var prefRepository: PreferencesRepository
|
||||
|
||||
@ -88,18 +93,19 @@ class SyncWorker : SimpleJobService() {
|
||||
|
||||
disposable.add(student.getCurrentStudent()
|
||||
.flatMap { semester.getCurrentSemester(it, true).map { semester -> semester to it } }
|
||||
.flatMapPublisher {
|
||||
Single.merge(
|
||||
.flatMapCompletable {
|
||||
Completable.merge(
|
||||
listOf(
|
||||
gradesDetails.getGrades(it.first, true, notify),
|
||||
gradesSummary.getGradesSummary(it.first, true),
|
||||
attendance.getAttendance(it.first, start, end, true),
|
||||
exam.getExams(it.first, start, end, true),
|
||||
timetable.getTimetable(it.first, start, end, true),
|
||||
message.getMessages(it.second, RECEIVED, true, notify),
|
||||
note.getNotes(it.first, true, notify),
|
||||
homework.getHomework(it.first, LocalDate.now(), true),
|
||||
homework.getHomework(it.first, LocalDate.now().plusDays(1), true)
|
||||
gradesDetails.getGrades(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.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()
|
||||
)
|
||||
)
|
||||
}
|
||||
@ -119,6 +125,7 @@ class SyncWorker : SimpleJobService() {
|
||||
sendGradeNotifications()
|
||||
sendMessageNotification()
|
||||
sendNoteNotification()
|
||||
sendLuckyNumberNotification()
|
||||
}
|
||||
|
||||
private fun sendGradeNotifications() {
|
||||
@ -170,6 +177,19 @@ class SyncWorker : SimpleJobService() {
|
||||
)
|
||||
}
|
||||
|
||||
private fun sendLuckyNumberNotification() {
|
||||
disposable.add(student.getCurrentStudent()
|
||||
.flatMap { semester.getCurrentSemester(it) }
|
||||
.flatMapMaybe { luckyNumber.getLuckyNumber(it) }
|
||||
.filter { !it.isNotified }
|
||||
.doOnSuccess {
|
||||
LuckyNumberNotification(applicationContext).sendNotification(it)
|
||||
}
|
||||
.map { it.apply { isNotified = true } }
|
||||
.flatMapCompletable { luckyNumber.updateLuckyNumber(it) }
|
||||
.subscribe({}, { Timber.e("Lucky number notification sending failed") }))
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
disposable.clear()
|
||||
|
@ -0,0 +1,48 @@
|
||||
package io.github.wulkanowy.services.notification
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.app.Notification
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.LuckyNumber
|
||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||
|
||||
class LuckyNumberNotification(context: Context) : BaseNotification(context) {
|
||||
|
||||
private val channelId = "Lucky_Number_Notify"
|
||||
|
||||
@TargetApi(26)
|
||||
override fun createChannel(channelId: String) {
|
||||
notificationManager.createNotificationChannel(NotificationChannel(
|
||||
channelId, context.getString(R.string.notify_lucky_number_channel), NotificationManager.IMPORTANCE_HIGH
|
||||
).apply {
|
||||
enableLights(true)
|
||||
enableVibration(true)
|
||||
lockscreenVisibility = Notification.VISIBILITY_PUBLIC
|
||||
})
|
||||
}
|
||||
|
||||
fun sendNotification(luckyNumber: LuckyNumber) {
|
||||
notify(notificationBuilder(channelId)
|
||||
.setContentTitle(context.getString(R.string.notify_lucky_number_new_item_title))
|
||||
.setContentText(context.getString(R.string.notify_lucky_number_new_item, luckyNumber.luckyNumber))
|
||||
.setSmallIcon(R.drawable.ic_stat_notify_lucky_number)
|
||||
.setAutoCancel(true)
|
||||
.setDefaults(NotificationCompat.DEFAULT_ALL)
|
||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||
.setColor(ContextCompat.getColor(context, R.color.colorPrimary))
|
||||
.setContentIntent(
|
||||
PendingIntent.getActivity(context, 0,
|
||||
MainActivity.getStartIntent(context).putExtra(MainActivity.EXTRA_START_MENU_INDEX, 4),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
)
|
||||
.build()
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package io.github.wulkanowy.ui.modules.luckynumber
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.LuckyNumber
|
||||
import io.github.wulkanowy.ui.base.session.BaseSessionFragment
|
||||
import io.github.wulkanowy.ui.modules.main.MainView
|
||||
import kotlinx.android.synthetic.main.fragment_lucky_number.*
|
||||
import javax.inject.Inject
|
||||
|
||||
class LuckyNumberFragment : BaseSessionFragment(), LuckyNumberView, MainView.TitledView {
|
||||
|
||||
@Inject
|
||||
lateinit var presenter: LuckyNumberPresenter
|
||||
|
||||
companion object {
|
||||
fun newInstance() = LuckyNumberFragment()
|
||||
}
|
||||
|
||||
override val titleStringId: Int
|
||||
get() = R.string.lucky_number_title
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.fragment_lucky_number, container, false)
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
presenter.onAttachView(this)
|
||||
}
|
||||
|
||||
override fun initView() {
|
||||
showContent(false)
|
||||
showProgress(true)
|
||||
luckyNumberSwipe.setOnRefreshListener { presenter.onSwipeRefresh() }
|
||||
}
|
||||
|
||||
override fun updateData(data: LuckyNumber) {
|
||||
luckyNumberText.text = data.luckyNumber.toString()
|
||||
}
|
||||
|
||||
override fun hideRefresh() {
|
||||
luckyNumberSwipe.isRefreshing = false
|
||||
}
|
||||
|
||||
override fun showEmpty(show: Boolean) {
|
||||
luckyNumberEmpty.visibility = if (show) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
override fun showProgress(show: Boolean) {
|
||||
luckyNumberProgress.visibility = if (show) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
override fun showContent(show: Boolean) {
|
||||
luckyNumberContent.visibility = if (show) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
override fun isViewEmpty(): Boolean {
|
||||
return luckyNumberText.text.isBlank()
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
package io.github.wulkanowy.ui.modules.luckynumber
|
||||
|
||||
import io.github.wulkanowy.data.repositories.LuckyNumberRepository
|
||||
import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.session.SessionErrorHandler
|
||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||
import io.github.wulkanowy.utils.SchedulersProvider
|
||||
import io.reactivex.MaybeSource
|
||||
import javax.inject.Inject
|
||||
|
||||
class LuckyNumberPresenter @Inject constructor(
|
||||
private val errorHandler: SessionErrorHandler,
|
||||
private val schedulers: SchedulersProvider,
|
||||
private val luckyNumberRepository: LuckyNumberRepository,
|
||||
private val studentRepository: StudentRepository,
|
||||
private val semesterRepository: SemesterRepository,
|
||||
private val analytics: FirebaseAnalyticsHelper
|
||||
) : BasePresenter<LuckyNumberView>(errorHandler) {
|
||||
|
||||
override fun onAttachView(view: LuckyNumberView) {
|
||||
super.onAttachView(view)
|
||||
view.initView()
|
||||
loadData()
|
||||
}
|
||||
|
||||
private fun loadData(forceRefresh: Boolean = false) {
|
||||
disposable.apply {
|
||||
clear()
|
||||
add(studentRepository.getCurrentStudent()
|
||||
.flatMap { semesterRepository.getCurrentSemester(it) }
|
||||
.flatMapMaybe { luckyNumberRepository.getLuckyNumber(it, forceRefresh) }
|
||||
.subscribeOn(schedulers.backgroundThread)
|
||||
.observeOn(schedulers.mainThread)
|
||||
.doFinally {
|
||||
view?.run {
|
||||
hideRefresh()
|
||||
showProgress(false)
|
||||
}
|
||||
}
|
||||
.subscribe({
|
||||
view?.apply {
|
||||
updateData(it)
|
||||
showContent(true)
|
||||
showEmpty(false)
|
||||
}
|
||||
analytics.logEvent("load_lucky_number", mapOf("force_refresh" to forceRefresh))
|
||||
}, {
|
||||
view?.run { showEmpty(isViewEmpty()) }
|
||||
errorHandler.dispatch(it)
|
||||
}, {
|
||||
view?.run {
|
||||
showContent(false)
|
||||
showEmpty(true)
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun onSwipeRefresh() {
|
||||
loadData(true)
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package io.github.wulkanowy.ui.modules.luckynumber
|
||||
|
||||
import io.github.wulkanowy.data.db.entities.LuckyNumber
|
||||
import io.github.wulkanowy.ui.base.session.BaseSessionView
|
||||
|
||||
interface LuckyNumberView : BaseSessionView {
|
||||
|
||||
fun initView()
|
||||
|
||||
fun updateData(data: LuckyNumber)
|
||||
|
||||
fun hideRefresh()
|
||||
|
||||
fun showEmpty(show: Boolean)
|
||||
|
||||
fun showProgress(show: Boolean)
|
||||
|
||||
fun showContent(show: Boolean)
|
||||
|
||||
fun isViewEmpty(): Boolean
|
||||
}
|
@ -16,6 +16,7 @@ import io.github.wulkanowy.ui.modules.exam.ExamFragment
|
||||
import io.github.wulkanowy.ui.modules.grade.GradeFragment
|
||||
import io.github.wulkanowy.ui.modules.grade.GradeModule
|
||||
import io.github.wulkanowy.ui.modules.homework.HomeworkFragment
|
||||
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
|
||||
@ -86,6 +87,10 @@ abstract class MainModule {
|
||||
@ContributesAndroidInjector
|
||||
abstract fun bindHomeworkFragment(): HomeworkFragment
|
||||
|
||||
@PerFragment
|
||||
@ContributesAndroidInjector
|
||||
abstract fun bindLuckyNumberFragment(): LuckyNumberFragment
|
||||
|
||||
@PerFragment
|
||||
@ContributesAndroidInjector
|
||||
abstract fun bindsAccountDialog(): AccountDialog
|
||||
|
@ -13,6 +13,7 @@ import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.ui.base.BaseFragment
|
||||
import io.github.wulkanowy.ui.modules.about.AboutFragment
|
||||
import io.github.wulkanowy.ui.modules.homework.HomeworkFragment
|
||||
import io.github.wulkanowy.ui.modules.luckynumber.LuckyNumberFragment
|
||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||
import io.github.wulkanowy.ui.modules.main.MainView
|
||||
import io.github.wulkanowy.ui.modules.message.MessageFragment
|
||||
@ -60,6 +61,14 @@ class MoreFragment : BaseFragment(), MoreView, MainView.TitledView, MainView.Mai
|
||||
}
|
||||
}
|
||||
|
||||
override val luckyNumberRes: Pair<String, Drawable?>?
|
||||
get() {
|
||||
return context?.run {
|
||||
getString(R.string.lucky_number_title) to
|
||||
ContextCompat.getDrawable(this, R.drawable.ic_more_lucky_number_24dp)
|
||||
}
|
||||
}
|
||||
|
||||
override val settingsRes: Pair<String, Drawable?>?
|
||||
get() {
|
||||
return context?.run {
|
||||
@ -114,6 +123,10 @@ class MoreFragment : BaseFragment(), MoreView, MainView.TitledView, MainView.Mai
|
||||
(activity as? MainActivity)?.pushView(NoteFragment.newInstance())
|
||||
}
|
||||
|
||||
override fun openLuckyNumberView() {
|
||||
(activity as? MainActivity)?.pushView(LuckyNumberFragment.newInstance())
|
||||
}
|
||||
|
||||
override fun openSettingsView() {
|
||||
(activity as? MainActivity)?.pushView(SettingsFragment.newInstance())
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ class MorePresenter @Inject constructor(errorHandler: ErrorHandler) : BasePresen
|
||||
messagesRes?.first -> openMessagesView()
|
||||
homeworkRes?.first -> openHomeworkView()
|
||||
noteRes?.first -> openNoteView()
|
||||
luckyNumberRes?.first -> openLuckyNumberView()
|
||||
settingsRes?.first -> openSettingsView()
|
||||
aboutRes?.first -> openAboutView()
|
||||
}
|
||||
@ -42,6 +43,7 @@ class MorePresenter @Inject constructor(errorHandler: ErrorHandler) : BasePresen
|
||||
messagesRes?.let { MoreItem(it.first, it.second) },
|
||||
homeworkRes?.let { MoreItem(it.first, it.second) },
|
||||
noteRes?.let { MoreItem(it.first, it.second) },
|
||||
luckyNumberRes?.let { MoreItem(it.first, it.second) },
|
||||
settingsRes?.let { MoreItem(it.first, it.second) },
|
||||
aboutRes?.let { MoreItem(it.first, it.second) })
|
||||
)
|
||||
|
@ -11,6 +11,8 @@ interface MoreView : BaseView {
|
||||
|
||||
val noteRes: Pair<String, Drawable?>?
|
||||
|
||||
val luckyNumberRes: Pair<String, Drawable?>?
|
||||
|
||||
val settingsRes: Pair<String, Drawable?>?
|
||||
|
||||
val aboutRes: Pair<String, Drawable?>?
|
||||
@ -30,4 +32,6 @@ interface MoreView : BaseView {
|
||||
fun openHomeworkView()
|
||||
|
||||
fun openNoteView()
|
||||
|
||||
fun openLuckyNumberView()
|
||||
}
|
||||
|
@ -0,0 +1,14 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="26.086956"
|
||||
android:viewportHeight="26.086956"
|
||||
android:tint="#FFFFFF">
|
||||
<group
|
||||
android:translateX="1.0434783"
|
||||
android:translateY="1.0434783">
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M12,11.18C15.3,8.18 17,6.64 17,4.69C17,3.19 15.75,2 14.25,2C13.39,2 12.57,2.36 12,3C11.43,2.36 10.61,2 9.69,2C8.19,2 7,3.25 7,4.75C7,6.64 8.7,8.18 12,11.18M11.18,12C8.18,8.7 6.64,7 4.69,7C3.19,7 2,8.25 2,9.75C2,10.61 2.36,11.43 3,12C2.36,12.57 2,13.39 2,14.31C2,15.81 3.25,17 4.75,17C6.64,17 8.18,15.3 11.18,12M12.83,12C15.82,15.3 17.36,17 19.31,17C20.81,17 22,15.75 22,14.25C22,13.39 21.64,12.57 21,12C21.64,11.43 22,10.61 22,9.69C22,8.19 20.75,7 19.25,7C17.36,7 15.82,8.7 12.83,12M12,12.82C8.7,15.82 7,17.36 7,19.31C7,20.81 8.25,22 9.75,22C10.61,22 11.43,21.64 12,21C12.57,21.64 13.39,22 14.31,22C15.81,22 17,20.75 17,19.25C17,17.36 15.3,15.82 12,12.82Z" />
|
||||
</group>
|
||||
</vector>
|
BIN
app/src/main/res/drawable-hdpi/ic_stat_notify_lucky_number.png
Normal file
BIN
app/src/main/res/drawable-hdpi/ic_stat_notify_lucky_number.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 473 B |
BIN
app/src/main/res/drawable-mdpi/ic_stat_notify_lucky_number.png
Normal file
BIN
app/src/main/res/drawable-mdpi/ic_stat_notify_lucky_number.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 343 B |
BIN
app/src/main/res/drawable-xhdpi/ic_stat_notify_lucky_number.png
Normal file
BIN
app/src/main/res/drawable-xhdpi/ic_stat_notify_lucky_number.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 713 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_stat_notify_lucky_number.png
Normal file
BIN
app/src/main/res/drawable-xxhdpi/ic_stat_notify_lucky_number.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
9
app/src/main/res/drawable/ic_more_lucky_number_24dp.xml
Normal file
9
app/src/main/res/drawable/ic_more_lucky_number_24dp.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M12,11.18C15.3,8.18 17,6.64 17,4.69C17,3.19 15.75,2 14.25,2C13.39,2 12.57,2.36 12,3C11.43,2.36 10.61,2 9.69,2C8.19,2 7,3.25 7,4.75C7,6.64 8.7,8.18 12,11.18M11.18,12C8.18,8.7 6.64,7 4.69,7C3.19,7 2,8.25 2,9.75C2,10.61 2.36,11.43 3,12C2.36,12.57 2,13.39 2,14.31C2,15.81 3.25,17 4.75,17C6.64,17 8.18,15.3 11.18,12M12.83,12C15.82,15.3 17.36,17 19.31,17C20.81,17 22,15.75 22,14.25C22,13.39 21.64,12.57 21,12C21.64,11.43 22,10.61 22,9.69C22,8.19 20.75,7 19.25,7C17.36,7 15.82,8.7 12.83,12M12,12.82C8.7,15.82 7,17.36 7,19.31C7,20.81 8.25,22 9.75,22C10.61,22 11.43,21.64 12,21C12.57,21.64 13.39,22 14.31,22C15.81,22 17,20.75 17,19.25C17,17.36 15.3,15.82 12,12.82Z"/>
|
||||
</vector>
|
73
app/src/main/res/layout/fragment_lucky_number.xml
Normal file
73
app/src/main/res/layout/fragment_lucky_number.xml
Normal file
@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/luckyNumberProgress"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:indeterminate="true"
|
||||
android:visibility="gone" />
|
||||
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
android:id="@+id/luckyNumberSwipe"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/luckyNumberContent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="300dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="@string/lucky_number_header"
|
||||
android:textSize="24sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/luckyNumberText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
tools:text="14"
|
||||
android:textSize="52sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/luckyNumberEmpty"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:padding="10dp"
|
||||
android:visibility="gone">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:minWidth="100dp"
|
||||
android:minHeight="100dp"
|
||||
app:srcCompat="@drawable/ic_more_lucky_number_24dp"
|
||||
app:tint="?android:attr/textColorPrimary" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/lucky_number_empty"
|
||||
android:textSize="20sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
@ -184,6 +184,15 @@
|
||||
<!--Homework-->
|
||||
<string name="homework_no_items">Brak zadań domowych</string>
|
||||
|
||||
<!--Lucky number-->
|
||||
<string name="lucky_number_title">Szczęśliwy numerek</string>
|
||||
<string name="lucky_number_header">Dzisiejszym szczęśliwym numerkiem jest</string>
|
||||
<string name="lucky_number_empty">Brak informacji o szczęśliwym numerku</string>
|
||||
|
||||
<!--Lucky number notify-->
|
||||
<string name="notify_lucky_number_channel">Nowe szczęśliwe numerki</string>
|
||||
<string name="notify_lucky_number_new_item_title">Szczęśliwy numerek na dzisiaj</string>
|
||||
<string name="notify_lucky_number_new_item">Dziś szczęśliwym numerkiem jest: %d</string>
|
||||
|
||||
<!--Account-->
|
||||
<string name="account_add_new">Dodaj konto</string>
|
||||
|
@ -167,6 +167,15 @@
|
||||
<!--Homework-->
|
||||
<string name="homework_no_items">No info about homework</string>
|
||||
|
||||
<!--Lucky number-->
|
||||
<string name="lucky_number_title">Lucky number</string>
|
||||
<string name="lucky_number_header">Today\'s lucky number is</string>
|
||||
<string name="lucky_number_empty">No info about the lucky number</string>
|
||||
|
||||
<!--Lucky number notify-->
|
||||
<string name="notify_lucky_number_channel">New lucky numbers</string>
|
||||
<string name="notify_lucky_number_new_item_title">Lucky number for today</string>
|
||||
<string name="notify_lucky_number_new_item">Today\'s lucky number is: %d</string>
|
||||
|
||||
<!--Account-->
|
||||
<string name="account_add_new">Add account</string>
|
||||
|
@ -0,0 +1,44 @@
|
||||
package io.github.wulkanowy.data.repositories.remote
|
||||
|
||||
import io.github.wulkanowy.api.Api
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.mockk.MockKAnnotations
|
||||
import io.mockk.every
|
||||
import io.mockk.impl.annotations.MockK
|
||||
import io.mockk.impl.annotations.SpyK
|
||||
import io.reactivex.Maybe
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.threeten.bp.LocalDate
|
||||
|
||||
class LuckyNumberRemoteTest {
|
||||
|
||||
@SpyK
|
||||
private var mockApi = Api()
|
||||
|
||||
@MockK
|
||||
private lateinit var semesterMock: Semester
|
||||
|
||||
@Before
|
||||
fun initApi() {
|
||||
MockKAnnotations.init(this)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getLuckyNumberTest() {
|
||||
every { mockApi.getLuckyNumber() } returns Maybe.just(14)
|
||||
|
||||
every { mockApi.diaryId } returns 1
|
||||
every { semesterMock.studentId } returns 1
|
||||
every { semesterMock.diaryId } returns 1
|
||||
|
||||
val luckyNumber = LuckyNumberRemote(mockApi)
|
||||
.getLuckyNumber(semesterMock)
|
||||
.blockingGet()
|
||||
|
||||
assertEquals(14, luckyNumber.luckyNumber)
|
||||
assertEquals(LocalDate.now(), luckyNumber.date)
|
||||
assertEquals(semesterMock.studentId, luckyNumber.studentId)
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user