forked from github/wulkanowy-mirror
Add additional lessons feature (#1550)
This commit is contained in:
parent
cc22985dc5
commit
094df212b4
@ -167,7 +167,7 @@ huaweiPublish {
|
||||
ext {
|
||||
work_manager = "2.7.1"
|
||||
android_hilt = "1.0.0"
|
||||
room = "2.3.0"
|
||||
room = "2.4.0"
|
||||
chucker = "3.5.2"
|
||||
mockk = "1.12.1"
|
||||
coroutines = "1.5.2"
|
||||
|
2430
app/schemas/io.github.wulkanowy.data.db.AppDatabase/45.json
Normal file
2430
app/schemas/io.github.wulkanowy.data.db.AppDatabase/45.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -114,7 +114,6 @@
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
|
||||
<receiver
|
||||
android:name=".ui.modules.timetablewidget.TimetableWidgetProvider"
|
||||
android:exported="true"
|
||||
|
@ -1,6 +1,7 @@
|
||||
package io.github.wulkanowy.data.db
|
||||
|
||||
import android.content.Context
|
||||
import androidx.room.AutoMigration
|
||||
import androidx.room.Database
|
||||
import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
@ -146,6 +147,9 @@ import javax.inject.Singleton
|
||||
Notification::class,
|
||||
AdminMessage::class
|
||||
],
|
||||
autoMigrations = [
|
||||
AutoMigration(from = 44, to = 45)
|
||||
],
|
||||
version = AppDatabase.VERSION_SCHEMA,
|
||||
exportSchema = true
|
||||
)
|
||||
@ -153,7 +157,7 @@ import javax.inject.Singleton
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
|
||||
companion object {
|
||||
const val VERSION_SCHEMA = 44
|
||||
const val VERSION_SCHEMA = 45
|
||||
|
||||
fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf(
|
||||
Migration2(),
|
||||
@ -198,7 +202,7 @@ abstract class AppDatabase : RoomDatabase() {
|
||||
Migration41(sharedPrefProvider),
|
||||
Migration42(),
|
||||
Migration43(),
|
||||
Migration44()
|
||||
Migration44(),
|
||||
)
|
||||
|
||||
fun newInstance(
|
||||
|
@ -5,6 +5,7 @@ import androidx.room.Query
|
||||
import io.github.wulkanowy.data.db.entities.TimetableAdditional
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import java.time.LocalDate
|
||||
import java.util.UUID
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Dao
|
||||
@ -12,5 +13,13 @@ import javax.inject.Singleton
|
||||
interface TimetableAdditionalDao : BaseDao<TimetableAdditional> {
|
||||
|
||||
@Query("SELECT * FROM TimetableAdditional WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :from AND date <= :end")
|
||||
fun loadAll(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): Flow<List<TimetableAdditional>>
|
||||
fun loadAll(
|
||||
diaryId: Int,
|
||||
studentId: Int,
|
||||
from: LocalDate,
|
||||
end: LocalDate
|
||||
): Flow<List<TimetableAdditional>>
|
||||
|
||||
@Query("DELETE FROM TimetableAdditional WHERE repeat_id = :repeatId")
|
||||
suspend fun deleteAllByRepeatId(repeatId: UUID)
|
||||
}
|
||||
|
@ -42,7 +42,6 @@ data class Semester(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Long = 0
|
||||
|
||||
|
||||
@ColumnInfo(name = "is_current")
|
||||
var current: Boolean = false
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import androidx.room.PrimaryKey
|
||||
import java.io.Serializable
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalDateTime
|
||||
import java.util.UUID
|
||||
|
||||
@Entity(tableName = "TimetableAdditional")
|
||||
data class TimetableAdditional(
|
||||
@ -27,4 +28,10 @@ data class TimetableAdditional(
|
||||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Long = 0
|
||||
|
||||
@ColumnInfo(name = "repeat_id", defaultValue = "NULL")
|
||||
var repeatId: UUID? = null
|
||||
|
||||
@ColumnInfo(name = "is_added_by_user", defaultValue = "0")
|
||||
var isAddedByUser: Boolean = false
|
||||
}
|
||||
|
@ -152,7 +152,8 @@ class TimetableRepository @Inject constructor(
|
||||
old: List<TimetableAdditional>,
|
||||
new: List<TimetableAdditional>
|
||||
) {
|
||||
timetableAdditionalDb.deleteAll(old uniqueSubtract new)
|
||||
val oldFiltered = old.filter { !it.isAddedByUser }
|
||||
timetableAdditionalDb.deleteAll(oldFiltered uniqueSubtract new)
|
||||
timetableAdditionalDb.insertAll(new uniqueSubtract old)
|
||||
}
|
||||
|
||||
@ -160,4 +161,14 @@ class TimetableRepository @Inject constructor(
|
||||
timetableHeaderDb.deleteAll(old uniqueSubtract new)
|
||||
timetableHeaderDb.insertAll(new uniqueSubtract old)
|
||||
}
|
||||
|
||||
suspend fun saveAdditionalList(additionalList: List<TimetableAdditional>) =
|
||||
timetableAdditionalDb.insertAll(additionalList)
|
||||
|
||||
suspend fun deleteAdditional(additional: TimetableAdditional, deleteSeries: Boolean) =
|
||||
if (deleteSeries) {
|
||||
timetableAdditionalDb.deleteAllByRepeatId(additional.repeatId!!)
|
||||
} else {
|
||||
timetableAdditionalDb.deleteAll(listOf(additional))
|
||||
}
|
||||
}
|
||||
|
@ -29,8 +29,8 @@ import io.github.wulkanowy.ui.modules.message.send.SendMessageActivity
|
||||
import io.github.wulkanowy.ui.widgets.DividerItemDecoration
|
||||
import io.github.wulkanowy.utils.SchoolDaysValidator
|
||||
import io.github.wulkanowy.utils.dpToPx
|
||||
import io.github.wulkanowy.utils.firstSchoolDayInSchoolYear
|
||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||
import io.github.wulkanowy.utils.schoolYearStart
|
||||
import io.github.wulkanowy.utils.toLocalDateTime
|
||||
import io.github.wulkanowy.utils.toTimestamp
|
||||
import java.time.LocalDate
|
||||
@ -225,7 +225,7 @@ class AttendanceFragment : BaseFragment<FragmentAttendanceBinding>(R.layout.frag
|
||||
}
|
||||
|
||||
override fun showDatePickerDialog(currentDate: LocalDate) {
|
||||
val baseDate = currentDate.schoolYearStart
|
||||
val baseDate = currentDate.firstSchoolDayInSchoolYear
|
||||
val rangeStart = baseDate.toTimestamp()
|
||||
val rangeEnd = LocalDate.now().plusWeeks(1).toTimestamp()
|
||||
|
||||
|
@ -11,6 +11,8 @@ import dagger.hilt.android.AndroidEntryPoint
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.databinding.DialogHomeworkAddBinding
|
||||
import io.github.wulkanowy.ui.base.BaseDialogFragment
|
||||
import io.github.wulkanowy.utils.SchoolDaysValidator
|
||||
import io.github.wulkanowy.utils.lastSchoolDayInSchoolYear
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import io.github.wulkanowy.utils.toLocalDateTime
|
||||
import io.github.wulkanowy.utils.toTimestamp
|
||||
@ -98,11 +100,14 @@ class HomeworkAddDialog : BaseDialogFragment<DialogHomeworkAddBinding>(), Homewo
|
||||
}
|
||||
|
||||
override fun showDatePickerDialog(currentDate: LocalDate) {
|
||||
val rangeStart = LocalDate.now().toTimestamp()
|
||||
val rangeEnd = LocalDate.now().lastSchoolDayInSchoolYear.toTimestamp()
|
||||
val constraintsBuilder = CalendarConstraints.Builder().apply {
|
||||
setStart(LocalDate.now().toEpochDay())
|
||||
setStart(rangeStart)
|
||||
setEnd(rangeEnd)
|
||||
setValidator(SchoolDaysValidator(rangeStart, rangeEnd))
|
||||
}
|
||||
val datePicker =
|
||||
MaterialDatePicker.Builder.datePicker()
|
||||
val datePicker = MaterialDatePicker.Builder.datePicker()
|
||||
.setCalendarConstraints(constraintsBuilder.build())
|
||||
.setSelection(currentDate.toTimestamp())
|
||||
.build()
|
||||
|
@ -16,7 +16,7 @@ import io.github.wulkanowy.ui.modules.main.MainView
|
||||
import io.github.wulkanowy.ui.widgets.DividerItemDecoration
|
||||
import io.github.wulkanowy.utils.SchoolDaysValidator
|
||||
import io.github.wulkanowy.utils.dpToPx
|
||||
import io.github.wulkanowy.utils.schoolYearStart
|
||||
import io.github.wulkanowy.utils.firstSchoolDayInSchoolYear
|
||||
import io.github.wulkanowy.utils.toLocalDateTime
|
||||
import io.github.wulkanowy.utils.toTimestamp
|
||||
import java.time.LocalDate
|
||||
@ -112,7 +112,7 @@ class LuckyNumberHistoryFragment :
|
||||
}
|
||||
|
||||
override fun showDatePickerDialog(currentDate: LocalDate) {
|
||||
val baseDate = currentDate.schoolYearStart
|
||||
val baseDate = currentDate.firstSchoolDayInSchoolYear
|
||||
val rangeStart = baseDate.toTimestamp()
|
||||
val rangeEnd = LocalDate.now().plusWeeks(1).toTimestamp()
|
||||
|
||||
|
@ -24,9 +24,9 @@ import io.github.wulkanowy.ui.modules.timetable.completed.CompletedLessonsFragme
|
||||
import io.github.wulkanowy.ui.widgets.DividerItemDecoration
|
||||
import io.github.wulkanowy.utils.SchoolDaysValidator
|
||||
import io.github.wulkanowy.utils.dpToPx
|
||||
import io.github.wulkanowy.utils.firstSchoolDayInSchoolYear
|
||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||
import io.github.wulkanowy.utils.schoolYearEnd
|
||||
import io.github.wulkanowy.utils.schoolYearStart
|
||||
import io.github.wulkanowy.utils.lastSchoolDayInSchoolYear
|
||||
import io.github.wulkanowy.utils.toLocalDateTime
|
||||
import io.github.wulkanowy.utils.toTimestamp
|
||||
import java.time.LocalDate
|
||||
@ -194,9 +194,9 @@ class TimetableFragment : BaseFragment<FragmentTimetableBinding>(R.layout.fragme
|
||||
}
|
||||
|
||||
override fun showDatePickerDialog(currentDate: LocalDate) {
|
||||
val baseDate = currentDate.schoolYearStart
|
||||
val baseDate = currentDate.firstSchoolDayInSchoolYear
|
||||
val rangeStart = baseDate.toTimestamp()
|
||||
val rangeEnd = LocalDate.now().schoolYearEnd.toTimestamp()
|
||||
val rangeEnd = LocalDate.now().lastSchoolDayInSchoolYear.toTimestamp()
|
||||
|
||||
val constraintsBuilder = CalendarConstraints.Builder().apply {
|
||||
setValidator(SchoolDaysValidator(rangeStart, rangeEnd))
|
||||
|
@ -3,6 +3,7 @@ package io.github.wulkanowy.ui.modules.timetable.additional
|
||||
import android.annotation.SuppressLint
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import io.github.wulkanowy.data.db.entities.TimetableAdditional
|
||||
import io.github.wulkanowy.databinding.ItemTimetableAdditionalBinding
|
||||
@ -14,6 +15,8 @@ class AdditionalLessonsAdapter @Inject constructor() :
|
||||
|
||||
var items = emptyList<TimetableAdditional>()
|
||||
|
||||
var onDeleteClickListener: (timetableAdditional: TimetableAdditional) -> Unit = {}
|
||||
|
||||
override fun getItemCount() = items.size
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder(
|
||||
@ -25,8 +28,12 @@ class AdditionalLessonsAdapter @Inject constructor() :
|
||||
val item = items[position]
|
||||
|
||||
with(holder.binding) {
|
||||
additionalLessonItemTime.text = "${item.start.toFormattedString("HH:mm")} - ${item.end.toFormattedString("HH:mm")}"
|
||||
additionalLessonItemTime.text =
|
||||
"${item.start.toFormattedString("HH:mm")} - ${item.end.toFormattedString("HH:mm")}"
|
||||
additionalLessonItemSubject.text = item.subject
|
||||
|
||||
additionalLessonItemDelete.isVisible = item.isAddedByUser
|
||||
additionalLessonItemDelete.setOnClickListener { onDeleteClickListener(item) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ package io.github.wulkanowy.ui.modules.timetable.additional
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.google.android.material.datepicker.CalendarConstraints
|
||||
import com.google.android.material.datepicker.MaterialDatePicker
|
||||
@ -10,13 +11,15 @@ import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.TimetableAdditional
|
||||
import io.github.wulkanowy.databinding.FragmentTimetableAdditionalBinding
|
||||
import io.github.wulkanowy.ui.base.BaseFragment
|
||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||
import io.github.wulkanowy.ui.modules.main.MainView
|
||||
import io.github.wulkanowy.ui.modules.timetable.additional.add.AdditionalLessonAddDialog
|
||||
import io.github.wulkanowy.ui.widgets.DividerItemDecoration
|
||||
import io.github.wulkanowy.utils.SchoolDaysValidator
|
||||
import io.github.wulkanowy.utils.dpToPx
|
||||
import io.github.wulkanowy.utils.firstSchoolDayInSchoolYear
|
||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||
import io.github.wulkanowy.utils.schoolYearEnd
|
||||
import io.github.wulkanowy.utils.schoolYearStart
|
||||
import io.github.wulkanowy.utils.lastSchoolDayInSchoolYear
|
||||
import io.github.wulkanowy.utils.toLocalDateTime
|
||||
import io.github.wulkanowy.utils.toTimestamp
|
||||
import java.time.LocalDate
|
||||
@ -53,7 +56,9 @@ class AdditionalLessonsFragment :
|
||||
override fun initView() {
|
||||
with(binding.additionalLessonsRecycler) {
|
||||
layoutManager = LinearLayoutManager(context)
|
||||
adapter = additionalLessonsAdapter
|
||||
adapter = additionalLessonsAdapter.apply {
|
||||
onDeleteClickListener = { presenter.onDeleteLessonsSelected(it) }
|
||||
}
|
||||
addItemDecoration(DividerItemDecoration(context))
|
||||
}
|
||||
|
||||
@ -61,9 +66,7 @@ class AdditionalLessonsFragment :
|
||||
additionalLessonsSwipe.setOnRefreshListener(presenter::onSwipeRefresh)
|
||||
additionalLessonsSwipe.setColorSchemeColors(requireContext().getThemeAttrColor(R.attr.colorPrimary))
|
||||
additionalLessonsSwipe.setProgressBackgroundColorSchemeColor(
|
||||
requireContext().getThemeAttrColor(
|
||||
R.attr.colorSwipeRefresh
|
||||
)
|
||||
requireContext().getThemeAttrColor(R.attr.colorSwipeRefresh)
|
||||
)
|
||||
additionalLessonsErrorRetry.setOnClickListener { presenter.onRetry() }
|
||||
additionalLessonsErrorDetails.setOnClickListener { presenter.onDetailsClick() }
|
||||
@ -72,6 +75,8 @@ class AdditionalLessonsFragment :
|
||||
additionalLessonsNavDate.setOnClickListener { presenter.onPickDate() }
|
||||
additionalLessonsNextButton.setOnClickListener { presenter.onNextDay() }
|
||||
|
||||
openAddAdditionalLessonButton.setOnClickListener { presenter.onAdditionalLessonAddButtonClicked() }
|
||||
|
||||
additionalLessonsNavContainer.elevation = requireContext().dpToPx(8f)
|
||||
}
|
||||
}
|
||||
@ -90,6 +95,10 @@ class AdditionalLessonsFragment :
|
||||
}
|
||||
}
|
||||
|
||||
override fun showSuccessMessage() {
|
||||
getString(R.string.additional_lessons_delete_success)
|
||||
}
|
||||
|
||||
override fun updateNavigationDay(date: String) {
|
||||
binding.additionalLessonsNavDate.text = date
|
||||
}
|
||||
@ -131,18 +140,21 @@ class AdditionalLessonsFragment :
|
||||
binding.additionalLessonsNextButton.visibility = if (show) View.VISIBLE else View.INVISIBLE
|
||||
}
|
||||
|
||||
override fun showAddAdditionalLessonDialog() {
|
||||
(activity as? MainActivity)?.showDialogFragment(AdditionalLessonAddDialog.newInstance())
|
||||
}
|
||||
|
||||
override fun showDatePickerDialog(currentDate: LocalDate) {
|
||||
val now = LocalDate.now()
|
||||
val startOfSchoolYear = now.schoolYearStart.toTimestamp()
|
||||
val endOfSchoolYear = now.schoolYearEnd.toTimestamp()
|
||||
val startOfSchoolYear = now.firstSchoolDayInSchoolYear.toTimestamp()
|
||||
val endOfSchoolYear = now.lastSchoolDayInSchoolYear.toTimestamp()
|
||||
|
||||
val constraintsBuilder = CalendarConstraints.Builder().apply {
|
||||
setValidator(SchoolDaysValidator(startOfSchoolYear, endOfSchoolYear))
|
||||
setStart(startOfSchoolYear)
|
||||
setEnd(endOfSchoolYear)
|
||||
}
|
||||
val datePicker =
|
||||
MaterialDatePicker.Builder.datePicker()
|
||||
val datePicker = MaterialDatePicker.Builder.datePicker()
|
||||
.setCalendarConstraints(constraintsBuilder.build())
|
||||
.setSelection(currentDate.toTimestamp())
|
||||
.build()
|
||||
@ -157,6 +169,18 @@ class AdditionalLessonsFragment :
|
||||
}
|
||||
}
|
||||
|
||||
override fun showDeleteLessonDialog(timetableAdditional: TimetableAdditional) {
|
||||
AlertDialog.Builder(requireContext())
|
||||
.setTitle(getString(R.string.additional_lessons_delete_title))
|
||||
.setItems(
|
||||
arrayOf(
|
||||
getString(R.string.additional_lessons_delete_one),
|
||||
getString(R.string.additional_lessons_delete_series)
|
||||
)
|
||||
) { _, position -> presenter.onDeleteDialogSelectItem(position, timetableAdditional) }
|
||||
.show()
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
outState.putLong(SAVED_DATE_KEY, presenter.currentDate.toEpochDay())
|
||||
|
@ -2,6 +2,7 @@ package io.github.wulkanowy.ui.modules.timetable.additional
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import io.github.wulkanowy.data.Status
|
||||
import io.github.wulkanowy.data.db.entities.TimetableAdditional
|
||||
import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.data.repositories.TimetableRepository
|
||||
@ -20,6 +21,7 @@ import io.github.wulkanowy.utils.toFormattedString
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import java.time.LocalDate
|
||||
import javax.inject.Inject
|
||||
@ -63,6 +65,10 @@ class AdditionalLessonsPresenter @Inject constructor(
|
||||
view?.showDatePickerDialog(currentDate)
|
||||
}
|
||||
|
||||
fun onAdditionalLessonAddButtonClicked() {
|
||||
view?.showAddAdditionalLessonDialog()
|
||||
}
|
||||
|
||||
fun onDateSet(year: Int, month: Int, day: Int) {
|
||||
loadData(LocalDate.of(year, month, day))
|
||||
reloadView()
|
||||
@ -98,6 +104,36 @@ class AdditionalLessonsPresenter @Inject constructor(
|
||||
}.launch("holidays")
|
||||
}
|
||||
|
||||
fun onDeleteLessonsSelected(timetableAdditional: TimetableAdditional) {
|
||||
if (timetableAdditional.repeatId == null) {
|
||||
deleteAdditionalLessons(timetableAdditional, false)
|
||||
} else {
|
||||
view?.showDeleteLessonDialog(timetableAdditional)
|
||||
}
|
||||
}
|
||||
|
||||
fun onDeleteDialogSelectItem(position: Int, timetableAdditional: TimetableAdditional) {
|
||||
deleteAdditionalLessons(timetableAdditional, position == 1)
|
||||
}
|
||||
|
||||
private fun deleteAdditionalLessons(
|
||||
timetableAdditional: TimetableAdditional,
|
||||
deleteSeries: Boolean
|
||||
) {
|
||||
presenterScope.launch {
|
||||
Timber.i("Additional Lesson delete start")
|
||||
runCatching { timetableRepository.deleteAdditional(timetableAdditional, deleteSeries) }
|
||||
.onSuccess {
|
||||
Timber.i("Additional Lesson delete: Success")
|
||||
view?.showSuccessMessage()
|
||||
}
|
||||
.onFailure {
|
||||
Timber.i("Additional Lesson delete result: An exception occurred")
|
||||
errorHandler.dispatch(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadData(date: LocalDate, forceRefresh: Boolean = false) {
|
||||
currentDate = date
|
||||
|
||||
@ -111,7 +147,7 @@ class AdditionalLessonsPresenter @Inject constructor(
|
||||
Status.SUCCESS -> {
|
||||
Timber.i("Loading additional lessons lessons result: Success")
|
||||
view?.apply {
|
||||
updateData(it.data!!.additional.sortedBy { item -> item.date })
|
||||
updateData(it.data!!.additional.sortedBy { item -> item.start })
|
||||
showEmpty(it.data.additional.isEmpty())
|
||||
showErrorView(false)
|
||||
showContent(it.data.additional.isNotEmpty())
|
||||
|
@ -35,4 +35,10 @@ interface AdditionalLessonsView : BaseView {
|
||||
fun showNextButton(show: Boolean)
|
||||
|
||||
fun showDatePickerDialog(currentDate: LocalDate)
|
||||
|
||||
fun showAddAdditionalLessonDialog()
|
||||
|
||||
fun showSuccessMessage()
|
||||
|
||||
fun showDeleteLessonDialog(timetableAdditional: TimetableAdditional)
|
||||
}
|
||||
|
@ -0,0 +1,188 @@
|
||||
package io.github.wulkanowy.ui.modules.timetable.additional.add
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import com.google.android.material.datepicker.CalendarConstraints
|
||||
import com.google.android.material.datepicker.MaterialDatePicker
|
||||
import com.google.android.material.timepicker.MaterialTimePicker
|
||||
import com.google.android.material.timepicker.TimeFormat
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.databinding.DialogAdditionalAddBinding
|
||||
import io.github.wulkanowy.ui.base.BaseDialogFragment
|
||||
import io.github.wulkanowy.utils.SchoolDaysValidator
|
||||
import io.github.wulkanowy.utils.lastSchoolDayInSchoolYear
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import io.github.wulkanowy.utils.toLocalDateTime
|
||||
import io.github.wulkanowy.utils.toTimestamp
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalTime
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class AdditionalLessonAddDialog : BaseDialogFragment<DialogAdditionalAddBinding>(),
|
||||
AdditionalLessonAddView {
|
||||
|
||||
@Inject
|
||||
lateinit var presenter: AdditionalLessonAddPresenter
|
||||
|
||||
companion object {
|
||||
fun newInstance() = AdditionalLessonAddDialog()
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setStyle(STYLE_NO_TITLE, 0)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
) = DialogAdditionalAddBinding.inflate(inflater).apply { binding = this }.root
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
presenter.onAttachView(this)
|
||||
}
|
||||
|
||||
override fun initView() {
|
||||
with(binding) {
|
||||
additionalLessonDialogStartEdit.doOnTextChanged { _, _, _, _ ->
|
||||
additionalLessonDialogStart.isErrorEnabled = false
|
||||
additionalLessonDialogStart.error = null
|
||||
}
|
||||
additionalLessonDialogEndEdit.doOnTextChanged { _, _, _, _ ->
|
||||
additionalLessonDialogEnd.isErrorEnabled = false
|
||||
additionalLessonDialogEnd.error = null
|
||||
}
|
||||
additionalLessonDialogDateEdit.doOnTextChanged { _, _, _, _ ->
|
||||
additionalLessonDialogDate.isErrorEnabled = false
|
||||
additionalLessonDialogDate.error = null
|
||||
}
|
||||
additionalLessonDialogContentEdit.doOnTextChanged { _, _, _, _ ->
|
||||
additionalLessonDialogContent.isErrorEnabled = false
|
||||
additionalLessonDialogContent.error = null
|
||||
}
|
||||
|
||||
additionalLessonDialogAdd.setOnClickListener {
|
||||
presenter.onAddAdditionalClicked(
|
||||
start = additionalLessonDialogStartEdit.text?.toString(),
|
||||
end = additionalLessonDialogEndEdit.text?.toString(),
|
||||
date = additionalLessonDialogDateEdit.text?.toString(),
|
||||
content = additionalLessonDialogContentEdit.text?.toString(),
|
||||
isRepeat = additionalLessonDialogRepeat.isChecked
|
||||
)
|
||||
}
|
||||
additionalLessonDialogClose.setOnClickListener { dismiss() }
|
||||
additionalLessonDialogDateEdit.setOnClickListener { presenter.showDatePicker() }
|
||||
additionalLessonDialogStartEdit.setOnClickListener { presenter.showStartTimePicker() }
|
||||
additionalLessonDialogEndEdit.setOnClickListener { presenter.showEndTimePicker() }
|
||||
}
|
||||
}
|
||||
|
||||
override fun showSuccessMessage() {
|
||||
showMessage(getString(R.string.additional_lessons_add_success))
|
||||
}
|
||||
|
||||
override fun setErrorDateRequired() {
|
||||
with(binding.additionalLessonDialogDate) {
|
||||
isErrorEnabled = true
|
||||
error = getString(R.string.error_field_required)
|
||||
}
|
||||
}
|
||||
|
||||
override fun setErrorStartRequired() {
|
||||
with(binding.additionalLessonDialogStart) {
|
||||
isErrorEnabled = true
|
||||
error = getString(R.string.error_field_required)
|
||||
}
|
||||
}
|
||||
|
||||
override fun setErrorEndRequired() {
|
||||
with(binding.additionalLessonDialogEnd) {
|
||||
isErrorEnabled = true
|
||||
error = getString(R.string.error_field_required)
|
||||
}
|
||||
}
|
||||
|
||||
override fun setErrorContentRequired() {
|
||||
with(binding.additionalLessonDialogContent) {
|
||||
isErrorEnabled = true
|
||||
error = getString(R.string.error_field_required)
|
||||
}
|
||||
}
|
||||
|
||||
override fun setErrorIncorrectEndTime() {
|
||||
with(binding.additionalLessonDialogEnd) {
|
||||
isErrorEnabled = true
|
||||
error = getString(R.string.additional_lessons_end_time_error)
|
||||
}
|
||||
}
|
||||
|
||||
override fun closeDialog() {
|
||||
dismiss()
|
||||
}
|
||||
|
||||
override fun showDatePickerDialog(selectedDate: LocalDate) {
|
||||
val rangeStart = LocalDate.now().toTimestamp()
|
||||
val rangeEnd = LocalDate.now().lastSchoolDayInSchoolYear.toTimestamp()
|
||||
val constraintsBuilder = CalendarConstraints.Builder().apply {
|
||||
setStart(rangeStart)
|
||||
setEnd(rangeEnd)
|
||||
setValidator(SchoolDaysValidator(rangeStart, rangeEnd))
|
||||
}
|
||||
val datePicker = MaterialDatePicker.Builder.datePicker()
|
||||
.setCalendarConstraints(constraintsBuilder.build())
|
||||
.setSelection(selectedDate.toTimestamp())
|
||||
.build()
|
||||
|
||||
datePicker.addOnPositiveButtonClickListener {
|
||||
val date = it.toLocalDateTime().toLocalDate()
|
||||
presenter.onDateSelected(date)
|
||||
binding.additionalLessonDialogDateEdit.setText(date.toFormattedString())
|
||||
}
|
||||
|
||||
if (!parentFragmentManager.isStateSaved) {
|
||||
datePicker.show(parentFragmentManager, null)
|
||||
}
|
||||
}
|
||||
|
||||
override fun showStartTimePickerDialog(selectedTime: LocalTime) {
|
||||
showTimePickerDialog(selectedTime) {
|
||||
presenter.onStartTimeSelected(it)
|
||||
binding.additionalLessonDialogStartEdit.setText(it.toString())
|
||||
}
|
||||
}
|
||||
|
||||
override fun showEndTimePickerDialog(selectedTime: LocalTime) {
|
||||
showTimePickerDialog(selectedTime) {
|
||||
presenter.onEndTimeSelected(it)
|
||||
binding.additionalLessonDialogEndEdit.setText(it.toString())
|
||||
}
|
||||
}
|
||||
|
||||
private fun showTimePickerDialog(defaultTime: LocalTime, onTimeSelected: (LocalTime) -> Unit) {
|
||||
val timePicker = MaterialTimePicker.Builder()
|
||||
.setTimeFormat(TimeFormat.CLOCK_24H)
|
||||
.setHour(defaultTime.hour)
|
||||
.setMinute(defaultTime.minute)
|
||||
.build()
|
||||
|
||||
timePicker.addOnPositiveButtonClickListener {
|
||||
onTimeSelected(LocalTime.of(timePicker.hour, timePicker.minute))
|
||||
}
|
||||
|
||||
if (!parentFragmentManager.isStateSaved) {
|
||||
timePicker.show(parentFragmentManager, null)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
presenter.onDetachView()
|
||||
super.onDestroyView()
|
||||
}
|
||||
}
|
@ -0,0 +1,166 @@
|
||||
package io.github.wulkanowy.ui.modules.timetable.additional.add
|
||||
|
||||
import io.github.wulkanowy.data.db.entities.TimetableAdditional
|
||||
import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.data.repositories.TimetableRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.lastSchoolDayInSchoolYear
|
||||
import io.github.wulkanowy.utils.toLocalDate
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalDateTime
|
||||
import java.time.LocalTime
|
||||
import java.time.temporal.ChronoUnit
|
||||
import java.util.UUID
|
||||
import javax.inject.Inject
|
||||
|
||||
class AdditionalLessonAddPresenter @Inject constructor(
|
||||
errorHandler: ErrorHandler,
|
||||
studentRepository: StudentRepository,
|
||||
private val timetableRepository: TimetableRepository,
|
||||
private val semesterRepository: SemesterRepository
|
||||
) : BasePresenter<AdditionalLessonAddView>(errorHandler, studentRepository) {
|
||||
|
||||
private var selectedStartTime = LocalTime.of(15, 0)
|
||||
|
||||
private var selectedEndTime = LocalTime.of(15, 45)
|
||||
|
||||
private var selectedDate = LocalDate.now()
|
||||
|
||||
override fun onAttachView(view: AdditionalLessonAddView) {
|
||||
super.onAttachView(view)
|
||||
view.initView()
|
||||
Timber.i("AdditionalLesson details view was initialized")
|
||||
}
|
||||
|
||||
fun showDatePicker() {
|
||||
view?.showDatePickerDialog(selectedDate)
|
||||
}
|
||||
|
||||
fun showStartTimePicker() {
|
||||
view?.showStartTimePickerDialog(selectedStartTime)
|
||||
}
|
||||
|
||||
fun showEndTimePicker() {
|
||||
view?.showEndTimePickerDialog(selectedEndTime)
|
||||
}
|
||||
|
||||
fun onStartTimeSelected(time: LocalTime) {
|
||||
selectedStartTime = time
|
||||
}
|
||||
|
||||
fun onEndTimeSelected(time: LocalTime) {
|
||||
selectedEndTime = time
|
||||
}
|
||||
|
||||
fun onDateSelected(date: LocalDate) {
|
||||
selectedDate = date
|
||||
}
|
||||
|
||||
fun onAddAdditionalClicked(
|
||||
start: String?,
|
||||
end: String?,
|
||||
date: String?,
|
||||
content: String?,
|
||||
isRepeat: Boolean
|
||||
) {
|
||||
if (isUserInputValid(start, end, date, content)) {
|
||||
addAdditionalLesson(
|
||||
start = LocalTime.parse(start!!),
|
||||
end = LocalTime.parse(end),
|
||||
date = date!!.toLocalDate(),
|
||||
subject = content!!,
|
||||
isRepeat = isRepeat
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isUserInputValid(
|
||||
start: String?,
|
||||
end: String?,
|
||||
date: String?,
|
||||
content: String?
|
||||
): Boolean {
|
||||
var isValid = true
|
||||
|
||||
if (start.isNullOrBlank()) {
|
||||
view?.setErrorStartRequired()
|
||||
isValid = false
|
||||
}
|
||||
|
||||
if (end.isNullOrBlank()) {
|
||||
view?.setErrorEndRequired()
|
||||
isValid = false
|
||||
}
|
||||
|
||||
if (date.isNullOrBlank()) {
|
||||
view?.setErrorDateRequired()
|
||||
isValid = false
|
||||
}
|
||||
|
||||
if (content.isNullOrBlank()) {
|
||||
view?.setErrorContentRequired()
|
||||
isValid = false
|
||||
}
|
||||
|
||||
if (selectedStartTime >= selectedEndTime) {
|
||||
view?.setErrorIncorrectEndTime()
|
||||
isValid = false
|
||||
}
|
||||
|
||||
return isValid
|
||||
}
|
||||
|
||||
private fun addAdditionalLesson(
|
||||
start: LocalTime,
|
||||
end: LocalTime,
|
||||
date: LocalDate,
|
||||
subject: String,
|
||||
isRepeat: Boolean
|
||||
) {
|
||||
presenterScope.launch {
|
||||
val semester = runCatching {
|
||||
val student = studentRepository.getCurrentStudent()
|
||||
semesterRepository.getCurrentSemester(student)
|
||||
}
|
||||
.onFailure(errorHandler::dispatch)
|
||||
.getOrNull() ?: return@launch
|
||||
|
||||
val weeks = if (isRepeat) {
|
||||
ChronoUnit.WEEKS.between(date, date.lastSchoolDayInSchoolYear)
|
||||
} else 0
|
||||
val uniqueRepeatId = UUID.randomUUID().takeIf { isRepeat }
|
||||
|
||||
val lessonsToAdd = (0..weeks).map {
|
||||
TimetableAdditional(
|
||||
studentId = semester.studentId,
|
||||
diaryId = semester.diaryId,
|
||||
start = LocalDateTime.of(date, start),
|
||||
end = LocalDateTime.of(date, end),
|
||||
date = date.plusWeeks(it),
|
||||
subject = subject
|
||||
).apply {
|
||||
isAddedByUser = true
|
||||
repeatId = uniqueRepeatId
|
||||
}
|
||||
}
|
||||
|
||||
Timber.i("AdditionalLesson insert start")
|
||||
runCatching { timetableRepository.saveAdditionalList(lessonsToAdd) }
|
||||
.onSuccess {
|
||||
Timber.i("AdditionalLesson insert: Success")
|
||||
view?.run {
|
||||
showSuccessMessage()
|
||||
closeDialog()
|
||||
}
|
||||
}
|
||||
.onFailure {
|
||||
Timber.i("AdditionalLesson insert result: An exception occurred")
|
||||
errorHandler.dispatch(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package io.github.wulkanowy.ui.modules.timetable.additional.add
|
||||
|
||||
import io.github.wulkanowy.ui.base.BaseView
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalTime
|
||||
|
||||
interface AdditionalLessonAddView : BaseView {
|
||||
|
||||
fun initView()
|
||||
|
||||
fun closeDialog()
|
||||
|
||||
fun showDatePickerDialog(selectedDate: LocalDate)
|
||||
|
||||
fun showStartTimePickerDialog(selectedTime: LocalTime)
|
||||
|
||||
fun showEndTimePickerDialog(selectedTime: LocalTime)
|
||||
|
||||
fun showSuccessMessage()
|
||||
|
||||
fun setErrorDateRequired()
|
||||
|
||||
fun setErrorStartRequired()
|
||||
|
||||
fun setErrorEndRequired()
|
||||
|
||||
fun setErrorContentRequired()
|
||||
|
||||
fun setErrorIncorrectEndTime()
|
||||
}
|
@ -18,10 +18,10 @@ import io.github.wulkanowy.ui.modules.main.MainView
|
||||
import io.github.wulkanowy.ui.widgets.DividerItemDecoration
|
||||
import io.github.wulkanowy.utils.SchoolDaysValidator
|
||||
import io.github.wulkanowy.utils.dpToPx
|
||||
import io.github.wulkanowy.utils.firstSchoolDayInSchoolYear
|
||||
import io.github.wulkanowy.utils.getCompatDrawable
|
||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||
import io.github.wulkanowy.utils.schoolYearEnd
|
||||
import io.github.wulkanowy.utils.schoolYearStart
|
||||
import io.github.wulkanowy.utils.lastSchoolDayInSchoolYear
|
||||
import io.github.wulkanowy.utils.toLocalDateTime
|
||||
import io.github.wulkanowy.utils.toTimestamp
|
||||
import java.time.LocalDate
|
||||
@ -68,9 +68,7 @@ class CompletedLessonsFragment :
|
||||
completedLessonsSwipe.setOnRefreshListener(presenter::onSwipeRefresh)
|
||||
completedLessonsSwipe.setColorSchemeColors(requireContext().getThemeAttrColor(R.attr.colorPrimary))
|
||||
completedLessonsSwipe.setProgressBackgroundColorSchemeColor(
|
||||
requireContext().getThemeAttrColor(
|
||||
R.attr.colorSwipeRefresh
|
||||
)
|
||||
requireContext().getThemeAttrColor(R.attr.colorSwipeRefresh)
|
||||
)
|
||||
completedLessonErrorRetry.setOnClickListener { presenter.onRetry() }
|
||||
completedLessonErrorDetails.setOnClickListener { presenter.onDetailsClick() }
|
||||
@ -154,16 +152,15 @@ class CompletedLessonsFragment :
|
||||
|
||||
override fun showDatePickerDialog(currentDate: LocalDate) {
|
||||
val now = LocalDate.now()
|
||||
val startOfSchoolYear = now.schoolYearStart.toTimestamp()
|
||||
val endOfSchoolYear = now.schoolYearEnd.toTimestamp()
|
||||
val startOfSchoolYear = now.firstSchoolDayInSchoolYear.toTimestamp()
|
||||
val endOfSchoolYear = now.lastSchoolDayInSchoolYear.toTimestamp()
|
||||
|
||||
val constraintsBuilder = CalendarConstraints.Builder().apply {
|
||||
setValidator(SchoolDaysValidator(startOfSchoolYear, endOfSchoolYear))
|
||||
setStart(startOfSchoolYear)
|
||||
setEnd(endOfSchoolYear)
|
||||
}
|
||||
val datePicker =
|
||||
MaterialDatePicker.Builder.datePicker()
|
||||
val datePicker = MaterialDatePicker.Builder.datePicker()
|
||||
.setCalendarConstraints(constraintsBuilder.build())
|
||||
.setSelection(currentDate.toTimestamp())
|
||||
.build()
|
||||
|
@ -85,35 +85,31 @@ inline val LocalDate.previousOrSameSchoolDay: LocalDate
|
||||
inline val LocalDate.weekDayName: String
|
||||
get() = format(DateTimeFormatter.ofPattern("EEEE", Locale.getDefault()))
|
||||
|
||||
inline val LocalDate.monday: LocalDate
|
||||
get() = with(MONDAY)
|
||||
inline val LocalDate.monday: LocalDate get() = with(MONDAY)
|
||||
|
||||
inline val LocalDate.sunday: LocalDate
|
||||
get() = with(SUNDAY)
|
||||
inline val LocalDate.sunday: LocalDate get() = with(SUNDAY)
|
||||
|
||||
/**
|
||||
* [Dz.U. 2016 poz. 1335](http://prawo.sejm.gov.pl/isap.nsf/DocDetails.xsp?id=WDU20160001335)
|
||||
*/
|
||||
inline val LocalDate.isHolidays: Boolean
|
||||
get() = isBefore(firstSchoolDay) && isAfter(lastSchoolDay)
|
||||
val LocalDate.isHolidays: Boolean
|
||||
get() = isBefore(firstSchoolDayInCalendarYear) && isAfter(lastSchoolDayInCalendarYear)
|
||||
|
||||
inline val LocalDate.firstSchoolDay: LocalDate
|
||||
get() = LocalDate.of(year, 9, 1).run {
|
||||
when (dayOfWeek) {
|
||||
FRIDAY, SATURDAY, SUNDAY -> with(firstInMonth(MONDAY))
|
||||
else -> this
|
||||
}
|
||||
val LocalDate.firstSchoolDayInSchoolYear: LocalDate
|
||||
get() = withYear(if (this.monthValue <= 6) this.year - 1 else this.year).firstSchoolDayInCalendarYear
|
||||
|
||||
val LocalDate.lastSchoolDayInSchoolYear: LocalDate
|
||||
get() = withYear(if (this.monthValue > 6) this.year + 1 else this.year).lastSchoolDayInCalendarYear
|
||||
|
||||
fun LocalDate.getLastSchoolDayIfHoliday(schoolYear: Int): LocalDate {
|
||||
val date = LocalDate.of(schoolYear.getSchoolYearByMonth(monthValue), monthValue, dayOfMonth)
|
||||
|
||||
if (date.isHolidays) {
|
||||
return date.lastSchoolDayInCalendarYear
|
||||
}
|
||||
|
||||
inline val LocalDate.lastSchoolDay: LocalDate
|
||||
get() = LocalDate.of(year, 6, 20)
|
||||
.with(next(FRIDAY))
|
||||
|
||||
inline val LocalDate.schoolYearStart: LocalDate
|
||||
get() = withYear(if (this.monthValue <= 6) this.year - 1 else this.year).firstSchoolDay
|
||||
|
||||
inline val LocalDate.schoolYearEnd: LocalDate
|
||||
get() = withYear(if (this.monthValue > 6) this.year + 1 else this.year).lastSchoolDay
|
||||
return date
|
||||
}
|
||||
|
||||
private fun Int.getSchoolYearByMonth(monthValue: Int): Int {
|
||||
return when (monthValue) {
|
||||
@ -122,12 +118,15 @@ private fun Int.getSchoolYearByMonth(monthValue: Int): Int {
|
||||
}
|
||||
}
|
||||
|
||||
fun LocalDate.getLastSchoolDayIfHoliday(schoolYear: Int): LocalDate {
|
||||
val date = LocalDate.of(schoolYear.getSchoolYearByMonth(monthValue), monthValue, dayOfMonth)
|
||||
|
||||
if (date.isHolidays) {
|
||||
return date.lastSchoolDay
|
||||
private inline val LocalDate.firstSchoolDayInCalendarYear: LocalDate
|
||||
get() = LocalDate.of(year, 9, 1).run {
|
||||
when (dayOfWeek) {
|
||||
FRIDAY, SATURDAY, SUNDAY -> with(firstInMonth(MONDAY))
|
||||
else -> this
|
||||
}
|
||||
}
|
||||
|
||||
return date
|
||||
}
|
||||
private inline val LocalDate.lastSchoolDayInCalendarYear: LocalDate
|
||||
get() = LocalDate.of(year, 6, 20)
|
||||
.with(next(FRIDAY))
|
||||
|
||||
|
12
app/src/main/res/drawable/ic_all_clock.xml
Normal file
12
app/src/main/res/drawable/ic_all_clock.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<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="@android:color/white"
|
||||
android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z" />
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12.5,7H11v6l5.25,3.15 0.75,-1.23 -4.5,-2.67z" />
|
||||
</vector>
|
10
app/src/main/res/drawable/ic_calendat_all.xml
Normal file
10
app/src/main/res/drawable/ic_calendat_all.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M19,3h-1L18,1h-2v2L8,3L8,1L6,1v2L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM19,19L5,19L5,9h14v10zM19,7L5,7L5,5h14v2zM7,11h5v5L7,16z" />
|
||||
</vector>
|
156
app/src/main/res/layout/dialog_additional_add.xml
Normal file
156
app/src/main/res/layout/dialog_additional_add.xml
Normal file
@ -0,0 +1,156 @@
|
||||
<ScrollView 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"
|
||||
android:fillViewport="true"
|
||||
android:minWidth="300dp"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingEnd="8dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minWidth="300dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/addadditionalLessonHeader"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:text="@string/additional_lessons_add_title"
|
||||
android:textSize="21sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/additionalLessonDialogDate"
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginTop="28dp"
|
||||
android:hint="@string/all_date"
|
||||
app:startIconDrawable="@drawable/ic_calendat_all">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/additionalLessonDialogDateEdit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:editable="false"
|
||||
android:focusable="false"
|
||||
android:inputType="text"
|
||||
tools:ignore="Deprecated" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||
android:id="@+id/additionalLessonDialogRepeat"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:text="@string/additional_lessons_repeat" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/additionalLessonDialogStart"
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:hint="@string/additional_lessons_start"
|
||||
app:startIconDrawable="@drawable/ic_all_clock">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/additionalLessonDialogStartEdit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:editable="false"
|
||||
android:focusable="false"
|
||||
android:inputType="text"
|
||||
tools:ignore="Deprecated" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/additionalLessonDialogEnd"
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:hint="@string/additional_lessons_end"
|
||||
app:startIconDrawable="@drawable/ic_all_clock">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/additionalLessonDialogEndEdit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:editable="false"
|
||||
android:focusable="false"
|
||||
android:inputType="text"
|
||||
tools:ignore="Deprecated" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/additionalLessonDialogContent"
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:hint="@string/all_subject">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/additionalLessonDialogContentEdit"
|
||||
android:layout_width="match_parent"
|
||||
android:inputType="text"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="1" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="end"
|
||||
android:minHeight="52dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/additionalLessonDialogClose"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton.Dialog"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="36dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="0dp"
|
||||
android:layout_marginLeft="0dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:insetLeft="0dp"
|
||||
android:insetTop="0dp"
|
||||
android:insetRight="0dp"
|
||||
android:insetBottom="0dp"
|
||||
android:minWidth="88dp"
|
||||
android:text="@string/all_close"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/additionalLessonDialogAdd"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton.Dialog"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="36dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:insetLeft="0dp"
|
||||
android:insetTop="0dp"
|
||||
android:insetRight="0dp"
|
||||
android:insetBottom="0dp"
|
||||
android:minWidth="88dp"
|
||||
android:text="@string/all_add"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
@ -204,7 +204,6 @@
|
||||
android:insetBottom="0dp"
|
||||
android:minWidth="88dp"
|
||||
android:text="@string/all_close" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -5,8 +5,8 @@
|
||||
android:layout_height="match_parent"
|
||||
android:fillViewport="true"
|
||||
android:minWidth="300dp"
|
||||
android:paddingStart="24dp"
|
||||
android:paddingEnd="24dp">
|
||||
android:paddingStart="8dp"
|
||||
android:paddingEnd="8dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
@ -18,7 +18,7 @@
|
||||
android:id="@+id/addHomeworkHeader"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="0dp"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:text="@string/homework_add"
|
||||
@ -30,10 +30,10 @@
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="0dp"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginTop="28dp"
|
||||
android:hint="@string/all_date"
|
||||
app:startIconDrawable="@drawable/ic_main_timetable">
|
||||
app:startIconDrawable="@drawable/ic_calendat_all">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/homeworkDialogDateEdit"
|
||||
@ -51,7 +51,7 @@
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="0dp"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:hint="@string/all_subject">
|
||||
|
||||
@ -66,7 +66,7 @@
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="0dp"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:hint="@string/all_teacher">
|
||||
|
||||
@ -81,7 +81,7 @@
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="0dp"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:hint="@string/all_content">
|
||||
@ -105,13 +105,12 @@
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="0dp"
|
||||
android:layout_marginLeft="0dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:insetLeft="0dp"
|
||||
android:insetTop="0dp"
|
||||
android:insetRight="0dp"
|
||||
android:insetBottom="0dp"
|
||||
android:minWidth="88dp"
|
||||
android:text="@string/all_close"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
@ -126,6 +125,7 @@
|
||||
android:insetTop="0dp"
|
||||
android:insetRight="0dp"
|
||||
android:insetBottom="0dp"
|
||||
android:minWidth="88dp"
|
||||
android:text="@string/all_add"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
@ -26,6 +26,8 @@
|
||||
android:id="@+id/additionalLessonsRecycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:paddingBottom="64dp"
|
||||
tools:listitem="@layout/item_timetable_additional" />
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
|
||||
@ -108,6 +110,18 @@
|
||||
android:text="@string/all_retry" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
android:id="@+id/openAddAdditionalLessonButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_margin="16dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:text="@string/additional_lessons_add"
|
||||
android:tint="?colorOnSecondary"
|
||||
app:icon="@drawable/ic_all_add" />
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
<io.github.wulkanowy.ui.widgets.MaterialLinearLayout
|
||||
|
@ -17,13 +17,13 @@
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textSize="15sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/additionalLessonItemDelete"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="@tools:sample/lorem" />
|
||||
tools:maxLines="2"
|
||||
tools:text="@tools:sample/lorem/random" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/additionalLessonItemTime"
|
||||
@ -38,4 +38,16 @@
|
||||
app:layout_constraintTop_toBottomOf="@id/additionalLessonItemSubject"
|
||||
tools:text="11:11 - 12:12" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/additionalLessonItemDelete"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:padding="5dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/ic_menu_message_delete"
|
||||
app:tint="?colorPrimary"
|
||||
tools:ignore="ContentDescription" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
@ -198,6 +198,17 @@
|
||||
<string name="additional_lessons_title">Additional lessons</string>
|
||||
<string name="additional_lessons_button">Show additional lessons</string>
|
||||
<string name="additional_lessons_no_items">No info about additional lessons</string>
|
||||
<string name="additional_lessons_add">New lesson</string>
|
||||
<string name="additional_lessons_add_title">New additional lesson</string>
|
||||
<string name="additional_lessons_add_success">Additional lesson added successfully</string>
|
||||
<string name="additional_lessons_delete_success">Additional lesson deleted successfully</string>
|
||||
<string name="additional_lessons_repeat">Repeat weekly</string>
|
||||
<string name="additional_lessons_delete_title">Delete additional lesson</string>
|
||||
<string name="additional_lessons_delete_one">Just this lesson</string>
|
||||
<string name="additional_lessons_delete_series">All in the series</string>
|
||||
<string name="additional_lessons_start">Start time</string>
|
||||
<string name="additional_lessons_end">End time</string>
|
||||
<string name="additional_lessons_end_time_error">End time must be greater than start time</string>
|
||||
|
||||
|
||||
<!--Attendance-->
|
||||
|
@ -1,6 +1,6 @@
|
||||
buildscript {
|
||||
ext {
|
||||
kotlin_version = '1.6.0'
|
||||
kotlin_version = '1.6.10'
|
||||
about_libraries = '8.9.4'
|
||||
hilt_version = "2.40.5"
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user