Merge branch 'develop'

This commit is contained in:
Kuba Szczodrzyński 2022-12-27 12:09:04 +01:00
commit 8d7dc511ea
No known key found for this signature in database
GPG Key ID: 70CB8A85BA1633CB
39 changed files with 208 additions and 114 deletions

View File

@ -156,6 +156,7 @@ dependencies {
implementation "androidx.navigation:navigation-fragment-ktx:2.5.2" implementation "androidx.navigation:navigation-fragment-ktx:2.5.2"
implementation "androidx.recyclerview:recyclerview:1.2.1" implementation "androidx.recyclerview:recyclerview:1.2.1"
implementation "androidx.room:room-runtime:2.4.3" implementation "androidx.room:room-runtime:2.4.3"
implementation "androidx.room:room-ktx:2.4.3"
implementation "androidx.work:work-runtime-ktx:2.7.1" implementation "androidx.work:work-runtime-ktx:2.7.1"
kapt "androidx.room:room-compiler:2.4.3" kapt "androidx.room:room-compiler:2.4.3"

View File

@ -1,5 +1,9 @@
<h3>Wersja 4.13.2, 2022-11-28</h3> <h3>Wersja 4.13.4, 2022-12-26</h3>
<ul> <ul>
<li>USOS: zaktualizowano rodzaje wydarzeń. Wybór przedmiotu jest teraz zawsze widoczny.</li>
<li>Opcja wyświetlania nazwy przedmiotu w miejscu rodzaju wydarzenia.</li>
<li>Notatki zastępujące treść lekcji są teraz wyświetlane wszędzie.</li>
<li>Na ekranie odliczania czasu lekcji również pada śnieg.</li>
<li>Poprawiono synchronizację w Mobidzienniku bez ustawionego adresu e-mail.</li> <li>Poprawiono synchronizację w Mobidzienniku bez ustawionego adresu e-mail.</li>
<li>Poprawiono błąd synchronizacji w Vulcanie.</li> <li>Poprawiono błąd synchronizacji w Vulcanie.</li>
</ul> </ul>

View File

@ -9,7 +9,7 @@
/*secret password - removed for source code publication*/ /*secret password - removed for source code publication*/
static toys AES_IV[16] = { static toys AES_IV[16] = {
0x8c, 0xad, 0x9c, 0x3e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 0x4b, 0x43, 0x7e, 0xa2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
unsigned char *agony(unsigned int laugh, unsigned char *box, unsigned char *heat); unsigned char *agony(unsigned int laugh, unsigned char *box, unsigned char *heat);

View File

@ -422,6 +422,12 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
try { try {
App.data = AppData.get(profile.loginStoreType) App.data = AppData.get(profile.loginStoreType)
d("App", "Loaded AppData: ${App.data}") d("App", "Loaded AppData: ${App.data}")
// apply newly-added config overrides, if not changed by the user yet
for ((key, value) in App.data.configOverrides) {
val config = App.profile.config
if (!config.has(key))
config.set(key, value)
}
} catch (e: Exception) { } catch (e: Exception) {
Log.e("App", "Cannot load AppData", e) Log.e("App", "Cannot load AppData", e)
Toast.makeText(this, R.string.app_cannot_load_data, Toast.LENGTH_LONG).show() Toast.makeText(this, R.string.app_cannot_load_data, Toast.LENGTH_LONG).show()

View File

@ -322,7 +322,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
// IT'S WINTER MY DUDES // IT'S WINTER MY DUDES
val today = Date.getToday() val today = Date.getToday()
if ((today.month % 11 == 1) && app.config.ui.snowfall) { if ((today.month / 3 % 4 == 0) && app.config.ui.snowfall) {
b.rootFrame.addView(layoutInflater.inflate(R.layout.snowfall, b.rootFrame, false)) b.rootFrame.addView(layoutInflater.inflate(R.layout.snowfall, b.rootFrame, false))
} else if (app.config.ui.eggfall && BigNightUtil().isDataWielkanocyNearDzisiaj()) { } else if (app.config.ui.eggfall && BigNightUtil().isDataWielkanocyNearDzisiaj()) {
val eggfall = layoutInflater.inflate( val eggfall = layoutInflater.inflate(

View File

@ -59,10 +59,11 @@ data class AppData(
val lessonHeight: Int, val lessonHeight: Int,
val enableMarkAsReadAnnouncements: Boolean, val enableMarkAsReadAnnouncements: Boolean,
val enableNoticePoints: Boolean, val enableNoticePoints: Boolean,
val eventManualShowSubjectDropdown: Boolean,
) )
data class EventType( data class EventType(
val id: Int, val id: Long,
val color: String, val color: String,
val name: String, val name: String,
) )

View File

@ -43,4 +43,6 @@ abstract class BaseConfig(
db.configDao().add(ConfigEntry(profileId ?: -1, key, value)) db.configDao().add(ConfigEntry(profileId ?: -1, key, value))
} }
} }
fun has(key: String) = values.containsKey(key)
} }

View File

@ -15,7 +15,7 @@ class ProfileConfig(
entries: List<ConfigEntry>?, entries: List<ConfigEntry>?,
) : BaseConfig(db, profileId, entries) { ) : BaseConfig(db, profileId, entries) {
companion object { companion object {
const val DATA_VERSION = 4 const val DATA_VERSION = 5
} }
val grades by lazy { ProfileConfigGrades(this) } val grades by lazy { ProfileConfigGrades(this) }

View File

@ -15,6 +15,7 @@ class ProfileConfigUI(base: ProfileConfig) {
var agendaGroupByType by base.config<Boolean>(false) var agendaGroupByType by base.config<Boolean>(false)
var agendaLessonChanges by base.config<Boolean>(true) var agendaLessonChanges by base.config<Boolean>(true)
var agendaTeacherAbsence by base.config<Boolean>(true) var agendaTeacherAbsence by base.config<Boolean>(true)
var agendaSubjectImportant by base.config<Boolean>(false)
var agendaElearningMark by base.config<Boolean>(false) var agendaElearningMark by base.config<Boolean>(false)
var agendaElearningGroup by base.config<Boolean>(true) var agendaElearningGroup by base.config<Boolean>(true)

View File

@ -16,6 +16,8 @@ import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.YEAR_AL
class ProfileConfigMigration(config: ProfileConfig) { class ProfileConfigMigration(config: ProfileConfig) {
init { config.apply { init { config.apply {
val profile = db.profileDao().getByIdNow(profileId ?: -1)
if (dataVersion < 2) { if (dataVersion < 2) {
sync.notificationFilter = sync.notificationFilter + NotificationType.TEACHER_ABSENCE sync.notificationFilter = sync.notificationFilter + NotificationType.TEACHER_ABSENCE
@ -37,11 +39,23 @@ class ProfileConfigMigration(config: ProfileConfig) {
// switch to new event types (USOS) // switch to new event types (USOS)
dataVersion = 4 dataVersion = 4
val profile = db.profileDao().getByIdNow(profileId ?: -1)
if (profile?.loginStoreType?.schoolType == SchoolType.UNIVERSITY) { if (profile?.loginStoreType?.schoolType == SchoolType.UNIVERSITY) {
db.eventTypeDao().clear(profileId ?: -1) db.eventTypeDao().clear(profileId ?: -1)
db.eventTypeDao().addDefaultTypes(profile) db.eventTypeDao().addDefaultTypes(profile)
} }
} }
if (dataVersion < 5) {
// update USOS event types and the appropriate events (2022-12-25)
dataVersion = 5
if (profile?.loginStoreType?.schoolType == SchoolType.UNIVERSITY) {
db.eventTypeDao().getAllWithDefaults(profile)
// wejściówka (4) -> kartkówka (3)
db.eventDao().getRawNow("UPDATE events SET eventType = 3 WHERE profileId = $profileId AND eventType = 4;")
// zadanie (6) -> zadanie domowe (-1)
db.eventDao().getRawNow("UPDATE events SET eventType = -1 WHERE profileId = $profileId AND eventType = 6;")
}
}
}} }}
} }

View File

@ -46,6 +46,6 @@ object Signing {
/*fun provideKey(param1: String, param2: Long): ByteArray {*/ /*fun provideKey(param1: String, param2: Long): ByteArray {*/
fun pleaseStopRightNow(param1: String, param2: Long): ByteArray { fun pleaseStopRightNow(param1: String, param2: Long): ByteArray {
return "$param1.MTIzNDU2Nzg5MDLUEjNGMN===.$param2".sha256() return "$param1.MTIzNDU2Nzg5MD4BikzMWC===.$param2".sha256()
} }
} }

View File

@ -25,6 +25,9 @@ abstract class EventTypeDao {
@Query("DELETE FROM eventTypes WHERE profileId = :profileId") @Query("DELETE FROM eventTypes WHERE profileId = :profileId")
abstract fun clear(profileId: Int) abstract fun clear(profileId: Int)
@Query("DELETE FROM eventTypes WHERE profileId = :profileId AND eventTypeSource = :source")
abstract fun clearBySource(profileId: Int, source: Int)
@Query("SELECT * FROM eventTypes WHERE profileId = :profileId AND eventType = :typeId") @Query("SELECT * FROM eventTypes WHERE profileId = :profileId AND eventType = :typeId")
abstract fun getByIdNow(profileId: Int, typeId: Long): EventType? abstract fun getByIdNow(profileId: Int, typeId: Long): EventType?
@ -43,7 +46,7 @@ abstract class EventTypeDao {
val typeList = data.eventTypes.map { val typeList = data.eventTypes.map {
EventType( EventType(
profileId = profile.id, profileId = profile.id,
id = it.id.toLong(), id = it.id,
name = it.name, name = it.name,
color = Color.parseColor(it.color), color = Color.parseColor(it.color),
order = order++, order = order++,
@ -53,4 +56,21 @@ abstract class EventTypeDao {
addAll(typeList) addAll(typeList)
return typeList return typeList
} }
fun getAllWithDefaults(profile: Profile): List<EventType> {
val eventTypes = getAllNow(profile.id)
val defaultIdsExpected = AppData.get(profile.loginStoreType).eventTypes
.map { it.id }
val defaultIdsFound = eventTypes.filter { it.source == SOURCE_DEFAULT }
.sortedBy { it.order }
.map { it.id }
if (defaultIdsExpected == defaultIdsFound)
return eventTypes
clearBySource(profile.id, SOURCE_DEFAULT)
addDefaultTypes(profile)
return eventTypes
}
} }

View File

@ -28,6 +28,9 @@ interface ProfileDao {
@Query("SELECT * FROM profiles WHERE profileId = :profileId") @Query("SELECT * FROM profiles WHERE profileId = :profileId")
fun getByIdNow(profileId: Int): Profile? fun getByIdNow(profileId: Int): Profile?
@Query("SELECT * FROM profiles WHERE profileId = :profileId")
suspend fun getByIdSuspend(profileId: Int): Profile?
@get:Query("SELECT * FROM profiles WHERE profileId >= 0 ORDER BY profileId") @get:Query("SELECT * FROM profiles WHERE profileId >= 0 ORDER BY profileId")
val all: LiveData<List<Profile>> val all: LiveData<List<Profile>>

View File

@ -5,31 +5,6 @@ package pl.szczodrzynski.edziennik.data.db.entity
import androidx.room.ColumnInfo import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.COLOR_CLASS_EVENT
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.COLOR_DEFAULT
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.COLOR_ELEARNING
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.COLOR_ESSAY
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.COLOR_EXAM
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.COLOR_EXCURSION
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.COLOR_HOMEWORK
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.COLOR_INFORMATION
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.COLOR_PROJECT
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.COLOR_PT_MEETING
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.COLOR_READING
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.COLOR_SHORT_QUIZ
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.TYPE_CLASS_EVENT
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.TYPE_DEFAULT
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.TYPE_ELEARNING
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.TYPE_ESSAY
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.TYPE_EXAM
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.TYPE_EXCURSION
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.TYPE_HOMEWORK
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.TYPE_INFORMATION
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.TYPE_PROJECT
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.TYPE_PT_MEETING
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.TYPE_READING
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.TYPE_SHORT_QUIZ
@Entity( @Entity(
tableName = "eventTypes", tableName = "eventTypes",
@ -55,35 +30,5 @@ class EventType(
const val SOURCE_REGISTER = 1 const val SOURCE_REGISTER = 1
const val SOURCE_CUSTOM = 2 const val SOURCE_CUSTOM = 2
const val SOURCE_SHARED = 3 const val SOURCE_SHARED = 3
fun getTypeColorMap() = mapOf(
TYPE_ELEARNING to COLOR_ELEARNING,
TYPE_HOMEWORK to COLOR_HOMEWORK,
TYPE_DEFAULT to COLOR_DEFAULT,
TYPE_EXAM to COLOR_EXAM,
TYPE_SHORT_QUIZ to COLOR_SHORT_QUIZ,
TYPE_ESSAY to COLOR_ESSAY,
TYPE_PROJECT to COLOR_PROJECT,
TYPE_PT_MEETING to COLOR_PT_MEETING,
TYPE_EXCURSION to COLOR_EXCURSION,
TYPE_READING to COLOR_READING,
TYPE_CLASS_EVENT to COLOR_CLASS_EVENT,
TYPE_INFORMATION to COLOR_INFORMATION
)
fun getTypeNameMap() = mapOf(
TYPE_ELEARNING to R.string.event_type_elearning,
TYPE_HOMEWORK to R.string.event_type_homework,
TYPE_DEFAULT to R.string.event_other,
TYPE_EXAM to R.string.event_exam,
TYPE_SHORT_QUIZ to R.string.event_short_quiz,
TYPE_ESSAY to R.string.event_essay,
TYPE_PROJECT to R.string.event_project,
TYPE_PT_MEETING to R.string.event_pt_meeting,
TYPE_EXCURSION to R.string.event_excursion,
TYPE_READING to R.string.event_reading,
TYPE_CLASS_EVENT to R.string.event_class_event,
TYPE_INFORMATION to R.string.event_information
)
} }
} }

View File

@ -73,7 +73,8 @@ fun JsonObject(vararg properties: Pair<String, Any?>): JsonObject {
is Number -> addProperty(key, value) is Number -> addProperty(key, value)
is Boolean -> addProperty(key, value) is Boolean -> addProperty(key, value)
is Enum<*> -> addProperty(key, value.toInt()) is Enum<*> -> addProperty(key, value.toInt())
else -> add(key, property.toJsonElement()) null -> add(key, null)
else -> add(key, value.toJsonElement())
} }
} }
} }

View File

@ -8,6 +8,7 @@ import android.content.Context
import android.content.res.Resources import android.content.res.Resources
import android.graphics.Rect import android.graphics.Rect
import android.view.View import android.view.View
import android.view.ViewGroup
import android.view.WindowManager import android.view.WindowManager
import android.widget.* import android.widget.*
import androidx.annotation.StringRes import androidx.annotation.StringRes
@ -161,3 +162,12 @@ val SwipeRefreshLayout.onScrollListener: RecyclerView.OnScrollListener
} }
} }
fun View.removeFromParent() {
(parent as? ViewGroup)?.removeView(this)
}
fun View.appendView(child: View) {
val parent = parent as? ViewGroup ?: return
val index = parent.indexOfChild(this)
parent.addView(child, index + 1)
}

View File

@ -142,13 +142,7 @@ class AgendaFragment : Fragment(), CoroutineScope {
private suspend fun checkEventTypes() { private suspend fun checkEventTypes() {
withContext(Dispatchers.Default) { withContext(Dispatchers.Default) {
val eventTypes = app.db.eventTypeDao().getAllNow(app.profileId).map { app.db.eventTypeDao().getAllWithDefaults(app.profile)
it.id
}
val defaultEventTypes = EventType.getTypeColorMap().keys
if (!eventTypes.containsAll(defaultEventTypes)) {
app.db.eventTypeDao().addDefaultTypes(app.profile)
}
} }
} }

View File

@ -11,6 +11,7 @@ import android.widget.TextView
import androidx.core.view.isVisible import androidx.core.view.isVisible
import com.github.tibolte.agendacalendarview.render.EventRenderer import com.github.tibolte.agendacalendarview.render.EventRenderer
import com.mikepenz.iconics.view.IconicsTextView import com.mikepenz.iconics.view.IconicsTextView
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.databinding.AgendaWrappedEventBinding import pl.szczodrzynski.edziennik.databinding.AgendaWrappedEventBinding
import pl.szczodrzynski.edziennik.databinding.AgendaWrappedEventCompactBinding import pl.szczodrzynski.edziennik.databinding.AgendaWrappedEventCompactBinding
@ -53,16 +54,24 @@ class AgendaEventRenderer(
else else
event.time!!.stringHM event.time!!.stringHM
val agendaSubjectImportant = App.profile.config.ui.agendaSubjectImportant
val eventSubtitle = listOfNotNull( val eventSubtitle = listOfNotNull(
timeText, timeText,
event.subjectLongName, event.subjectLongName.takeIf { !agendaSubjectImportant },
event.typeName.takeIf { agendaSubjectImportant },
event.teacherName, event.teacherName,
event.teamName event.teamName
).join(", ") ).join(", ")
card.foreground.setTintColor(event.eventColor) card.foreground.setTintColor(event.eventColor)
card.background.setTintColor(event.eventColor) card.background.setTintColor(event.eventColor)
manager.setEventTopic(title, event, doneIconColor = textColor) manager.setEventTopic(
title = title,
event = event,
doneIconColor = textColor,
showType = !agendaSubjectImportant,
showSubject = agendaSubjectImportant,
)
title.setTextColor(textColor) title.setTextColor(textColor)
subtitle?.text = eventSubtitle subtitle?.text = eventSubtitle
subtitle?.setTextColor(textColor) subtitle?.setTextColor(textColor)

View File

@ -23,6 +23,7 @@ import kotlinx.coroutines.launch
import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.config.Config import pl.szczodrzynski.edziennik.config.Config
import pl.szczodrzynski.edziennik.data.api.szkolny.interceptor.SignatureInterceptor import pl.szczodrzynski.edziennik.data.api.szkolny.interceptor.SignatureInterceptor
import pl.szczodrzynski.edziennik.data.db.entity.EventType.Companion.SOURCE_DEFAULT
import pl.szczodrzynski.edziennik.databinding.LabFragmentBinding import pl.szczodrzynski.edziennik.databinding.LabFragmentBinding
import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.ext.*
import pl.szczodrzynski.edziennik.ui.base.lazypager.LazyFragment import pl.szczodrzynski.edziennik.ui.base.lazypager.LazyFragment
@ -65,6 +66,7 @@ class LabPageFragment : LazyFragment(), CoroutineScope {
b.clearEndpointTimers.isVisible = false b.clearEndpointTimers.isVisible = false
b.rodo.isVisible = false b.rodo.isVisible = false
b.removeHomework.isVisible = false b.removeHomework.isVisible = false
b.resetEventTypes.isVisible = false
b.unarchive.isVisible = false b.unarchive.isVisible = false
b.profile.isVisible = false b.profile.isVisible = false
} }
@ -100,6 +102,11 @@ class LabPageFragment : LazyFragment(), CoroutineScope {
app.db.eventDao().getRawNow("UPDATE events SET homeworkBody = NULL WHERE profileId = ${App.profileId}") app.db.eventDao().getRawNow("UPDATE events SET homeworkBody = NULL WHERE profileId = ${App.profileId}")
} }
b.resetEventTypes.onClick {
app.db.eventTypeDao().clearBySource(App.profileId, SOURCE_DEFAULT)
app.db.eventTypeDao().getAllWithDefaults(App.profile)
}
b.chucker.isChecked = App.enableChucker b.chucker.isChecked = App.enableChucker
b.chucker.onChange { _, isChecked -> b.chucker.onChange { _, isChecked ->
app.config.enableChucker = isChecked app.config.enableChucker = isChecked

View File

@ -113,9 +113,20 @@ class EventDetailsDialog(
b.typeColor.background?.setTintColor(event.eventColor) b.typeColor.background?.setTintColor(event.eventColor)
b.details = mutableListOf( val agendaSubjectImportant = event.subjectLongName != null
&& App.config[event.profileId].ui.agendaSubjectImportant
b.name = if (agendaSubjectImportant)
event.subjectLongName
else
event.typeName
b.details = listOfNotNull(
if (agendaSubjectImportant)
event.typeName
else
event.subjectLongName, event.subjectLongName,
event.teamName?.asColoredSpannable(colorSecondary) event.teamName?.asColoredSpannable(colorSecondary)
).concat(bullet) ).concat(bullet)
b.addedBy.setText( b.addedBy.setText(

View File

@ -24,6 +24,7 @@ class EventListAdapter(
val showDate: Boolean = false, val showDate: Boolean = false,
val showColor: Boolean = true, val showColor: Boolean = true,
val showType: Boolean = true, val showType: Boolean = true,
val showTypeColor: Boolean = showType,
val showTime: Boolean = true, val showTime: Boolean = true,
val showSubject: Boolean = true, val showSubject: Boolean = true,
val markAsSeen: Boolean = true, val markAsSeen: Boolean = true,

View File

@ -19,7 +19,9 @@ import kotlinx.coroutines.withContext
import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode import org.greenrobot.eventbus.ThreadMode
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.config.AppData
import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask
import pl.szczodrzynski.edziennik.data.api.events.ApiTaskAllFinishedEvent import pl.szczodrzynski.edziennik.data.api.events.ApiTaskAllFinishedEvent
import pl.szczodrzynski.edziennik.data.api.events.ApiTaskErrorEvent import pl.szczodrzynski.edziennik.data.api.events.ApiTaskErrorEvent
@ -35,9 +37,11 @@ import pl.szczodrzynski.edziennik.data.db.full.EventFull
import pl.szczodrzynski.edziennik.data.db.full.LessonFull import pl.szczodrzynski.edziennik.data.db.full.LessonFull
import pl.szczodrzynski.edziennik.databinding.DialogEventManualV2Binding import pl.szczodrzynski.edziennik.databinding.DialogEventManualV2Binding
import pl.szczodrzynski.edziennik.ext.JsonObject import pl.szczodrzynski.edziennik.ext.JsonObject
import pl.szczodrzynski.edziennik.ext.appendView
import pl.szczodrzynski.edziennik.ext.getStudentData import pl.szczodrzynski.edziennik.ext.getStudentData
import pl.szczodrzynski.edziennik.ext.onChange import pl.szczodrzynski.edziennik.ext.onChange
import pl.szczodrzynski.edziennik.ext.onClick import pl.szczodrzynski.edziennik.ext.onClick
import pl.szczodrzynski.edziennik.ext.removeFromParent
import pl.szczodrzynski.edziennik.ext.setText import pl.szczodrzynski.edziennik.ext.setText
import pl.szczodrzynski.edziennik.ext.setTintColor import pl.szczodrzynski.edziennik.ext.setTintColor
import pl.szczodrzynski.edziennik.ui.dialogs.base.BindingDialog import pl.szczodrzynski.edziennik.ui.dialogs.base.BindingDialog
@ -117,6 +121,15 @@ class EventManualDialog(
} }
override suspend fun onShow() { override suspend fun onShow() {
val data = withContext(Dispatchers.IO) {
val profile = app.db.profileDao().getByIdSuspend(profileId) ?: return@withContext null
AppData.get(profile.loginStoreType)
}
if (data?.uiConfig?.eventManualShowSubjectDropdown == true) {
b.subjectDropdownLayout.removeFromParent()
b.timeDropdownLayout.appendView(b.subjectDropdownLayout)
}
b.showMore.onClick { // TODO iconics is broken b.showMore.onClick { // TODO iconics is broken
it.apply { it.apply {
refreshDrawableState() refreshDrawableState()

View File

@ -113,7 +113,7 @@ class EventViewHolder(
b.attachmentIcon.isVisible = item.hasAttachments b.attachmentIcon.isVisible = item.hasAttachments
b.typeColor.background?.setTintColor(item.eventColor) b.typeColor.background?.setTintColor(item.eventColor)
b.typeColor.isVisible = adapter.showType && adapter.showColor b.typeColor.isVisible = adapter.showTypeColor
b.editButton.isVisible = !adapter.simpleMode b.editButton.isVisible = !adapter.simpleMode
&& item.addedManually && item.addedManually

View File

@ -4,8 +4,10 @@
package pl.szczodrzynski.edziennik.ui.home package pl.szczodrzynski.edziennik.ui.home
import android.graphics.BitmapFactory
import android.os.Bundle import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import com.jetradarmobile.snowfall.SnowfallView
import com.mikepenz.iconics.IconicsDrawable import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.utils.colorInt import com.mikepenz.iconics.utils.colorInt
import com.mikepenz.iconics.utils.sizeDp import com.mikepenz.iconics.utils.sizeDp
@ -20,6 +22,7 @@ import pl.szczodrzynski.edziennik.ext.startCoroutineTimer
import pl.szczodrzynski.edziennik.ext.timeLeft import pl.szczodrzynski.edziennik.ext.timeLeft
import pl.szczodrzynski.edziennik.ext.timeTill import pl.szczodrzynski.edziennik.ext.timeTill
import pl.szczodrzynski.edziennik.ui.dialogs.BellSyncTimeChooseDialog import pl.szczodrzynski.edziennik.ui.dialogs.BellSyncTimeChooseDialog
import pl.szczodrzynski.edziennik.utils.BigNightUtil
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 kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
@ -61,6 +64,7 @@ class CounterActivity : AppCompatActivity(), CoroutineScope {
it.type != Lesson.TYPE_SHIFTED_SOURCE it.type != Lesson.TYPE_SHIFTED_SOURCE
}) })
} }
lessonList.onEach { it.filterNotes() }
} }
b.bellSync.setImageDrawable( b.bellSync.setImageDrawable(
@ -81,6 +85,27 @@ class CounterActivity : AppCompatActivity(), CoroutineScope {
counterJob = startCoroutineTimer(repeatMillis = 500) { counterJob = startCoroutineTimer(repeatMillis = 500) {
update() update()
} }
// IT'S WINTER MY DUDES
val today = Date.getToday()
if ((today.month / 3 % 4 == 0) && app.config.ui.snowfall) {
b.rootFrame.addView(layoutInflater.inflate(R.layout.snowfall, b.rootFrame, false))
} else if (app.config.ui.eggfall && BigNightUtil().isDataWielkanocyNearDzisiaj()) {
val eggfall = layoutInflater.inflate(
R.layout.eggfall,
b.rootFrame,
false
) as SnowfallView
eggfall.setSnowflakeBitmaps(listOf(
BitmapFactory.decodeResource(resources, R.drawable.egg1),
BitmapFactory.decodeResource(resources, R.drawable.egg2),
BitmapFactory.decodeResource(resources, R.drawable.egg3),
BitmapFactory.decodeResource(resources, R.drawable.egg4),
BitmapFactory.decodeResource(resources, R.drawable.egg5),
BitmapFactory.decodeResource(resources, R.drawable.egg6)
))
b.rootFrame.addView(eggfall)
}
}} }}
private fun update() { private fun update() {
@ -101,13 +126,15 @@ class CounterActivity : AppCompatActivity(), CoroutineScope {
when { when {
actual != null -> { actual != null -> {
b.lessonName.text = actual.displaySubjectName b.lessonName.text = actual.getNoteSubstituteText(showNotes = true)
?: actual.displaySubjectName
val left = actual.displayEndTime!! - now val left = actual.displayEndTime!! - now
b.timeLeft.text = timeLeft(left.toInt(), "\n", countInSeconds) b.timeLeft.text = timeLeft(left.toInt(), "\n", countInSeconds)
} }
next != null -> { next != null -> {
b.lessonName.text = next.displaySubjectName b.lessonName.text = next.getNoteSubstituteText(showNotes = true)
?: next.displaySubjectName
val till = next.displayStartTime!! - now val till = next.displayStartTime!! - now
b.timeLeft.text = timeTill(till.toInt(), "\n", countInSeconds) b.timeLeft.text = timeTill(till.toInt(), "\n", countInSeconds)

View File

@ -63,9 +63,10 @@ class HomeEventsCard(
simpleMode = true, simpleMode = true,
showWeekDay = true, showWeekDay = true,
showDate = true, showDate = true,
showType = true, showType = !profile.config.ui.agendaSubjectImportant,
showTypeColor = true,
showTime = false, showTime = false,
showSubject = false, showSubject = profile.config.ui.agendaSubjectImportant,
markAsSeen = false, markAsSeen = false,
onEventClick = { onEventClick = {
EventDetailsDialog( EventDetailsDialog(

View File

@ -232,6 +232,7 @@ class HomeTimetableCard(
} }
lessons = lessons.filter { it.type != Lesson.TYPE_NO_LESSONS } lessons = lessons.filter { it.type != Lesson.TYPE_NO_LESSONS }
lessons.onEach { it.filterNotes() }
b.timetableLayout.visibility = View.VISIBLE b.timetableLayout.visibility = View.VISIBLE
b.noTimetableLayout.visibility = View.GONE b.noTimetableLayout.visibility = View.GONE
@ -344,6 +345,7 @@ class HomeTimetableCard(
private val LessonFull?.subjectSpannable: CharSequence private val LessonFull?.subjectSpannable: CharSequence
get() = if (this == null) "?" else when { get() = if (this == null) "?" else when {
hasReplacingNotes() -> getNoteSubstituteText(showNotes = true) ?: "?"
isCancelled -> displaySubjectName?.asStrikethroughSpannable() ?: "?" isCancelled -> displaySubjectName?.asStrikethroughSpannable() ?: "?"
isChange -> displaySubjectName?.asItalicSpannable() ?: "?" isChange -> displaySubjectName?.asItalicSpannable() ?: "?"
else -> displaySubjectName ?: "?" else -> displaySubjectName ?: "?"

View File

@ -33,13 +33,8 @@ class EventTypeDropdown : TextInputDropDown {
suspend fun loadItems() { suspend fun loadItems() {
val types = withContext(Dispatchers.Default) { val types = withContext(Dispatchers.Default) {
val list = mutableListOf<Item>() val list = mutableListOf<Item>()
val types = db.eventTypeDao().getAllNow(profileId)
var types = db.eventTypeDao().getAllNow(profileId) .sortedBy { it.order }
if (types.none { it.id in -1L..10L }) {
val profile = db.profileDao().getByIdNow(profileId) ?: return@withContext listOf()
types = db.eventTypeDao().addDefaultTypes(profile)
}
list += types.map { list += types.map {
Item(it.id, it.name, tag = it, icon = IconicsDrawable(context).apply { Item(it.id, it.name, tag = it, icon = IconicsDrawable(context).apply {

View File

@ -337,8 +337,11 @@ class WidgetTimetableProvider : AppWidgetProvider() {
scrollPos = pos + 1 scrollPos = pos + 1
} }
// remove notes from other profiles
lesson.filterNotes()
// set the subject and classroom name // set the subject and classroom name
model.subjectName = lesson.displaySubjectName model.subjectName = lesson.getNoteSubstituteText(showNotes = true)
?: lesson.displaySubjectName
model.classroomName = lesson.displayClassroom model.classroomName = lesson.displayClassroom
// set the bell sync to calculate progress in ListProvider // set the bell sync to calculate progress in ListProvider

View File

@ -48,6 +48,7 @@ class EventManager(val app: App) : CoroutineScope {
title: TextView, title: TextView,
event: EventFull, event: EventFull,
showType: Boolean = true, showType: Boolean = true,
showSubject: Boolean = false,
showNotes: Boolean = true, showNotes: Boolean = true,
doneIconColor: Int? = null doneIconColor: Int? = null
) { ) {
@ -60,6 +61,7 @@ class EventManager(val app: App) : CoroutineScope {
if (event.hasNotes() && hasReplacingNotes && showNotes) "{cmd-swap-horizontal} " else null, if (event.hasNotes() && hasReplacingNotes && showNotes) "{cmd-swap-horizontal} " else null,
if (event.hasNotes() && !hasReplacingNotes && showNotes) "{cmd-playlist-edit} " else null, if (event.hasNotes() && !hasReplacingNotes && showNotes) "{cmd-playlist-edit} " else null,
if (showType) "${event.typeName ?: "wydarzenie"} - " else null, if (showType) "${event.typeName ?: "wydarzenie"} - " else null,
if (showSubject) event.subjectLongName?.plus(" - ") else null,
topicSpan, topicSpan,
).concat() ).concat()

View File

@ -171,7 +171,7 @@ class NoteManager(private val app: App) {
activity = activity, activity = activity,
simpleMode = true, simpleMode = true,
showDate = true, showDate = true,
showColor = false, showTypeColor = false,
showTime = false, showTime = false,
markAsSeen = false, markAsSeen = false,
showNotes = false, showNotes = false,

View File

@ -19,7 +19,7 @@ public class ItemWidgetTimetableModel {
public Time endTime; public Time endTime;
public boolean lessonPassed; public boolean lessonPassed;
public boolean lessonCurrent; public boolean lessonCurrent;
public String subjectName = ""; public CharSequence subjectName = "";
public String classroomName = ""; public String classroomName = "";
public boolean lessonChange = false; public boolean lessonChange = false;
public boolean lessonChangeNoClassroom = false; public boolean lessonChangeNoClassroom = false;

View File

@ -1,6 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<layout xmlns:tools="http://schemas.android.com/tools" <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android"> xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/rootFrame"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
@ -50,4 +53,4 @@
android:textSize="48sp" android:textSize="48sp"
tools:text="Zostało 2341 sekund" /> tools:text="Zostało 2341 sekund" />
</LinearLayout> </LinearLayout>
</layout> </FrameLayout>

View File

@ -50,6 +50,14 @@
android:minHeight="32dp" android:minHeight="32dp"
android:text="@string/agenda_config_teacher_absence" /> android:text="@string/agenda_config_teacher_absence" />
<com.google.android.material.checkbox.MaterialCheckBox
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:checked="@={config.ui.agendaSubjectImportant}"
android:minHeight="32dp"
android:text="@string/agenda_config_subject_important" />
<com.google.android.material.checkbox.MaterialCheckBox <com.google.android.material.checkbox.MaterialCheckBox
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View File

@ -17,6 +17,7 @@
type="pl.szczodrzynski.edziennik.data.db.full.EventFull" /> type="pl.szczodrzynski.edziennik.data.db.full.EventFull" />
<variable name="eventShared" type="boolean" /> <variable name="eventShared" type="boolean" />
<variable name="eventOwn" type="boolean" /> <variable name="eventOwn" type="boolean" />
<variable name="name" type="java.lang.CharSequence" />
<variable name="details" type="java.lang.CharSequence" /> <variable name="details" type="java.lang.CharSequence" />
<variable name="monthName" type="String" /> <variable name="monthName" type="String" />
</data> </data>
@ -55,7 +56,7 @@
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@{event.typeName}" android:text="@{name}"
android:textIsSelectable="true" android:textIsSelectable="true"
android:textAppearance="@style/NavView.TextView.Title" android:textAppearance="@style/NavView.TextView.Title"
android:visibility="@{event.typeName == null ? View.GONE : View.VISIBLE}" android:visibility="@{event.typeName == null ? View.GONE : View.VISIBLE}"

View File

@ -13,6 +13,7 @@
android:layout_height="match_parent"> android:layout_height="match_parent">
<LinearLayout <LinearLayout
android:id="@+id/mainLayout"
android:orientation="vertical" android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -34,6 +35,7 @@
</com.google.android.material.textfield.TextInputLayout> </com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout <com.google.android.material.textfield.TextInputLayout
android:id="@+id/timeDropdownLayout"
style="@style/Widget.MaterialComponents.TextInputLayout.FilledBox.Dense" style="@style/Widget.MaterialComponents.TextInputLayout.FilledBox.Dense"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -163,6 +165,7 @@
tools:visibility="visible"> tools:visibility="visible">
<com.google.android.material.textfield.TextInputLayout <com.google.android.material.textfield.TextInputLayout
android:id="@+id/subjectDropdownLayout"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense" style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View File

@ -100,6 +100,13 @@
android:text="Remove all homework body (null)" android:text="Remove all homework body (null)"
android:textAllCaps="false" /> android:textAllCaps="false" />
<Button
android:id="@+id/resetEventTypes"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Reset event types"
android:textAllCaps="false" />
<TextView <TextView
android:id="@+id/cookies" android:id="@+id/cookies"
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -12,7 +12,8 @@
"uiConfig": { "uiConfig": {
"lessonHeight": 60, "lessonHeight": 60,
"enableMarkAsReadAnnouncements": true, "enableMarkAsReadAnnouncements": true,
"enableNoticePoints": false "enableNoticePoints": false,
"eventManualShowSubjectDropdown": false
}, },
"eventTypes": [ "eventTypes": [
{ {
@ -83,43 +84,40 @@
}, },
"university": { "university": {
"configOverrides": { "configOverrides": {
"agendaSubjectImportant": true,
"shareByDefault": true, "shareByDefault": true,
"timetableColorSubjectName": true, "timetableColorSubjectName": true,
"timetableTrimHourRange": true "timetableTrimHourRange": true
}, },
"uiConfig": { "uiConfig": {
"lessonHeight": 45 "lessonHeight": 45,
"eventManualShowSubjectDropdown": true
}, },
"eventTypes": [ "eventTypes": [
{ {
"id": 1, "id": 3,
"color": "#f44336", "color": "#76ff03",
"name": "egzamin" "name": "kartkówka"
}, },
{ {
"id": 2, "id": 2,
"color": "#e91e63", "color": "#e91e63",
"name": "kolokwium" "name": "kolokwium"
}, },
{
"id": 3,
"color": "#76ff03",
"name": "kartkówka"
},
{
"id": 4,
"color": "#ffeb3b",
"name": "wejściówka"
},
{ {
"id": 5, "id": 5,
"color": "#90caf9", "color": "#90caf9",
"name": "zaliczenie" "name": "zaliczenie"
}, },
{ {
"id": 6, "id": 1,
"color": "#4050b5", "color": "#f44336",
"name": "zadanie" "name": "egzamin"
},
{
"id": 11,
"color": "#3d5afe",
"name": "poprawka"
}, },
{ {
"id": 7, "id": 7,

View File

@ -1551,4 +1551,5 @@
<string name="settings_register_share_by_default_subtext">Ustaw tworzone wydarzenia domyślnie jako udostępnione</string> <string name="settings_register_share_by_default_subtext">Ustaw tworzone wydarzenia domyślnie jako udostępnione</string>
<string name="settings_registration_section">Rejestracja</string> <string name="settings_registration_section">Rejestracja</string>
<string name="home_timetable_all_lessons">Wszystkie lekcje:</string> <string name="home_timetable_all_lessons">Wszystkie lekcje:</string>
<string name="agenda_config_subject_important">Wyświetl nazwę przedmiotu zamiast rodzaju</string>
</resources> </resources>

View File

@ -5,8 +5,8 @@ buildscript {
kotlin_version = '1.6.10' kotlin_version = '1.6.10'
release = [ release = [
versionName: "4.13.2", versionName: "4.13.4",
versionCode: 4130299 versionCode: 4130499
] ]
setup = [ setup = [