blob: 389f8f6264983a95ff71a0b1b326d48cef22e5a8 [file] [log] [blame]
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.android.customization.picker.quickaffordance.ui.binder
import android.app.AlertDialog
import android.app.Dialog
import android.content.Context
import android.graphics.Rect
import android.view.LayoutInflater
import android.view.View
import androidx.core.view.ViewCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.android.customization.picker.quickaffordance.ui.adapter.AffordancesAdapter
import com.android.customization.picker.quickaffordance.ui.adapter.SlotTabAdapter
import com.android.customization.picker.quickaffordance.ui.viewmodel.KeyguardQuickAffordancePickerViewModel
import com.android.wallpaper.R
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
object KeyguardQuickAffordancePickerBinder {
/** Binds view with view-model for a lock screen quick affordance picker experience. */
@JvmStatic
fun bind(
view: View,
viewModel: KeyguardQuickAffordancePickerViewModel,
lifecycleOwner: LifecycleOwner,
) {
val slotTabView: RecyclerView = view.requireViewById(R.id.slot_tabs)
val affordancesView: RecyclerView = view.requireViewById(R.id.affordances)
val slotTabAdapter = SlotTabAdapter()
slotTabView.adapter = slotTabAdapter
slotTabView.layoutManager =
LinearLayoutManager(view.context, RecyclerView.HORIZONTAL, false)
slotTabView.addItemDecoration(ItemSpacing())
val affordancesAdapter = AffordancesAdapter()
affordancesView.adapter = affordancesAdapter
affordancesView.layoutManager =
LinearLayoutManager(view.context, RecyclerView.HORIZONTAL, false)
affordancesView.addItemDecoration(ItemSpacing())
var dialog: Dialog? = null
lifecycleOwner.lifecycleScope.launch {
lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
launch {
viewModel.slots
.map { slotById -> slotById.values }
.collect { slots -> slotTabAdapter.setItems(slots.toList()) }
}
launch {
viewModel.quickAffordances.collect { affordances ->
affordancesAdapter.setItems(affordances)
}
}
launch {
viewModel.dialog.distinctUntilChanged().collect { dialogRequest ->
dialog?.dismiss()
dialog =
if (dialogRequest != null) {
showDialog(
context = view.context,
request = dialogRequest,
onDismissed = viewModel::onDialogDismissed
)
} else {
null
}
}
}
}
}
}
private fun showDialog(
context: Context,
request: KeyguardQuickAffordancePickerViewModel.DialogViewModel,
onDismissed: () -> Unit,
): Dialog {
val view: View =
LayoutInflater.from(context)
.inflate(
R.layout.keyguard_quick_affordance_enablement_dialog,
null,
)
KeyguardQuickAffordanceEnablementDialogBinder.bind(
view = view,
viewModel = request,
onDismissed = onDismissed,
)
return AlertDialog.Builder(context, R.style.LightDialogTheme)
.setView(view)
.setOnDismissListener { onDismissed() }
.show()
}
private class ItemSpacing : RecyclerView.ItemDecoration() {
override fun getItemOffsets(outRect: Rect, itemPosition: Int, parent: RecyclerView) {
val addSpacingToStart = itemPosition > 0
val addSpacingToEnd = itemPosition < (parent.adapter?.itemCount ?: 0) - 1
val isRtl = parent.layoutManager?.layoutDirection == ViewCompat.LAYOUT_DIRECTION_RTL
val density = parent.context.resources.displayMetrics.density
if (!isRtl) {
outRect.left = if (addSpacingToStart) ITEM_SPACING_DP.toPx(density) else 0
outRect.right = if (addSpacingToEnd) ITEM_SPACING_DP.toPx(density) else 0
} else {
outRect.left = if (addSpacingToEnd) ITEM_SPACING_DP.toPx(density) else 0
outRect.right = if (addSpacingToStart) ITEM_SPACING_DP.toPx(density) else 0
}
}
private fun Int.toPx(density: Float): Int {
return (this * density).toInt()
}
companion object {
private const val ITEM_SPACING_DP = 8
}
}
}