Fix permission banners in search results
This commit is contained in:
parent
7a48a148ff
commit
b8304f1c1c
@ -477,4 +477,5 @@
|
||||
<string name="no_account_microsoft">Sie haben noch kein Microsoft-Konto verbunden</string>
|
||||
<string name="no_account_google">Sie haben noch kein Google-Konto verbunden</string>
|
||||
<string name="connect_account">Konto verbinden</string>
|
||||
<string name="turn_off">Deaktivieren</string>
|
||||
</resources>
|
||||
@ -516,4 +516,6 @@
|
||||
<string name="no_account_microsoft">You haven\'t connected a Microsoft account yet</string>
|
||||
<string name="no_account_google">You haven\'t connected a Google account yet</string>
|
||||
<string name="connect_account">Connect account</string>
|
||||
|
||||
<string name="turn_off">Turn off</string>
|
||||
</resources>
|
||||
|
||||
@ -7,7 +7,12 @@ import de.mm20.launcher2.icons.LauncherIcon
|
||||
import de.mm20.launcher2.permissions.PermissionGroup
|
||||
import de.mm20.launcher2.permissions.R
|
||||
|
||||
class MissingPermission(override val label: String, val permissionGroup: PermissionGroup): Searchable() {
|
||||
class MissingPermission(
|
||||
override val label: String,
|
||||
val permissionGroup: PermissionGroup,
|
||||
val secondaryActionLabel: String? = null,
|
||||
val secondaryAction: (() -> Unit)? = null
|
||||
): Searchable() {
|
||||
override val key: String
|
||||
get() = "permission://${permissionGroup.ordinal}"
|
||||
|
||||
|
||||
@ -8,15 +8,19 @@ import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MediatorLiveData
|
||||
import androidx.lifecycle.asLiveData
|
||||
import de.mm20.launcher2.ktx.lifecycleScope
|
||||
import de.mm20.launcher2.permissions.PermissionGroup
|
||||
import de.mm20.launcher2.permissions.PermissionsManager
|
||||
import de.mm20.launcher2.preferences.LauncherPreferences
|
||||
import de.mm20.launcher2.search.data.CalendarEvent
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.search.data.MissingPermission
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.launcher.search.SearchVM
|
||||
import de.mm20.launcher2.ui.legacy.search.SearchListView
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.get
|
||||
|
||||
@ -30,40 +34,84 @@ class CalendarView : FrameLayout, KoinComponent {
|
||||
defStyleRes
|
||||
)
|
||||
|
||||
private val calendarEvents: LiveData<List<CalendarEvent>?>
|
||||
|
||||
init {
|
||||
val permissionsManager: PermissionsManager = get()
|
||||
val dataStore: LauncherDataStore = get()
|
||||
View.inflate(context, R.layout.view_search_category_list, this)
|
||||
layoutTransition = LayoutTransition()
|
||||
layoutTransition.enableTransitionType(LayoutTransition.CHANGING)
|
||||
val card = findViewById<ViewGroup>(R.id.card)
|
||||
card.layoutTransition.enableTransitionType(LayoutTransition.CHANGING)
|
||||
val list = findViewById<SearchListView>(R.id.list)
|
||||
val viewModel: SearchVM by (context as AppCompatActivity).viewModels()
|
||||
calendarEvents = viewModel.calendarResults
|
||||
calendarEvents.observe(context as AppCompatActivity, {
|
||||
if (it == null) {
|
||||
visibility = View.GONE
|
||||
return@observe
|
||||
|
||||
val showMissingPermissionBanner = combine(
|
||||
dataStore.data.map { it.calendarSearch.enabled },
|
||||
permissionsManager.hasPermission(PermissionGroup.Calendar)
|
||||
) { calendarSearchEnabled, hasPermission ->
|
||||
!hasPermission && calendarSearchEnabled
|
||||
}.asLiveData()
|
||||
|
||||
val searchQuery = viewModel.searchQuery
|
||||
val calendarResults = viewModel.calendarResults
|
||||
|
||||
val show = MediatorLiveData<Boolean>()
|
||||
show.addSource(showMissingPermissionBanner) {
|
||||
show.value = !searchQuery.value.isNullOrBlank() &&
|
||||
(showMissingPermissionBanner.value == true || !calendarResults.value.isNullOrEmpty())
|
||||
}
|
||||
show.addSource(calendarResults) {
|
||||
show.value = !searchQuery.value.isNullOrBlank() &&
|
||||
(showMissingPermissionBanner.value == true || !calendarResults.value.isNullOrEmpty())
|
||||
}
|
||||
show.addSource(searchQuery) {
|
||||
show.value = !searchQuery.value.isNullOrBlank() &&
|
||||
(showMissingPermissionBanner.value == true || !calendarResults.value.isNullOrEmpty())
|
||||
}
|
||||
|
||||
show.observe(context as AppCompatActivity) {
|
||||
visibility = if (it) {
|
||||
View.VISIBLE
|
||||
} else {
|
||||
View.GONE
|
||||
}
|
||||
if (it.isEmpty() && LauncherPreferences.instance.searchCalendars && !permissionsManager.checkPermissionOnce(
|
||||
PermissionGroup.Calendar
|
||||
)
|
||||
) {
|
||||
visibility = View.VISIBLE
|
||||
list.submitItems(
|
||||
listOf(
|
||||
MissingPermission(
|
||||
context.getString(R.string.permission_calendar_search),
|
||||
PermissionGroup.Calendar
|
||||
)
|
||||
}
|
||||
|
||||
val list = findViewById<SearchListView>(R.id.list)
|
||||
calendarResults.observe(context as AppCompatActivity) {
|
||||
if (showMissingPermissionBanner.value == true) {
|
||||
list.submitItems(listOf(
|
||||
MissingPermission(
|
||||
context.getString(R.string.permission_calendar_search),
|
||||
PermissionGroup.Calendar,
|
||||
secondaryActionLabel = context.getString(R.string.turn_off),
|
||||
secondaryAction = {
|
||||
lifecycleScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setCalendarSearch(it.calendarSearch.toBuilder().setEnabled(false))
|
||||
.build()
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
return@observe
|
||||
) + it)
|
||||
} else {
|
||||
list.submitItems(it)
|
||||
}
|
||||
visibility = if (it.isEmpty()) View.GONE else View.VISIBLE
|
||||
list.submitItems(it)
|
||||
})
|
||||
}
|
||||
|
||||
showMissingPermissionBanner.observe(context as AppCompatActivity) {
|
||||
if (it == true) {
|
||||
list.submitItems(listOf(
|
||||
MissingPermission(
|
||||
context.getString(R.string.permission_calendar_search),
|
||||
PermissionGroup.Calendar,
|
||||
secondaryActionLabel = context.getString(R.string.turn_off)
|
||||
)
|
||||
) + calendarResults.value!!)
|
||||
} else {
|
||||
list.submitItems(calendarResults.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -8,20 +8,23 @@ import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MediatorLiveData
|
||||
import androidx.lifecycle.asLiveData
|
||||
import de.mm20.launcher2.ktx.lifecycleScope
|
||||
import de.mm20.launcher2.permissions.PermissionGroup
|
||||
import de.mm20.launcher2.permissions.PermissionsManager
|
||||
import de.mm20.launcher2.preferences.LauncherPreferences
|
||||
import de.mm20.launcher2.search.data.Contact
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.search.data.MissingPermission
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.launcher.search.SearchVM
|
||||
import de.mm20.launcher2.ui.legacy.search.SearchListView
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.get
|
||||
|
||||
class ContactView : FrameLayout, KoinComponent {
|
||||
private val contacts: LiveData<List<Contact>?>
|
||||
|
||||
constructor(context: Context) : super(context)
|
||||
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
|
||||
@ -33,36 +36,82 @@ class ContactView : FrameLayout, KoinComponent {
|
||||
|
||||
init {
|
||||
val permissionsManager: PermissionsManager = get()
|
||||
val dataStore: LauncherDataStore = get()
|
||||
View.inflate(context, R.layout.view_search_category_list, this)
|
||||
layoutTransition = LayoutTransition()
|
||||
layoutTransition.enableTransitionType(LayoutTransition.CHANGING)
|
||||
val card = findViewById<ViewGroup>(R.id.card)
|
||||
card.layoutTransition.enableTransitionType(LayoutTransition.CHANGING)
|
||||
val viewModel: SearchVM by (context as AppCompatActivity).viewModels()
|
||||
contacts = viewModel.contactResults
|
||||
|
||||
val showMissingPermissionBanner = combine(
|
||||
dataStore.data.map { it.contactsSearch.enabled },
|
||||
permissionsManager.hasPermission(PermissionGroup.Contacts)
|
||||
) { contactSearchEnabled, hasPermission ->
|
||||
!hasPermission && contactSearchEnabled
|
||||
}.asLiveData()
|
||||
|
||||
val searchQuery = viewModel.searchQuery
|
||||
val contactResults = viewModel.contactResults
|
||||
|
||||
val show = MediatorLiveData<Boolean>()
|
||||
show.addSource(showMissingPermissionBanner) {
|
||||
show.value = !searchQuery.value.isNullOrBlank() &&
|
||||
(showMissingPermissionBanner.value == true || !contactResults.value.isNullOrEmpty())
|
||||
}
|
||||
show.addSource(contactResults) {
|
||||
show.value = !searchQuery.value.isNullOrBlank() &&
|
||||
(showMissingPermissionBanner.value == true || !contactResults.value.isNullOrEmpty())
|
||||
}
|
||||
show.addSource(searchQuery) {
|
||||
show.value = !searchQuery.value.isNullOrBlank() &&
|
||||
(showMissingPermissionBanner.value == true || !contactResults.value.isNullOrEmpty())
|
||||
}
|
||||
|
||||
show.observe(context as AppCompatActivity) {
|
||||
visibility = if (it) {
|
||||
View.VISIBLE
|
||||
} else {
|
||||
View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
val list = findViewById<SearchListView>(R.id.list)
|
||||
contacts.observe(context as AppCompatActivity, {
|
||||
if (it == null) {
|
||||
visibility = View.GONE
|
||||
return@observe
|
||||
}
|
||||
if (it.isEmpty() && LauncherPreferences.instance.searchContacts && !permissionsManager.checkPermissionOnce(
|
||||
PermissionGroup.Contacts
|
||||
)
|
||||
) {
|
||||
visibility = View.VISIBLE
|
||||
list.submitItems(
|
||||
listOf(
|
||||
MissingPermission(
|
||||
context.getString(R.string.permission_contact_search),
|
||||
PermissionGroup.Contacts
|
||||
)
|
||||
contactResults.observe(context as AppCompatActivity) {
|
||||
if (showMissingPermissionBanner.value == true) {
|
||||
list.submitItems(listOf(
|
||||
MissingPermission(
|
||||
context.getString(R.string.permission_contact_search),
|
||||
PermissionGroup.Contacts,
|
||||
secondaryActionLabel = context.getString(R.string.turn_off),
|
||||
secondaryAction = {
|
||||
lifecycleScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setContactsSearch(it.contactsSearch.toBuilder().setEnabled(false))
|
||||
.build()
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
return@observe
|
||||
) + it)
|
||||
} else {
|
||||
list.submitItems(it)
|
||||
}
|
||||
visibility = if (it.isEmpty()) View.GONE else View.VISIBLE
|
||||
list.submitItems(it)
|
||||
})
|
||||
}
|
||||
|
||||
showMissingPermissionBanner.observe(context as AppCompatActivity) {
|
||||
if (it == true) {
|
||||
list.submitItems(listOf(
|
||||
MissingPermission(
|
||||
context.getString(R.string.permission_contact_search),
|
||||
PermissionGroup.Contacts,
|
||||
secondaryActionLabel = context.getString(R.string.turn_off)
|
||||
)
|
||||
) + contactResults.value!!)
|
||||
} else {
|
||||
list.submitItems(contactResults.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -9,18 +9,24 @@ import android.widget.FrameLayout
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MediatorLiveData
|
||||
import androidx.lifecycle.asLiveData
|
||||
import de.mm20.launcher2.ktx.lifecycleScope
|
||||
import de.mm20.launcher2.permissions.PermissionGroup
|
||||
import de.mm20.launcher2.permissions.PermissionsManager
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.search.data.File
|
||||
import de.mm20.launcher2.search.data.MissingPermission
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.launcher.search.SearchVM
|
||||
import de.mm20.launcher2.ui.legacy.search.SearchListView
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.get
|
||||
|
||||
class FileView : FrameLayout, KoinComponent {
|
||||
private val files: LiveData<List<File>?>
|
||||
|
||||
constructor(context: Context) : super(context)
|
||||
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
|
||||
@ -32,36 +38,82 @@ class FileView : FrameLayout, KoinComponent {
|
||||
|
||||
init {
|
||||
val permissionsManager: PermissionsManager = get()
|
||||
val dataStore: LauncherDataStore = get()
|
||||
View.inflate(context, R.layout.view_search_category_list, this)
|
||||
layoutTransition = LayoutTransition()
|
||||
layoutTransition.enableTransitionType(LayoutTransition.CHANGING)
|
||||
val card = findViewById<ViewGroup>(R.id.card)
|
||||
card.layoutTransition.enableTransitionType(LayoutTransition.CHANGING)
|
||||
val list = findViewById<SearchListView>(R.id.list)
|
||||
val viewModel: SearchVM by (context as AppCompatActivity).viewModels()
|
||||
files = viewModel.fileResults
|
||||
files.observe(context as AppCompatActivity, {
|
||||
if (it == null) {
|
||||
visibility = View.GONE
|
||||
return@observe
|
||||
|
||||
val showMissingPermissionBanner = combine(
|
||||
dataStore.data.map { it.fileSearch.localFiles },
|
||||
permissionsManager.hasPermission(PermissionGroup.ExternalStorage)
|
||||
) { localFileSearchEnabled, hasPermission ->
|
||||
!hasPermission && localFileSearchEnabled
|
||||
}.asLiveData()
|
||||
|
||||
val searchQuery = viewModel.searchQuery
|
||||
val fileResults = viewModel.fileResults
|
||||
|
||||
val show = MediatorLiveData<Boolean>()
|
||||
show.addSource(showMissingPermissionBanner) {
|
||||
show.value = !searchQuery.value.isNullOrBlank() &&
|
||||
(showMissingPermissionBanner.value == true || !fileResults.value.isNullOrEmpty())
|
||||
}
|
||||
show.addSource(fileResults) {
|
||||
show.value = !searchQuery.value.isNullOrBlank() &&
|
||||
(showMissingPermissionBanner.value == true || !fileResults.value.isNullOrEmpty())
|
||||
}
|
||||
show.addSource(searchQuery) {
|
||||
show.value = !searchQuery.value.isNullOrBlank() &&
|
||||
(showMissingPermissionBanner.value == true || !fileResults.value.isNullOrEmpty())
|
||||
}
|
||||
|
||||
show.observe(context as AppCompatActivity) {
|
||||
visibility = if (it) {
|
||||
View.VISIBLE
|
||||
} else {
|
||||
View.GONE
|
||||
}
|
||||
if (it.isEmpty() && !permissionsManager.checkPermissionOnce(
|
||||
PermissionGroup.ExternalStorage
|
||||
)
|
||||
) {
|
||||
visibility = View.VISIBLE
|
||||
list.submitItems(
|
||||
listOf(
|
||||
MissingPermission(
|
||||
context.getString(R.string.permission_files_search),
|
||||
PermissionGroup.ExternalStorage
|
||||
)
|
||||
}
|
||||
|
||||
val list = findViewById<SearchListView>(R.id.list)
|
||||
fileResults.observe(context as AppCompatActivity) {
|
||||
if (showMissingPermissionBanner.value == true) {
|
||||
list.submitItems(listOf(
|
||||
MissingPermission(
|
||||
context.getString(R.string.permission_files_search),
|
||||
PermissionGroup.ExternalStorage,
|
||||
secondaryActionLabel = context.getString(R.string.turn_off),
|
||||
secondaryAction = {
|
||||
lifecycleScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder()
|
||||
.setFileSearch(it.fileSearch.toBuilder().setLocalFiles(false))
|
||||
.build()
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
return@observe
|
||||
) + it)
|
||||
} else {
|
||||
list.submitItems(it)
|
||||
}
|
||||
visibility = if (it.isEmpty()) View.GONE else View.VISIBLE
|
||||
list.submitItems(it)
|
||||
})
|
||||
}
|
||||
|
||||
showMissingPermissionBanner.observe(context as AppCompatActivity) {
|
||||
if (it == true) {
|
||||
list.submitItems(listOf(
|
||||
MissingPermission(
|
||||
context.getString(R.string.permission_files_search),
|
||||
PermissionGroup.ExternalStorage,
|
||||
secondaryActionLabel = context.getString(R.string.turn_off)
|
||||
)
|
||||
) + fileResults.value!!)
|
||||
} else {
|
||||
list.submitItems(fileResults.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,30 +1,53 @@
|
||||
package de.mm20.launcher2.ui.legacy.search
|
||||
|
||||
import android.app.Activity
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.transition.Scene
|
||||
import de.mm20.launcher2.permissions.PermissionsManager
|
||||
import de.mm20.launcher2.search.data.MissingPermission
|
||||
import de.mm20.launcher2.search.data.Searchable
|
||||
import de.mm20.launcher2.ui.LegacyLauncherTheme
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.component.MissingPermissionBanner
|
||||
import de.mm20.launcher2.ui.legacy.searchable.SearchableView
|
||||
import de.mm20.launcher2.ui.legacy.view.InnerCardView
|
||||
import de.mm20.launcher2.ui.legacy.view.LauncherIconView
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.get
|
||||
|
||||
class PermissionListRepresentation : Representation, KoinComponent {
|
||||
override fun getScene(rootView: SearchableView, searchable: Searchable, previousRepresentation: Int?): Scene {
|
||||
override fun getScene(
|
||||
rootView: SearchableView,
|
||||
searchable: Searchable,
|
||||
previousRepresentation: Int?
|
||||
): Scene {
|
||||
val missingPermission = searchable as MissingPermission
|
||||
val context = rootView.context
|
||||
val scene = Scene.getSceneForLayout(rootView, R.layout.view_permission_list, rootView.context)
|
||||
val scene =
|
||||
Scene.getSceneForLayout(rootView, R.layout.view_permission_list, rootView.context)
|
||||
scene.setEnterAction {
|
||||
val permissionsManager: PermissionsManager = get()
|
||||
rootView.findViewById<TextView>(R.id.permissionText).text = missingPermission.label
|
||||
rootView.findViewById<LauncherIconView>(R.id.permissionIcon).icon = missingPermission.getPlaceholderIcon(context)
|
||||
rootView.findViewById<InnerCardView>(R.id.card).setOnClickListener {
|
||||
permissionsManager.requestPermission(context as AppCompatActivity, missingPermission.permissionGroup)
|
||||
rootView.findViewById<ComposeView>(R.id.composeView).setContent {
|
||||
LegacyLauncherTheme {
|
||||
MissingPermissionBanner(
|
||||
text = missingPermission.label,
|
||||
onClick = {
|
||||
permissionsManager.requestPermission(
|
||||
context as AppCompatActivity,
|
||||
missingPermission.permissionGroup
|
||||
)
|
||||
},
|
||||
secondaryAction = {
|
||||
val secondaryAction = missingPermission.secondaryAction
|
||||
val secondaryActionLabel = missingPermission.secondaryActionLabel
|
||||
if (secondaryAction != null && secondaryActionLabel != null)
|
||||
TextButton(onClick = secondaryAction) {
|
||||
Text(text = secondaryActionLabel, style = MaterialTheme.typography.labelLarge)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
return scene
|
||||
|
||||
@ -1,37 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<de.mm20.launcher2.ui.legacy.view.InnerCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/card"
|
||||
<androidx.compose.ui.platform.ComposeView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/composeView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="0dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:foreground="?selectableItemBackground"
|
||||
android:transitionName="root">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/permissionText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center_vertical"
|
||||
android:padding="12dp"
|
||||
android:layout_marginStart="56dp"
|
||||
android:textAppearance="?textAppearanceBodyMedium"
|
||||
app:layout_constraintBottom_toTopOf="@+id/guideline4"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/calendarColor"
|
||||
android:layout_gravity="center_vertical"
|
||||
tools:text="Information" />
|
||||
|
||||
<de.mm20.launcher2.ui.legacy.view.LauncherIconView
|
||||
android:id="@+id/permissionIcon"
|
||||
android:elevation="1dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_width="48dp"
|
||||
android:layout_margin="8dp"
|
||||
android:layout_height="48dp" />
|
||||
|
||||
</de.mm20.launcher2.ui.legacy.view.InnerCardView>
|
||||
android:transitionName="root" />
|
||||
Loading…
x
Reference in New Issue
Block a user