Add assistant activity

This commit is contained in:
MM20 2022-09-03 16:18:49 +02:00
parent 56e08ab02c
commit 2d60797830
No known key found for this signature in database
GPG Key ID: 0B61A8F2DEAFA389
4 changed files with 245 additions and 221 deletions

View File

@ -24,19 +24,29 @@
<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/debug_shortcuts" />
</activity>
<activity
android:name=".assistant.AssistantActivity"
android:excludeFromRecents="true"
android:exported="true"
android:launchMode="singleTask"
android:theme="@style/LauncherTheme"
android:stateNotNeeded="true"
android:resumeWhilePausing="true"
android:windowSoftInputMode="stateHidden|adjustResize">
<intent-filter>
<action android:name="android.intent.action.ASSIST" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name=".settings.SettingsActivity"
android:exported="true"
android:label="@string/settings"
android:launchMode="singleTask"
android:parentActivityName=".launcher.LauncherActivity"
android:parentActivityName=".launcher.SharedLauncherActivity"
android:taskAffinity="de.mm20.launcher2.settings"
android:theme="@style/SettingsTheme.NoActionBar">
<intent-filter>
@ -45,20 +55,20 @@
</intent-filter>
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="de.mm20.launcher2.ui.launcher.LauncherActivity" />
android:value="de.mm20.launcher2.ui.launcher.SharedLauncherActivity" />
</activity>
<activity
android:name=".launcher.widgets.picker.PickAppWidgetActivity"
android:exported="true"
android:launchMode="singleTask"
android:parentActivityName=".launcher.LauncherActivity"
android:parentActivityName=".launcher.SharedLauncherActivity"
android:screenOrientation="portrait"
android:taskAffinity="de.mm20.launcher2.settings"
android:theme="@style/SettingsTheme.NoActionBar">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="de.mm20.launcher2.ui.launcher.LauncherActivity" />
android:value="de.mm20.launcher2.ui.launcher.SharedLauncherActivity" />
</activity>
</application>

View File

@ -0,0 +1,5 @@
package de.mm20.launcher2.ui.assistant
import de.mm20.launcher2.ui.launcher.SharedLauncherActivity
class AssistantActivity: SharedLauncherActivity(LauncherActivityMode.Assistant)

View File

@ -1,214 +1,4 @@
package de.mm20.launcher2.ui.launcher
import android.app.WallpaperManager
import android.content.Intent
import android.content.res.Configuration
import android.content.res.Resources
import android.os.Bundle
import android.util.Log
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.gestures.forEachGesture
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.*
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.pointerInput
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsControllerCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.flowWithLifecycle
import com.afollestad.materialdialogs.LayoutMode
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.bottomsheets.BottomSheet
import com.afollestad.materialdialogs.callbacks.onDismiss
import com.afollestad.materialdialogs.customview.customView
import com.android.launcher3.GestureNavContract
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import de.mm20.launcher2.preferences.Settings
import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.base.BaseActivity
import de.mm20.launcher2.ui.base.ProvideCurrentTime
import de.mm20.launcher2.ui.base.ProvideSettings
import de.mm20.launcher2.ui.component.NavBarEffects
import de.mm20.launcher2.ui.ktx.animateTo
import de.mm20.launcher2.ui.launcher.modals.EditFavoritesView
import de.mm20.launcher2.ui.launcher.transitions.HomeTransitionManager
import de.mm20.launcher2.ui.launcher.transitions.LocalHomeTransitionManager
import de.mm20.launcher2.ui.locals.LocalSnackbarHostState
import de.mm20.launcher2.ui.locals.LocalWindowSize
import de.mm20.launcher2.ui.theme.LauncherTheme
class LauncherActivity : BaseActivity() {
private val viewModel: LauncherActivityVM by viewModels()
private val homeTransitionManager = HomeTransitionManager()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val wallpaperManager = WallpaperManager.getInstance(this)
val windowSize = Resources.getSystem().displayMetrics.let {
Size(it.widthPixels.toFloat(), it.heightPixels.toFloat())
}
WindowCompat.setDecorFitsSystemWindows(window, false)
viewModel.setDarkMode(resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES)
setContent {
val snackbarHostState = remember { SnackbarHostState() }
CompositionLocalProvider(
LocalHomeTransitionManager provides homeTransitionManager,
LocalWindowSize provides windowSize,
LocalSnackbarHostState provides snackbarHostState
) {
LauncherTheme {
ProvideCurrentTime {
ProvideSettings {
val lightStatus by viewModel.lightStatusBar.observeAsState(false)
val lightNav by viewModel.lightNavBar.observeAsState(false)
val hideStatus by viewModel.hideStatusBar.observeAsState(false)
val hideNav by viewModel.hideNavBar.observeAsState(false)
val dimBackground by viewModel.dimBackground.observeAsState(false)
val layout by viewModel.layout.observeAsState(null)
val systemUiController = rememberSystemUiController()
val enterTransition = remember { mutableStateOf(1f) }
LaunchedEffect(null) {
homeTransitionManager
.currentTransition
.flowWithLifecycle(lifecycle, Lifecycle.State.RESUMED)
.collect {
enterTransition.value = 0f
enterTransition.animateTo(1f)
}
}
LaunchedEffect(hideStatus) {
systemUiController.isStatusBarVisible = !hideStatus
}
LaunchedEffect(hideNav) {
systemUiController.isNavigationBarVisible = !hideNav
}
Box(
modifier = Modifier
.fillMaxSize()
.pointerInput(null) {
detectTapGestures {
wallpaperManager?.sendWallpaperCommand(
window.decorView.applicationWindowToken,
WallpaperManager.COMMAND_TAP,
it.x.toInt(),
it.y.toInt(),
0,
null
)
}
}
.background(if (dimBackground) Color.Black.copy(alpha = 0.30f) else Color.Transparent),
contentAlignment = Alignment.BottomCenter
) {
NavBarEffects(modifier = Modifier.fillMaxSize())
when (layout) {
Settings.AppearanceSettings.Layout.PullDown -> {
PullDownScaffold(
modifier = Modifier
.fillMaxSize()
.graphicsLayer {
scaleX = 0.5f + enterTransition.value * 0.5f
scaleY = 0.5f + enterTransition.value * 0.5f
alpha = enterTransition.value
},
darkStatusBarIcons = lightStatus,
darkNavBarIcons = lightNav,
)
}
Settings.AppearanceSettings.Layout.Pager,
Settings.AppearanceSettings.Layout.PagerReversed -> {
PagerScaffold(
modifier = Modifier
.fillMaxSize()
.graphicsLayer {
scaleX = enterTransition.value
scaleY = enterTransition.value
alpha = enterTransition.value
},
darkStatusBarIcons = lightStatus,
darkNavBarIcons = lightNav,
reverse = layout == Settings.AppearanceSettings.Layout.PagerReversed
)
}
else -> {}
}
SnackbarHost(
snackbarHostState,
modifier = Modifier
.navigationBarsPadding()
.imePadding()
)
}
}
}
}
}
}
var editFavoritesDialog: MaterialDialog? = null
viewModel.isEditFavoritesShown.observe(this) {
if (it) {
val view = EditFavoritesView(this@LauncherActivity)
editFavoritesDialog =
MaterialDialog(this, BottomSheet(LayoutMode.MATCH_PARENT)).show {
customView(view = view)
title(res = R.string.menu_item_edit_favs)
positiveButton(res = R.string.close) {
viewModel.hideEditFavorites()
it.dismiss()
}
onDismiss {
view.save()
viewModel.hideEditFavorites()
}
}
} else {
editFavoritesDialog?.dismiss()
editFavoritesDialog = null
}
}
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
val windowController = WindowCompat.getInsetsController(window, window.decorView.rootView)
windowController.systemBarsBehavior =
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
}
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
val navContract = intent?.let { GestureNavContract.fromIntent(it) }
if (navContract != null) {
homeTransitionManager.resolve(navContract)
} else {
onBackPressed()
}
}
}
class LauncherActivity: SharedLauncherActivity(LauncherActivityMode.Launcher)

View File

@ -0,0 +1,219 @@
package de.mm20.launcher2.ui.launcher
import android.app.WallpaperManager
import android.content.Intent
import android.content.res.Configuration
import android.content.res.Resources
import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.*
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.pointerInput
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsControllerCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.flowWithLifecycle
import com.afollestad.materialdialogs.LayoutMode
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.bottomsheets.BottomSheet
import com.afollestad.materialdialogs.callbacks.onDismiss
import com.afollestad.materialdialogs.customview.customView
import com.android.launcher3.GestureNavContract
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import de.mm20.launcher2.preferences.Settings
import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.base.BaseActivity
import de.mm20.launcher2.ui.base.ProvideCurrentTime
import de.mm20.launcher2.ui.base.ProvideSettings
import de.mm20.launcher2.ui.component.NavBarEffects
import de.mm20.launcher2.ui.ktx.animateTo
import de.mm20.launcher2.ui.launcher.modals.EditFavoritesView
import de.mm20.launcher2.ui.launcher.transitions.HomeTransitionManager
import de.mm20.launcher2.ui.launcher.transitions.LocalHomeTransitionManager
import de.mm20.launcher2.ui.locals.LocalSnackbarHostState
import de.mm20.launcher2.ui.locals.LocalWindowSize
import de.mm20.launcher2.ui.theme.LauncherTheme
abstract class SharedLauncherActivity(
private val mode: LauncherActivityMode
) : BaseActivity() {
private val viewModel: LauncherActivityVM by viewModels()
private val homeTransitionManager = HomeTransitionManager()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val wallpaperManager = WallpaperManager.getInstance(this)
val windowSize = Resources.getSystem().displayMetrics.let {
Size(it.widthPixels.toFloat(), it.heightPixels.toFloat())
}
WindowCompat.setDecorFitsSystemWindows(window, false)
viewModel.setDarkMode(resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES)
setContent {
val snackbarHostState = remember { SnackbarHostState() }
CompositionLocalProvider(
LocalHomeTransitionManager provides homeTransitionManager,
LocalWindowSize provides windowSize,
LocalSnackbarHostState provides snackbarHostState
) {
LauncherTheme {
ProvideCurrentTime {
ProvideSettings {
val lightStatus by viewModel.lightStatusBar.observeAsState(false)
val lightNav by viewModel.lightNavBar.observeAsState(false)
val hideStatus by viewModel.hideStatusBar.observeAsState(false)
val hideNav by viewModel.hideNavBar.observeAsState(false)
val dimBackground by viewModel.dimBackground.observeAsState(false)
val layout by viewModel.layout.observeAsState(null)
val systemUiController = rememberSystemUiController()
val enterTransition = remember { mutableStateOf(1f) }
LaunchedEffect(null) {
homeTransitionManager
.currentTransition
.flowWithLifecycle(lifecycle, Lifecycle.State.RESUMED)
.collect {
enterTransition.value = 0f
enterTransition.animateTo(1f)
}
}
LaunchedEffect(hideStatus) {
systemUiController.isStatusBarVisible = !hideStatus
}
LaunchedEffect(hideNav) {
systemUiController.isNavigationBarVisible = !hideNav
}
Box(
modifier = Modifier
.fillMaxSize()
.pointerInput(null) {
detectTapGestures {
wallpaperManager?.sendWallpaperCommand(
window.decorView.applicationWindowToken,
WallpaperManager.COMMAND_TAP,
it.x.toInt(),
it.y.toInt(),
0,
null
)
}
}
.background(if (dimBackground) Color.Black.copy(alpha = 0.30f) else Color.Transparent),
contentAlignment = Alignment.BottomCenter
) {
NavBarEffects(modifier = Modifier.fillMaxSize())
when (layout) {
Settings.AppearanceSettings.Layout.PullDown -> {
PullDownScaffold(
modifier = Modifier
.fillMaxSize()
.graphicsLayer {
scaleX = 0.5f + enterTransition.value * 0.5f
scaleY = 0.5f + enterTransition.value * 0.5f
alpha = enterTransition.value
},
darkStatusBarIcons = lightStatus,
darkNavBarIcons = lightNav,
)
}
Settings.AppearanceSettings.Layout.Pager,
Settings.AppearanceSettings.Layout.PagerReversed -> {
PagerScaffold(
modifier = Modifier
.fillMaxSize()
.graphicsLayer {
scaleX = enterTransition.value
scaleY = enterTransition.value
alpha = enterTransition.value
},
darkStatusBarIcons = lightStatus,
darkNavBarIcons = lightNav,
reverse = layout == Settings.AppearanceSettings.Layout.PagerReversed
)
}
else -> {}
}
SnackbarHost(
snackbarHostState,
modifier = Modifier
.navigationBarsPadding()
.imePadding()
)
}
}
}
}
}
}
var editFavoritesDialog: MaterialDialog? = null
viewModel.isEditFavoritesShown.observe(this) {
if (it) {
val view = EditFavoritesView(this@SharedLauncherActivity)
editFavoritesDialog =
MaterialDialog(this, BottomSheet(LayoutMode.MATCH_PARENT)).show {
customView(view = view)
title(res = R.string.menu_item_edit_favs)
positiveButton(res = R.string.close) {
viewModel.hideEditFavorites()
it.dismiss()
}
onDismiss {
view.save()
viewModel.hideEditFavorites()
}
}
} else {
editFavoritesDialog?.dismiss()
editFavoritesDialog = null
}
}
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
val windowController = WindowCompat.getInsetsController(window, window.decorView.rootView)
windowController.systemBarsBehavior =
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
}
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
val navContract = intent?.let { GestureNavContract.fromIntent(it) }
if (navContract != null) {
homeTransitionManager.resolve(navContract)
} else {
onBackPressed()
}
}
enum class LauncherActivityMode {
Launcher,
Assistant
}
}