Use dependency injection for most singletons
This commit is contained in:
@@ -42,6 +42,8 @@ dependencies {
|
||||
|
||||
implementation(libs.textdrawable)
|
||||
|
||||
implementation(libs.koin.android)
|
||||
|
||||
api(project(":search"))
|
||||
implementation(project(":preferences"))
|
||||
implementation(project(":ktx"))
|
||||
|
||||
@@ -10,13 +10,16 @@ import de.mm20.launcher2.search.data.CalendarEvent
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class CalendarRepository private constructor(val context: Context) : BaseSearchableRepository() {
|
||||
class CalendarRepository(
|
||||
val context: Context,
|
||||
hiddenItemsRepository: HiddenItemsRepository
|
||||
) : BaseSearchableRepository() {
|
||||
|
||||
val calendarEvents = MediatorLiveData<List<CalendarEvent>?>()
|
||||
val upcomingCalendarEvents = MutableLiveData<List<CalendarEvent>>(emptyList())
|
||||
|
||||
private val allEvents = MutableLiveData<List<CalendarEvent>?>(emptyList())
|
||||
private val hiddenItemKeys = HiddenItemsRepository.getInstance(context).hiddenItemsKeys
|
||||
private val hiddenItemKeys = hiddenItemsRepository.hiddenItemsKeys
|
||||
|
||||
init {
|
||||
calendarEvents.addSource(hiddenItemKeys) { keys ->
|
||||
@@ -40,17 +43,17 @@ class CalendarRepository private constructor(val context: Context) : BaseSearcha
|
||||
val end = now + 14 * 24 * 60 * 60 * 1000L
|
||||
val events = withContext(Dispatchers.IO) {
|
||||
CalendarEvent.search(
|
||||
context = context,
|
||||
query = "",
|
||||
intervalStart = now,
|
||||
intervalEnd = end,
|
||||
limit = 700,
|
||||
hideAllDayEvents = hideAlldayEvents,
|
||||
unselectedCalendars = unselectedCalendars,
|
||||
hiddenEvents = hiddenItemKeys.value?.mapNotNull {
|
||||
if (it.startsWith("calendar")) it.substringAfterLast("/").toLong()
|
||||
else null
|
||||
} ?: emptyList()
|
||||
context = context,
|
||||
query = "",
|
||||
intervalStart = now,
|
||||
intervalEnd = end,
|
||||
limit = 700,
|
||||
hideAllDayEvents = hideAlldayEvents,
|
||||
unselectedCalendars = unselectedCalendars,
|
||||
hiddenEvents = hiddenItemKeys.value?.mapNotNull {
|
||||
if (it.startsWith("calendar")) it.substringAfterLast("/").toLong()
|
||||
else null
|
||||
} ?: emptyList()
|
||||
)
|
||||
}
|
||||
upcomingCalendarEvents.value = events
|
||||
@@ -69,13 +72,4 @@ class CalendarRepository private constructor(val context: Context) : BaseSearcha
|
||||
}
|
||||
allEvents.value = events
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
private lateinit var instance: CalendarRepository
|
||||
fun getInstance(context: Context): CalendarRepository {
|
||||
if (!::instance.isInitialized) instance = CalendarRepository(context.applicationContext)
|
||||
return instance
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package de.mm20.launcher2.calendar
|
||||
|
||||
import android.Manifest
|
||||
import android.content.ContentUris
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.provider.CalendarContract
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.database.getStringOrNull
|
||||
import de.mm20.launcher2.search.SearchableDeserializer
|
||||
import de.mm20.launcher2.search.SearchableSerializer
|
||||
import de.mm20.launcher2.search.data.CalendarEvent
|
||||
import de.mm20.launcher2.search.data.Searchable
|
||||
import org.json.JSONObject
|
||||
import java.util.*
|
||||
|
||||
class CalendarEventSerializer: SearchableSerializer {
|
||||
override fun serialize(searchable: Searchable): String {
|
||||
searchable as CalendarEvent
|
||||
val json = JSONObject()
|
||||
json.put("id", searchable.id)
|
||||
return json.toString()
|
||||
}
|
||||
|
||||
override val typePrefix: String
|
||||
get() = "calendar"
|
||||
}
|
||||
|
||||
class CalendarEventDeserializer(val context: Context): SearchableDeserializer {
|
||||
override fun deserialize(serialized: String): Searchable? {
|
||||
if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_CALENDAR) != PackageManager.PERMISSION_GRANTED) return null
|
||||
val json = JSONObject(serialized)
|
||||
val id = json.getLong("id")
|
||||
val builder = CalendarContract.Instances.CONTENT_URI.buildUpon()
|
||||
ContentUris.appendId(builder, System.currentTimeMillis())
|
||||
ContentUris.appendId(builder, System.currentTimeMillis() + 63072000000L)
|
||||
val uri = builder.build()
|
||||
val projection = arrayOf(
|
||||
CalendarContract.Instances.EVENT_ID,
|
||||
CalendarContract.Instances.TITLE,
|
||||
CalendarContract.Instances.BEGIN,
|
||||
CalendarContract.Instances.END,
|
||||
CalendarContract.Instances.ALL_DAY,
|
||||
CalendarContract.Instances.DISPLAY_COLOR,
|
||||
CalendarContract.Instances.EVENT_LOCATION,
|
||||
CalendarContract.Instances.CALENDAR_ID,
|
||||
CalendarContract.Instances.DESCRIPTION
|
||||
)
|
||||
val selection = CalendarContract.Instances.EVENT_ID + " = ?"
|
||||
val selArgs = arrayOf(id.toString())
|
||||
val cursor = context.contentResolver.query(uri, projection, selection, selArgs, null)
|
||||
?: return null
|
||||
if (cursor.moveToNext()) {
|
||||
val title = cursor.getString(1)
|
||||
val begin = cursor.getLong(2)
|
||||
val end = cursor.getLong(3)
|
||||
val allday = cursor.getInt(4) != 0
|
||||
val color = cursor.getInt(5)
|
||||
val location = cursor.getString(6)
|
||||
val calendar = cursor.getLong(7)
|
||||
val description = cursor.getStringOrNull(8)
|
||||
?: ""
|
||||
cursor.close()
|
||||
val proj = arrayOf(
|
||||
CalendarContract.Attendees.EVENT_ID,
|
||||
CalendarContract.Attendees.ATTENDEE_NAME,
|
||||
CalendarContract.Attendees.ATTENDEE_EMAIL
|
||||
)
|
||||
val sel = "${CalendarContract.Attendees.EVENT_ID} = $id"
|
||||
val s = "${CalendarContract.Attendees.ATTENDEE_NAME} COLLATE NOCASE ASC"
|
||||
val cur = context.contentResolver.query(
|
||||
CalendarContract.Attendees.CONTENT_URI,
|
||||
proj, sel, null, s
|
||||
) ?: return null
|
||||
val attendees = mutableListOf<String>()
|
||||
while (cur.moveToNext()) {
|
||||
attendees.add(cur.getString(1).takeUnless { it.isNullOrBlank() }
|
||||
?: cur.getString(2))
|
||||
}
|
||||
cur.close()
|
||||
val tzOffset = if (allday) {
|
||||
Calendar.getInstance().timeZone.getOffset(begin)
|
||||
} else {
|
||||
0
|
||||
}
|
||||
return CalendarEvent(
|
||||
label = title,
|
||||
id = id,
|
||||
color = color,
|
||||
startTime = begin - tzOffset,
|
||||
endTime = end - tzOffset - if (allday) 1 else 0,
|
||||
allDay = allday,
|
||||
location = location ?: "",
|
||||
attendees = attendees,
|
||||
description = description,
|
||||
calendar = calendar
|
||||
)
|
||||
}
|
||||
cursor.close()
|
||||
return null
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
package de.mm20.launcher2.calendar
|
||||
|
||||
import android.app.Application
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import de.mm20.launcher2.search.data.CalendarEvent
|
||||
|
||||
class CalendarViewModel(app:Application): AndroidViewModel(app) {
|
||||
val calendarEvents: LiveData<List<CalendarEvent>?> = CalendarRepository.getInstance(app).calendarEvents
|
||||
val upcomingCalendarEvents: LiveData<List<CalendarEvent>> = CalendarRepository.getInstance(app).upcomingCalendarEvents
|
||||
class CalendarViewModel(
|
||||
calendarRepository: CalendarRepository
|
||||
): ViewModel() {
|
||||
val calendarEvents: LiveData<List<CalendarEvent>?> = calendarRepository.calendarEvents
|
||||
val upcomingCalendarEvents: LiveData<List<CalendarEvent>> = calendarRepository.upcomingCalendarEvents
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package de.mm20.launcher2.calendar
|
||||
|
||||
import org.koin.android.ext.koin.androidContext
|
||||
import org.koin.androidx.viewmodel.dsl.viewModel
|
||||
import org.koin.dsl.module
|
||||
|
||||
val calendarModule = module {
|
||||
single { CalendarRepository(androidContext(), get()) }
|
||||
viewModel { CalendarViewModel(get()) }
|
||||
}
|
||||
@@ -41,12 +41,6 @@ class CalendarEvent(
|
||||
val calendar: Long
|
||||
) : Searchable() {
|
||||
|
||||
override fun serialize(): String {
|
||||
val json = JSONObject()
|
||||
json.put("id", id)
|
||||
return json.toString()
|
||||
}
|
||||
|
||||
override val key: String
|
||||
get() = "calendar://$id"
|
||||
|
||||
@@ -175,79 +169,6 @@ class CalendarEvent(
|
||||
return results
|
||||
}
|
||||
|
||||
fun deserialize(context: Context, serialized: String): CalendarEvent? {
|
||||
if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_CALENDAR) != PackageManager.PERMISSION_GRANTED) return null
|
||||
val json = JSONObject(serialized)
|
||||
val id = json.getLong("id")
|
||||
val builder = CalendarContract.Instances.CONTENT_URI.buildUpon()
|
||||
ContentUris.appendId(builder, System.currentTimeMillis())
|
||||
ContentUris.appendId(builder, System.currentTimeMillis() + 63072000000L)
|
||||
val uri = builder.build()
|
||||
val projection = arrayOf(
|
||||
CalendarContract.Instances.EVENT_ID,
|
||||
CalendarContract.Instances.TITLE,
|
||||
CalendarContract.Instances.BEGIN,
|
||||
CalendarContract.Instances.END,
|
||||
CalendarContract.Instances.ALL_DAY,
|
||||
CalendarContract.Instances.DISPLAY_COLOR,
|
||||
CalendarContract.Instances.EVENT_LOCATION,
|
||||
CalendarContract.Instances.CALENDAR_ID,
|
||||
CalendarContract.Instances.DESCRIPTION
|
||||
)
|
||||
val selection = CalendarContract.Instances.EVENT_ID + " = ?"
|
||||
val selArgs = arrayOf(id.toString())
|
||||
val cursor = context.contentResolver.query(uri, projection, selection, selArgs, null)
|
||||
?: return null
|
||||
if (cursor.moveToNext()) {
|
||||
val title = cursor.getString(1)
|
||||
val begin = cursor.getLong(2)
|
||||
val end = cursor.getLong(3)
|
||||
val allday = cursor.getInt(4) != 0
|
||||
val color = cursor.getInt(5)
|
||||
val location = cursor.getString(6)
|
||||
val calendar = cursor.getLong(7)
|
||||
val description = cursor.getStringOrNull(8)
|
||||
?: ""
|
||||
cursor.close()
|
||||
val proj = arrayOf(
|
||||
CalendarContract.Attendees.EVENT_ID,
|
||||
CalendarContract.Attendees.ATTENDEE_NAME,
|
||||
CalendarContract.Attendees.ATTENDEE_EMAIL
|
||||
)
|
||||
val sel = "${CalendarContract.Attendees.EVENT_ID} = $id"
|
||||
val s = "${CalendarContract.Attendees.ATTENDEE_NAME} COLLATE NOCASE ASC"
|
||||
val cur = context.contentResolver.query(
|
||||
CalendarContract.Attendees.CONTENT_URI,
|
||||
proj, sel, null, s
|
||||
) ?: return null
|
||||
val attendees = mutableListOf<String>()
|
||||
while (cur.moveToNext()) {
|
||||
attendees.add(cur.getString(1).takeUnless { it.isNullOrBlank() }
|
||||
?: cur.getString(2))
|
||||
}
|
||||
cur.close()
|
||||
val tzOffset = if (allday) {
|
||||
Calendar.getInstance().timeZone.getOffset(begin)
|
||||
} else {
|
||||
0
|
||||
}
|
||||
return CalendarEvent(
|
||||
label = title,
|
||||
id = id,
|
||||
color = color,
|
||||
startTime = begin - tzOffset,
|
||||
endTime = end - tzOffset - if (allday) 1 else 0,
|
||||
allDay = allday,
|
||||
location = location ?: "",
|
||||
attendees = attendees,
|
||||
description = description,
|
||||
calendar = calendar
|
||||
)
|
||||
}
|
||||
cursor.close()
|
||||
return null
|
||||
}
|
||||
|
||||
fun getCalendars(context: Context): List<UserCalendar> {
|
||||
val calendars = mutableListOf<UserCalendar>()
|
||||
val uri = CalendarContract.Calendars.CONTENT_URI
|
||||
|
||||
Reference in New Issue
Block a user