Annual refactor
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
package de.mm20.launcher2.search
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import androidx.core.content.ContextCompat
|
||||
import de.mm20.launcher2.base.R
|
||||
import de.mm20.launcher2.icons.ColorLayer
|
||||
import de.mm20.launcher2.icons.StaticLauncherIcon
|
||||
import de.mm20.launcher2.icons.TintedIconLayer
|
||||
|
||||
interface AppShortcut : SavableSearchable {
|
||||
|
||||
val appName: String?
|
||||
val componentName: ComponentName?
|
||||
val packageName: String?
|
||||
|
||||
override val preferDetailsOverLaunch: Boolean
|
||||
get() = false
|
||||
|
||||
override fun getPlaceholderIcon(context: Context): StaticLauncherIcon {
|
||||
return StaticLauncherIcon(
|
||||
foregroundLayer = TintedIconLayer(
|
||||
color = 0xFF3DDA84.toInt(),
|
||||
icon = ContextCompat.getDrawable(context, R.drawable.ic_file_android)!!,
|
||||
scale = 0.65f,
|
||||
),
|
||||
backgroundLayer = ColorLayer(0xFF3DDA84.toInt()),
|
||||
)
|
||||
}
|
||||
|
||||
val canDelete: Boolean
|
||||
get() = false
|
||||
|
||||
suspend fun delete(context: Context) {}
|
||||
|
||||
val isUnavailable: Boolean
|
||||
get() = false
|
||||
|
||||
val profile: AppProfile
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package de.mm20.launcher2.search
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.UserHandle
|
||||
import androidx.core.content.ContextCompat
|
||||
import de.mm20.launcher2.base.R
|
||||
import de.mm20.launcher2.icons.ColorLayer
|
||||
import de.mm20.launcher2.icons.StaticLauncherIcon
|
||||
import de.mm20.launcher2.icons.TintedIconLayer
|
||||
|
||||
enum class AppProfile {
|
||||
Personal,
|
||||
Work,
|
||||
}
|
||||
|
||||
interface Application: SavableSearchable {
|
||||
override val preferDetailsOverLaunch: Boolean
|
||||
get() = false
|
||||
|
||||
val componentName: ComponentName
|
||||
val isSystemApp: Boolean
|
||||
val isSuspended: Boolean
|
||||
val profile: AppProfile
|
||||
val user: UserHandle
|
||||
val versionName: String?
|
||||
|
||||
override fun getPlaceholderIcon(context: Context): StaticLauncherIcon {
|
||||
return StaticLauncherIcon(
|
||||
foregroundLayer = TintedIconLayer(
|
||||
icon = ContextCompat.getDrawable(context, R.drawable.ic_file_android)!!,
|
||||
scale = 0.65f,
|
||||
color = 0xff3dda84.toInt(),
|
||||
),
|
||||
backgroundLayer = ColorLayer(0xff3dda84.toInt())
|
||||
)
|
||||
}
|
||||
|
||||
val canUninstall: Boolean
|
||||
fun uninstall(context: Context)
|
||||
fun openAppDetails(context: Context)
|
||||
|
||||
val canShareApk: Boolean
|
||||
suspend fun shareApkFile(context: Context) {}
|
||||
|
||||
fun getStoreDetails(context: Context): StoreLink? = null
|
||||
|
||||
fun getActivityInfo(context: Context): ActivityInfo? {
|
||||
return try {
|
||||
context.packageManager.getActivityInfo(componentName, 0)
|
||||
} catch (e: PackageManager.NameNotFoundException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class StoreLink(
|
||||
val label: String,
|
||||
val url: String
|
||||
)
|
||||
@@ -0,0 +1,17 @@
|
||||
package de.mm20.launcher2.search
|
||||
|
||||
import android.content.Context
|
||||
|
||||
interface Article: SavableSearchable {
|
||||
|
||||
val text: String
|
||||
val imageUrl: String?
|
||||
val sourceUrl: String
|
||||
val sourceName: String
|
||||
|
||||
val canShare: Boolean
|
||||
fun share(context: Context) {}
|
||||
|
||||
override val preferDetailsOverLaunch: Boolean
|
||||
get() = false
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package de.mm20.launcher2.search
|
||||
|
||||
import android.content.Context
|
||||
import de.mm20.launcher2.icons.ColorLayer
|
||||
import de.mm20.launcher2.icons.StaticLauncherIcon
|
||||
import de.mm20.launcher2.icons.TextLayer
|
||||
import java.text.SimpleDateFormat
|
||||
|
||||
interface CalendarEvent: SavableSearchable {
|
||||
val color: Int?
|
||||
val startTime: Long
|
||||
val endTime: Long
|
||||
val allDay: Boolean
|
||||
val description: String?
|
||||
val location: String?
|
||||
val attendees: List<String>
|
||||
|
||||
|
||||
override val preferDetailsOverLaunch: Boolean
|
||||
get() = true
|
||||
|
||||
|
||||
override fun getPlaceholderIcon(context: Context): StaticLauncherIcon {
|
||||
val df = SimpleDateFormat("dd")
|
||||
return StaticLauncherIcon(
|
||||
foregroundLayer = TextLayer(
|
||||
text = df.format(startTime),
|
||||
color = color ?: 0,
|
||||
),
|
||||
backgroundLayer = ColorLayer(color ?: 0)
|
||||
)
|
||||
}
|
||||
|
||||
fun openLocation(context: Context) {}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package de.mm20.launcher2.search
|
||||
|
||||
import android.content.Intent
|
||||
|
||||
interface Contact: SavableSearchable {
|
||||
val firstName: String
|
||||
val lastName: String
|
||||
val displayName: String
|
||||
val summary: String
|
||||
val contactInfos: Iterable<ContactInfo>
|
||||
|
||||
override val preferDetailsOverLaunch: Boolean
|
||||
get() = true
|
||||
}
|
||||
|
||||
/**
|
||||
* Type of the contact info
|
||||
* Acts as a hint for the UI, so that it can display the correct icon and group them accordingly
|
||||
*/
|
||||
enum class ContactInfoType {
|
||||
Phone,
|
||||
Message,
|
||||
Email,
|
||||
Postal,
|
||||
Telegram,
|
||||
Whatsapp,
|
||||
Signal,
|
||||
Other
|
||||
}
|
||||
|
||||
interface ContactInfo {
|
||||
val type: ContactInfoType
|
||||
val label: String
|
||||
val intent: Intent
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
package de.mm20.launcher2.search
|
||||
|
||||
import android.content.Context
|
||||
import androidx.core.content.ContextCompat
|
||||
import de.mm20.launcher2.base.R
|
||||
import de.mm20.launcher2.icons.ColorLayer
|
||||
import de.mm20.launcher2.icons.StaticLauncherIcon
|
||||
import de.mm20.launcher2.icons.TintedIconLayer
|
||||
import java.util.Locale
|
||||
|
||||
interface File : SavableSearchable {
|
||||
val path: String
|
||||
val mimeType: String
|
||||
val size: Long
|
||||
val isDirectory: Boolean
|
||||
val metaData: List<Pair<Int, String>>
|
||||
|
||||
val isStoredInCloud: Boolean
|
||||
|
||||
override val preferDetailsOverLaunch: Boolean
|
||||
get() = false
|
||||
|
||||
val providerIconRes: Int?
|
||||
get() = null
|
||||
|
||||
override fun getPlaceholderIcon(context: Context): StaticLauncherIcon {
|
||||
val (resId, bgColor) = when {
|
||||
isDirectory -> R.drawable.ic_file_folder to R.color.lightblue
|
||||
mimeType.startsWith("image/") -> R.drawable.ic_file_picture to R.color.teal
|
||||
mimeType.startsWith("audio/") -> R.drawable.ic_file_music to R.color.orange
|
||||
mimeType.startsWith("video/") -> R.drawable.ic_file_video to R.color.purple
|
||||
else -> when (mimeType) {
|
||||
"application/zip", "application/x-gtar", "application/x-tar",
|
||||
"application/java-archive", "application/x-7z-compressed",
|
||||
"application/x-compressed-tar", "application/x-gzip", "application/x-bzip2" -> R.drawable.ic_file_archive to R.color.brown
|
||||
"application/pdf" -> R.drawable.ic_file_pdf to R.color.red
|
||||
"application/vnd.oasis.opendocument.text",
|
||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||
"application/msword", "text/plain", "application/vnd.google-apps.document" -> R.drawable.ic_file_document to R.color.blue
|
||||
"application/vnd.oasis.opendocument.spreadsheet",
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
"application/vnd.ms-excel", "application/vnd.google-apps.spreadsheet" -> R.drawable.ic_file_spreadsheet to R.color.green
|
||||
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
||||
"application/vnd.ms-powerpoint", "application/vnd.google-apps.presentation" -> R.drawable.ic_file_presentation to R.color.amber
|
||||
"text/x-asm", "text/x-c", "text/x-java-source", "text/x-script.phyton", "text/x-pascal",
|
||||
"text/x-script.perl", "text/javascript", "application/json" -> R.drawable.ic_file_code to R.color.pink
|
||||
"text/xml", "text/html" -> R.drawable.ic_file_markup to R.color.deeporange
|
||||
"application/vnd.android.package-archive" -> R.drawable.ic_file_android to R.color.lightgreen
|
||||
"application/vnd.google-apps.form" -> R.drawable.ic_file_form to R.color.deeppurple
|
||||
"application/vnd.google-apps.drawing" -> R.drawable.ic_file_picture to R.color.teal
|
||||
"application/vnd.de.mm20.launcher2.backup" -> R.drawable.ic_file_backup to R.color.brown
|
||||
"application/vnd.de.mm20.launcher2.theme" -> R.drawable.ic_file_theme to R.color.amber
|
||||
else -> R.drawable.ic_file_generic to R.color.bluegrey
|
||||
}
|
||||
}
|
||||
return StaticLauncherIcon(
|
||||
foregroundLayer = TintedIconLayer(
|
||||
icon = ContextCompat.getDrawable(context, resId)!!,
|
||||
scale = 0.5f,
|
||||
color = ContextCompat.getColor(context, bgColor)
|
||||
),
|
||||
backgroundLayer = ColorLayer(ContextCompat.getColor(context, bgColor))
|
||||
)
|
||||
}
|
||||
|
||||
fun getFileType(context: Context): String {
|
||||
if (isDirectory) return context.getString(R.string.file_type_directory)
|
||||
if (mimeType == "application/vnd.de.mm20.launcher2.backup") {
|
||||
return context.getString(
|
||||
R.string.file_type_launcherbackup,
|
||||
context.getString(R.string.app_name)
|
||||
)
|
||||
}
|
||||
if (mimeType == "application/vnd.de.mm20.launcher2.theme") {
|
||||
return context.getString(
|
||||
R.string.file_type_launchertheme,
|
||||
context.getString(R.string.app_name)
|
||||
)
|
||||
}
|
||||
val resource = when (mimeType) {
|
||||
"application/zip",
|
||||
"application/x-zip-compressed",
|
||||
"application/x-gtar",
|
||||
"application/x-tar",
|
||||
"application/java-archive",
|
||||
"application/x-7z-compressed" -> R.string.file_type_archive
|
||||
"application/x-gzip",
|
||||
"application/x-bzip2" -> R.string.file_type_compressed
|
||||
"application/vnd.android.package-archive" -> R.string.file_type_android
|
||||
"text/x-asm",
|
||||
"text/x-c",
|
||||
"text/x-java-source",
|
||||
"text/x-script.phyton",
|
||||
"text/x-pascal",
|
||||
"text/x-script.perl",
|
||||
"text/javascript",
|
||||
"application/json" -> R.string.file_type_source_code
|
||||
"application/vnd.oasis.opendocument.text",
|
||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||
"application/msword",
|
||||
"application/x-iwork-pages-sffpages",
|
||||
"application/vnd.apple.pages",
|
||||
"application/vnd.google-apps.document" -> R.string.file_type_document
|
||||
"application/vnd.oasis.opendocument.spreadsheet",
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
"application/vnd.ms-excel",
|
||||
"application/x-iwork-numbers-sffnumbers",
|
||||
"application/vnd.apple.numbers",
|
||||
"application/vnd.google-apps.spreadsheet" -> R.string.file_type_spreadsheet
|
||||
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
||||
"application/vnd.ms-powerpoint",
|
||||
"application/x-iwork-keynote-sffkey",
|
||||
"application/vnd.apple.keynote",
|
||||
"application/vnd.google-apps.presentation" -> R.string.file_type_presentation
|
||||
"text/plain" -> R.string.file_type_text
|
||||
"application/vnd.google-apps.drawing" -> R.string.file_type_drawing
|
||||
"application/vnd.google-apps.form" -> R.string.file_type_form
|
||||
"application/epub+zip" -> R.string.file_type_ebook
|
||||
else -> when {
|
||||
mimeType.startsWith("image/") -> R.string.file_type_image
|
||||
mimeType.startsWith("video/") -> R.string.file_type_video
|
||||
mimeType.startsWith("audio/") -> R.string.file_type_music
|
||||
else -> R.string.file_type_none
|
||||
}
|
||||
}
|
||||
if (resource == R.string.file_type_none && label.matches(Regex(".+\\..+"))) {
|
||||
val extension = label.substringAfterLast(".").uppercase(Locale.getDefault())
|
||||
return context.getString(R.string.file_type_generic, extension)
|
||||
}
|
||||
return context.getString(resource)
|
||||
}
|
||||
|
||||
val isDeletable: Boolean
|
||||
get() = false
|
||||
|
||||
val canShare: Boolean
|
||||
get() = false
|
||||
|
||||
fun share(context: Context) {}
|
||||
suspend fun delete(context: Context) {}
|
||||
|
||||
}
|
||||
@@ -8,8 +8,6 @@ import de.mm20.launcher2.ktx.romanize
|
||||
import java.text.Collator
|
||||
|
||||
interface SavableSearchable : Searchable, Comparable<SavableSearchable> {
|
||||
|
||||
val domain: String
|
||||
val key: String
|
||||
|
||||
val label: String
|
||||
@@ -41,4 +39,11 @@ interface SavableSearchable : Searchable, Comparable<SavableSearchable> {
|
||||
.compare(label1.romanize(), label2.romanize())
|
||||
}
|
||||
|
||||
val domain: String
|
||||
fun getSerializer(): SearchableSerializer
|
||||
|
||||
interface Companion {
|
||||
val Domain: String
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
package de.mm20.launcher2.search
|
||||
|
||||
interface SearchableDeserializer {
|
||||
fun deserialize(serialized: String): SavableSearchable?
|
||||
suspend fun deserialize(serialized: String): SavableSearchable?
|
||||
}
|
||||
|
||||
class NullDeserializer: SearchableDeserializer {
|
||||
override fun deserialize(serialized: String): SavableSearchable? {
|
||||
override suspend fun deserialize(serialized: String): SavableSearchable? {
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package de.mm20.launcher2.search
|
||||
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface SearchableRepository<T : Searchable> {
|
||||
fun search(query: String): Flow<ImmutableList<T>>
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package de.mm20.launcher2.search
|
||||
|
||||
import android.content.Context
|
||||
|
||||
interface Website: SavableSearchable {
|
||||
|
||||
val url: String
|
||||
val description: String?
|
||||
val imageUrl: String?
|
||||
val faviconUrl: String?
|
||||
val color: Int?
|
||||
|
||||
override val preferDetailsOverLaunch: Boolean
|
||||
get() = false
|
||||
|
||||
val canShare: Boolean
|
||||
fun share(context: Context) {}
|
||||
}
|
||||
Reference in New Issue
Block a user