fix(search): Correct regressions found during final testing

This commit is contained in:
SuperDragonXD
2025-07-28 23:16:42 +08:00
parent 64f0d29671
commit 0a40691711
10 changed files with 38 additions and 15 deletions

View File

@@ -796,6 +796,8 @@
<string name="all_apps_search_result_calculator">Calculator</string>
<!-- Description for each search result type -->
<string name="search_pref_files_search_on">Search on</string>
<string name="search_pref_result_files_description">Media, files, and more</string>
<string name="search_pref_result_contacts_description">Contacts and more</string>
<string name="search_pref_result_web_provider_description">Via <xliff:g id="web_search_provider">%1$s</xliff:g></string>

View File

@@ -238,16 +238,23 @@ class SearchTargetFactory(
fun createWebSearchActionTarget(
query: String,
providerName: String, // The actual display name, not an ID
searchUrl: String, // The final, pre-formatted search URL
providerName: String,
searchUrl: String,
@DrawableRes providerIconRes: Int,
tintIcon: Boolean = false,
): SearchTargetCompat {
val id = "browser:$query:$providerName"
val browserIntent = Intent(Intent.ACTION_VIEW, searchUrl.toUri())
val title = context.getString(R.string.all_apps_search_on_web_message, providerName)
val icon = Icon.createWithResource(context, providerIconRes).apply {
if (tintIcon) {
setTint(ColorTokens.TextColorSecondary.resolveColor(context))
}
}
val action = SearchActionCompat.Builder(id, title)
.setIcon(Icon.createWithResource(context, providerIconRes))
.setIcon(icon)
.setIntent(browserIntent)
.build()

View File

@@ -147,7 +147,7 @@ class LawnchairLocalSearchAlgorithm(context: Context) : LawnchairSearchAlgorithm
val webProvider = provider.configure(context)
val providerName = if (webProvider is CustomWebSearchProvider) {
webProvider.getDisplayName(context.getString(webProvider.label))
webProvider.getDisplayName()
} else {
context.getString(webProvider.label)
}
@@ -158,6 +158,7 @@ class LawnchairLocalSearchAlgorithm(context: Context) : LawnchairSearchAlgorithm
providerName = providerName,
searchUrl = webProvider.getSearchUrl(query),
providerIconRes = webProvider.iconRes,
tintIcon = webProvider is CustomWebSearchProvider,
),
)
}
@@ -174,8 +175,8 @@ class LawnchairLocalSearchAlgorithm(context: Context) : LawnchairSearchAlgorithm
private val sectionBuilders: List<SectionBuilder> = listOf(
AppsAndShortcutsSectionBuilder,
WebSuggestionsSectionBuilder,
CalculationSectionBuilder,
WebSuggestionsSectionBuilder,
ContactsSectionBuilder,
FilesSectionBuilder,
SettingsSectionBuilder,

View File

@@ -30,6 +30,7 @@ sealed class SearchResult {
val providerName: String,
val searchUrl: String,
@DrawableRes val providerIconRes: Int,
val tintIcon: Boolean = false,
) : Action()
data class EmptyState(
@StringRes val titleRes: Int,

View File

@@ -176,6 +176,7 @@ object ActionsSectionBuilder : SectionBuilder {
providerName = webSearch.first().providerName,
searchUrl = webSearch.first().searchUrl,
providerIconRes = webSearch.first().providerIconRes,
tintIcon = webSearch.first().tintIcon,
).let {
targets.add(it)
}

View File

@@ -44,7 +44,7 @@ object CustomWebSearchProvider : WebSearchProvider {
private var displayName: String = ""
private val okHttpClient = OkHttpClient()
fun getDisplayName(getDisplayNamedefault: String): String = displayName
fun getDisplayName(): String = displayName
override fun configure(context: Context): WebSearchProvider {
val prefs = PreferenceManager2.getInstance(context)

View File

@@ -21,6 +21,7 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.ripple
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@@ -81,6 +82,10 @@ fun FileSearchProvider(
val mainAdapter = prefs.searchResultFilesToggle.getAdapter()
val hasAnyPermissions by viewModel.hasAnyPermissions.collectAsStateWithLifecycle()
LaunchedEffect(Unit) {
viewModel.refreshAccessStates()
}
LifecycleResumeEffect(Unit) {
viewModel.refreshAccessStates()
onPauseOrDispose {}
@@ -93,18 +98,21 @@ fun FileSearchProvider(
enabled = hasAnyPermissions,
modifier = modifier,
)
PreferenceGroup {
PreferenceGroup(
heading = stringResource(R.string.search_pref_files_search_on),
) {
val allFilesAccessState by viewModel.allFilesAccessState.collectAsStateWithLifecycle()
val allFilesAccessAdapter = prefs.searchResultAllFiles.getAdapter()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
ManageExternalStorageSetting(
accessState = allFilesAccessState,
adapter = prefs.searchResultAllFiles.getAdapter(),
adapter = allFilesAccessAdapter,
onPermissionRequest = viewModel::refreshAccessStates,
)
} else {
GenericAccessSetting(
adapter = prefs.searchResultAllFiles.getAdapter(),
adapter = allFilesAccessAdapter,
requiredPermission = android.Manifest.permission.READ_EXTERNAL_STORAGE,
switchEnabled = { allFilesAccessState != FileAccessState.Denied },
label = stringResource(R.string.search_pref_result_all_files_title),
@@ -122,6 +130,7 @@ fun FileSearchProvider(
accessState = visualMediaAccessState,
adapter = prefs.searchResultVisualMedia.getAdapter(),
onPermissionRequest = viewModel::refreshAccessStates,
alwaysEnabled = allFilesAccessAdapter.state.value && allFilesAccessState == FileAccessState.Full,
)
GenericAccessSetting(
@@ -132,6 +141,7 @@ fun FileSearchProvider(
permissionTitle = stringResource(R.string.permissions_music_audio),
permissionDescription = stringResource(R.string.permissions_music_audio_description),
onPermissionResult = { viewModel.refreshAccessStates() },
alwaysEnabled = allFilesAccessAdapter.state.value && allFilesAccessState == FileAccessState.Full,
)
}
}
@@ -182,7 +192,7 @@ private fun ManageExternalStorageSetting(
showPermissionDialog = true
}
},
switchEnabled = !isPlayStoreFlavor(),
switchEnabled = !isPlayStoreFlavor() && (accessState != FileAccessState.Denied),
modifier = modifier,
)
}
@@ -190,8 +200,8 @@ private fun ManageExternalStorageSetting(
if (showPermissionDialog) {
if (!isPlayStoreFlavor()) {
PermissionDialog(
title = stringResource(R.string.permissions_photos_videos),
text = stringResource(R.string.permissions_photos_videos_description),
title = stringResource(R.string.permissions_manage_storage),
text = stringResource(R.string.permissions_manage_storage_description),
isPermanentlyDenied = true,
onConfirm = { },
onDismiss = { showPermissionDialog = false },
@@ -273,7 +283,7 @@ private fun VisualMediaSetting(
PermissionDialog(
title = stringResource(R.string.permissions_photos_videos),
text = stringResource(R.string.permissions_photos_videos_description),
isPermanentlyDenied = !permissionState.shouldShowRationale && !permissionState.allPermissionsGranted,
isPermanentlyDenied = permissionState.allPermissionsGranted,
onConfirm = { permissionState.launchMultiplePermissionRequest() },
onDismiss = { showPermissionDialog = false },
onGoToSettings = { context.openAppPermissionSettings() },

View File

@@ -157,7 +157,7 @@ fun ContactsSearchProvider(
PermissionDialog(
title = stringResource(R.string.warn_contact_permission_title),
text = stringResource(id = R.string.warn_contact_permission_content),
isPermanentlyDenied = !contactsPermissionState.status.isGranted && !contactsPermissionState.status.shouldShowRationale,
isPermanentlyDenied = contactsPermissionState.status.shouldShowRationale,
onConfirm = { contactsPermissionState.launchPermissionRequest() },
onDismiss = {
backDispatcher?.onBackPressed()

View File

@@ -102,6 +102,7 @@ class FileAccessManager private constructor(private val context: Context) : Safe
_allFilesAccessState.value = getCurrentAllFilesAccessState()
_visualMediaAccessState.value = getCurrentVisualMediaState()
_audioAccessState.value = getCurrentAudioState()
_hasAnyPermission.value = hasAnyPermissions()
}
private fun hasAnyPermissions(): Boolean {