forked from github/wulkanowy-mirror
Add notes (#179)
This commit is contained in:
parent
240e61df0e
commit
cb7e70471b
1
.gitignore
vendored
1
.gitignore
vendored
@ -47,3 +47,4 @@ Thumbs.db
|
|||||||
./app/key.p12
|
./app/key.p12
|
||||||
./app/upload-key.jks
|
./app/upload-key.jks
|
||||||
*.log
|
*.log
|
||||||
|
.idea/assetWizardSettings.xml
|
||||||
|
@ -78,7 +78,7 @@ ext.androidx_version = "1.0.0"
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||||
implementation('com.github.wulkanowy:api:e829b094de') { exclude module: "threetenbp" }
|
implementation('com.github.wulkanowy:api:96be34a') { exclude module: "threetenbp" }
|
||||||
|
|
||||||
implementation "androidx.legacy:legacy-support-v4:$androidx_version"
|
implementation "androidx.legacy:legacy-support-v4:$androidx_version"
|
||||||
implementation "androidx.appcompat:appcompat:$androidx_version"
|
implementation "androidx.appcompat:appcompat:$androidx_version"
|
||||||
|
@ -67,4 +67,8 @@ internal class RepositoryModule {
|
|||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
fun provideTimetableDao(database: AppDatabase) = database.timetableDao()
|
fun provideTimetableDao(database: AppDatabase) = database.timetableDao()
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@Provides
|
||||||
|
fun provideNoteDao(database: AppDatabase) = database.noteDao()
|
||||||
}
|
}
|
||||||
|
@ -5,23 +5,38 @@ import androidx.room.Database
|
|||||||
import androidx.room.Room
|
import androidx.room.Room
|
||||||
import androidx.room.RoomDatabase
|
import androidx.room.RoomDatabase
|
||||||
import androidx.room.TypeConverters
|
import androidx.room.TypeConverters
|
||||||
import io.github.wulkanowy.data.db.dao.*
|
import io.github.wulkanowy.data.db.dao.AttendanceDao
|
||||||
import io.github.wulkanowy.data.db.entities.*
|
import io.github.wulkanowy.data.db.dao.ExamDao
|
||||||
|
import io.github.wulkanowy.data.db.dao.GradeDao
|
||||||
|
import io.github.wulkanowy.data.db.dao.GradeSummaryDao
|
||||||
|
import io.github.wulkanowy.data.db.dao.NoteDao
|
||||||
|
import io.github.wulkanowy.data.db.dao.SemesterDao
|
||||||
|
import io.github.wulkanowy.data.db.dao.StudentDao
|
||||||
|
import io.github.wulkanowy.data.db.dao.TimetableDao
|
||||||
|
import io.github.wulkanowy.data.db.entities.Attendance
|
||||||
|
import io.github.wulkanowy.data.db.entities.Exam
|
||||||
|
import io.github.wulkanowy.data.db.entities.Grade
|
||||||
|
import io.github.wulkanowy.data.db.entities.GradeSummary
|
||||||
|
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.Timetable
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Database(
|
@Database(
|
||||||
entities = [
|
entities = [
|
||||||
Student::class,
|
Student::class,
|
||||||
Semester::class,
|
Semester::class,
|
||||||
Exam::class,
|
Exam::class,
|
||||||
Timetable::class,
|
Timetable::class,
|
||||||
Attendance::class,
|
Attendance::class,
|
||||||
Grade::class,
|
Grade::class,
|
||||||
GradeSummary::class
|
GradeSummary::class,
|
||||||
],
|
Note::class
|
||||||
version = 1,
|
],
|
||||||
exportSchema = false
|
version = 1,
|
||||||
|
exportSchema = false
|
||||||
)
|
)
|
||||||
@TypeConverters(Converters::class)
|
@TypeConverters(Converters::class)
|
||||||
abstract class AppDatabase : RoomDatabase() {
|
abstract class AppDatabase : RoomDatabase() {
|
||||||
@ -29,7 +44,7 @@ abstract class AppDatabase : RoomDatabase() {
|
|||||||
companion object {
|
companion object {
|
||||||
fun newInstance(context: Context): AppDatabase {
|
fun newInstance(context: Context): AppDatabase {
|
||||||
return Room.databaseBuilder(context, AppDatabase::class.java, "wulkanowy_database")
|
return Room.databaseBuilder(context, AppDatabase::class.java, "wulkanowy_database")
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,4 +61,6 @@ abstract class AppDatabase : RoomDatabase() {
|
|||||||
abstract fun gradeDao(): GradeDao
|
abstract fun gradeDao(): GradeDao
|
||||||
|
|
||||||
abstract fun gradeSummaryDao(): GradeSummaryDao
|
abstract fun gradeSummaryDao(): GradeSummaryDao
|
||||||
|
|
||||||
|
abstract fun noteDao(): NoteDao
|
||||||
}
|
}
|
||||||
|
31
app/src/main/java/io/github/wulkanowy/data/db/dao/NoteDao.kt
Normal file
31
app/src/main/java/io/github/wulkanowy/data/db/dao/NoteDao.kt
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
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.Note
|
||||||
|
import io.reactivex.Maybe
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface NoteDao {
|
||||||
|
|
||||||
|
@Insert
|
||||||
|
fun insertAll(notes: List<Note>)
|
||||||
|
|
||||||
|
@Update
|
||||||
|
fun update(note: Note)
|
||||||
|
|
||||||
|
@Update
|
||||||
|
fun updateAll(notes: List<Note>)
|
||||||
|
|
||||||
|
@Delete
|
||||||
|
fun deleteAll(notes: List<Note>)
|
||||||
|
|
||||||
|
@Query("SELECT * FROM Notes WHERE semester_id = :semesterId AND student_id = :studentId")
|
||||||
|
fun getNotes(semesterId: Int, studentId: Int): Maybe<List<Note>>
|
||||||
|
|
||||||
|
@Query("SELECT * FROM Notes WHERE is_read = 0 AND semester_id = :semesterId AND student_id = :studentId")
|
||||||
|
fun getNewNotes(semesterId: Int, studentId: Int): Maybe<List<Note>>
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
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 = "Notes")
|
||||||
|
data class Note(
|
||||||
|
|
||||||
|
@ColumnInfo(name = "semester_id")
|
||||||
|
var semesterId: Int,
|
||||||
|
|
||||||
|
@ColumnInfo(name = "student_id")
|
||||||
|
var studentId: Int,
|
||||||
|
|
||||||
|
var date: LocalDate,
|
||||||
|
|
||||||
|
var teacher: String,
|
||||||
|
|
||||||
|
var category: String,
|
||||||
|
|
||||||
|
var content: String
|
||||||
|
) : Serializable {
|
||||||
|
|
||||||
|
@PrimaryKey(autoGenerate = true)
|
||||||
|
var id: Long = 0
|
||||||
|
|
||||||
|
@ColumnInfo(name = "is_read")
|
||||||
|
var isRead: Boolean = false
|
||||||
|
|
||||||
|
@ColumnInfo(name = "is_notified")
|
||||||
|
var isNotified: Boolean = true
|
||||||
|
}
|
@ -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.Note
|
||||||
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
|
import io.github.wulkanowy.data.repositories.local.NoteLocal
|
||||||
|
import io.github.wulkanowy.data.repositories.remote.NoteRemote
|
||||||
|
import io.reactivex.Completable
|
||||||
|
import io.reactivex.Single
|
||||||
|
import java.net.UnknownHostException
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class NoteRepository @Inject constructor(
|
||||||
|
private val settings: InternetObservingSettings,
|
||||||
|
private val local: NoteLocal,
|
||||||
|
private val remote: NoteRemote
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun getNotes(semester: Semester, forceRefresh: Boolean = false, notify: Boolean = false): Single<List<Note>> {
|
||||||
|
return local.getNotes(semester).filter { !forceRefresh }
|
||||||
|
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||||
|
.flatMap {
|
||||||
|
if (it) remote.getNotes(semester)
|
||||||
|
else Single.error(UnknownHostException())
|
||||||
|
}.flatMap { new ->
|
||||||
|
local.getNotes(semester).toSingle(emptyList())
|
||||||
|
.doOnSuccess { old ->
|
||||||
|
local.deleteNotes(old - new)
|
||||||
|
local.saveNotes((new - old)
|
||||||
|
.onEach {
|
||||||
|
if (notify) it.isNotified = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}.flatMap { local.getNotes(semester).toSingle(emptyList()) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getNewNotes(semester: Semester): Single<List<Note>> {
|
||||||
|
return local.getNewNotes(semester).toSingle(emptyList())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateNote(note: Note): Completable {
|
||||||
|
return local.updateNote(note)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateNotes(notes: List<Note>): Completable {
|
||||||
|
return local.updateNotes(notes)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
package io.github.wulkanowy.data.repositories.local
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.db.dao.NoteDao
|
||||||
|
import io.github.wulkanowy.data.db.entities.Note
|
||||||
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
|
import io.reactivex.Completable
|
||||||
|
import io.reactivex.Maybe
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class NoteLocal @Inject constructor(private val noteDb: NoteDao) {
|
||||||
|
|
||||||
|
fun getNotes(semester: Semester): Maybe<List<Note>> {
|
||||||
|
return noteDb.getNotes(semester.semesterId, semester.studentId).filter { !it.isEmpty() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getNewNotes(semester: Semester): Maybe<List<Note>> {
|
||||||
|
return noteDb.getNewNotes(semester.semesterId, semester.studentId)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveNotes(notes: List<Note>) {
|
||||||
|
noteDb.insertAll(notes)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateNote(note: Note): Completable {
|
||||||
|
return Completable.fromCallable { noteDb.update(note) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateNotes(notes: List<Note>): Completable {
|
||||||
|
return Completable.fromCallable { noteDb.updateAll(notes) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deleteNotes(notes: List<Note>) {
|
||||||
|
noteDb.deleteAll(notes)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
package io.github.wulkanowy.data.repositories.remote
|
||||||
|
|
||||||
|
import io.github.wulkanowy.api.Api
|
||||||
|
import io.github.wulkanowy.data.db.entities.Note
|
||||||
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
|
import io.github.wulkanowy.utils.toLocalDate
|
||||||
|
import io.reactivex.Single
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class NoteRemote @Inject constructor(private val api: Api) {
|
||||||
|
|
||||||
|
fun getNotes(semester: Semester): Single<List<Note>> {
|
||||||
|
return Single.just(api.run {
|
||||||
|
if (diaryId != semester.diaryId) {
|
||||||
|
diaryId = semester.diaryId
|
||||||
|
notifyDataChanged()
|
||||||
|
}
|
||||||
|
}).flatMap { api.getNotes() }
|
||||||
|
.map { notes ->
|
||||||
|
notes.map {
|
||||||
|
Note(
|
||||||
|
semesterId = semester.semesterId,
|
||||||
|
studentId = semester.studentId,
|
||||||
|
date = it.date.toLocalDate(),
|
||||||
|
teacher = it.teacher,
|
||||||
|
category = it.category,
|
||||||
|
content = it.content
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -7,10 +7,12 @@ import io.github.wulkanowy.data.repositories.AttendanceRepository
|
|||||||
import io.github.wulkanowy.data.repositories.ExamRepository
|
import io.github.wulkanowy.data.repositories.ExamRepository
|
||||||
import io.github.wulkanowy.data.repositories.GradeRepository
|
import io.github.wulkanowy.data.repositories.GradeRepository
|
||||||
import io.github.wulkanowy.data.repositories.GradeSummaryRepository
|
import io.github.wulkanowy.data.repositories.GradeSummaryRepository
|
||||||
|
import io.github.wulkanowy.data.repositories.NoteRepository
|
||||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
import io.github.wulkanowy.data.repositories.SessionRepository
|
import io.github.wulkanowy.data.repositories.SessionRepository
|
||||||
import io.github.wulkanowy.data.repositories.TimetableRepository
|
import io.github.wulkanowy.data.repositories.TimetableRepository
|
||||||
import io.github.wulkanowy.services.notification.GradeNotification
|
import io.github.wulkanowy.services.notification.GradeNotification
|
||||||
|
import io.github.wulkanowy.services.notification.NoteNotification
|
||||||
import io.github.wulkanowy.utils.friday
|
import io.github.wulkanowy.utils.friday
|
||||||
import io.github.wulkanowy.utils.isHolidays
|
import io.github.wulkanowy.utils.isHolidays
|
||||||
import io.github.wulkanowy.utils.monday
|
import io.github.wulkanowy.utils.monday
|
||||||
@ -40,6 +42,9 @@ class SyncWorker : SimpleJobService() {
|
|||||||
@Inject
|
@Inject
|
||||||
lateinit var timetable: TimetableRepository
|
lateinit var timetable: TimetableRepository
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var note: NoteRepository
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var prefRepository: PreferencesRepository
|
lateinit var prefRepository: PreferencesRepository
|
||||||
|
|
||||||
@ -73,7 +78,8 @@ class SyncWorker : SimpleJobService() {
|
|||||||
gradesSummary.getGradesSummary(it, true),
|
gradesSummary.getGradesSummary(it, true),
|
||||||
attendance.getAttendance(it, start, end, true),
|
attendance.getAttendance(it, start, end, true),
|
||||||
exam.getExams(it, start, end, true),
|
exam.getExams(it, start, end, true),
|
||||||
timetable.getTimetable(it, start, end, true)
|
timetable.getTimetable(it, start, end, true),
|
||||||
|
note.getNotes(it, true, true)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -90,7 +96,12 @@ class SyncWorker : SimpleJobService() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun sendNotifications() {
|
private fun sendNotifications() {
|
||||||
disposable.add(session.getSemesters(true)
|
sendGradeNotifications()
|
||||||
|
sendNoteNotification()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun sendGradeNotifications() {
|
||||||
|
disposable.add(session.getSemesters()
|
||||||
.map { it.single { semester -> semester.current } }
|
.map { it.single { semester -> semester.current } }
|
||||||
.flatMap { gradesDetails.getNewGrades(it) }
|
.flatMap { gradesDetails.getNewGrades(it) }
|
||||||
.map { it.filter { grade -> !grade.isNotified } }
|
.map { it.filter { grade -> !grade.isNotified } }
|
||||||
@ -103,6 +114,20 @@ class SyncWorker : SimpleJobService() {
|
|||||||
}) { Timber.e("Notifications sending failed") })
|
}) { Timber.e("Notifications sending failed") })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun sendNoteNotification() {
|
||||||
|
disposable.add(session.getSemesters()
|
||||||
|
.map { it.single { semester -> semester.current } }
|
||||||
|
.flatMap { note.getNewNotes(it) }
|
||||||
|
.map { it.filter { note -> !note.isNotified } }
|
||||||
|
.subscribe({
|
||||||
|
if (it.isNotEmpty()) {
|
||||||
|
Timber.d("Found ${it.size} unread notes")
|
||||||
|
NoteNotification(applicationContext).sendNotification(it)
|
||||||
|
note.updateNotes(it.map { note -> note.apply { isNotified = true } }).subscribe()
|
||||||
|
}
|
||||||
|
}) { Timber.e("Notifications sending failed") })
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
disposable.clear()
|
disposable.clear()
|
||||||
|
@ -0,0 +1,58 @@
|
|||||||
|
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.Note
|
||||||
|
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
class NoteNotification(context: Context) : BaseNotification(context) {
|
||||||
|
|
||||||
|
private val channelId = "Note_Notify"
|
||||||
|
|
||||||
|
@TargetApi(26)
|
||||||
|
override fun createChannel(channelId: String) {
|
||||||
|
notificationManager.createNotificationChannel(NotificationChannel(
|
||||||
|
channelId, context.getString(R.string.notify_note_channel), NotificationManager.IMPORTANCE_HIGH
|
||||||
|
).apply {
|
||||||
|
enableLights(true)
|
||||||
|
enableVibration(true)
|
||||||
|
lockscreenVisibility = Notification.VISIBILITY_PUBLIC
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fun sendNotification(items: List<Note>) {
|
||||||
|
notify(notificationBuilder(channelId)
|
||||||
|
.setContentTitle(context.resources.getQuantityString(R.plurals.note_new_items, items.size, items.size))
|
||||||
|
.setContentText(context.resources.getQuantityString(R.plurals.notify_note_new_items, items.size, items.size))
|
||||||
|
.setSmallIcon(R.drawable.ic_stat_notify_note)
|
||||||
|
.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
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.setStyle(NotificationCompat.InboxStyle().run {
|
||||||
|
setSummaryText(context.resources.getQuantityString(R.plurals.note_number_item, items.size, items.size))
|
||||||
|
items.forEach {
|
||||||
|
addLine("${it.teacher}: ${it.category}")
|
||||||
|
}
|
||||||
|
this
|
||||||
|
})
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
|
||||||
|
Timber.d("Notification sent")
|
||||||
|
}
|
||||||
|
}
|
@ -18,7 +18,6 @@ import io.github.wulkanowy.ui.modules.grade.GradeFragment
|
|||||||
import io.github.wulkanowy.ui.modules.more.MoreFragment
|
import io.github.wulkanowy.ui.modules.more.MoreFragment
|
||||||
import io.github.wulkanowy.ui.modules.timetable.TimetableFragment
|
import io.github.wulkanowy.ui.modules.timetable.TimetableFragment
|
||||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||||
import io.github.wulkanowy.utils.logLogin
|
|
||||||
import io.github.wulkanowy.utils.safelyPopFragment
|
import io.github.wulkanowy.utils.safelyPopFragment
|
||||||
import io.github.wulkanowy.utils.setOnViewChangeListener
|
import io.github.wulkanowy.utils.setOnViewChangeListener
|
||||||
import kotlinx.android.synthetic.main.activity_main.*
|
import kotlinx.android.synthetic.main.activity_main.*
|
||||||
|
@ -14,6 +14,7 @@ import io.github.wulkanowy.ui.modules.exam.ExamFragment
|
|||||||
import io.github.wulkanowy.ui.modules.grade.GradeFragment
|
import io.github.wulkanowy.ui.modules.grade.GradeFragment
|
||||||
import io.github.wulkanowy.ui.modules.grade.GradeModule
|
import io.github.wulkanowy.ui.modules.grade.GradeModule
|
||||||
import io.github.wulkanowy.ui.modules.more.MoreFragment
|
import io.github.wulkanowy.ui.modules.more.MoreFragment
|
||||||
|
import io.github.wulkanowy.ui.modules.note.NoteFragment
|
||||||
import io.github.wulkanowy.ui.modules.settings.SettingsFragment
|
import io.github.wulkanowy.ui.modules.settings.SettingsFragment
|
||||||
import io.github.wulkanowy.ui.modules.timetable.TimetableFragment
|
import io.github.wulkanowy.ui.modules.timetable.TimetableFragment
|
||||||
|
|
||||||
@ -57,4 +58,7 @@ abstract class MainModule {
|
|||||||
|
|
||||||
@ContributesAndroidInjector
|
@ContributesAndroidInjector
|
||||||
abstract fun bindSettingsFragment(): SettingsFragment
|
abstract fun bindSettingsFragment(): SettingsFragment
|
||||||
|
|
||||||
|
@ContributesAndroidInjector
|
||||||
|
abstract fun bindNoteFragment(): NoteFragment
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ class MainPresenter @Inject constructor(
|
|||||||
when (initMenuIndex) {
|
when (initMenuIndex) {
|
||||||
1 -> logLogin("Grades")
|
1 -> logLogin("Grades")
|
||||||
3 -> logLogin("Timetable")
|
3 -> logLogin("Timetable")
|
||||||
|
4 -> logLogin("More")
|
||||||
}
|
}
|
||||||
|
|
||||||
serviceHelper.startFullSyncService()
|
serviceHelper.startFullSyncService()
|
||||||
|
@ -14,6 +14,7 @@ import io.github.wulkanowy.ui.base.BaseFragment
|
|||||||
import io.github.wulkanowy.ui.modules.about.AboutFragment
|
import io.github.wulkanowy.ui.modules.about.AboutFragment
|
||||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||||
import io.github.wulkanowy.ui.modules.main.MainView
|
import io.github.wulkanowy.ui.modules.main.MainView
|
||||||
|
import io.github.wulkanowy.ui.modules.note.NoteFragment
|
||||||
import io.github.wulkanowy.ui.modules.settings.SettingsFragment
|
import io.github.wulkanowy.ui.modules.settings.SettingsFragment
|
||||||
import io.github.wulkanowy.utils.setOnItemClickListener
|
import io.github.wulkanowy.utils.setOnItemClickListener
|
||||||
import kotlinx.android.synthetic.main.fragment_more.*
|
import kotlinx.android.synthetic.main.fragment_more.*
|
||||||
@ -34,11 +35,18 @@ class MoreFragment : BaseFragment(), MoreView, MainView.TitledView, MainView.Mai
|
|||||||
override val titleStringId: Int
|
override val titleStringId: Int
|
||||||
get() = R.string.more_title
|
get() = R.string.more_title
|
||||||
|
|
||||||
|
override val noteRes: Pair<String, Drawable?>?
|
||||||
|
get() {
|
||||||
|
return context?.run {
|
||||||
|
getString(R.string.note_title) to ContextCompat.getDrawable(this, R.drawable.ic_menu_main_note_24dp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override val settingsRes: Pair<String, Drawable?>?
|
override val settingsRes: Pair<String, Drawable?>?
|
||||||
get() {
|
get() {
|
||||||
return context?.run {
|
return context?.run {
|
||||||
getString(R.string.settings_title) to
|
getString(R.string.settings_title) to
|
||||||
ContextCompat.getDrawable(this, R.drawable.ic_more_settings_24dp)
|
ContextCompat.getDrawable(this, R.drawable.ic_more_settings_24dp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,7 +54,7 @@ class MoreFragment : BaseFragment(), MoreView, MainView.TitledView, MainView.Mai
|
|||||||
get() {
|
get() {
|
||||||
return context?.run {
|
return context?.run {
|
||||||
getString(R.string.about_title) to
|
getString(R.string.about_title) to
|
||||||
ContextCompat.getDrawable(this, R.drawable.ic_more_about_24dp)
|
ContextCompat.getDrawable(this, R.drawable.ic_more_about_24dp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,6 +84,10 @@ class MoreFragment : BaseFragment(), MoreView, MainView.TitledView, MainView.Mai
|
|||||||
moreAdapter.updateDataSet(data)
|
moreAdapter.updateDataSet(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun openNoteView() {
|
||||||
|
(activity as? MainActivity)?.pushView(NoteFragment.newInstance())
|
||||||
|
}
|
||||||
|
|
||||||
override fun openSettingsView() {
|
override fun openSettingsView() {
|
||||||
(activity as? MainActivity)?.pushView(SettingsFragment.newInstance())
|
(activity as? MainActivity)?.pushView(SettingsFragment.newInstance())
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,7 @@ import io.github.wulkanowy.data.ErrorHandler
|
|||||||
import io.github.wulkanowy.ui.base.BasePresenter
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class MorePresenter @Inject constructor(errorHandler: ErrorHandler)
|
class MorePresenter @Inject constructor(errorHandler: ErrorHandler) : BasePresenter<MoreView>(errorHandler) {
|
||||||
: BasePresenter<MoreView>(errorHandler) {
|
|
||||||
|
|
||||||
override fun onAttachView(view: MoreView) {
|
override fun onAttachView(view: MoreView) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
@ -18,6 +17,7 @@ class MorePresenter @Inject constructor(errorHandler: ErrorHandler)
|
|||||||
if (item is MoreItem) {
|
if (item is MoreItem) {
|
||||||
view?.run {
|
view?.run {
|
||||||
when (item.title) {
|
when (item.title) {
|
||||||
|
noteRes?.first -> openNoteView()
|
||||||
settingsRes?.first -> openSettingsView()
|
settingsRes?.first -> openSettingsView()
|
||||||
aboutRes?.first -> openAboutView()
|
aboutRes?.first -> openAboutView()
|
||||||
}
|
}
|
||||||
@ -32,8 +32,10 @@ class MorePresenter @Inject constructor(errorHandler: ErrorHandler)
|
|||||||
private fun loadData() {
|
private fun loadData() {
|
||||||
view?.run {
|
view?.run {
|
||||||
updateData(listOfNotNull(
|
updateData(listOfNotNull(
|
||||||
settingsRes?.let { MoreItem(it.first, it.second) },
|
noteRes?.let { MoreItem(it.first, it.second) },
|
||||||
aboutRes?.let { MoreItem(it.first, it.second) }))
|
settingsRes?.let { MoreItem(it.first, it.second) },
|
||||||
|
aboutRes?.let { MoreItem(it.first, it.second) })
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,8 @@ import io.github.wulkanowy.ui.base.BaseView
|
|||||||
|
|
||||||
interface MoreView : BaseView {
|
interface MoreView : BaseView {
|
||||||
|
|
||||||
|
val noteRes: Pair<String, Drawable?>?
|
||||||
|
|
||||||
val settingsRes: Pair<String, Drawable?>?
|
val settingsRes: Pair<String, Drawable?>?
|
||||||
|
|
||||||
val aboutRes: Pair<String, Drawable?>?
|
val aboutRes: Pair<String, Drawable?>?
|
||||||
@ -18,4 +20,5 @@ interface MoreView : BaseView {
|
|||||||
fun openAboutView()
|
fun openAboutView()
|
||||||
|
|
||||||
fun popView()
|
fun popView()
|
||||||
|
fun openNoteView()
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,48 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.note
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.fragment.app.DialogFragment
|
||||||
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.data.db.entities.Note
|
||||||
|
import io.github.wulkanowy.utils.toFormattedString
|
||||||
|
import kotlinx.android.synthetic.main.dialog_note.*
|
||||||
|
|
||||||
|
class NoteDialog : DialogFragment() {
|
||||||
|
|
||||||
|
private lateinit var note: Note
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val ARGUMENT_KEY = "Item"
|
||||||
|
|
||||||
|
fun newInstance(exam: Note): NoteDialog {
|
||||||
|
return NoteDialog().apply {
|
||||||
|
arguments = Bundle().apply { putSerializable(ARGUMENT_KEY, exam) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setStyle(STYLE_NO_TITLE, 0)
|
||||||
|
arguments?.run {
|
||||||
|
note = getSerializable(ARGUMENT_KEY) as Note
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
|
return inflater.inflate(R.layout.dialog_note, container, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
|
super.onActivityCreated(savedInstanceState)
|
||||||
|
|
||||||
|
noteDialogDate.text = note.date.toFormattedString()
|
||||||
|
noteDialogCategory.text = note.category
|
||||||
|
noteDialogTeacher.text = note.teacher
|
||||||
|
noteDialogContent.text = note.content
|
||||||
|
noteDialogClose.setOnClickListener { dismiss() }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,95 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.note
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.View.GONE
|
||||||
|
import android.view.View.VISIBLE
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
|
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
|
||||||
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||||
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.data.db.entities.Note
|
||||||
|
import io.github.wulkanowy.ui.base.BaseFragment
|
||||||
|
import io.github.wulkanowy.ui.modules.main.MainView
|
||||||
|
import io.github.wulkanowy.utils.setOnItemClickListener
|
||||||
|
import kotlinx.android.synthetic.main.fragment_note.*
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class NoteFragment : BaseFragment(), NoteView, MainView.TitledView {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var presenter: NotePresenter
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var noteAdapter: FlexibleAdapter<AbstractFlexibleItem<*>>
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun newInstance() = NoteFragment()
|
||||||
|
}
|
||||||
|
|
||||||
|
override val titleStringId: Int
|
||||||
|
get() = R.string.note_title
|
||||||
|
|
||||||
|
override val isViewEmpty: Boolean
|
||||||
|
get() = noteAdapter.isEmpty
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
|
return inflater.inflate(R.layout.fragment_note, container, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
|
super.onActivityCreated(savedInstanceState)
|
||||||
|
presenter.onAttachView(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun initView() {
|
||||||
|
noteAdapter.run {
|
||||||
|
setOnItemClickListener { presenter.onNoteItemSelected(getItem(it)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
noteRecycler.run {
|
||||||
|
layoutManager = SmoothScrollLinearLayoutManager(context)
|
||||||
|
adapter = noteAdapter
|
||||||
|
}
|
||||||
|
noteSwipe.setOnRefreshListener { presenter.onSwipeRefresh() }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showNoteDialog(note: Note) {
|
||||||
|
NoteDialog.newInstance(note).show(fragmentManager, note.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateData(data: List<NoteItem>) {
|
||||||
|
noteAdapter.updateDataSet(data, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateItem(item: AbstractFlexibleItem<*>) {
|
||||||
|
noteAdapter.updateItem(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clearData() {
|
||||||
|
noteAdapter.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showEmpty(show: Boolean) {
|
||||||
|
noteEmpty.visibility = if (show) VISIBLE else GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showProgress(show: Boolean) {
|
||||||
|
noteProgress.visibility = if (show) VISIBLE else GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showContent(show: Boolean) {
|
||||||
|
noteRecycler.visibility = if (show) VISIBLE else GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hideRefresh() {
|
||||||
|
noteSwipe.isRefreshing = false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
presenter.onDetachView()
|
||||||
|
super.onDestroyView()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,61 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.note
|
||||||
|
|
||||||
|
import android.graphics.Typeface.BOLD
|
||||||
|
import android.graphics.Typeface.NORMAL
|
||||||
|
import android.view.View
|
||||||
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||||
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
|
import eu.davidea.viewholders.FlexibleViewHolder
|
||||||
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.data.db.entities.Note
|
||||||
|
import io.github.wulkanowy.utils.toFormattedString
|
||||||
|
import kotlinx.android.extensions.LayoutContainer
|
||||||
|
import kotlinx.android.synthetic.main.item_note.*
|
||||||
|
|
||||||
|
class NoteItem(val note: Note) : AbstractFlexibleItem<NoteItem.ViewHolder>() {
|
||||||
|
|
||||||
|
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<*>>): NoteItem.ViewHolder {
|
||||||
|
return NoteItem.ViewHolder(view, adapter)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getLayoutRes(): Int = R.layout.item_note
|
||||||
|
|
||||||
|
override fun bindViewHolder(
|
||||||
|
adapter: FlexibleAdapter<IFlexible<*>>,
|
||||||
|
holder: NoteItem.ViewHolder, position: Int, payloads: MutableList<Any>?
|
||||||
|
) {
|
||||||
|
holder.apply {
|
||||||
|
noteItemDate.apply {
|
||||||
|
text = note.date.toFormattedString()
|
||||||
|
setTypeface(null, if (note.isRead) NORMAL else BOLD)
|
||||||
|
}
|
||||||
|
noteItemType.apply {
|
||||||
|
text = note.category
|
||||||
|
setTypeface(null, if (note.isRead) NORMAL else BOLD)
|
||||||
|
}
|
||||||
|
noteItemTeacher.text = note.teacher
|
||||||
|
noteItemContent.text = note.content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
|
||||||
|
other as NoteItem
|
||||||
|
|
||||||
|
if (note != other.note) return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return note.hashCode()
|
||||||
|
}
|
||||||
|
|
||||||
|
class ViewHolder(val view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer {
|
||||||
|
|
||||||
|
override val containerView: View
|
||||||
|
get() = contentView
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,80 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.note
|
||||||
|
|
||||||
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||||
|
import io.github.wulkanowy.data.ErrorHandler
|
||||||
|
import io.github.wulkanowy.data.db.entities.Note
|
||||||
|
import io.github.wulkanowy.data.repositories.NoteRepository
|
||||||
|
import io.github.wulkanowy.data.repositories.SessionRepository
|
||||||
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
|
import io.github.wulkanowy.utils.SchedulersProvider
|
||||||
|
import io.github.wulkanowy.utils.logEvent
|
||||||
|
import timber.log.Timber
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class NotePresenter @Inject constructor(
|
||||||
|
private val errorHandler: ErrorHandler,
|
||||||
|
private val schedulers: SchedulersProvider,
|
||||||
|
private val sessionRepository: SessionRepository,
|
||||||
|
private val noteRepository: NoteRepository
|
||||||
|
) : BasePresenter<NoteView>(errorHandler) {
|
||||||
|
|
||||||
|
override fun onAttachView(view: NoteView) {
|
||||||
|
super.onAttachView(view)
|
||||||
|
view.initView()
|
||||||
|
loadData()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onSwipeRefresh() {
|
||||||
|
loadData(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadData(forceRefresh: Boolean = false) {
|
||||||
|
disposable.add(sessionRepository.getSemesters()
|
||||||
|
.map { it.single { semester -> semester.current } }
|
||||||
|
.flatMap { noteRepository.getNotes(it, forceRefresh) }
|
||||||
|
.map { items -> items.map { NoteItem(it) } }
|
||||||
|
.map { items -> items.sortedByDescending { it.note.date } }
|
||||||
|
.subscribeOn(schedulers.backgroundThread)
|
||||||
|
.observeOn(schedulers.mainThread)
|
||||||
|
.doFinally {
|
||||||
|
view?.run {
|
||||||
|
hideRefresh()
|
||||||
|
showProgress(false)
|
||||||
|
}
|
||||||
|
}.subscribe({
|
||||||
|
view?.apply {
|
||||||
|
updateData(it)
|
||||||
|
showEmpty(it.isEmpty())
|
||||||
|
showContent(it.isNotEmpty())
|
||||||
|
}
|
||||||
|
logEvent("Note load", mapOf("items" to it.size, "forceRefresh" to forceRefresh))
|
||||||
|
}, {
|
||||||
|
view?.run { showEmpty(isViewEmpty) }
|
||||||
|
errorHandler.proceed(it)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onNoteItemSelected(item: AbstractFlexibleItem<*>?) {
|
||||||
|
if (item is NoteItem) {
|
||||||
|
view?.run {
|
||||||
|
showNoteDialog(item.note)
|
||||||
|
if (!item.note.isRead) {
|
||||||
|
item.note.isRead = true
|
||||||
|
updateItem(item)
|
||||||
|
updateNote(item.note)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateNote(note: Note) {
|
||||||
|
disposable.add(noteRepository.updateNote(note)
|
||||||
|
.subscribeOn(schedulers.backgroundThread)
|
||||||
|
.observeOn(schedulers.mainThread)
|
||||||
|
.subscribe({
|
||||||
|
Timber.d("Note ${note.id} updated")
|
||||||
|
}) { error -> errorHandler.proceed(error) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.note
|
||||||
|
|
||||||
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||||
|
import io.github.wulkanowy.data.db.entities.Note
|
||||||
|
import io.github.wulkanowy.ui.base.BaseView
|
||||||
|
|
||||||
|
interface NoteView : BaseView {
|
||||||
|
|
||||||
|
val isViewEmpty: Boolean
|
||||||
|
|
||||||
|
fun initView()
|
||||||
|
|
||||||
|
fun updateData(data: List<NoteItem>)
|
||||||
|
|
||||||
|
fun updateItem(item: AbstractFlexibleItem<*>)
|
||||||
|
|
||||||
|
fun clearData()
|
||||||
|
|
||||||
|
fun showEmpty(show: Boolean)
|
||||||
|
|
||||||
|
fun showProgress(show: Boolean)
|
||||||
|
|
||||||
|
fun showContent(show: Boolean)
|
||||||
|
|
||||||
|
fun hideRefresh()
|
||||||
|
|
||||||
|
fun showNoteDialog(note: Note)
|
||||||
|
}
|
BIN
app/src/main/res/drawable-hdpi/ic_stat_notify_note.png
Normal file
BIN
app/src/main/res/drawable-hdpi/ic_stat_notify_note.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 414 B |
BIN
app/src/main/res/drawable-mdpi/ic_stat_notify_note.png
Normal file
BIN
app/src/main/res/drawable-mdpi/ic_stat_notify_note.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 302 B |
BIN
app/src/main/res/drawable-xhdpi/ic_stat_notify_note.png
Normal file
BIN
app/src/main/res/drawable-xhdpi/ic_stat_notify_note.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 554 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_stat_notify_note.png
Normal file
BIN
app/src/main/res/drawable-xxhdpi/ic_stat_notify_note.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 801 B |
BIN
app/src/main/res/drawable-xxxhdpi/ic_stat_notify_note.png
Normal file
BIN
app/src/main/res/drawable-xxxhdpi/ic_stat_notify_note.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
10
app/src/main/res/drawable/ic_menu_main_note_24dp.xml
Normal file
10
app/src/main/res/drawable/ic_menu_main_note_24dp.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<!--https://materialdesignicons.com/icon/trophy-->
|
||||||
|
<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="M20.2,2H19.5H18C17.1,2 16,3 16,4H8C8,3 6.9,2 6,2H4.5H3.8H2V11C2,12 3,13 4,13H6.2C6.6,15 7.9,16.7 11,17V19.1C8.8,19.3 8,20.4 8,21.7V22H16V21.7C16,20.4 15.2,19.3 13,19.1V17C16.1,16.7 17.4,15 17.8,13H20C21,13 22,12 22,11V2H20.2M4,11V4H6V6V11C5.1,11 4.3,11 4,11M20,11C19.7,11 18.9,11 18,11V6V4H20V11Z" />
|
||||||
|
</vector>
|
@ -1,8 +1,8 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:viewportHeight="24"
|
android:viewportWidth="24"
|
||||||
android:viewportWidth="24">
|
android:viewportHeight="24">
|
||||||
<path
|
<path
|
||||||
android:fillColor="#000"
|
android:fillColor="#000"
|
||||||
android:pathData="M14 14H7v2h7m5 3H5V8h14m0-5h-1V1h-2v2H8V1H6v2H5a2
|
android:pathData="M14 14H7v2h7m5 3H5V8h14m0-5h-1V1h-2v2H8V1H6v2H5a2
|
||||||
|
96
app/src/main/res/layout/dialog_note.xml
Normal file
96
app/src/main/res/layout/dialog_note.xml
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="300dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="20dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/note_dialog_details"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:layout_marginBottom="20dp"
|
||||||
|
android:text="@string/all_details"
|
||||||
|
android:textSize="20sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/all_category"
|
||||||
|
android:textSize="17sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/noteDialogCategory"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="3dp"
|
||||||
|
android:text="@string/all_no_data"
|
||||||
|
android:textIsSelectable="true"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:text="@string/all_teacher"
|
||||||
|
android:textSize="17sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/noteDialogTeacher"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="3dp"
|
||||||
|
android:text="@string/all_no_data"
|
||||||
|
android:textIsSelectable="true"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:text="@string/all_date"
|
||||||
|
android:textSize="17sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/noteDialogDate"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="3dp"
|
||||||
|
android:text="@string/all_no_data"
|
||||||
|
android:textIsSelectable="true"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:text="@string/note_content"
|
||||||
|
android:textSize="17sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/noteDialogContent"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="3dp"
|
||||||
|
android:lineSpacingMultiplier="1.2"
|
||||||
|
android:text="@string/all_no_data"
|
||||||
|
android:textIsSelectable="true"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/noteDialogClose"
|
||||||
|
style="@style/Widget.AppCompat.Button.Borderless"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:layout_marginTop="15dp"
|
||||||
|
android:text="@string/all_close"
|
||||||
|
android:textAllCaps="true"
|
||||||
|
android:textSize="15sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
51
app/src/main/res/layout/fragment_note.xml
Normal file
51
app/src/main/res/layout/fragment_note.xml
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/noteProgress"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:indeterminate="true" />
|
||||||
|
|
||||||
|
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||||
|
android:id="@+id/noteSwipe"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/noteRecycler"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/noteEmpty"
|
||||||
|
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_menu_main_note_24dp"
|
||||||
|
app:tint="?android:attr/textColorPrimary"
|
||||||
|
tools:ignore="contentDescription" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/note_no_items"
|
||||||
|
android:textSize="20sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
60
app/src/main/res/layout/item_note.xml
Normal file
60
app/src/main/res/layout/item_note.xml
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/note_subitem_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/ic_all_divider"
|
||||||
|
android:foreground="?attr/selectableItemBackgroundBorderless">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/noteItemDate"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="15dp"
|
||||||
|
android:layout_marginLeft="15dp"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:text="@string/all_date"
|
||||||
|
android:textSize="15sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/noteItemTeacher"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
android:layout_marginLeft="10dp"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:layout_marginEnd="15dp"
|
||||||
|
android:layout_marginRight="15dp"
|
||||||
|
android:layout_toEndOf="@id/noteItemDate"
|
||||||
|
android:layout_toRightOf="@id/noteItemDate"
|
||||||
|
android:gravity="end"
|
||||||
|
android:text="@string/all_teacher"
|
||||||
|
android:textSize="13sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/noteItemType"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/noteItemDate"
|
||||||
|
android:layout_alignStart="@id/noteItemDate"
|
||||||
|
android:layout_alignLeft="@id/noteItemDate"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginBottom="5dp"
|
||||||
|
android:text="@string/exam_type"
|
||||||
|
android:textSize="13sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/noteItemContent"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/noteItemType"
|
||||||
|
android:layout_alignStart="@id/noteItemDate"
|
||||||
|
android:layout_alignLeft="@id/noteItemDate"
|
||||||
|
android:layout_marginEnd="15dp"
|
||||||
|
android:layout_marginRight="15dp"
|
||||||
|
android:layout_marginBottom="15dp"
|
||||||
|
android:lineSpacingMultiplier="1.2"
|
||||||
|
android:text="@string/all_description"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
</RelativeLayout>
|
@ -11,6 +11,7 @@
|
|||||||
<string name="settings_title">Ustawienia</string>
|
<string name="settings_title">Ustawienia</string>
|
||||||
<string name="more_title">Więcej</string>
|
<string name="more_title">Więcej</string>
|
||||||
<string name="about_title">O aplikacji</string>
|
<string name="about_title">O aplikacji</string>
|
||||||
|
<string name="note_title">Uwagi i osiągnięcia</string>
|
||||||
|
|
||||||
|
|
||||||
<!--Login form-->
|
<!--Login form-->
|
||||||
@ -72,6 +73,16 @@
|
|||||||
</plurals>
|
</plurals>
|
||||||
|
|
||||||
|
|
||||||
|
<!--Note notify-->
|
||||||
|
<string name="notify_note_channel">Nowe uwagi</string>
|
||||||
|
<plurals name="notify_note_new_items">
|
||||||
|
<item quantity="one">Dostałeś %1$d uwagę</item>
|
||||||
|
<item quantity="few">"Dostałeś %1$d uwagi</item>
|
||||||
|
<item quantity="many">Dostałeś %1$d uwag</item>
|
||||||
|
<item quantity="other">Dostałeś %1$d uwag</item>
|
||||||
|
</plurals>
|
||||||
|
|
||||||
|
|
||||||
<!--Timetable-->
|
<!--Timetable-->
|
||||||
<string name="timetable_lesson">Lekcja</string>
|
<string name="timetable_lesson">Lekcja</string>
|
||||||
<string name="timetable_room">Sala</string>
|
<string name="timetable_room">Sala</string>
|
||||||
@ -107,6 +118,24 @@
|
|||||||
<string name="about_source_code">Kod źródłowy</string>
|
<string name="about_source_code">Kod źródłowy</string>
|
||||||
<string name="about_feedback">Zgłoś błąd</string>
|
<string name="about_feedback">Zgłoś błąd</string>
|
||||||
|
|
||||||
|
<!--Note-->
|
||||||
|
<string name="note_no_items">Brak informacji o uwagach</string>
|
||||||
|
<string name="note_content">Treść</string>
|
||||||
|
<plurals name="note_number_item">
|
||||||
|
<item quantity="one">%d uwaga</item>
|
||||||
|
<item quantity="few">%d uwagi</item>
|
||||||
|
<item quantity="many">%d uwag</item>
|
||||||
|
<item quantity="other">%d uwag</item>
|
||||||
|
</plurals>
|
||||||
|
|
||||||
|
<plurals name="note_new_items">
|
||||||
|
<item quantity="one">Nowa uwaga</item>
|
||||||
|
<item quantity="few">Nowe uwagi</item>
|
||||||
|
<item quantity="many">Nowych uwag</item>
|
||||||
|
<item quantity="other">Nowych uwag</item>
|
||||||
|
</plurals>
|
||||||
|
|
||||||
|
|
||||||
<!--Generic-->
|
<!--Generic-->
|
||||||
<string name="all_description">Opis</string>
|
<string name="all_description">Opis</string>
|
||||||
<string name="all_no_description">Brak opisu</string>
|
<string name="all_no_description">Brak opisu</string>
|
||||||
@ -114,6 +143,7 @@
|
|||||||
<string name="all_date">Data</string>
|
<string name="all_date">Data</string>
|
||||||
<string name="all_color">Kolor</string>
|
<string name="all_color">Kolor</string>
|
||||||
<string name="all_details">Szczegóły</string>
|
<string name="all_details">Szczegóły</string>
|
||||||
|
<string name="all_category">Kategoria</string>
|
||||||
<string name="all_close">Zamknij</string>
|
<string name="all_close">Zamknij</string>
|
||||||
<string name="all_cancel">Anuluj</string>
|
<string name="all_cancel">Anuluj</string>
|
||||||
<string name="all_no_data">Brak danych</string>
|
<string name="all_no_data">Brak danych</string>
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
<string name="settings_title">Settings</string>
|
<string name="settings_title">Settings</string>
|
||||||
<string name="more_title">More</string>
|
<string name="more_title">More</string>
|
||||||
<string name="about_title">About</string>
|
<string name="about_title">About</string>
|
||||||
|
<string name="note_title">Notes and achievements</string>
|
||||||
|
|
||||||
|
|
||||||
<!--Login form-->
|
<!--Login form-->
|
||||||
@ -64,6 +65,13 @@
|
|||||||
<item quantity="other">You received %1$d grades</item>
|
<item quantity="other">You received %1$d grades</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
|
|
||||||
|
<!--Note notify-->
|
||||||
|
<string name="notify_note_channel">New notes</string>
|
||||||
|
<plurals name="notify_note_new_items">
|
||||||
|
<item quantity="one">You received %1$d note</item>
|
||||||
|
<item quantity="other">You received %1$d notes</item>
|
||||||
|
</plurals>
|
||||||
|
|
||||||
|
|
||||||
<!--Timetable-->
|
<!--Timetable-->
|
||||||
<string name="timetable_lesson">Lesson</string>
|
<string name="timetable_lesson">Lesson</string>
|
||||||
@ -99,6 +107,19 @@
|
|||||||
<string name="about_source_code">Source code</string>
|
<string name="about_source_code">Source code</string>
|
||||||
<string name="about_feedback">Report a bug</string>
|
<string name="about_feedback">Report a bug</string>
|
||||||
|
|
||||||
|
<!--Note-->
|
||||||
|
<string name="note_no_items">No info about notes</string>
|
||||||
|
<string name="note_content">Content</string>
|
||||||
|
<plurals name="note_number_item">
|
||||||
|
<item quantity="one">%d note</item>
|
||||||
|
<item quantity="other">%d notes</item>
|
||||||
|
</plurals>
|
||||||
|
|
||||||
|
<plurals name="note_new_items">
|
||||||
|
<item quantity="one">New note</item>
|
||||||
|
<item quantity="other">New notes</item>
|
||||||
|
</plurals>
|
||||||
|
|
||||||
|
|
||||||
<!--Generic-->
|
<!--Generic-->
|
||||||
<string name="all_description">Description</string>
|
<string name="all_description">Description</string>
|
||||||
@ -107,6 +128,7 @@
|
|||||||
<string name="all_date">Date</string>
|
<string name="all_date">Date</string>
|
||||||
<string name="all_color">Color</string>
|
<string name="all_color">Color</string>
|
||||||
<string name="all_details">Details</string>
|
<string name="all_details">Details</string>
|
||||||
|
<string name="all_category">Category</string>
|
||||||
<string name="all_close">Close</string>
|
<string name="all_close">Close</string>
|
||||||
<string name="all_cancel">Cancel</string>
|
<string name="all_cancel">Cancel</string>
|
||||||
<string name="all_no_data">No data</string>
|
<string name="all_no_data">No data</string>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user