diff --git a/app/src/main/java/com/yuanxuan/rokid/MainActivity.kt b/app/src/main/java/com/yuanxuan/rokid/MainActivity.kt index 7e7f133..23212f2 100644 --- a/app/src/main/java/com/yuanxuan/rokid/MainActivity.kt +++ b/app/src/main/java/com/yuanxuan/rokid/MainActivity.kt @@ -1,25 +1,23 @@ package com.yuanxuan.rokid -import android.os.Build 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 import androidx.lifecycle.lifecycleScope import com.yuanxuan.rokid.databinding.ActivityMainBinding -import com.yuanxuan.rokid.dependencies.AppDependencies -import com.yuanxuan.rokid.device.DeviceServiceManager import com.yuanxuan.rokid.extension.fadeIn import com.yuanxuan.rokid.extension.fadeOut import kotlinx.coroutines.launch -import timber.log.Timber class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding + private val viewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -45,11 +43,9 @@ class MainActivity : AppCompatActivity() { } override fun dispatchKeyEvent(event: KeyEvent): Boolean { - return if (AppDependencies.deviceServiceManager.instructState.value == - DeviceServiceManager.InstructState.WaitingInstructState - ) { + return if (viewModel.uiState.value.isVoiceInputVisible) { if (event.keyCode == KeyEvent.KEYCODE_BACK) { - AppDependencies.deviceServiceManager.quitInstructReceived() + viewModel.quitInstructReceived() } true } else { @@ -59,36 +55,17 @@ class MainActivity : AppCompatActivity() { private fun observer() { lifecycleScope.launch { - /** - * 监听电量 - */ - AppDependencies.deviceServiceManager.batteryPercentage.collect { - binding.batteryLevel.text = resources.getString(R.string.status_bar_battery, it) - binding.batteryLevelIv.setImageLevel(it) - } - } - lifecycleScope.launch { - AppDependencies.deviceServiceManager.wifiState.collect { - when (it) { - is DeviceServiceManager.WifiState.Connected -> binding.wifiIv.setImageLevel(it.level) - - DeviceServiceManager.WifiState.Unconnected -> binding.wifiIv.setImageLevel(0) - } - } - } - - lifecycleScope.launch { - AppDependencies.deviceServiceManager.instructState.collect { - when (it) { - DeviceServiceManager.InstructState.None -> { - binding.lottieVoiceInput.cancelAnimation() - binding.lottieVoiceInput.fadeOut(300) - } - - DeviceServiceManager.InstructState.WaitingInstructState -> { - binding.lottieVoiceInput.playAnimation() - binding.lottieVoiceInput.fadeIn(300) - } + viewModel.uiState.collect { uiState -> + binding.batteryLevel.text = + resources.getString(R.string.status_bar_battery, uiState.batteryLevel) + binding.batteryLevelIv.setImageLevel(uiState.batteryLevel) + binding.wifiIv.setImageLevel(uiState.wifiLevel) + if (uiState.isVoiceInputVisible) { + binding.lottieVoiceInput.playAnimation() + binding.lottieVoiceInput.fadeIn(300) + } else { + binding.lottieVoiceInput.cancelAnimation() + binding.lottieVoiceInput.fadeOut(300) } } } diff --git a/app/src/main/java/com/yuanxuan/rokid/MainViewModel.kt b/app/src/main/java/com/yuanxuan/rokid/MainViewModel.kt index e0467e6..da58a0a 100644 --- a/app/src/main/java/com/yuanxuan/rokid/MainViewModel.kt +++ b/app/src/main/java/com/yuanxuan/rokid/MainViewModel.kt @@ -1,10 +1,14 @@ package com.yuanxuan.rokid -import androidx.activity.result.launch import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.yuanxuan.rokid.dependencies.AppDependencies.deviceServiceManager +import com.yuanxuan.rokid.device.DeviceServiceManager import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch class MainViewModel : ViewModel() { @@ -12,6 +16,30 @@ class MainViewModel : ViewModel() { private val _keyEventFlow = MutableSharedFlow() val keyEventFlow = _keyEventFlow.asSharedFlow() + val uiState = combine( + deviceServiceManager.batteryPercentage, + deviceServiceManager.wifiState, + deviceServiceManager.instructState + ) { battery, wifi, instruct -> + MainUiState( + batteryLevel = battery, + wifiLevel = if (wifi is DeviceServiceManager.WifiState.Connected) wifi.level else 0, + isVoiceInputVisible = instruct == DeviceServiceManager.InstructState.WaitingInstructState + ) + }.stateIn( + scope = viewModelScope, + initialValue = MainUiState( + batteryLevel = 0, + wifiLevel = 0, + isVoiceInputVisible = false + ), + started = SharingStarted.Eagerly, + ) + + fun quitInstructReceived(){ + deviceServiceManager.quitInstructReceived() + } + fun onKeyEventDispatched(event: KeyEvent) { viewModelScope.launch { _keyEventFlow.emit(event) @@ -24,4 +52,10 @@ class MainViewModel : ViewModel() { data object Enter : KeyEvent //前滑 } + data class MainUiState( + val batteryLevel: Int, + val wifiLevel: Int, + val isVoiceInputVisible: Boolean, + ) + } \ No newline at end of file diff --git a/app/src/main/java/com/yuanxuan/rokid/RokidApplication.kt b/app/src/main/java/com/yuanxuan/rokid/RokidApplication.kt index 7c83cb3..5495fca 100644 --- a/app/src/main/java/com/yuanxuan/rokid/RokidApplication.kt +++ b/app/src/main/java/com/yuanxuan/rokid/RokidApplication.kt @@ -2,10 +2,10 @@ package com.yuanxuan.rokid import android.app.Application import android.content.Intent -import android.os.Build import com.yuanxuan.rokid.dependencies.AppDependencies import com.yuanxuan.rokid.dependencies.ApplicationDependencyProvider import com.yuanxuan.rokid.keeplive.KeepLiveService +import com.yuanxuan.rokid.network.websocket.WebSocketReconnectWorker import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob @@ -28,7 +28,7 @@ class RokidApplication : Application() { runCatching { AppDependencies.deviceServiceManager.getSn() }.onSuccess { - AppDependencies.webSocketManager.connect() + WebSocketReconnectWorker.schedule(this@RokidApplication) }.onFailure { Timber.e(it) } diff --git a/app/src/main/java/com/yuanxuan/rokid/device/DeviceServiceManager.kt b/app/src/main/java/com/yuanxuan/rokid/device/DeviceServiceManager.kt index 085d8fd..9a183ce 100644 --- a/app/src/main/java/com/yuanxuan/rokid/device/DeviceServiceManager.kt +++ b/app/src/main/java/com/yuanxuan/rokid/device/DeviceServiceManager.kt @@ -57,7 +57,7 @@ class DeviceServiceManager(val context: Application) : ConnectivityManager.Netwo /** * 系统电量 */ - private val _batteryPercentage = MutableStateFlow(-1) + private val _batteryPercentage = MutableStateFlow(getBatteryLevel(context)) val batteryPercentage = _batteryPercentage.asStateFlow() /** @@ -293,6 +293,11 @@ class DeviceServiceManager(val context: Application) : ConnectivityManager.Netwo } } + private fun getBatteryLevel(context: Context): Int { + val bm = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager + return bm.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY) + } + inner class SysKeyReceiver : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { val action = intent?.action ?: return diff --git a/app/src/main/java/com/yuanxuan/rokid/network/NetUtils.kt b/app/src/main/java/com/yuanxuan/rokid/network/NetUtils.kt index 2f7fcfb..2332357 100644 --- a/app/src/main/java/com/yuanxuan/rokid/network/NetUtils.kt +++ b/app/src/main/java/com/yuanxuan/rokid/network/NetUtils.kt @@ -6,8 +6,8 @@ import java.net.NetworkInterface object NetUtils { - fun getBaseUrl() = "http://${getLocalIPV4address()}.70:7070" -// fun getBaseUrl() = "http://${getLocalIPV4address()}.83:8765" +// fun getBaseUrl() = "http://${getLocalIPV4address()}.70:7070" + fun getBaseUrl() = "http://${getLocalIPV4address()}.52:8765" /** diff --git a/app/src/main/java/com/yuanxuan/rokid/network/websocket/OkHttpWebSocketConnection.kt b/app/src/main/java/com/yuanxuan/rokid/network/websocket/OkHttpWebSocketConnection.kt index 7055049..e329e6d 100644 --- a/app/src/main/java/com/yuanxuan/rokid/network/websocket/OkHttpWebSocketConnection.kt +++ b/app/src/main/java/com/yuanxuan/rokid/network/websocket/OkHttpWebSocketConnection.kt @@ -22,13 +22,14 @@ class OkHttpWebSocketConnection() : WebSocketListener(), WebSocketConnection { private var client: WebSocket? = null @Synchronized - override fun connect() { + override fun connect(sn: String) { val okHttpClient = OkHttpClient.Builder() .readTimeout(DEFAULT_SEND_TIMEOUT) .pingInterval(PING_INTERVAL_TIME) .build() - val request = Request.Builder().url(NetUtils.getBaseUrl()).build() + val request = Request.Builder().url(NetUtils.getBaseUrl()) + .addHeader("sn", sn).build() _webSocketConnectionStateFlow.update { WebSocketConnectionState.CONNECTING } @@ -55,6 +56,7 @@ class OkHttpWebSocketConnection() : WebSocketListener(), WebSocketConnection { } override fun onOpen(webSocket: WebSocket, response: Response) { + _webSocketConnectionStateFlow.update { WebSocketConnectionState.CONNECTED } Timber.d("websocket onOpen") } diff --git a/app/src/main/java/com/yuanxuan/rokid/network/websocket/WebSocketConnection.kt b/app/src/main/java/com/yuanxuan/rokid/network/websocket/WebSocketConnection.kt index c294300..24901bd 100644 --- a/app/src/main/java/com/yuanxuan/rokid/network/websocket/WebSocketConnection.kt +++ b/app/src/main/java/com/yuanxuan/rokid/network/websocket/WebSocketConnection.kt @@ -1,6 +1,5 @@ package com.yuanxuan.rokid.network.websocket -import kotlinx.coroutines.flow.MutableStateFlow import kotlin.time.Duration.Companion.seconds interface WebSocketConnection { @@ -10,7 +9,7 @@ interface WebSocketConnection { val PING_INTERVAL_TIME = 30.seconds } - fun connect() + fun connect(sn: String) fun isDead(): Boolean diff --git a/app/src/main/java/com/yuanxuan/rokid/network/websocket/WebSocketManager.kt b/app/src/main/java/com/yuanxuan/rokid/network/websocket/WebSocketManager.kt index 1427966..bdf8c01 100644 --- a/app/src/main/java/com/yuanxuan/rokid/network/websocket/WebSocketManager.kt +++ b/app/src/main/java/com/yuanxuan/rokid/network/websocket/WebSocketManager.kt @@ -29,8 +29,8 @@ class WebSocketManager(context: Context, scope: CoroutineScope) { } } - fun connect() { - webSocketConnection.connect() + fun connect(sn: String) { + webSocketConnection.connect(sn) } diff --git a/app/src/main/java/com/yuanxuan/rokid/network/websocket/WebSocketReconnectWorker.kt b/app/src/main/java/com/yuanxuan/rokid/network/websocket/WebSocketReconnectWorker.kt index 0dc3085..e1621ab 100644 --- a/app/src/main/java/com/yuanxuan/rokid/network/websocket/WebSocketReconnectWorker.kt +++ b/app/src/main/java/com/yuanxuan/rokid/network/websocket/WebSocketReconnectWorker.kt @@ -19,7 +19,7 @@ class WebSocketReconnectWorker(context: Context, workerParams: WorkerParameters) override fun doWork(): Result { Timber.d("尝试开始重连") AppDependencies.deviceServiceManager.playTTS("开始重连") - AppDependencies.webSocketManager.connect() + AppDependencies.webSocketManager.connect(AppDependencies.deviceServiceManager.sn) return Result.success() } diff --git a/app/src/main/java/com/yuanxuan/rokid/ui/BrightnessFragment.kt b/app/src/main/java/com/yuanxuan/rokid/ui/BrightnessFragment.kt index 948aedb..2741ca8 100644 --- a/app/src/main/java/com/yuanxuan/rokid/ui/BrightnessFragment.kt +++ b/app/src/main/java/com/yuanxuan/rokid/ui/BrightnessFragment.kt @@ -10,7 +10,6 @@ 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() { @@ -37,7 +36,6 @@ class BrightnessFragment : Fragment() { binding.tip.text = resources.getString(R.string.setting_brightness_tip) binding.recyclerView.adapter = adapter - viewLifecycleOwner.lifecycleScope.launch { viewModel.brightnessFlow.collect { data -> adapter.submitList(data) @@ -49,12 +47,12 @@ class BrightnessFragment : Fragment() { return@setOnKeyListener if (event.action == KeyEvent.ACTION_UP) { when (event.keyCode) { KeyEvent.KEYCODE_DPAD_RIGHT -> { - AppDependencies.deviceServiceManager.brightnessAdd() + viewModel.brightnessAdd() true } KeyEvent.KEYCODE_DPAD_LEFT -> { - AppDependencies.deviceServiceManager.brightnessSubtract() + viewModel.brightnessSubtract() true } diff --git a/app/src/main/java/com/yuanxuan/rokid/ui/HomeFragment.kt b/app/src/main/java/com/yuanxuan/rokid/ui/HomeFragment.kt index 144c12a..ab59dff 100644 --- a/app/src/main/java/com/yuanxuan/rokid/ui/HomeFragment.kt +++ b/app/src/main/java/com/yuanxuan/rokid/ui/HomeFragment.kt @@ -43,7 +43,8 @@ class HomeFragment : Fragment() { binding.recyclerView.adapter = adapter binding.recyclerView.itemAnimator = null - lifecycleScope.launch { + + viewLifecycleOwner.lifecycleScope.launch { viewModel.homeMenuBeans.collect { adapter.submitList(it) } diff --git a/app/src/main/java/com/yuanxuan/rokid/ui/SettingViewModel.kt b/app/src/main/java/com/yuanxuan/rokid/ui/SettingViewModel.kt index 9544241..2cbb34d 100644 --- a/app/src/main/java/com/yuanxuan/rokid/ui/SettingViewModel.kt +++ b/app/src/main/java/com/yuanxuan/rokid/ui/SettingViewModel.kt @@ -47,4 +47,22 @@ class SettingViewModel : ViewModel() { replay = 1 ) + fun brightnessAdd(){ + AppDependencies.deviceServiceManager.brightnessAdd() + } + + fun brightnessSubtract(){ + AppDependencies.deviceServiceManager.brightnessSubtract() + } + + fun volumeAdd(){ + AppDependencies.deviceServiceManager.volumeAdd() + } + + fun volumeSubtract(){ + AppDependencies.deviceServiceManager.volumeSubtract() + } + + fun deviceSn()= AppDependencies.deviceServiceManager.sn + } \ No newline at end of file diff --git a/app/src/main/java/com/yuanxuan/rokid/ui/SnFragment.kt b/app/src/main/java/com/yuanxuan/rokid/ui/SnFragment.kt index 1c3c92b..3e31d92 100644 --- a/app/src/main/java/com/yuanxuan/rokid/ui/SnFragment.kt +++ b/app/src/main/java/com/yuanxuan/rokid/ui/SnFragment.kt @@ -5,14 +5,16 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels import com.yuanxuan.rokid.BuildConfig import com.yuanxuan.rokid.R import com.yuanxuan.rokid.databinding.FragmentSnBinding -import com.yuanxuan.rokid.dependencies.AppDependencies class SnFragment : Fragment() { private lateinit var binding: FragmentSnBinding + private val viewModel by viewModels() + override fun onCreateView( inflater: LayoutInflater, @@ -26,7 +28,7 @@ class SnFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) binding.sn.text = - resources.getString(R.string.device_info_sn, AppDependencies.deviceServiceManager.sn) + resources.getString(R.string.device_info_sn, viewModel.deviceSn()) binding.appVersion.text = resources.getString(R.string.device_info_app_version, BuildConfig.VERSION_NAME) } diff --git a/app/src/main/java/com/yuanxuan/rokid/ui/VolumeFragment.kt b/app/src/main/java/com/yuanxuan/rokid/ui/VolumeFragment.kt index da9f64d..48cda76 100644 --- a/app/src/main/java/com/yuanxuan/rokid/ui/VolumeFragment.kt +++ b/app/src/main/java/com/yuanxuan/rokid/ui/VolumeFragment.kt @@ -10,7 +10,6 @@ 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() { @@ -49,12 +48,12 @@ class VolumeFragment : Fragment() { return@setOnKeyListener if (event.action == KeyEvent.ACTION_DOWN) { when (event.keyCode) { KeyEvent.KEYCODE_DPAD_RIGHT -> { - AppDependencies.deviceServiceManager.volumeAdd() + viewModel.volumeAdd() true } KeyEvent.KEYCODE_DPAD_LEFT -> { - AppDependencies.deviceServiceManager.volumeSubtract() + viewModel.volumeSubtract() true }