mirror of
https://github.com/wulkanowy/wulkanowy.git
synced 2025-01-18 13:26:44 -06:00
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/upload-key.jks
|
||||
*.log
|
||||
.idea/assetWizardSettings.xml
|
||||
|
@ -78,7 +78,7 @@ ext.androidx_version = "1.0.0"
|
||||
|
||||
dependencies {
|
||||
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.appcompat:appcompat:$androidx_version"
|
||||
|
@ -67,4 +67,8 @@ internal class RepositoryModule {
|
||||
@Singleton
|
||||
@Provides
|
||||
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.RoomDatabase
|
||||
import androidx.room.TypeConverters
|
||||
import io.github.wulkanowy.data.db.dao.*
|
||||
import io.github.wulkanowy.data.db.entities.*
|
||||
import io.github.wulkanowy.data.db.dao.AttendanceDao
|
||||
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
|
||||
|
||||
@Singleton
|
||||
@Database(
|
||||
entities = [
|
||||
Student::class,
|
||||
Semester::class,
|
||||
Exam::class,
|
||||
Timetable::class,
|
||||
Attendance::class,
|
||||
Grade::class,
|
||||
GradeSummary::class
|
||||
],
|
||||
version = 1,
|
||||
exportSchema = false
|
||||
entities = [
|
||||
Student::class,
|
||||
Semester::class,
|
||||
Exam::class,
|
||||
Timetable::class,
|
||||
Attendance::class,
|
||||
Grade::class,
|
||||
GradeSummary::class,
|
||||
Note::class
|
||||
],
|
||||
version = 1,
|
||||
exportSchema = false
|
||||
)
|
||||
@TypeConverters(Converters::class)
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
@ -29,7 +44,7 @@ abstract class AppDatabase : RoomDatabase() {
|
||||
companion object {
|
||||
fun newInstance(context: Context): AppDatabase {
|
||||
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 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.GradeRepository
|
||||
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.SessionRepository
|
||||
import io.github.wulkanowy.data.repositories.TimetableRepository
|
||||
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.isHolidays
|
||||
import io.github.wulkanowy.utils.monday
|
||||
@ -40,6 +42,9 @@ class SyncWorker : SimpleJobService() {
|
||||
@Inject
|
||||
lateinit var timetable: TimetableRepository
|
||||
|
||||
@Inject
|
||||
lateinit var note: NoteRepository
|
||||
|
||||
@Inject
|
||||
lateinit var prefRepository: PreferencesRepository
|
||||
|
||||
@ -73,7 +78,8 @@ class SyncWorker : SimpleJobService() {
|
||||
gradesSummary.getGradesSummary(it, true),
|
||||
attendance.getAttendance(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() {
|
||||
disposable.add(session.getSemesters(true)
|
||||
sendGradeNotifications()
|
||||
sendNoteNotification()
|
||||
}
|
||||
|
||||
private fun sendGradeNotifications() {
|
||||
disposable.add(session.getSemesters()
|
||||
.map { it.single { semester -> semester.current } }
|
||||
.flatMap { gradesDetails.getNewGrades(it) }
|
||||
.map { it.filter { grade -> !grade.isNotified } }
|
||||
@ -103,6 +114,20 @@ class SyncWorker : SimpleJobService() {
|
||||
}) { 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() {
|
||||
super.onDestroy()
|
||||
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.timetable.TimetableFragment
|
||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||
import io.github.wulkanowy.utils.logLogin
|
||||
import io.github.wulkanowy.utils.safelyPopFragment
|
||||
import io.github.wulkanowy.utils.setOnViewChangeListener
|
||||
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.GradeModule
|
||||
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.timetable.TimetableFragment
|
||||
|
||||
@ -57,4 +58,7 @@ abstract class MainModule {
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract fun bindSettingsFragment(): SettingsFragment
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract fun bindNoteFragment(): NoteFragment
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ class MainPresenter @Inject constructor(
|
||||
when (initMenuIndex) {
|
||||
1 -> logLogin("Grades")
|
||||
3 -> logLogin("Timetable")
|
||||
4 -> logLogin("More")
|
||||
}
|
||||
|
||||
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.main.MainActivity
|
||||
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.utils.setOnItemClickListener
|
||||
import kotlinx.android.synthetic.main.fragment_more.*
|
||||
@ -34,11 +35,18 @@ class MoreFragment : BaseFragment(), MoreView, MainView.TitledView, MainView.Mai
|
||||
override val titleStringId: Int
|
||||
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?>?
|
||||
get() {
|
||||
return context?.run {
|
||||
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() {
|
||||
return context?.run {
|
||||
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)
|
||||
}
|
||||
|
||||
override fun openNoteView() {
|
||||
(activity as? MainActivity)?.pushView(NoteFragment.newInstance())
|
||||
}
|
||||
|
||||
override fun openSettingsView() {
|
||||
(activity as? MainActivity)?.pushView(SettingsFragment.newInstance())
|
||||
}
|
||||
|
@ -5,8 +5,7 @@ import io.github.wulkanowy.data.ErrorHandler
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import javax.inject.Inject
|
||||
|
||||
class MorePresenter @Inject constructor(errorHandler: ErrorHandler)
|
||||
: BasePresenter<MoreView>(errorHandler) {
|
||||
class MorePresenter @Inject constructor(errorHandler: ErrorHandler) : BasePresenter<MoreView>(errorHandler) {
|
||||
|
||||
override fun onAttachView(view: MoreView) {
|
||||
super.onAttachView(view)
|
||||
@ -18,6 +17,7 @@ class MorePresenter @Inject constructor(errorHandler: ErrorHandler)
|
||||
if (item is MoreItem) {
|
||||
view?.run {
|
||||
when (item.title) {
|
||||
noteRes?.first -> openNoteView()
|
||||
settingsRes?.first -> openSettingsView()
|
||||
aboutRes?.first -> openAboutView()
|
||||
}
|
||||
@ -32,8 +32,10 @@ class MorePresenter @Inject constructor(errorHandler: ErrorHandler)
|
||||
private fun loadData() {
|
||||
view?.run {
|
||||
updateData(listOfNotNull(
|
||||
settingsRes?.let { MoreItem(it.first, it.second) },
|
||||
aboutRes?.let { MoreItem(it.first, it.second) }))
|
||||
noteRes?.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 {
|
||||
|
||||
val noteRes: Pair<String, Drawable?>?
|
||||
|
||||
val settingsRes: Pair<String, Drawable?>?
|
||||
|
||||
val aboutRes: Pair<String, Drawable?>?
|
||||
@ -18,4 +20,5 @@ interface MoreView : BaseView {
|
||||
fun openAboutView()
|
||||
|
||||
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"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24"
|
||||
android:viewportWidth="24">
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#000"
|
||||
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="more_title">Więcej</string>
|
||||
<string name="about_title">O aplikacji</string>
|
||||
<string name="note_title">Uwagi i osiągnięcia</string>
|
||||
|
||||
|
||||
<!--Login form-->
|
||||
@ -72,6 +73,16 @@
|
||||
</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-->
|
||||
<string name="timetable_lesson">Lekcja</string>
|
||||
<string name="timetable_room">Sala</string>
|
||||
@ -107,6 +118,24 @@
|
||||
<string name="about_source_code">Kod źródłowy</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-->
|
||||
<string name="all_description">Opis</string>
|
||||
<string name="all_no_description">Brak opisu</string>
|
||||
@ -114,6 +143,7 @@
|
||||
<string name="all_date">Data</string>
|
||||
<string name="all_color">Kolor</string>
|
||||
<string name="all_details">Szczegóły</string>
|
||||
<string name="all_category">Kategoria</string>
|
||||
<string name="all_close">Zamknij</string>
|
||||
<string name="all_cancel">Anuluj</string>
|
||||
<string name="all_no_data">Brak danych</string>
|
||||
|
@ -11,6 +11,7 @@
|
||||
<string name="settings_title">Settings</string>
|
||||
<string name="more_title">More</string>
|
||||
<string name="about_title">About</string>
|
||||
<string name="note_title">Notes and achievements</string>
|
||||
|
||||
|
||||
<!--Login form-->
|
||||
@ -64,6 +65,13 @@
|
||||
<item quantity="other">You received %1$d grades</item>
|
||||
</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-->
|
||||
<string name="timetable_lesson">Lesson</string>
|
||||
@ -99,6 +107,19 @@
|
||||
<string name="about_source_code">Source code</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-->
|
||||
<string name="all_description">Description</string>
|
||||
@ -107,6 +128,7 @@
|
||||
<string name="all_date">Date</string>
|
||||
<string name="all_color">Color</string>
|
||||
<string name="all_details">Details</string>
|
||||
<string name="all_category">Category</string>
|
||||
<string name="all_close">Close</string>
|
||||
<string name="all_cancel">Cancel</string>
|
||||
<string name="all_no_data">No data</string>
|
||||
|
Loading…
x
Reference in New Issue
Block a user