feat: 基础功能
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
package com.yuanxuan.rokid
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.KeyEvent
|
||||
import androidx.activity.addCallback
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
@@ -38,38 +38,44 @@ class MainActivity : AppCompatActivity() {
|
||||
* 拦截返回键事件,防止返回到桌面
|
||||
*/
|
||||
onBackPressedDispatcher.addCallback {
|
||||
if (AppDependencies.deviceServiceManager.instructState.value
|
||||
== DeviceServiceManager.InstructState.WaitingInstructState
|
||||
) {
|
||||
AppDependencies.deviceServiceManager.quitInstructReceived()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 触摸板事件
|
||||
* [KeyEvent.KEYCODE_DPAD_DOWN] 和 [KeyEvent.KEYCODE_DPAD_RIGHT] 同时响应
|
||||
* 所以直接消费掉一个
|
||||
*/
|
||||
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
|
||||
return if (event.action == KeyEvent.ACTION_DOWN) {
|
||||
when (event.keyCode) {
|
||||
KeyEvent.KEYCODE_DPAD_DOWN -> {
|
||||
true
|
||||
}
|
||||
|
||||
KeyEvent.KEYCODE_DPAD_UP -> {
|
||||
true
|
||||
}
|
||||
|
||||
else -> super.dispatchKeyEvent(event)
|
||||
}
|
||||
} else {
|
||||
super.dispatchKeyEvent(event)
|
||||
}
|
||||
}
|
||||
// /**
|
||||
// * 触摸板事件
|
||||
// * [KeyEvent.KEYCODE_DPAD_DOWN] 和 [KeyEvent.KEYCODE_DPAD_RIGHT] 同时响应
|
||||
// * 所以直接消费掉一个
|
||||
// */
|
||||
// override fun dispatchKeyEvent(event: KeyEvent): Boolean {
|
||||
// return if (event.action == KeyEvent.ACTION_DOWN) {
|
||||
// when (event.keyCode) {
|
||||
// KeyEvent.KEYCODE_DPAD_DOWN -> {
|
||||
// true
|
||||
// }
|
||||
//
|
||||
// KeyEvent.KEYCODE_DPAD_UP -> {
|
||||
// true
|
||||
// }
|
||||
//
|
||||
// KeyEvent.KEYCODE_DPAD_LEFT -> {
|
||||
// viewModel.onKeyEventDispatched(MainViewModel.KeyEvent.DpadLeft)
|
||||
// true
|
||||
// }
|
||||
//
|
||||
// KeyEvent.KEYCODE_DPAD_RIGHT -> {
|
||||
// viewModel.onKeyEventDispatched(MainViewModel.KeyEvent.DpadRight)
|
||||
// true
|
||||
// }
|
||||
//
|
||||
// else -> super.dispatchKeyEvent(event)
|
||||
// }
|
||||
// } else {
|
||||
// super.dispatchKeyEvent(event)
|
||||
// }
|
||||
// }
|
||||
|
||||
private fun observer() {
|
||||
lifecycleScope.launch {
|
||||
|
||||
@@ -42,6 +42,8 @@ class DeviceServiceManager(val context: Application) : ConnectivityManager.Netwo
|
||||
* 语音指令等待超时
|
||||
*/
|
||||
private const val INSTRUCT_WAITE_TIME = 15000L
|
||||
const val MAX_VOLUME = 15
|
||||
const val MAX_BRIGHTNESS = 15
|
||||
}
|
||||
|
||||
private var instructService: IInstructService? = null
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.yuanxuan.rokid.ui
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.KeyEvent
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.yuanxuan.rokid.R
|
||||
import com.yuanxuan.rokid.databinding.FragmentSettingBinding
|
||||
import com.yuanxuan.rokid.dependencies.AppDependencies
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class BrightnessFragment : Fragment() {
|
||||
|
||||
private lateinit var binding: FragmentSettingBinding
|
||||
private val viewModel by viewModels<SettingViewModel>()
|
||||
|
||||
private val adapter by lazy {
|
||||
SeekBarAdapter()
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
binding = FragmentSettingBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
binding.title.text = resources.getString(R.string.setting_brightness_title)
|
||||
binding.tip.text = resources.getString(R.string.setting_brightness_tip)
|
||||
|
||||
binding.recyclerView.adapter = adapter
|
||||
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
viewModel.brightnessFlow.collect { data ->
|
||||
adapter.submitList(data)
|
||||
}
|
||||
}
|
||||
|
||||
binding.root.requestFocus()
|
||||
binding.root.setOnKeyListener { _, _, event ->
|
||||
return@setOnKeyListener if (event.action == KeyEvent.ACTION_UP) {
|
||||
when (event.keyCode) {
|
||||
KeyEvent.KEYCODE_DPAD_RIGHT -> {
|
||||
AppDependencies.deviceServiceManager.brightnessAdd()
|
||||
true
|
||||
}
|
||||
|
||||
KeyEvent.KEYCODE_DPAD_LEFT -> {
|
||||
AppDependencies.deviceServiceManager.brightnessSubtract()
|
||||
true
|
||||
}
|
||||
|
||||
else -> {
|
||||
false
|
||||
}
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,6 @@ import androidx.navigation.fragment.findNavController
|
||||
import com.yuanxuan.rokid.R
|
||||
import com.yuanxuan.rokid.databinding.FragmentHomeBinding
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
||||
class HomeFragment : Fragment() {
|
||||
|
||||
@@ -21,10 +20,9 @@ class HomeFragment : Fragment() {
|
||||
private val adapter by lazy {
|
||||
HomeMenuAdapter { item ->
|
||||
when (item.type) {
|
||||
is HomeMenuAdapter.HomeMenuBean.Type.Brightness -> {}
|
||||
is HomeMenuAdapter.HomeMenuBean.Type.Sn ->
|
||||
findNavController().navigate(R.id.home_to_sn)
|
||||
is HomeMenuAdapter.HomeMenuBean.Type.Volume -> {}
|
||||
is HomeMenuAdapter.HomeMenuBean.Type.Brightness -> findNavController().navigate(R.id.home_to_brightness)
|
||||
is HomeMenuAdapter.HomeMenuBean.Type.Sn -> findNavController().navigate(R.id.home_to_sn)
|
||||
is HomeMenuAdapter.HomeMenuBean.Type.Volume -> findNavController().navigate(R.id.home_to_volume)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,7 +45,6 @@ class HomeFragment : Fragment() {
|
||||
|
||||
lifecycleScope.launch {
|
||||
viewModel.homeMenuBeans.collect {
|
||||
Timber.d(it.toString())
|
||||
adapter.submitList(it)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.yuanxuan.rokid.ui
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
@@ -49,10 +50,11 @@ class HomeMenuAdapter(val itemClick: (HomeMenuBean) -> Unit) :
|
||||
}
|
||||
|
||||
private fun bindTitle(holder: ViewHolder, item: HomeMenuBean) {
|
||||
val title = holder.binding.root.context.getString(item.title)
|
||||
val displayTitle = when (val type = item.type) {
|
||||
is HomeMenuBean.Type.Sn -> item.title
|
||||
is HomeMenuBean.Type.Sn -> title
|
||||
is HomeMenuBean.Type.Brightness,
|
||||
is HomeMenuBean.Type.Volume -> "${item.title}: ${type.value}"
|
||||
is HomeMenuBean.Type.Volume -> "${title}: ${type.value}"
|
||||
}
|
||||
holder.binding.title.text = displayTitle
|
||||
}
|
||||
@@ -68,7 +70,7 @@ class HomeMenuAdapter(val itemClick: (HomeMenuBean) -> Unit) :
|
||||
}
|
||||
|
||||
data class HomeMenuBean(
|
||||
val title: String,
|
||||
@param:StringRes val title: Int,
|
||||
@param:DrawableRes val icon: Int,
|
||||
val type: Type,
|
||||
) {
|
||||
@@ -83,6 +85,9 @@ class HomeMenuAdapter(val itemClick: (HomeMenuBean) -> Unit) :
|
||||
|
||||
class DiffCallback : DiffUtil.ItemCallback<HomeMenuBean>() {
|
||||
|
||||
/**
|
||||
* 其实没有必要 因为只有一个变化 直接返回一个payload就行了 不需要计算
|
||||
*/
|
||||
companion object {
|
||||
const val FLAG_TYPE_VALUE_CHANGED = 1
|
||||
}
|
||||
|
||||
@@ -4,69 +4,36 @@ import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.yuanxuan.rokid.R
|
||||
import com.yuanxuan.rokid.dependencies.AppDependencies
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.shareIn
|
||||
|
||||
class HomeViewModel : ViewModel() {
|
||||
|
||||
private val _homeMenuBeans = MutableStateFlow(
|
||||
listOf(
|
||||
HomeMenuAdapter.HomeMenuBean(
|
||||
title = "音量",
|
||||
icon = R.drawable.icon_battery_100,
|
||||
type = HomeMenuAdapter.HomeMenuBean.Type.Volume("0"),
|
||||
),
|
||||
HomeMenuAdapter.HomeMenuBean(
|
||||
title = "亮度",
|
||||
icon = R.drawable.icon_battery_100,
|
||||
type = HomeMenuAdapter.HomeMenuBean.Type.Brightness("0"),
|
||||
),
|
||||
HomeMenuAdapter.HomeMenuBean(
|
||||
title = "SN",
|
||||
icon = R.drawable.icon_battery_100,
|
||||
type = HomeMenuAdapter.HomeMenuBean.Type.Sn("0"),
|
||||
),
|
||||
val homeMenuBeans =
|
||||
combine(
|
||||
AppDependencies.deviceServiceManager.brightness,
|
||||
AppDependencies.deviceServiceManager.volume,
|
||||
) { brightness, volume ->
|
||||
listOf(
|
||||
HomeMenuAdapter.HomeMenuBean(
|
||||
title = R.string.home_item_volume,
|
||||
icon = R.drawable.icon_battery_100,
|
||||
type = HomeMenuAdapter.HomeMenuBean.Type.Volume("$volume"),
|
||||
),
|
||||
HomeMenuAdapter.HomeMenuBean(
|
||||
title = R.string.home_item_brightness,
|
||||
icon = R.drawable.icon_battery_100,
|
||||
type = HomeMenuAdapter.HomeMenuBean.Type.Brightness("$brightness"),
|
||||
),
|
||||
HomeMenuAdapter.HomeMenuBean(
|
||||
title = R.string.home_item_sn,
|
||||
icon = R.drawable.icon_battery_100,
|
||||
type = HomeMenuAdapter.HomeMenuBean.Type.Sn("0"), // 这里用不上 随便填一个
|
||||
),
|
||||
)
|
||||
}.shareIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.Eagerly,
|
||||
replay = 1
|
||||
)
|
||||
)
|
||||
val homeMenuBeans = _homeMenuBeans.asStateFlow()
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
AppDependencies.deviceServiceManager.brightness.collect { brightness ->
|
||||
_homeMenuBeans.update { oldBeans ->
|
||||
oldBeans.map { data ->
|
||||
when (data.type) {
|
||||
is HomeMenuAdapter.HomeMenuBean.Type.Brightness -> data.copy(
|
||||
type = data.type.copy(
|
||||
value = "$brightness"
|
||||
)
|
||||
)
|
||||
|
||||
else -> data
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
viewModelScope.launch {
|
||||
AppDependencies.deviceServiceManager.volume.collect { volume ->
|
||||
_homeMenuBeans.update { oldBeans ->
|
||||
oldBeans.map { data ->
|
||||
when (data.type) {
|
||||
is HomeMenuAdapter.HomeMenuBean.Type.Volume -> data.copy(
|
||||
type = data.type.copy(
|
||||
value = "$volume"
|
||||
)
|
||||
)
|
||||
|
||||
else -> data
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.yuanxuan.rokid.ui
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.yuanxuan.rokid.databinding.ItemSeekBarBinding
|
||||
|
||||
class SeekBarAdapter :
|
||||
ListAdapter<SeekBarAdapter.SeekBarBean, SeekBarAdapter.ViewHolder>(DiffCallback()) {
|
||||
override fun onCreateViewHolder(
|
||||
parent: ViewGroup,
|
||||
viewType: Int
|
||||
): ViewHolder {
|
||||
val binding = ItemSeekBarBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
return ViewHolder(binding)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(
|
||||
holder: ViewHolder,
|
||||
position: Int
|
||||
) {
|
||||
bindSeekBar(item = getItem(position), holder = holder)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int, payloads: List<Any?>) {
|
||||
if (payloads.isEmpty()) {
|
||||
super.onBindViewHolder(holder, position, payloads)
|
||||
} else {
|
||||
bindSeekBar(item = getItem(position), holder = holder)
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindSeekBar(item: SeekBarBean, holder: ViewHolder) {
|
||||
holder.binding.root.isEnabled = item.checked
|
||||
}
|
||||
|
||||
|
||||
class ViewHolder(val binding: ItemSeekBarBinding) : RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
|
||||
data class SeekBarBean(
|
||||
val value: Int,
|
||||
val checked: Boolean,
|
||||
)
|
||||
|
||||
class DiffCallback : DiffUtil.ItemCallback<SeekBarBean>() {
|
||||
override fun areItemsTheSame(
|
||||
oldItem: SeekBarBean,
|
||||
newItem: SeekBarBean
|
||||
): Boolean {
|
||||
return oldItem.value == newItem.value
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(
|
||||
oldItem: SeekBarBean,
|
||||
newItem: SeekBarBean
|
||||
): Boolean {
|
||||
return oldItem == newItem
|
||||
}
|
||||
|
||||
override fun getChangePayload(oldItem: SeekBarBean, newItem: SeekBarBean): Any {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
package com.yuanxuan.rokid.ui
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
|
||||
class SettingFragment: Fragment() {
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.yuanxuan.rokid.ui
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.yuanxuan.rokid.dependencies.AppDependencies
|
||||
import com.yuanxuan.rokid.device.DeviceServiceManager
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.shareIn
|
||||
|
||||
class SettingViewModel : ViewModel() {
|
||||
|
||||
val volumeFlow: SharedFlow<List<SeekBarAdapter.SeekBarBean>> =
|
||||
AppDependencies.deviceServiceManager.volume.map { volume ->
|
||||
buildList {
|
||||
(1..DeviceServiceManager.MAX_VOLUME).map { i ->
|
||||
add(
|
||||
SeekBarAdapter.SeekBarBean(
|
||||
value = i,
|
||||
checked = i <= volume
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}.shareIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.Eagerly,
|
||||
replay = 1
|
||||
)
|
||||
|
||||
val brightnessFlow: SharedFlow<List<SeekBarAdapter.SeekBarBean>> =
|
||||
AppDependencies.deviceServiceManager.brightness.map { volume ->
|
||||
buildList {
|
||||
(1..DeviceServiceManager.MAX_BRIGHTNESS).map { i ->
|
||||
add(
|
||||
SeekBarAdapter.SeekBarBean(
|
||||
value = i,
|
||||
checked = i <= volume
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}.shareIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.Eagerly,
|
||||
replay = 1
|
||||
)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.yuanxuan.rokid.ui
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.KeyEvent
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.yuanxuan.rokid.R
|
||||
import com.yuanxuan.rokid.databinding.FragmentSettingBinding
|
||||
import com.yuanxuan.rokid.dependencies.AppDependencies
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class VolumeFragment : Fragment() {
|
||||
|
||||
private lateinit var binding: FragmentSettingBinding
|
||||
private val viewModel by viewModels<SettingViewModel>()
|
||||
|
||||
private val adapter by lazy {
|
||||
SeekBarAdapter()
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
binding = FragmentSettingBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
binding.title.text = resources.getString(R.string.setting_volume_title)
|
||||
binding.tip.text = resources.getString(R.string.setting_volume_tip)
|
||||
|
||||
binding.recyclerView.adapter = adapter
|
||||
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
viewModel.volumeFlow.collect { data ->
|
||||
adapter.submitList(data)
|
||||
}
|
||||
}
|
||||
|
||||
binding.root.requestFocus()
|
||||
binding.root.setOnKeyListener { _, _, event ->
|
||||
return@setOnKeyListener if (event.action == KeyEvent.ACTION_DOWN) {
|
||||
when (event.keyCode) {
|
||||
KeyEvent.KEYCODE_DPAD_RIGHT -> {
|
||||
AppDependencies.deviceServiceManager.volumeAdd()
|
||||
true
|
||||
}
|
||||
|
||||
KeyEvent.KEYCODE_DPAD_LEFT -> {
|
||||
AppDependencies.deviceServiceManager.volumeSubtract()
|
||||
true
|
||||
}
|
||||
|
||||
else -> {
|
||||
false
|
||||
}
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user