Use dependency injection for most singletons

This commit is contained in:
MM20
2021-10-10 12:15:54 +02:00
parent 023bb2cbb1
commit 087d4fd455
144 changed files with 1789 additions and 1277 deletions
+2
View File
@@ -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