Merge branch 'main' of https://github.com/MM2-0/Kvaesitso
Some checks failed
Deploy static content to Pages / deploy (push) Has been cancelled
Build Nightly APK / build (push) Has been cancelled

# Conflicts:
#	app/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/SearchVM.kt
#	services/widgets/src/main/java/de/mm20/launcher2/services/widgets/WidgetsService.kt
...
This commit is contained in:
lunaticbum 2025-08-14 18:25:00 +09:00
commit 5f74a9d9b4
18 changed files with 182 additions and 72 deletions

1
.gitignore vendored
View File

@ -308,5 +308,6 @@ fabric.properties
.idea/deploymentTargetSelector.xml .idea/deploymentTargetSelector.xml
.idea/copilot .idea/copilot
.idea/other.xml .idea/other.xml
.idea/studiobot.xml
.kotlin .kotlin

View File

@ -7,8 +7,8 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.staticCompositionLocalOf import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.lifecycle.repeatOnLifecycle import androidx.lifecycle.repeatOnLifecycle
import de.mm20.launcher2.crashreporter.CrashReporter import de.mm20.launcher2.crashreporter.CrashReporter
import kotlinx.coroutines.awaitCancellation import kotlinx.coroutines.awaitCancellation
@ -24,7 +24,7 @@ fun ProvideAppWidgetHost(
val context = LocalContext.current val context = LocalContext.current
val widgetHost = remember { AppWidgetHost(context.applicationContext, 44203) } val widgetHost = remember { AppWidgetHost(context.applicationContext, 44203) }
LaunchedEffect(null) { LaunchedEffect(null) {
lifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { lifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.RESUMED) {
widgetHost.startListening() widgetHost.startListening()
try { try {
awaitCancellation() awaitCancellation()

View File

@ -77,7 +77,6 @@ import de.mm20.launcher2.ui.locals.LocalWindowSize
import de.mm20.launcher2.ui.overlays.OverlayHost import de.mm20.launcher2.ui.overlays.OverlayHost
import de.mm20.launcher2.ui.theme.LauncherTheme import de.mm20.launcher2.ui.theme.LauncherTheme
import de.mm20.launcher2.ui.theme.wallpaperColorsAsState import de.mm20.launcher2.ui.theme.wallpaperColorsAsState
import kotlin.math.pow
abstract class SharedLauncherActivity( abstract class SharedLauncherActivity(
@ -195,7 +194,10 @@ abstract class SharedLauncherActivity(
if (it != null) { if (it != null) {
enterTransitionProgress.value = 0f enterTransitionProgress.value = 0f
enterTransition = it enterTransition = it
enterTransitionProgress.animateTo(100f, animationSpec = animMotionSpec) enterTransitionProgress.animateTo(
100f,
animationSpec = animMotionSpec
)
enterTransition = null enterTransition = null
} }
} }
@ -275,10 +277,15 @@ abstract class SharedLauncherActivity(
}, },
) )
is GestureAction.Widgets -> ScaffoldGesture( is GestureAction.Widgets ->
component = widgetComponent, if (widgetsOnHomeScreen == true) {
animation = if (gesture.orientation == null) ScaffoldAnimation.ZoomIn else ScaffoldAnimation.Push, null
) } else {
ScaffoldGesture(
component = widgetComponent,
animation = if (gesture.orientation == null) ScaffoldAnimation.ZoomIn else ScaffoldAnimation.Push,
)
}
is GestureAction.Notifications -> ScaffoldGesture( is GestureAction.Notifications -> ScaffoldGesture(
component = NotificationsComponent, component = NotificationsComponent,

View File

@ -214,7 +214,7 @@ class SearchVM : ViewModel(), KoinComponent {
if (query.isEmpty()) { if (query.isEmpty()) {
val hiddenItemKeys = if (!filters.hiddenItems) { val hiddenItemKeys = if (!filters.hiddenItems) {
searchableRepository.getKeys( searchableRepository.getKeys(
maxVisibility = VisibilityLevel.Hidden, maxVisibility = VisibilityLevel.SearchOnly,
includeTypes = listOf("app"), includeTypes = listOf("app"),
) )
} else { } else {
@ -275,18 +275,18 @@ class SearchVM : ViewModel(), KoinComponent {
appResults.updateItems( appResults.updateItems(
results.apps results.apps
?.filterNot { hiddenKeys.contains(it.key) } ?.filterNot { hiddenKeys.contains(it.key) }
?.applyRanking(query) ?.applyRanking(query)
) )
appShortcutResults.updateItems( appShortcutResults.updateItems(
results.shortcuts results.shortcuts
?.filterNot { hiddenKeys.contains(it.key) } ?.filterNot { hiddenKeys.contains(it.key) }
?.applyRanking(query) ?.applyRanking(query)
) )
fileResults.updateItems( fileResults.updateItems(
results.files results.files
?.filterNot { hiddenKeys.contains(it.key) } ?.filterNot { hiddenKeys.contains(it.key) }
?.applyRanking(query) ?.applyRanking(query)
) )
contactResults.updateItems( contactResults.updateItems(

View File

@ -119,10 +119,13 @@ fun EditFavoritesSheet(
.align(Alignment.Center) .align(Alignment.Center)
) )
} }
} else if (createShortcutTarget != null) {
ShortcutPicker(viewModel, it)
} else { } else {
ReorderFavoritesGrid(viewModel, it) ReorderFavoritesGrid(viewModel, it)
if (createShortcutTarget != null) {
BottomSheetDialog({viewModel.cancelPickShortcut()}) {
ShortcutPicker(viewModel, it)
}
}
} }
} }
} }

View File

@ -52,6 +52,7 @@ fun GestureSettingsScreen() {
val viewModel: GestureSettingsScreenVM = viewModel() val viewModel: GestureSettingsScreenVM = viewModel()
val hasPermission by viewModel.hasPermission.collectAsStateWithLifecycle(null) val hasPermission by viewModel.hasPermission.collectAsStateWithLifecycle(null)
val allowWidgetGesture by viewModel.allowWidgetGesture.collectAsStateWithLifecycle(null)
val options = buildList { val options = buildList {
add(stringResource(R.string.gesture_action_none) to GestureAction.NoAction) add(stringResource(R.string.gesture_action_none) to GestureAction.NoAction)
@ -61,7 +62,7 @@ fun GestureSettingsScreen() {
add(stringResource(R.string.gesture_action_recents) to GestureAction.Recents) add(stringResource(R.string.gesture_action_recents) to GestureAction.Recents)
add(stringResource(R.string.gesture_action_power_menu) to GestureAction.PowerMenu) add(stringResource(R.string.gesture_action_power_menu) to GestureAction.PowerMenu)
add(stringResource(R.string.gesture_action_open_search) to GestureAction.Search) add(stringResource(R.string.gesture_action_open_search) to GestureAction.Search)
add(stringResource(R.string.gesture_action_widgets) to GestureAction.Widgets) if (allowWidgetGesture == true) add(stringResource(R.string.gesture_action_widgets) to GestureAction.Widgets)
add(stringResource(R.string.gesture_action_launch_app) to GestureAction.Launch(null)) add(stringResource(R.string.gesture_action_launch_app) to GestureAction.Launch(null))
} }
@ -265,7 +266,7 @@ fun GesturePreference(
icon = icon, icon = icon,
items = options, items = options,
value = value, value = value,
summary = options.find { value?.javaClass == it.second.javaClass }?.first, summary = options.find { value?.javaClass == it.second.javaClass }?.first ?: stringResource(R.string.gesture_action_none),
onValueChanged = { if (it != null) onValueChanged(it) } onValueChanged = { if (it != null) onValueChanged(it) }
) )
} }

View File

@ -34,6 +34,9 @@ class GestureSettingsScreenVM : ViewModel(), KoinComponent {
val hasPermission = permissionsManager.hasPermission(PermissionGroup.Accessibility) val hasPermission = permissionsManager.hasPermission(PermissionGroup.Accessibility)
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null) .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
val allowWidgetGesture = uiSettings.homeScreenWidgets.map { it == false }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
val swipeDown = gestureSettings.swipeDown val swipeDown = gestureSettings.swipeDown
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null) .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
val swipeLeft = gestureSettings.swipeLeft val swipeLeft = gestureSettings.swipeLeft

View File

@ -157,38 +157,6 @@ class HomescreenSettingsScreenVM(
fun setWidgetsOnHomeScreen(widgetsOnHomeScreen: Boolean) { fun setWidgetsOnHomeScreen(widgetsOnHomeScreen: Boolean) {
uiSettings.setHomeScreenWidgets(widgetsOnHomeScreen) uiSettings.setHomeScreenWidgets(widgetsOnHomeScreen)
viewModelScope.launch {
val gestures = gestureSettings.first()
if (widgetsOnHomeScreen) {
if (gestures.swipeUp is GestureAction.Widgets) {
gestureSettings.setSwipeUp(GestureAction.NoAction)
} else if (gestures.swipeRight is GestureAction.Widgets) {
gestureSettings.setSwipeUp(GestureAction.NoAction)
} else if (gestures.swipeLeft is GestureAction.Widgets) {
gestureSettings.setSwipeUp(GestureAction.NoAction)
} else if (gestures.swipeDown is GestureAction.Widgets) {
gestureSettings.setSwipeUp(GestureAction.NoAction)
} else if (gestures.longPress is GestureAction.Widgets) {
gestureSettings.setLongPress(GestureAction.NoAction)
} else if (gestures.doubleTap is GestureAction.Widgets) {
gestureSettings.setDoubleTap(GestureAction.NoAction)
}
} else {
if (gestures.swipeUp is GestureAction.NoAction || gestures.swipeUp is GestureAction.Widgets) {
gestureSettings.setSwipeUp(GestureAction.Widgets)
} else if (gestures.swipeRight is GestureAction.NoAction || gestures.swipeRight is GestureAction.Widgets) {
gestureSettings.setSwipeRight(GestureAction.Widgets)
} else if (gestures.swipeLeft is GestureAction.NoAction || gestures.swipeLeft is GestureAction.Widgets) {
gestureSettings.setSwipeLeft(GestureAction.Widgets)
} else if (gestures.swipeDown is GestureAction.NoAction || gestures.swipeDown is GestureAction.Widgets) {
gestureSettings.setSwipeDown(GestureAction.Widgets)
} else if (gestures.longPress is GestureAction.NoAction || gestures.longPress is GestureAction.Widgets) {
gestureSettings.setLongPress(GestureAction.Widgets)
} else if (gestures.doubleTap is GestureAction.NoAction || gestures.doubleTap is GestureAction.Widgets) {
gestureSettings.setDoubleTap(GestureAction.Widgets)
}
}
}
} }
companion object : KoinComponent { companion object : KoinComponent {

View File

@ -589,7 +589,7 @@
<string name="clock_style_digital2">Semplice</string> <string name="clock_style_digital2">Semplice</string>
<string name="clock_style_orbit">Orbita</string> <string name="clock_style_orbit">Orbita</string>
<string name="clock_style_binary">Binario</string> <string name="clock_style_binary">Binario</string>
<string name="clock_style_analog">Mani</string> <string name="clock_style_analog">Lancette</string>
<string name="clock_style_segment">7 segmenti</string> <string name="clock_style_segment">7 segmenti</string>
<string name="clock_style_empty">Nessun orologio</string> <string name="clock_style_empty">Nessun orologio</string>
<string name="clock_variant_outlined">Delineato</string> <string name="clock_variant_outlined">Delineato</string>

View File

@ -554,7 +554,7 @@
<string name="search_action_app">Aplicação</string> <string name="search_action_app">Aplicação</string>
<string name="search_action_websearch_url">Modelo de URL</string> <string name="search_action_websearch_url">Modelo de URL</string>
<string name="preference_plugin_enable">Ativar plugin</string> <string name="preference_plugin_enable">Ativar plugin</string>
<string name="plugin_type_filesearch">Pesquisa de ficheiros</string> <string name="plugin_type_filesearch">Ficheiros</string>
<string name="experimental_feature">Experimental</string> <string name="experimental_feature">Experimental</string>
<string name="tag_exists_error">Já existe uma etiqueta com este nome.</string> <string name="tag_exists_error">Já existe uma etiqueta com este nome.</string>
<string name="tag_exists_message">Já existe uma etiqueta com este nome. Se continuar, as etiquetas serão combinadas.</string> <string name="tag_exists_message">Já existe uma etiqueta com este nome. Se continuar, as etiquetas serão combinadas.</string>
@ -799,4 +799,63 @@
<string name="preference_clock_widget_time_format_24h">24 horas</string> <string name="preference_clock_widget_time_format_24h">24 horas</string>
<string name="preference_clock_widget_time_format_12h">12 horas</string> <string name="preference_clock_widget_time_format_12h">12 horas</string>
<string name="preference_clock_widget_time_format_system">Padrão do sistema</string> <string name="preference_clock_widget_time_format_system">Padrão do sistema</string>
<string name="theme_import_title">Importar tema</string>
<string name="import_theme_exists">O tema já existe e será atualizado</string>
<string name="preference_search_bar_style_transparent">Transparente</string>
<string name="preference_search_bar_style_solid">Sólida</string>
<string name="preference_search_bar_style_hidden">Oculta</string>
<string name="import_theme_contents">Conteúdo</string>
<string name="clock_variant_analog_ticks">Ponteiros 2</string>
<string name="theme_export_title">Exportar tema</string>
<string name="preference_colors_high_contrast">Alto contraste</string>
<string name="theme_bundle_name">Nome</string>
<string name="theme_bundle_author">Autor</string>
<string name="preference_shapes_default">Padrão</string>
<string name="preference_shapes_extra_round">Super redonda</string>
<string name="preference_screen_shapes">Formas</string>
<string name="preference_shapes_base">Forma base</string>
<string name="preference_shapes_rect">Retangular</string>
<string name="confirmation_delete_shapes_scheme">Tem a certeza de que deseja eliminar o esquema de formas %1$s?</string>
<string name="bad_configuration_title">Parabéns, acabou de se bloquear!</string>
<string name="preference_launch_breezyweather_app">Abrir Breezy Weather</string>
<string name="preference_screen_transparencies">Transparência</string>
<string name="preference_transparencies_default">Padrão</string>
<string name="preference_transparencies_semi_transparent">Semi-transparente</string>
<string name="provider_breezy">Breezy Weather</string>
<string name="new_theme_name">(sem nome)</string>
<string name="preference_breezyweather_integration_instructions">Para utilizar Breezy Weather como serviço meteorológico:\n\n1. Aceda a Breezy Weather &gt; Definições &gt; Widgets &amp; Papel de parede &gt; Enviara dados Gadgetbridge &gt; Ativar%1$s\n\n2. Em %1$s, selecione Breezy Weather como serviço de meteorologia.</string>
<string name="music_widget_interactive_progress_bar">Barra de progresso interativa</string>
<string name="missing_permission_tasks_integration">A permissão Tasks é necessária para a integração Tasks</string>
<string name="preference_location_breezy">Gerir localização em Breezy Weather</string>
<string name="no_selection">Nada selecionado</string>
<string name="save_as_file">Guardar como ficheiro</string>
<string name="preference_breezyweather_integration">Breezy Weather</string>
<string name="plugin_type_contacts">Contactos</string>
<string name="confirmation_delete_transparencies_scheme">Tem a certeza de que deseja eliminar o esquema de transparência %1$s?</string>
<string name="action_install">Instalar</string>
<string name="missing_permission_tasks_search_settings">A permissão Tasks é necessária para pesquisar tarefas</string>
<string name="preference_search_tasks">Tarefas</string>
<string name="preference_search_tasks_summary">Pesquisar tarefas na aplicação Tasks</string>
<string name="preference_tasks_integration">Tasks</string>
<string name="preference_tasks_integration_description">Tasks é uma aplicação open souce para gerir tarefas, listas e lembretes. Se instalada, %1$s pode mostrar e pesquisar as tarefas na aplicação.</string>
<string name="preference_tasks_integration_ready">Integração com Tasks finalizada e pronta para utilização.</string>
<plurals name="calendar_widget_running_tasks">
<item quantity="one">+%1$d tarefa por realizar</item>
<item quantity="many">+%1$d tarefas por realizar</item>
<item quantity="other">+%1$d tarefas por realizar</item>
</plurals>
<string name="preference_screen_typography">Tipografia</string>
<string name="preference_breezyweather_integration_description">Breezy Weather é uma aplicação open source de meteorologia. Se instalada, %1$s pode utilizar Breezy Weather com a fonte de dados meteorológicos.</string>
<string name="confirmation_delete_typography_scheme">Tem a certeza de que deseja eliminar o esquema tipográfico %1$s?</string>
<string name="preference_typography_fonts">Tipo de letra</string>
<string name="font_category_device_default">Definições do dispositivo</string>
<string name="font_name_device_headline">Tipo de letra padrão</string>
<string name="font_name_device_body">Tipo de letra do dispositivo</string>
<string name="font_category_generic">Genérica</string>
<string name="preference_widgets_on_home_screen">Widgets no ecrã principal</string>
<string name="preference_gesture_swipe_up">Deslize acima</string>
<string name="preference_widgets_on_home_screen_summary">Mostrar widgets no ecrã principal e não em página secundária</string>
<string name="gesture_action_widgets">Widgets</string>
<string name="bad_configuration_summary">Você conseguir encontrar uma combinação de definições em não é possível aceder às pesquisas e às definições. Acabou de se bloquear.</string>
<string name="preference_launch_tasks_app">Abrir Tasks</string>
</resources> </resources>

View File

@ -575,7 +575,7 @@
<string name="location_opens_other_day">开启于 %1$s, %2$s</string> <string name="location_opens_other_day">开启于 %1$s, %2$s</string>
<string name="menu_map">在地图上查看</string> <string name="menu_map">在地图上查看</string>
<string name="menu_website">打开网站</string> <string name="menu_website">打开网站</string>
<string name="plugin_state_setup_required">您需要先设置插件</string> <string name="plugin_state_setup_required">您需要先设置插件</string>
<string name="plugin_state_error">此插件未正常运行</string> <string name="plugin_state_error">此插件未正常运行</string>
<string name="menu_bugreport">Bug 报告</string> <string name="menu_bugreport">Bug 报告</string>
<string name="length_unit">长度单位</string> <string name="length_unit">长度单位</string>
@ -613,7 +613,7 @@
<string name="preference_search_supportedunits">支持的单位</string> <string name="preference_search_supportedunits">支持的单位</string>
<string name="note_widget_conflict_description">链接的文件不为空,且其内容与此笔记的上次保存版本不匹配。您想保留哪个版本?</string> <string name="note_widget_conflict_description">链接的文件不为空,且其内容与此笔记的上次保存版本不匹配。您想保留哪个版本?</string>
<string name="note_widget_file_read_error">错误读取注释</string> <string name="note_widget_file_read_error">错误读取注释</string>
<string name="note_widget_file_read_error_description">无法读取链接文件。可能已被移动或删除。已从启动器的内部存储中恢复副本。如果您编辑笔记,链接文件可能会被覆盖</string> <string name="note_widget_file_read_error_description">无法读取链接的文件,可能其已被移动或删除。已从启动器的存储中恢复副本。如果您编辑笔记,链接文件可能会被覆盖</string>
<string name="note_widget_file_write_error">保存笔记时出错</string> <string name="note_widget_file_write_error">保存笔记时出错</string>
<string name="theme_color_scheme_autogenerate">从原色开始</string> <string name="theme_color_scheme_autogenerate">从原色开始</string>
<string name="import_theme_error">无法读取所选文件。请确保您选择的是有效的主题文件 (*.kvtheme),并且该文件未损坏。</string> <string name="import_theme_error">无法读取所选文件。请确保您选择的是有效的主题文件 (*.kvtheme),并且该文件未损坏。</string>
@ -793,4 +793,63 @@
<string name="preference_clock_widget_time_format_12h">12小时</string> <string name="preference_clock_widget_time_format_12h">12小时</string>
<string name="preference_clock_widget_time_format_system">系统默认</string> <string name="preference_clock_widget_time_format_system">系统默认</string>
<string name="missing_permission_call_contacts_settings">需要通话权限才能开始通话</string> <string name="missing_permission_call_contacts_settings">需要通话权限才能开始通话</string>
<string name="import_theme_exists">已有的样式将会被覆盖</string>
<string name="preference_search_bar_style_transparent">透明</string>
<string name="preference_search_bar_style_hidden">隐藏</string>
<string name="preference_search_bar_style_solid">填充</string>
<string name="import_theme_contents">文件包含</string>
<string name="font_name_device_headline">标题字体</string>
<string name="theme_import_title">导入样式</string>
<string name="clock_variant_analog_ticks">刻度</string>
<string name="theme_export_title">导出样式</string>
<string name="preference_colors_high_contrast">高对比度</string>
<string name="preference_screen_shapes">形状</string>
<string name="preference_shapes_default">默认</string>
<string name="preference_shapes_rect">直角</string>
<string name="preference_shapes_extra_round">大圆角</string>
<string name="preference_shapes_base">基础形状</string>
<string name="preference_gesture_swipe_up">向上滑动</string>
<string name="gesture_action_widgets">组件页</string>
<string name="confirmation_delete_shapes_scheme">删除形状预设“%1$s”吗</string>
<string name="bad_configuration_summary">你探索出了一套访问不了搜索和组件页的配置,使你无法进入设置 — 让启动器桌面变成了启动弃。</string>
<string name="preference_transparencies_default">默认</string>
<string name="preference_screen_transparencies">透明度</string>
<string name="preference_transparencies_semi_transparent">半透明</string>
<string name="confirmation_delete_transparencies_scheme">删除透明度预设“%1$s”吗</string>
<string name="weather_condition_thunder">雷雨</string>
<string name="weather_condition_haze">雾霾</string>
<string name="preference_search_tasks">任务</string>
<string name="preference_launch_breezyweather_app">打开 Breezy Weather</string>
<string name="no_selection">未选</string>
<string name="save_as_file">保存为文件</string>
<string name="preference_breezyweather_integration">Breezy Weather</string>
<string name="theme_bundle_name">名称</string>
<string name="theme_bundle_author">作者</string>
<string name="provider_breezy">Breezy Weather</string>
<string name="preference_location_breezy">在 Breezy Weather 中管理位置</string>
<string name="preference_search_tasks_summary">搜索在 Tasks 应用中的任务</string>
<string name="new_theme_name">(新建)</string>
<string name="font_category_device_default">设备默认的</string>
<string name="music_widget_interactive_progress_bar">可交互进度条</string>
<string name="confirmation_delete_typography_scheme">删除字体预设“%1$s”吗</string>
<string name="bad_configuration_title">恭喜!你给你自个儿锁里头了!</string>
<string name="missing_permission_tasks_integration">需要 Tasks 权限来接入 Tasks 应用</string>
<string name="preference_breezyweather_integration_instructions">要使用 Breezy Weather 作为天气数据源:\n\n1. 启用 Breezy Weather &gt; 设置 &gt; 微件与动态壁纸 &gt; 发送天气数据到 Gadgetbridge 中的 %1$s\n\n2. 在 %1$s 中将 Breezy Weather 设为天气数据源</string>
<string name="action_install">安装</string>
<string name="preference_tasks_integration">Tasks</string>
<string name="preference_tasks_integration_ready">已成功接入 Tasks 并可以开始使用了。</string>
<string name="preference_tasks_integration_description">Tasks 是一个免费的开源 to-do 及提醒事项应用。如果已经安装,%1$s 可以显示并搜索在 Tasks 应用中的任务。</string>
<plurals name="calendar_widget_running_tasks">
<item quantity="other">+%1$d 个未完成任务</item>
</plurals>
<string name="missing_permission_tasks_search_settings">需要 Tasks 应用权限来搜索任务</string>
<string name="preference_screen_typography">文字</string>
<string name="preference_typography_fonts">字体</string>
<string name="preference_breezyweather_integration_description">Breezy Weather 是一款免费的开源天气应用。安装后 %1$s 可将其作为天气数据的数据源。</string>
<string name="font_name_device_body">正文字体</string>
<string name="font_category_generic">常规字体</string>
<string name="preference_widgets_on_home_screen">直达组件</string>
<string name="preference_widgets_on_home_screen_summary">在主屏幕而不是组件页显示组件</string>
<string name="tag_empty_name">标签必须拥有一个名字。如果继续设为空,这个标签会被删除。</string>
<string name="preference_launch_tasks_app">打开 Tasks 应用</string>
</resources> </resources>

View File

@ -4,7 +4,7 @@
<item quantity="other"></item> <item quantity="other"></item>
</plurals> </plurals>
<plurals name="unit_kilometer"> <plurals name="unit_kilometer">
<item quantity="other">公里</item> <item quantity="other">千米</item>
</plurals> </plurals>
<plurals name="unit_centimeter"> <plurals name="unit_centimeter">
<item quantity="other">厘米</item> <item quantity="other">厘米</item>
@ -119,28 +119,28 @@
<item quantity="other">吉位字节</item> <item quantity="other">吉位字节</item>
</plurals> </plurals>
<plurals name="unit_tebibyte"> <plurals name="unit_tebibyte">
<item quantity="other">万亿位字节</item> <item quantity="other">位字节</item>
</plurals> </plurals>
<plurals name="unit_kilobit"> <plurals name="unit_kilobit">
<item quantity="other">千比特</item> <item quantity="other">千比特</item>
</plurals> </plurals>
<string name="unit_kilobit_symbol">kbit</string> <string name="unit_kilobit_symbol">kb</string>
<string name="unit_megabit_symbol">Mbit</string> <string name="unit_megabit_symbol">Mb</string>
<plurals name="unit_megabit"> <plurals name="unit_megabit">
<item quantity="other">兆比特</item> <item quantity="other">兆比特</item>
</plurals> </plurals>
<string name="unit_gigabit_symbol">Gbit</string> <string name="unit_gigabit_symbol">Gb</string>
<plurals name="unit_gigabit"> <plurals name="unit_gigabit">
<item quantity="other">吉比特</item> <item quantity="other">吉比特</item>
</plurals> </plurals>
<string name="unit_terabit_symbol">万亿比特</string> <string name="unit_terabit_symbol">TB</string>
<plurals name="unit_terabit"> <plurals name="unit_terabit">
<item quantity="other">terabits</item> <item quantity="other">太比特</item>
</plurals> </plurals>
<string name="unit_meter_per_second_symbol">m/s</string> <string name="unit_meter_per_second_symbol">m/s</string>
<string name="unit_kilometer_per_hour_symbol">km/h</string> <string name="unit_kilometer_per_hour_symbol">km/h</string>
<plurals name="unit_kilometer_per_hour"> <plurals name="unit_kilometer_per_hour">
<item quantity="other">公里每小时</item> <item quantity="other">千米每小时</item>
</plurals> </plurals>
<string name="unit_mile_per_hour_symbol">mph</string> <string name="unit_mile_per_hour_symbol">mph</string>
<plurals name="unit_mile_per_hour"> <plurals name="unit_mile_per_hour">
@ -160,7 +160,7 @@
</plurals> </plurals>
<string name="unit_metric_ton_symbol">t</string> <string name="unit_metric_ton_symbol">t</string>
<plurals name="unit_metric_ton"> <plurals name="unit_metric_ton">
<item quantity="other"></item> <item quantity="other"></item>
</plurals> </plurals>
<string name="unit_long_ton_symbol">tn.l.</string> <string name="unit_long_ton_symbol">tn.l.</string>
<plurals name="unit_long_ton"> <plurals name="unit_long_ton">
@ -192,7 +192,7 @@
<item quantity="other"></item> <item quantity="other"></item>
</plurals> </plurals>
<plurals name="unit_terabyte"> <plurals name="unit_terabyte">
<item quantity="other">万亿字节</item> <item quantity="other">字节</item>
</plurals> </plurals>
<string name="unit_kibibyte_symbol">kiB</string> <string name="unit_kibibyte_symbol">kiB</string>
<plurals name="unit_kibibyte"> <plurals name="unit_kibibyte">

View File

@ -66,7 +66,7 @@
<string name="wind_west_north_west">西北偏西</string> <string name="wind_west_north_west">西北偏西</string>
<string name="wind_north_west">西北</string> <string name="wind_north_west">西北</string>
<string name="wind_north_north_west">西北偏北</string> <string name="wind_north_north_west">西北偏北</string>
<string name="wikipedia_url">https://en.wikipedia.org</string> <string name="wikipedia_url">https://zh.wikipedia.org/zh-tw/</string>
<string name="wikipedia_source">來自維基百科</string> <string name="wikipedia_source">來自維基百科</string>
<string name="file_meta_title">標題:%1$s</string> <string name="file_meta_title">標題:%1$s</string>
<string name="file_meta_artist">藝術家:%1$s</string> <string name="file_meta_artist">藝術家:%1$s</string>
@ -620,7 +620,7 @@
<string name="search_filter_online">線上結果</string> <string name="search_filter_online">線上結果</string>
<string name="search_filter_apps">應用程式</string> <string name="search_filter_apps">應用程式</string>
<string name="preference_clock_widget_alignment_center">中間</string> <string name="preference_clock_widget_alignment_center">中間</string>
<string name="preference_clock_widget_show_seconds">顯示秒</string> <string name="preference_clock_widget_show_seconds">顯示秒</string>
<string name="preference_clock_widget_alignment_bottom">底部</string> <string name="preference_clock_widget_alignment_bottom">底部</string>
<string name="preference_clockwidget_dynamic_zone">動態區域</string> <string name="preference_clockwidget_dynamic_zone">動態區域</string>
<string name="preference_customize_filter_bar">自訂篩選器列</string> <string name="preference_customize_filter_bar">自訂篩選器列</string>
@ -845,4 +845,9 @@
<string name="preference_gesture_swipe_up">向上滑動</string> <string name="preference_gesture_swipe_up">向上滑動</string>
<string name="gesture_action_widgets">小工具</string> <string name="gesture_action_widgets">小工具</string>
<string name="preference_launch_tasks_app">開啟 Tasks 應用程式</string> <string name="preference_launch_tasks_app">開啟 Tasks 應用程式</string>
<string name="preference_search_bar_style_solid">不透明</string>
<string name="preference_search_bar_style_hidden">隱藏</string>
<string name="preference_search_bar_style_transparent">透明</string>
<string name="clock_variant_analog_ticks">時鐘標記</string>
<string name="music_widget_interactive_progress_bar">互動式播放器進度條</string>
</resources> </resources>

View File

@ -54,5 +54,6 @@ dependencies {
implementation(project(":core:ktx")) implementation(project(":core:ktx"))
implementation(project(":core:crashreporter")) implementation(project(":core:crashreporter"))
implementation(project(":core:preferences")) implementation(project(":core:preferences"))
implementation(project(":core:profiles"))
} }

View File

@ -13,6 +13,7 @@ import de.mm20.launcher2.ktx.normalize
import de.mm20.launcher2.permissions.PermissionGroup import de.mm20.launcher2.permissions.PermissionGroup
import de.mm20.launcher2.permissions.PermissionsManager import de.mm20.launcher2.permissions.PermissionsManager
import de.mm20.launcher2.preferences.search.ShortcutSearchSettings import de.mm20.launcher2.preferences.search.ShortcutSearchSettings
import de.mm20.launcher2.profiles.ProfileManager
import de.mm20.launcher2.search.AppShortcut import de.mm20.launcher2.search.AppShortcut
import de.mm20.launcher2.search.ResultScore import de.mm20.launcher2.search.ResultScore
import de.mm20.launcher2.search.SearchableRepository import de.mm20.launcher2.search.SearchableRepository
@ -27,6 +28,7 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
@ -54,6 +56,7 @@ internal class AppShortcutRepositoryImpl(
private val context: Context, private val context: Context,
private val permissionsManager: PermissionsManager, private val permissionsManager: PermissionsManager,
private val settings: ShortcutSearchSettings, private val settings: ShortcutSearchSettings,
private val profileManager: ProfileManager,
) : AppShortcutRepository { ) : AppShortcutRepository {
private val scope = CoroutineScope(Dispatchers.Default + Job()) private val scope = CoroutineScope(Dispatchers.Default + Job())
@ -213,9 +216,9 @@ internal class AppShortcutRepositoryImpl(
val launcherApps = context.getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps val launcherApps = context.getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps
if (!launcherApps.hasShortcutHostPermission()) return emptyList() if (!launcherApps.hasShortcutHostPermission()) return emptyList()
val results = mutableListOf<AppShortcutConfigActivity>() val results = mutableListOf<AppShortcutConfigActivity>()
val profiles = launcherApps.profiles val profiles = profileManager.activeProfiles.first()
for (profile in profiles) { for (profile in profiles) {
val activities = launcherApps.getShortcutConfigActivityList(null, profile) val activities = launcherApps.getShortcutConfigActivityList(null, profile.userHandle)
results.addAll( results.addAll(
activities.map { activities.map {
AppShortcutConfigActivity(it) AppShortcutConfigActivity(it)

View File

@ -8,7 +8,7 @@ import org.koin.core.qualifier.named
import org.koin.dsl.module import org.koin.dsl.module
val appShortcutsModule = module { val appShortcutsModule = module {
factory<AppShortcutRepository> { AppShortcutRepositoryImpl(androidContext(), get(), get()) } factory<AppShortcutRepository> { AppShortcutRepositoryImpl(androidContext(), get(), get(), get()) }
factory<SearchableRepository<AppShortcut>>(named<AppShortcut>()) { get<AppShortcutRepository>() } factory<SearchableRepository<AppShortcut>>(named<AppShortcut>()) { get<AppShortcutRepository>() }
factory<SearchableDeserializer>(named(LauncherShortcut.Domain)) { LauncherShortcutDeserializer(androidContext()) } factory<SearchableDeserializer>(named(LauncherShortcut.Domain)) { LauncherShortcutDeserializer(androidContext()) }
factory<SearchableDeserializer>(named(LegacyShortcut.Domain)) { LegacyShortcutDeserializer(androidContext()) } factory<SearchableDeserializer>(named(LegacyShortcut.Domain)) { LegacyShortcutDeserializer(androidContext()) }

View File

@ -23,6 +23,6 @@ hero:
<img src="/img/screenshot-5.png"></img> <img src="/img/screenshot-5.png"></img>
<img src="/img/screenshot-6.png"></img> <img src="/img/screenshot-6.png"></img>
<div class="credits">Wallpaper by Allec Gomes on <a href="https://unsplash.com/de/fotos/ein-grunes-blatt-das-auf-einem-gewasser-schwimmt-UcWUMqIsld8" target="_blank">Unspash.com</a></div> <div class="credits">Wallpaper by Allec Gomes on <a href="https://unsplash.com/de/fotos/ein-grunes-blatt-das-auf-einem-gewasser-schwimmt-UcWUMqIsld8" target="_blank">Unsplash.com</a></div>
</div> </div>
<Footer></Footer> <Footer></Footer>

View File

@ -33,6 +33,7 @@ class WidgetsService(
for (profile in profiles) { for (profile in profiles) {
widgets.addAll(appWidgetManager.getInstalledProvidersForProfile(profile)) widgets.addAll(appWidgetManager.getInstalledProvidersForProfile(profile))
} }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
// Ignore widgets that the launcher is not supposed to access // Ignore widgets that the launcher is not supposed to access
widgets.filter { widgets.filter {
@ -41,7 +42,6 @@ class WidgetsService(
} else { } else {
widgets widgets
} }
widgets
} }
fun getAvailableBuiltInWidgets(): Flow<List<BuiltInWidgetInfo>> { fun getAvailableBuiltInWidgets(): Flow<List<BuiltInWidgetInfo>> {