mirror of
https://github.com/szkolny-eu/szkolny-android.git
synced 2024-11-24 19:04:38 -06:00
Merge remote-tracking branch 'origin/develop' into feature/usos
This commit is contained in:
commit
8d174bda01
@ -12,7 +12,7 @@
|
|||||||
<uses-permission android:name="android.permission.VIBRATE" />
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
<uses-permission android:name="android.permission.CAMERA" />
|
<uses-permission android:name="android.permission.CAMERA" />
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||||
<!-- PowerPermission uses minSdk 21, it's safe to override as it is used only in >= 23 -->
|
<!-- PowerPermission uses minSdk 21, it's safe to override as it is used only in >= 23 -->
|
||||||
<uses-sdk tools:overrideLibrary="com.qifan.powerpermission.coroutines, com.qifan.powerpermission.core" />
|
<uses-sdk tools:overrideLibrary="com.qifan.powerpermission.coroutines, com.qifan.powerpermission.core" />
|
||||||
|
|
||||||
|
@ -69,4 +69,24 @@ class ProfileConfigUI(private val config: ProfileConfig) {
|
|||||||
var messagesGreetingText: String?
|
var messagesGreetingText: String?
|
||||||
get() { mMessagesGreetingText = mMessagesGreetingText ?: config.values["messagesGreetingText"]; return mMessagesGreetingText }
|
get() { mMessagesGreetingText = mMessagesGreetingText ?: config.values["messagesGreetingText"]; return mMessagesGreetingText }
|
||||||
set(value) { config.set("messagesGreetingText", value); mMessagesGreetingText = value }
|
set(value) { config.set("messagesGreetingText", value); mMessagesGreetingText = value }
|
||||||
|
|
||||||
|
private var mTimetableShowAttendance: Boolean? = null
|
||||||
|
var timetableShowAttendance: Boolean
|
||||||
|
get() { mTimetableShowAttendance = mTimetableShowAttendance ?: config.values.get("timetableShowAttendance", true); return mTimetableShowAttendance ?: true }
|
||||||
|
set(value) { config.set("timetableShowAttendance", value); mTimetableShowAttendance = value }
|
||||||
|
|
||||||
|
private var mTimetableShowEvents: Boolean? = null
|
||||||
|
var timetableShowEvents: Boolean
|
||||||
|
get() { mTimetableShowEvents = mTimetableShowEvents ?: config.values.get("timetableShowEvents", true); return mTimetableShowEvents ?: true }
|
||||||
|
set(value) { config.set("timetableShowEvents", value); mTimetableShowEvents = value }
|
||||||
|
|
||||||
|
private var mTimetableTrimHourRange: Boolean? = null
|
||||||
|
var timetableTrimHourRange: Boolean
|
||||||
|
get() { mTimetableTrimHourRange = mTimetableTrimHourRange ?: config.values.get("timetableTrimHourRange", false); return mTimetableTrimHourRange ?: false }
|
||||||
|
set(value) { config.set("timetableTrimHourRange", value); mTimetableTrimHourRange = value }
|
||||||
|
|
||||||
|
private var mTimetableColorSubjectName: Boolean? = null
|
||||||
|
var timetableColorSubjectName: Boolean
|
||||||
|
get() { mTimetableColorSubjectName = mTimetableColorSubjectName ?: config.values.get("timetableColorSubjectName", false); return mTimetableColorSubjectName ?: false }
|
||||||
|
set(value) { config.set("timetableColorSubjectName", value); mTimetableColorSubjectName = value }
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2022-10-7.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.ui.dialogs.settings
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import pl.szczodrzynski.edziennik.MainActivity
|
||||||
|
import pl.szczodrzynski.edziennik.R
|
||||||
|
import pl.szczodrzynski.edziennik.databinding.TimetableConfigDialogBinding
|
||||||
|
import pl.szczodrzynski.edziennik.ext.Intent
|
||||||
|
import pl.szczodrzynski.edziennik.ext.onClick
|
||||||
|
import pl.szczodrzynski.edziennik.ui.dialogs.base.ConfigDialog
|
||||||
|
import pl.szczodrzynski.edziennik.ui.timetable.TimetableFragment
|
||||||
|
|
||||||
|
class TimetableConfigDialog(
|
||||||
|
activity: AppCompatActivity,
|
||||||
|
reloadOnDismiss: Boolean = true,
|
||||||
|
onShowListener: ((tag: String) -> Unit)? = null,
|
||||||
|
onDismissListener: ((tag: String) -> Unit)? = null,
|
||||||
|
) : ConfigDialog<TimetableConfigDialogBinding>(
|
||||||
|
activity,
|
||||||
|
reloadOnDismiss,
|
||||||
|
onShowListener,
|
||||||
|
onDismissListener,
|
||||||
|
) {
|
||||||
|
|
||||||
|
override val TAG = "TimetableConfigDialog"
|
||||||
|
|
||||||
|
override fun getTitleRes() = R.string.menu_timetable_config
|
||||||
|
override fun inflate(layoutInflater: LayoutInflater) =
|
||||||
|
TimetableConfigDialogBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
|
private val profileConfig by lazy { app.config.getFor(app.profileId).ui }
|
||||||
|
|
||||||
|
override suspend fun loadConfig() {
|
||||||
|
b.config = profileConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun saveConfig() {
|
||||||
|
activity.sendBroadcast(Intent(TimetableFragment.ACTION_RELOAD_PAGES))
|
||||||
|
}
|
||||||
|
}
|
@ -81,7 +81,8 @@ class HomeFragment : Fragment(), CoroutineScope {
|
|||||||
private val job: Job = Job()
|
private val job: Job = Job()
|
||||||
override val coroutineContext: CoroutineContext
|
override val coroutineContext: CoroutineContext
|
||||||
get() = job + Dispatchers.Main
|
get() = job + Dispatchers.Main
|
||||||
|
private val manager
|
||||||
|
get() = app.permissionManager
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
activity = (getActivity() as MainActivity?) ?: return null
|
activity = (getActivity() as MainActivity?) ?: return null
|
||||||
context ?: return null
|
context ?: return null
|
||||||
@ -96,6 +97,10 @@ class HomeFragment : Fragment(), CoroutineScope {
|
|||||||
if (!isAdded)
|
if (!isAdded)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if (!manager.isNotificationPermissionGranted) {
|
||||||
|
manager.requestNotificationsPermission(activity, 0, false){}
|
||||||
|
}
|
||||||
|
|
||||||
activity.bottomSheet.prependItems(
|
activity.bottomSheet.prependItems(
|
||||||
BottomSheetPrimaryItem(true)
|
BottomSheetPrimaryItem(true)
|
||||||
.withTitle(R.string.menu_add_remove_cards)
|
.withTitle(R.string.menu_add_remove_cards)
|
||||||
|
@ -23,8 +23,8 @@ import androidx.fragment.app.Fragment
|
|||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import pl.szczodrzynski.edziennik.*
|
import pl.szczodrzynski.edziennik.App
|
||||||
import pl.szczodrzynski.edziennik.data.api.*
|
import pl.szczodrzynski.edziennik.R
|
||||||
import pl.szczodrzynski.edziennik.databinding.LoginChooserFragmentBinding
|
import pl.szczodrzynski.edziennik.databinding.LoginChooserFragmentBinding
|
||||||
import pl.szczodrzynski.edziennik.ext.*
|
import pl.szczodrzynski.edziennik.ext.*
|
||||||
import pl.szczodrzynski.edziennik.ui.dialogs.sync.RegisterUnavailableDialog
|
import pl.szczodrzynski.edziennik.ui.dialogs.sync.RegisterUnavailableDialog
|
||||||
@ -51,7 +51,8 @@ class LoginChooserFragment : Fragment(), CoroutineScope {
|
|||||||
private val job: Job = Job()
|
private val job: Job = Job()
|
||||||
override val coroutineContext: CoroutineContext
|
override val coroutineContext: CoroutineContext
|
||||||
get() = job + Dispatchers.Main
|
get() = job + Dispatchers.Main
|
||||||
|
private val manager
|
||||||
|
get() = app.permissionManager
|
||||||
// local/private variables go here
|
// local/private variables go here
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
@ -67,6 +68,9 @@ class LoginChooserFragment : Fragment(), CoroutineScope {
|
|||||||
if (!isAdded) return
|
if (!isAdded) return
|
||||||
|
|
||||||
val adapter = LoginChooserAdapter(activity, this::onLoginModeClicked)
|
val adapter = LoginChooserAdapter(activity, this::onLoginModeClicked)
|
||||||
|
if (!manager.isNotificationPermissionGranted) {
|
||||||
|
manager.requestNotificationsPermission(activity, 0, false){}
|
||||||
|
}
|
||||||
|
|
||||||
b.versionText.setText(
|
b.versionText.setText(
|
||||||
R.string.login_chooser_version_format,
|
R.string.login_chooser_version_format,
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
package pl.szczodrzynski.edziennik.ui.timetable
|
package pl.szczodrzynski.edziennik.ui.timetable
|
||||||
|
|
||||||
|
import android.graphics.drawable.ColorDrawable
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@ -12,6 +13,7 @@ import android.widget.FrameLayout
|
|||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.asynclayoutinflater.view.AsyncLayoutInflater
|
import androidx.asynclayoutinflater.view.AsyncLayoutInflater
|
||||||
|
import androidx.core.graphics.ColorUtils
|
||||||
import androidx.core.view.*
|
import androidx.core.view.*
|
||||||
import com.linkedin.android.tachyon.DayView
|
import com.linkedin.android.tachyon.DayView
|
||||||
import com.linkedin.android.tachyon.DayViewConfig
|
import com.linkedin.android.tachyon.DayViewConfig
|
||||||
@ -33,9 +35,11 @@ import pl.szczodrzynski.edziennik.ext.*
|
|||||||
import pl.szczodrzynski.edziennik.ui.base.lazypager.LazyFragment
|
import pl.szczodrzynski.edziennik.ui.base.lazypager.LazyFragment
|
||||||
import pl.szczodrzynski.edziennik.ui.timetable.TimetableFragment.Companion.DEFAULT_END_HOUR
|
import pl.szczodrzynski.edziennik.ui.timetable.TimetableFragment.Companion.DEFAULT_END_HOUR
|
||||||
import pl.szczodrzynski.edziennik.ui.timetable.TimetableFragment.Companion.DEFAULT_START_HOUR
|
import pl.szczodrzynski.edziennik.ui.timetable.TimetableFragment.Companion.DEFAULT_START_HOUR
|
||||||
|
import pl.szczodrzynski.edziennik.utils.Colors
|
||||||
import pl.szczodrzynski.edziennik.utils.managers.NoteManager
|
import pl.szczodrzynski.edziennik.utils.managers.NoteManager
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||||
|
import pl.szczodrzynski.edziennik.utils.mutableLazy
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
@ -71,8 +75,9 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope {
|
|||||||
|
|
||||||
// find SwipeRefreshLayout in the hierarchy
|
// find SwipeRefreshLayout in the hierarchy
|
||||||
private val refreshLayout by lazy { view?.findParentById(R.id.refreshLayout) }
|
private val refreshLayout by lazy { view?.findParentById(R.id.refreshLayout) }
|
||||||
|
private val profileConfig by lazy { app.config.forProfile().ui }
|
||||||
|
|
||||||
private val dayView by lazy {
|
private val dayViewDelegate = mutableLazy {
|
||||||
val dayView = DayView(activity, DayViewConfig(
|
val dayView = DayView(activity, DayViewConfig(
|
||||||
startHour = startHour,
|
startHour = startHour,
|
||||||
endHour = endHour,
|
endHour = endHour,
|
||||||
@ -85,8 +90,9 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope {
|
|||||||
eventMargin = 2.dp
|
eventMargin = 2.dp
|
||||||
), true)
|
), true)
|
||||||
dayView.setPadding(10.dp)
|
dayView.setPadding(10.dp)
|
||||||
return@lazy dayView
|
return@mutableLazy dayView
|
||||||
}
|
}
|
||||||
|
private val dayView by dayViewDelegate
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
activity = (getActivity() as MainActivity?) ?: return null
|
activity = (getActivity() as MainActivity?) ?: return null
|
||||||
@ -173,8 +179,19 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
b.scrollView.isVisible = true
|
if (dayViewDelegate.isInitialized())
|
||||||
b.dayFrame.removeView(dayView)
|
b.dayFrame.removeView(dayView)
|
||||||
|
|
||||||
|
val lessonsActual = lessons.filter { it.type != Lesson.TYPE_NO_LESSONS }
|
||||||
|
|
||||||
|
if (profileConfig.timetableTrimHourRange) {
|
||||||
|
dayViewDelegate.deinitialize()
|
||||||
|
// end/start defaults are swapped on purpose
|
||||||
|
startHour = lessonsActual.minOf { it.displayStartTime?.hour ?: DEFAULT_END_HOUR }
|
||||||
|
endHour = lessonsActual.maxOf { it.displayEndTime?.hour?.plus(1) ?: DEFAULT_START_HOUR }
|
||||||
|
}
|
||||||
|
|
||||||
|
b.scrollView.isVisible = true
|
||||||
b.dayFrame.addView(dayView, 0)
|
b.dayFrame.addView(dayView, 0)
|
||||||
|
|
||||||
// Inflate a label view for each hour the day view will display
|
// Inflate a label view for each hour the day view will display
|
||||||
@ -195,7 +212,7 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope {
|
|||||||
|
|
||||||
lessons.forEach { it.showAsUnseen = !it.seen }
|
lessons.forEach { it.showAsUnseen = !it.seen }
|
||||||
|
|
||||||
buildLessonViews(lessons.filter { it.type != Lesson.TYPE_NO_LESSONS }, events, attendanceList)
|
buildLessonViews(lessonsActual, events, attendanceList)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildLessonViews(lessons: List<LessonFull>, events: List<EventFull>, attendanceList: List<AttendanceFull>) {
|
private fun buildLessonViews(lessons: List<LessonFull>, events: List<EventFull>, attendanceList: List<AttendanceFull>) {
|
||||||
@ -215,7 +232,10 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope {
|
|||||||
val colorSecondary = android.R.attr.textColorSecondary.resolveAttr(activity)
|
val colorSecondary = android.R.attr.textColorSecondary.resolveAttr(activity)
|
||||||
|
|
||||||
for (lesson in lessons) {
|
for (lesson in lessons) {
|
||||||
val attendance = attendanceList.find { it.startTime == lesson.startTime }
|
val attendance = if (profileConfig.timetableShowAttendance)
|
||||||
|
attendanceList.find { it.startTime == lesson.startTime }
|
||||||
|
else
|
||||||
|
null
|
||||||
val startTime = lesson.displayStartTime ?: continue
|
val startTime = lesson.displayStartTime ?: continue
|
||||||
val endTime = lesson.displayEndTime ?: continue
|
val endTime = lesson.displayEndTime ?: continue
|
||||||
|
|
||||||
@ -245,23 +265,20 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val eventIcons = listOf(lb.event1, lb.event2, lb.event3)
|
||||||
|
if (profileConfig.timetableShowEvents) {
|
||||||
val eventList = events.filter { it.time != null && it.time == lesson.displayStartTime }.take(3)
|
val eventList = events.filter { it.time != null && it.time == lesson.displayStartTime }.take(3)
|
||||||
eventList.getOrNull(0).let {
|
for ((i, eventIcon) in eventIcons.withIndex()) {
|
||||||
lb.event1.visibility = if (it == null) View.GONE else View.VISIBLE
|
eventList.getOrNull(i).let {
|
||||||
lb.event1.background = it?.let {
|
eventIcon.isVisible = it != null
|
||||||
|
eventIcon.background = it?.let {
|
||||||
R.drawable.bg_circle.resolveDrawable(activity).setTintColor(it.eventColor)
|
R.drawable.bg_circle.resolveDrawable(activity).setTintColor(it.eventColor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
eventList.getOrNull(1).let {
|
|
||||||
lb.event2.visibility = if (it == null) View.GONE else View.VISIBLE
|
|
||||||
lb.event2.background = it?.let {
|
|
||||||
R.drawable.bg_circle.resolveDrawable(activity).setTintColor(it.eventColor)
|
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
eventList.getOrNull(2).let {
|
for (eventIcon in eventIcons) {
|
||||||
lb.event3.visibility = if (it == null) View.GONE else View.VISIBLE
|
eventIcon.visibility = View.GONE
|
||||||
lb.event3.background = it?.let {
|
|
||||||
R.drawable.bg_circle.resolveDrawable(activity).setTintColor(it.eventColor)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -295,13 +312,36 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope {
|
|||||||
lesson.classroom?.let { add(it) }
|
lesson.classroom?.let { add(it) }
|
||||||
}.concat(arrowRight)
|
}.concat(arrowRight)
|
||||||
|
|
||||||
|
lb.annotationVisible = manager.getAnnotation(activity, lesson, lb.annotation)
|
||||||
|
|
||||||
lb.lessonNumber = lesson.displayLessonNumber
|
|
||||||
val lessonText =
|
val lessonText =
|
||||||
lesson.getNoteSubstituteText(showNotes = true) ?: lesson.displaySubjectName
|
lesson.getNoteSubstituteText(showNotes = true) ?: lesson.displaySubjectName
|
||||||
|
|
||||||
|
val (subjectTextPrimary, subjectTextSecondary) = if (profileConfig.timetableColorSubjectName) {
|
||||||
|
val subjectColor = Colors.stringToMaterialColorCRC(lessonText?.toString() ?: "")
|
||||||
|
if (lb.annotationVisible) {
|
||||||
|
lb.subjectContainer.background = ColorDrawable(subjectColor)
|
||||||
|
} else {
|
||||||
|
lb.subjectContainer.setBackgroundResource(R.drawable.timetable_subject_color_rounded)
|
||||||
|
lb.subjectContainer.background.setTintColor(subjectColor)
|
||||||
|
}
|
||||||
|
when (ColorUtils.calculateLuminance(subjectColor) > 0.5) {
|
||||||
|
true -> /* light */ 0xFF000000 to 0xFF666666
|
||||||
|
false -> /* dark */ 0xFFFFFFFF to 0xFFAAAAAA
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lb.subjectContainer.background = null
|
||||||
|
null to colorSecondary
|
||||||
|
}
|
||||||
|
|
||||||
|
lb.lessonNumber = lesson.displayLessonNumber
|
||||||
|
if (subjectTextPrimary != null)
|
||||||
|
lb.lessonNumberText.setTextColor(subjectTextPrimary.toInt())
|
||||||
lb.subjectName.text = lessonText?.let {
|
lb.subjectName.text = lessonText?.let {
|
||||||
if (lesson.type == Lesson.TYPE_CANCELLED || lesson.type == Lesson.TYPE_SHIFTED_SOURCE)
|
if (lesson.type == Lesson.TYPE_CANCELLED || lesson.type == Lesson.TYPE_SHIFTED_SOURCE)
|
||||||
it.asStrikethroughSpannable().asColoredSpannable(colorSecondary)
|
it.asStrikethroughSpannable().asColoredSpannable(subjectTextSecondary.toInt())
|
||||||
|
else if (subjectTextPrimary != null)
|
||||||
|
it.asColoredSpannable(subjectTextPrimary.toInt())
|
||||||
else
|
else
|
||||||
it
|
it
|
||||||
}
|
}
|
||||||
@ -328,7 +368,6 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//lb.subjectName.typeface = Typeface.create("sans-serif-light", Typeface.BOLD)
|
//lb.subjectName.typeface = Typeface.create("sans-serif-light", Typeface.BOLD)
|
||||||
lb.annotationVisible = manager.getAnnotation(activity, lesson, lb.annotation)
|
|
||||||
val lessonNumberMargin =
|
val lessonNumberMargin =
|
||||||
if (lb.annotationVisible) (-8).dp
|
if (lb.annotationVisible) (-8).dp
|
||||||
else 0
|
else 0
|
||||||
|
@ -26,6 +26,7 @@ import pl.szczodrzynski.edziennik.R
|
|||||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||||
import pl.szczodrzynski.edziennik.databinding.FragmentTimetableV2Binding
|
import pl.szczodrzynski.edziennik.databinding.FragmentTimetableV2Binding
|
||||||
import pl.szczodrzynski.edziennik.ext.getSchoolYearConstrains
|
import pl.szczodrzynski.edziennik.ext.getSchoolYearConstrains
|
||||||
|
import pl.szczodrzynski.edziennik.ui.dialogs.settings.TimetableConfigDialog
|
||||||
import pl.szczodrzynski.edziennik.ui.event.EventManualDialog
|
import pl.szczodrzynski.edziennik.ui.event.EventManualDialog
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem
|
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem
|
||||||
@ -52,6 +53,7 @@ class TimetableFragment : Fragment(), CoroutineScope {
|
|||||||
|
|
||||||
private var fabShown = false
|
private var fabShown = false
|
||||||
private val items = mutableListOf<Date>()
|
private val items = mutableListOf<Date>()
|
||||||
|
private val profileConfig by lazy { app.config.forProfile().ui }
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
activity = (getActivity() as MainActivity?) ?: return null
|
activity = (getActivity() as MainActivity?) ?: return null
|
||||||
@ -128,8 +130,8 @@ class TimetableFragment : Fragment(), CoroutineScope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val lessonRanges = app.db.lessonRangeDao().getAllNow(App.profileId)
|
val lessonRanges = app.db.lessonRangeDao().getAllNow(App.profileId)
|
||||||
startHour = lessonRanges.map { it.startTime.hour }.minOrNull() ?: DEFAULT_START_HOUR
|
startHour = lessonRanges.minOfOrNull { it.startTime.hour } ?: DEFAULT_START_HOUR
|
||||||
endHour = lessonRanges.map { it.endTime.hour }.maxOrNull()?.plus(1) ?: DEFAULT_END_HOUR
|
endHour = lessonRanges.maxOfOrNull { it.endTime.hour }?.plus(1) ?: DEFAULT_END_HOUR
|
||||||
}
|
}
|
||||||
deferred.await()
|
deferred.await()
|
||||||
if (!isAdded)
|
if (!isAdded)
|
||||||
@ -208,6 +210,13 @@ class TimetableFragment : Fragment(), CoroutineScope {
|
|||||||
activity.bottomSheet.close()
|
activity.bottomSheet.close()
|
||||||
GenerateBlockTimetableDialog(activity)
|
GenerateBlockTimetableDialog(activity)
|
||||||
}),
|
}),
|
||||||
|
BottomSheetPrimaryItem(true)
|
||||||
|
.withTitle(R.string.menu_timetable_config)
|
||||||
|
.withIcon(CommunityMaterial.Icon.cmd_cog_outline)
|
||||||
|
.withOnClickListener {
|
||||||
|
activity.bottomSheet.close()
|
||||||
|
TimetableConfigDialog(activity, false, null, null).show()
|
||||||
|
},
|
||||||
BottomSheetSeparatorItem(true),
|
BottomSheetSeparatorItem(true),
|
||||||
BottomSheetPrimaryItem(true)
|
BottomSheetPrimaryItem(true)
|
||||||
.withTitle(R.string.menu_mark_as_read)
|
.withTitle(R.string.menu_mark_as_read)
|
||||||
|
@ -15,6 +15,7 @@ import androidx.core.graphics.ColorUtils;
|
|||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
import java.util.zip.CRC32;
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Grade;
|
import pl.szczodrzynski.edziennik.data.db.entity.Grade;
|
||||||
|
|
||||||
@ -84,6 +85,28 @@ public class Colors {
|
|||||||
0xFF6D4C41
|
0xFF6D4C41
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public static final int[] materialColorsBasic = {
|
||||||
|
0xFFE53935, 0xFFD81B60, 0xFF8E24AA, 0xFF5E35B1,
|
||||||
|
0xFF3949AB, 0xFF1E88E5, 0xFF039BE5, 0xFF00ACC1,
|
||||||
|
0xFF00897B, 0xFF43A047, 0xFF7CB342, 0xFFC0CA33,
|
||||||
|
0xFFFDD835, 0xFFFFB300, 0xFFFB8C00, 0xFFF4511E,
|
||||||
|
0xFF6D4C41, 0xFF757575, 0xFF546E7A, 0xFF00E676,
|
||||||
|
|
||||||
|
0xFFEF9A9A, 0xFFF48FB1, 0xFFCE93D8, 0xFFB39DDB,
|
||||||
|
0xFF9FA8DA, 0xFF90CAF9, 0xFF81D4FA, 0xFF80DEEA,
|
||||||
|
0xFF80CBC4, 0xFFA5D6A7, 0xFFC5E1A5, 0xFFE6EE9C,
|
||||||
|
0xFFFFF59D, 0xFFFFE082, 0xFFFFCC80, 0xFFFFAB91,
|
||||||
|
0xFFBCAAA4, 0xFFEEEEEE, 0xFFB0BEC5, 0xFFCCFF90,
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final int[] metroColors = {
|
||||||
|
0xFF76FF03, 0xFF60A917, 0xFF00C853, 0xFF00ABA9,
|
||||||
|
0xFF1BA1E2, 0xFF0050EF, 0xFF6A00FF, 0xFFAA00FF,
|
||||||
|
0xFFF472D0, 0xFFD80073, 0xFFA20025, 0xFFE51400,
|
||||||
|
0xFFFA6800, 0xFFF0A30A, 0xFFE3C800, 0xFF795548,
|
||||||
|
0xFF6D8764, 0xFF647687, 0xFF76608A, 0xFFA0522D,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used for teacher's images (e.g. in messages or announcements).
|
* Used for teacher's images (e.g. in messages or announcements).
|
||||||
* @param s teacher's fullName
|
* @param s teacher's fullName
|
||||||
@ -115,6 +138,18 @@ public class Colors {
|
|||||||
return materialColors[getRandomNumberInRange(0, materialColors.length-1, seed)];
|
return materialColors[getRandomNumberInRange(0, materialColors.length-1, seed)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int stringToMaterialColorCRC(String s) {
|
||||||
|
long seed;
|
||||||
|
try {
|
||||||
|
CRC32 crc = new CRC32();
|
||||||
|
crc.update(s.getBytes());
|
||||||
|
seed = crc.getValue();
|
||||||
|
} catch (Exception e) {
|
||||||
|
seed = 1234;
|
||||||
|
}
|
||||||
|
return metroColors[(int) (seed % metroColors.length)];
|
||||||
|
}
|
||||||
|
|
||||||
public static int gradeToColor(Grade grade)
|
public static int gradeToColor(Grade grade)
|
||||||
{
|
{
|
||||||
if (grade.getType() == Grade.TYPE_POINT_SUM) {
|
if (grade.getType() == Grade.TYPE_POINT_SUM) {
|
||||||
|
@ -19,7 +19,6 @@ class MutableLazyImpl<T>(initializer: () -> T, lock: Any? = null) {
|
|||||||
return synchronized(lock) {
|
return synchronized(lock) {
|
||||||
val typedValue = initializer!!()
|
val typedValue = initializer!!()
|
||||||
_value = typedValue
|
_value = typedValue
|
||||||
initializer = null
|
|
||||||
typedValue
|
typedValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -29,6 +28,10 @@ class MutableLazyImpl<T>(initializer: () -> T, lock: Any? = null) {
|
|||||||
|
|
||||||
fun isInitialized() = _value !== UNINITIALIZED_VALUE
|
fun isInitialized() = _value !== UNINITIALIZED_VALUE
|
||||||
|
|
||||||
|
fun deinitialize() {
|
||||||
|
_value = UNINITIALIZED_VALUE
|
||||||
|
}
|
||||||
|
|
||||||
override fun toString() = if (isInitialized()) _value.toString() else "ChangeableLazy value not initialized yet."
|
override fun toString() = if (isInitialized()) _value.toString() else "ChangeableLazy value not initialized yet."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +36,13 @@ class PermissionManager(val app: App) : CoroutineScope {
|
|||||||
app.checkSelfPermission(name) == PackageManager.PERMISSION_GRANTED
|
app.checkSelfPermission(name) == PackageManager.PERMISSION_GRANTED
|
||||||
else
|
else
|
||||||
true
|
true
|
||||||
|
val isNotificationPermissionGranted by lazy {
|
||||||
|
if (Build.VERSION.SDK_INT >= 33) {
|
||||||
|
app.checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
private fun openPermissionSettings(activity: AppCompatActivity) {
|
private fun openPermissionSettings(activity: AppCompatActivity) {
|
||||||
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
|
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
|
||||||
val uri = Uri.fromParts("package", app.packageName, null)
|
val uri = Uri.fromParts("package", app.packageName, null)
|
||||||
@ -80,6 +86,10 @@ class PermissionManager(val app: App) : CoroutineScope {
|
|||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
result.hasPermanentDenied() -> {
|
result.hasPermanentDenied() -> {
|
||||||
|
if (!isRequired) {
|
||||||
|
onSuccess()
|
||||||
|
return@launch
|
||||||
|
}
|
||||||
MaterialAlertDialogBuilder(activity)
|
MaterialAlertDialogBuilder(activity)
|
||||||
.setTitle(R.string.permissions_required)
|
.setTitle(R.string.permissions_required)
|
||||||
.setMessage(R.string.permissions_denied)
|
.setMessage(R.string.permissions_denied)
|
||||||
@ -92,6 +102,18 @@ class PermissionManager(val app: App) : CoroutineScope {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fun requestNotificationsPermission(
|
||||||
|
activity: AppCompatActivity,
|
||||||
|
@StringRes permissionMessage: Int,
|
||||||
|
isRequired: Boolean = false,
|
||||||
|
onSuccess: suspend CoroutineScope.() -> Unit
|
||||||
|
) = requestPermission(
|
||||||
|
activity,
|
||||||
|
permissionMessage,
|
||||||
|
isRequired,
|
||||||
|
Manifest.permission.POST_NOTIFICATIONS,
|
||||||
|
onSuccess
|
||||||
|
)
|
||||||
|
|
||||||
fun requestStoragePermission(
|
fun requestStoragePermission(
|
||||||
activity: AppCompatActivity,
|
activity: AppCompatActivity,
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
<TextView
|
<TextView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/agenda_config_appearance"
|
android:text="@string/config_appearance"
|
||||||
android:textAppearance="@style/NavView.TextView.Subtitle" />
|
android:textAppearance="@style/NavView.TextView.Subtitle" />
|
||||||
|
|
||||||
<com.google.android.material.checkbox.MaterialCheckBox
|
<com.google.android.material.checkbox.MaterialCheckBox
|
||||||
|
64
app/src/main/res/layout/timetable_config_dialog.xml
Normal file
64
app/src/main/res/layout/timetable_config_dialog.xml
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright (c) Kuba Szczodrzyński 2022-10-7.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<data>
|
||||||
|
|
||||||
|
<variable
|
||||||
|
name="config"
|
||||||
|
type="pl.szczodrzynski.edziennik.config.ProfileConfigUI" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="24dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/config_appearance"
|
||||||
|
android:textAppearance="@style/NavView.TextView.Subtitle" />
|
||||||
|
|
||||||
|
<com.google.android.material.checkbox.MaterialCheckBox
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:checked="@={config.timetableShowEvents}"
|
||||||
|
android:minHeight="32dp"
|
||||||
|
android:text="@string/timetable_config_show_events" />
|
||||||
|
|
||||||
|
<com.google.android.material.checkbox.MaterialCheckBox
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:checked="@={config.timetableShowAttendance}"
|
||||||
|
android:minHeight="32dp"
|
||||||
|
android:text="@string/timetable_config_show_attendance" />
|
||||||
|
|
||||||
|
<com.google.android.material.checkbox.MaterialCheckBox
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:checked="@={config.timetableColorSubjectName}"
|
||||||
|
android:minHeight="32dp"
|
||||||
|
android:text="@string/timetable_config_color_subject_name" />
|
||||||
|
|
||||||
|
<com.google.android.material.checkbox.MaterialCheckBox
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:checked="@={config.timetableTrimHourRange}"
|
||||||
|
android:minHeight="32dp"
|
||||||
|
android:text="@string/timetable_config_trim_hour_range" />
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
||||||
|
</layout>
|
@ -45,14 +45,15 @@
|
|||||||
tools:visibility="gone" />
|
tools:visibility="gone" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
android:id="@+id/subjectContainer"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="top"
|
android:layout_gravity="top"
|
||||||
android:baselineAligned="false"
|
android:baselineAligned="false"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:paddingHorizontal="8dp"
|
android:paddingHorizontal="8dp"
|
||||||
android:paddingVertical="4dp">
|
android:paddingVertical="4dp"
|
||||||
<!--tools:background="@drawable/timetable_subject_color_rounded"-->
|
tools:background="@drawable/timetable_subject_color_rounded">
|
||||||
|
|
||||||
<com.mikepenz.iconics.view.IconicsTextView
|
<com.mikepenz.iconics.view.IconicsTextView
|
||||||
android:id="@+id/subjectName"
|
android:id="@+id/subjectName"
|
||||||
|
@ -1383,7 +1383,7 @@
|
|||||||
<string name="notes_type_grade">Grade</string>
|
<string name="notes_type_grade">Grade</string>
|
||||||
<string name="privacy_policy_dialog_html"><![CDATA[By using the application, you confirm that you have <a href="https://szkolny.eu/privacy-policy">read the Privacy Policy</a> and accept its provisions.<br /><br />The authors of the application are not responsible for the use of the Szkolny.eu application.]]></string>
|
<string name="privacy_policy_dialog_html"><![CDATA[By using the application, you confirm that you have <a href="https://szkolny.eu/privacy-policy">read the Privacy Policy</a> and accept its provisions.<br /><br />The authors of the application are not responsible for the use of the Szkolny.eu application.]]></string>
|
||||||
<string name="login_chooser_version_format">Szkolny.eu v%s\n%s</string>
|
<string name="login_chooser_version_format">Szkolny.eu v%s\n%s</string>
|
||||||
<string name="agenda_config_appearance">Appearance</string>
|
<string name="config_appearance">Appearance</string>
|
||||||
<string name="agenda_config_elearning">Online learning</string>
|
<string name="agenda_config_elearning">Online learning</string>
|
||||||
<string name="event_type_elearning">online lesson</string>
|
<string name="event_type_elearning">online lesson</string>
|
||||||
<string name="menu_messages_config">Messages settings</string>
|
<string name="menu_messages_config">Messages settings</string>
|
||||||
|
@ -1424,7 +1424,7 @@
|
|||||||
<string name="privacy_policy_dialog_html"><![CDATA[Korzystając z aplikacji potwierdzasz <a href="https://szkolny.eu/privacy-policy">przeczytanie Polityki prywatności</a> i akceptujesz jej postanowienia.<br /><br />Autorzy aplikacji nie biorą odpowiedzialności za korzystanie z aplikacji Szkolny.eu.]]></string>
|
<string name="privacy_policy_dialog_html"><![CDATA[Korzystając z aplikacji potwierdzasz <a href="https://szkolny.eu/privacy-policy">przeczytanie Polityki prywatności</a> i akceptujesz jej postanowienia.<br /><br />Autorzy aplikacji nie biorą odpowiedzialności za korzystanie z aplikacji Szkolny.eu.]]></string>
|
||||||
<string name="login_chooser_version_format">Szkolny.eu v%s\n%s</string>
|
<string name="login_chooser_version_format">Szkolny.eu v%s\n%s</string>
|
||||||
<string name="menu_agenda_config">Ustawienia terminarza</string>
|
<string name="menu_agenda_config">Ustawienia terminarza</string>
|
||||||
<string name="agenda_config_appearance">Wygląd</string>
|
<string name="config_appearance">Wygląd</string>
|
||||||
<string name="agenda_config_lesson_changes">Pokazuj zmiany planu lekcji</string>
|
<string name="agenda_config_lesson_changes">Pokazuj zmiany planu lekcji</string>
|
||||||
<string name="agenda_config_teacher_absence">Pokazuj nieobecności nauczycieli</string>
|
<string name="agenda_config_teacher_absence">Pokazuj nieobecności nauczycieli</string>
|
||||||
<string name="agenda_config_compact_mode">Tryb kompaktowy</string>
|
<string name="agenda_config_compact_mode">Tryb kompaktowy</string>
|
||||||
@ -1537,6 +1537,11 @@
|
|||||||
<string name="login_summary_account_parent">(rodzic)</string>
|
<string name="login_summary_account_parent">(rodzic)</string>
|
||||||
<string name="grades_subject_unknown">- nieznany przedmiot -</string>
|
<string name="grades_subject_unknown">- nieznany przedmiot -</string>
|
||||||
<string name="grades_subject_unknown_help">{cmd-information-outline} Oceny, których przedmiot nie został podany w dzienniku. Może to być na przykład taki, który nie jest prowadzony w tym roku szkolnym.</string>
|
<string name="grades_subject_unknown_help">{cmd-information-outline} Oceny, których przedmiot nie został podany w dzienniku. Może to być na przykład taki, który nie jest prowadzony w tym roku szkolnym.</string>
|
||||||
|
<string name="menu_timetable_config">Ustawienia planu lekcji</string>
|
||||||
|
<string name="timetable_config_show_events">Pokazuj wydarzenia przy lekcjach</string>
|
||||||
|
<string name="timetable_config_show_attendance">Pokazuj rodzaj obecności na lekcji</string>
|
||||||
|
<string name="timetable_config_color_subject_name">Koloruj nazwę przedmiotu</string>
|
||||||
|
<string name="timetable_config_trim_hour_range">Nie pokazuj godzin bez lekcji</string>
|
||||||
<string name="edziennik_progress_login_usos_api">Logowanie do USOS API...</string>
|
<string name="edziennik_progress_login_usos_api">Logowanie do USOS API...</string>
|
||||||
<string name="login_type_usos">USOS</string>
|
<string name="login_type_usos">USOS</string>
|
||||||
<string name="login_mode_usos_oauth">Logowanie z użyciem przeglądarki</string>
|
<string name="login_mode_usos_oauth">Logowanie z użyciem przeglądarki</string>
|
||||||
|
Loading…
Reference in New Issue
Block a user