Re-add websearches to search bar
This commit is contained in:
parent
872f55625f
commit
dbc2c6f62e
@ -46,6 +46,8 @@ abstract class AppDatabase : RoomDatabase() {
|
||||
abstract fun backupDao(): BackupRestoreDao
|
||||
abstract fun customAttrsDao(): CustomAttrsDao
|
||||
|
||||
abstract fun searchActionDao(): SearchActionDao
|
||||
|
||||
companion object {
|
||||
private var _instance: AppDatabase? = null
|
||||
fun getInstance(context: Context): AppDatabase {
|
||||
|
||||
@ -0,0 +1,12 @@
|
||||
package de.mm20.launcher2.database
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Query
|
||||
import de.mm20.launcher2.database.entities.SearchActionEntity
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
interface SearchActionDao {
|
||||
@Query("SELECT * FROM SearchAction ORDER BY position ASC")
|
||||
fun getSearchActions(): Flow<List<SearchActionEntity>>
|
||||
}
|
||||
@ -8,6 +8,7 @@ import de.mm20.launcher2.ktx.jsonObjectOf
|
||||
import de.mm20.launcher2.searchactions.builders.SearchActionBuilder
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONException
|
||||
@ -15,7 +16,7 @@ import java.io.File
|
||||
import java.util.UUID
|
||||
|
||||
interface SearchActionRepository {
|
||||
fun getSearchActionBuilders(filter: TextType?): Flow<List<SearchActionBuilder>>
|
||||
fun getSearchActionBuilders(): Flow<List<SearchActionBuilder>>
|
||||
|
||||
suspend fun export(toDir: File)
|
||||
suspend fun import(fromDir: File)
|
||||
@ -25,8 +26,9 @@ internal class SearchActionRepositoryImpl(
|
||||
private val context: Context,
|
||||
private val database: AppDatabase
|
||||
): SearchActionRepository {
|
||||
override fun getSearchActionBuilders(filter: TextType?): Flow<List<SearchActionBuilder>> {
|
||||
TODO("Not yet implemented")
|
||||
override fun getSearchActionBuilders(): Flow<List<SearchActionBuilder>> {
|
||||
val dao = database.searchActionDao()
|
||||
return dao.getSearchActions().map { it.mapNotNull { SearchActionBuilder.from(it) } }
|
||||
}
|
||||
|
||||
override suspend fun export(toDir: File) = withContext(Dispatchers.IO) {
|
||||
|
||||
@ -1,8 +1,14 @@
|
||||
package de.mm20.launcher2.searchactions
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.LauncherActivityInfo
|
||||
import android.content.pm.LauncherApps
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.pm.ResolveInfo
|
||||
import android.graphics.Bitmap
|
||||
import android.net.Uri
|
||||
import android.os.UserHandle
|
||||
import android.util.Log
|
||||
import android.util.Xml
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
@ -30,7 +36,9 @@ import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.emitAll
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.withContext
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
@ -51,6 +59,7 @@ interface SearchActionService {
|
||||
suspend fun importWebsearch(url: String, iconSize: Int): WebsearchActionBuilder?
|
||||
suspend fun createIcon(uri: Uri, size: Int): String?
|
||||
|
||||
suspend fun getSearchActivities(): List<ResolveInfo>
|
||||
}
|
||||
|
||||
internal class SearchActionServiceImpl(
|
||||
@ -80,8 +89,13 @@ internal class SearchActionServiceImpl(
|
||||
|
||||
val classificationResult = textClassifier.classify(context, query)
|
||||
|
||||
val other = repository.getSearchActionBuilders()
|
||||
|
||||
emit(builders.mapNotNull { it.build(context, classificationResult) }.toImmutableList())
|
||||
emitAll(
|
||||
other.map {
|
||||
(builders + it).mapNotNull { it.build(context, classificationResult) }.toImmutableList()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun importWebsearch(url: String, iconSize: Int): WebsearchActionBuilder? =
|
||||
@ -205,4 +219,10 @@ internal class SearchActionServiceImpl(
|
||||
out.close()
|
||||
return@withContext file.absolutePath
|
||||
}
|
||||
|
||||
override suspend fun getSearchActivities(): List<ResolveInfo> {
|
||||
val packageManager = context.packageManager
|
||||
val intent = Intent(Intent.ACTION_SEARCH)
|
||||
return packageManager.queryIntentActivities(intent, 0)
|
||||
}
|
||||
}
|
||||
@ -13,6 +13,7 @@ data class AppSearchAction(
|
||||
): SearchAction {
|
||||
override val icon: SearchActionIcon = SearchActionIcon.Search
|
||||
override val iconColor: Int = 0
|
||||
override val customIcon: String? = null
|
||||
|
||||
override fun start(context: Context) {
|
||||
val intent = Intent(Intent.ACTION_SEARCH).apply {
|
||||
|
||||
@ -13,6 +13,7 @@ data class CallAction(
|
||||
|
||||
override val icon: SearchActionIcon = SearchActionIcon.Phone
|
||||
override val iconColor: Int = 0
|
||||
override val customIcon: String? = null
|
||||
|
||||
override fun start(context: Context) {
|
||||
val intent = Intent(Intent.ACTION_DIAL).apply {
|
||||
|
||||
@ -13,6 +13,7 @@ class CreateContactAction(
|
||||
) : SearchAction {
|
||||
override val icon: SearchActionIcon = SearchActionIcon.Contact
|
||||
override val iconColor: Int = 0
|
||||
override val customIcon: String? = null
|
||||
|
||||
override fun start(context: Context) {
|
||||
val intent = Intent(Intent.ACTION_INSERT).apply {
|
||||
|
||||
@ -11,7 +11,7 @@ data class EmailAction(
|
||||
) : SearchAction {
|
||||
override val icon: SearchActionIcon = SearchActionIcon.Email
|
||||
override val iconColor: Int = 0
|
||||
|
||||
override val customIcon: String? = null
|
||||
override fun start(context: Context) {
|
||||
val intent = Intent(Intent.ACTION_SENDTO).apply {
|
||||
type = "*/*"
|
||||
|
||||
@ -11,7 +11,7 @@ data class MessageAction(
|
||||
): SearchAction {
|
||||
override val icon: SearchActionIcon = SearchActionIcon.Message
|
||||
override val iconColor: Int = 0
|
||||
|
||||
override val customIcon: String? = null
|
||||
override fun start(context: Context) {
|
||||
val intent = Intent(Intent.ACTION_SENDTO).apply {
|
||||
data = Uri.parse("sms:$number")
|
||||
|
||||
@ -8,13 +8,15 @@ import de.mm20.launcher2.ktx.tryStartActivity
|
||||
data class OpenUrlAction(
|
||||
override val label: String,
|
||||
val url: String,
|
||||
override val icon: SearchActionIcon = SearchActionIcon.Website,
|
||||
override val iconColor: Int = 0,
|
||||
override val customIcon: String? = null,
|
||||
) : SearchAction {
|
||||
|
||||
override val icon: SearchActionIcon = SearchActionIcon.Website
|
||||
override val iconColor: Int = 0
|
||||
|
||||
override fun start(context: Context) {
|
||||
val url = if (url.startsWith("https://") || url.startsWith("http://")) url else "https://$url"
|
||||
val url =
|
||||
if (url.startsWith("https://") || url.startsWith("http://")) url else "https://$url"
|
||||
val intent = Intent(Intent.ACTION_VIEW).apply {
|
||||
data = Uri.parse(url)
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
|
||||
@ -16,7 +16,7 @@ data class ScheduleEventAction(
|
||||
) : SearchAction {
|
||||
override val icon: SearchActionIcon = SearchActionIcon.Calendar
|
||||
override val iconColor: Int = 0
|
||||
|
||||
override val customIcon: String? = null
|
||||
override fun start(context: Context) {
|
||||
|
||||
val startTime = date.let {
|
||||
|
||||
@ -2,24 +2,58 @@ package de.mm20.launcher2.searchactions.actions
|
||||
|
||||
import android.content.Context
|
||||
import de.mm20.launcher2.search.Searchable
|
||||
import de.mm20.launcher2.searchactions.builders.WebsearchActionBuilder
|
||||
|
||||
interface SearchAction : Searchable {
|
||||
val label: String
|
||||
val icon: SearchActionIcon
|
||||
val iconColor: Int
|
||||
val customIcon: String?
|
||||
fun start(context: Context)
|
||||
}
|
||||
|
||||
enum class SearchActionIcon(value: Int) {
|
||||
Search(0),
|
||||
Custom(1),
|
||||
Website(2),
|
||||
Alarm(3),
|
||||
Timer(4),
|
||||
Contact(5),
|
||||
Phone(6),
|
||||
Email(7),
|
||||
Message(8),
|
||||
Calendar(9),
|
||||
Translate(10),
|
||||
enum class SearchActionIcon {
|
||||
Search,
|
||||
Custom,
|
||||
Website,
|
||||
Alarm,
|
||||
Timer,
|
||||
Contact,
|
||||
Phone,
|
||||
Email,
|
||||
Message,
|
||||
Calendar,
|
||||
Translate;
|
||||
fun toInt(): Int {
|
||||
return when (this) {
|
||||
Search -> 0
|
||||
Custom -> 1
|
||||
Website -> 2
|
||||
Alarm -> 3
|
||||
Timer -> 4
|
||||
Contact -> 5
|
||||
Phone -> 6
|
||||
Email -> 7
|
||||
Message -> 8
|
||||
Calendar -> 9
|
||||
Translate -> 10
|
||||
}
|
||||
}
|
||||
companion object {
|
||||
fun fromInt(value: Int?): SearchActionIcon {
|
||||
return when (value) {
|
||||
1 -> Custom
|
||||
2 -> Website
|
||||
3 -> Alarm
|
||||
4 -> Timer
|
||||
5 -> Contact
|
||||
6 -> Phone
|
||||
7 -> Email
|
||||
8 -> Message
|
||||
9 -> Calendar
|
||||
10 -> Translate
|
||||
else -> Search
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -12,7 +12,7 @@ data class SetAlarmAction(
|
||||
) : SearchAction {
|
||||
override val icon: SearchActionIcon = SearchActionIcon.Alarm
|
||||
override val iconColor: Int = 0
|
||||
|
||||
override val customIcon: String? = null
|
||||
override fun start(context: Context) {
|
||||
val intent = Intent(AlarmClock.ACTION_SET_ALARM).apply {
|
||||
putExtra(AlarmClock.EXTRA_HOUR, time.hour)
|
||||
|
||||
@ -13,7 +13,7 @@ data class TimerAction(
|
||||
|
||||
override val icon: SearchActionIcon = SearchActionIcon.Timer
|
||||
override val iconColor: Int = 0
|
||||
|
||||
override val customIcon: String? = null
|
||||
override fun start(context: Context) {
|
||||
val intent = Intent(AlarmClock.ACTION_SET_TIMER).apply {
|
||||
putExtra(AlarmClock.EXTRA_LENGTH, length.seconds.toInt())
|
||||
|
||||
@ -1,9 +1,42 @@
|
||||
package de.mm20.launcher2.searchactions.builders
|
||||
|
||||
import android.content.Context
|
||||
import de.mm20.launcher2.searchactions.actions.SearchAction
|
||||
import de.mm20.launcher2.database.entities.SearchActionEntity
|
||||
import de.mm20.launcher2.searchactions.TextClassificationResult
|
||||
import de.mm20.launcher2.searchactions.actions.SearchAction
|
||||
import de.mm20.launcher2.searchactions.actions.SearchActionIcon
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
|
||||
interface SearchActionBuilder {
|
||||
fun build(context: Context, classifiedQuery: TextClassificationResult): SearchAction?
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun from(entity: SearchActionEntity): SearchActionBuilder? {
|
||||
val options = entity.options?.let {
|
||||
try {
|
||||
JSONObject(it)
|
||||
} catch (_: JSONException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
when (entity.type) {
|
||||
"url" -> {
|
||||
return WebsearchActionBuilder(
|
||||
label = entity.label ?: "",
|
||||
urlTemplate = entity.data,
|
||||
color = entity.color,
|
||||
icon = SearchActionIcon.fromInt(entity.icon),
|
||||
customIcon = entity.customIcon,
|
||||
encoding = WebsearchActionBuilder.QueryEncoding.fromInt(options?.optInt("encoding"))
|
||||
)
|
||||
}
|
||||
"app" -> {
|
||||
return null
|
||||
}
|
||||
else -> return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@ class WebsearchActionBuilder(
|
||||
val label: String,
|
||||
val urlTemplate: String,
|
||||
val icon: SearchActionIcon = SearchActionIcon.Search,
|
||||
val color: Int = 0,
|
||||
val customIcon: String? = null,
|
||||
val encoding: QueryEncoding = QueryEncoding.UrlEncode,
|
||||
) : SearchActionBuilder {
|
||||
@ -21,6 +22,9 @@ class WebsearchActionBuilder(
|
||||
return OpenUrlAction(
|
||||
label = label,
|
||||
url = url,
|
||||
icon = icon,
|
||||
customIcon = customIcon,
|
||||
iconColor = color,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user