yacwc
This commit is contained in:
1
wear/TileService.kt
Normal file
1
wear/TileService.kt
Normal file
@@ -0,0 +1 @@
|
||||
class TileService {}
|
||||
@@ -9,12 +9,16 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.wear.compose.material.CompactChip
|
||||
import androidx.wear.compose.material.MaterialTheme
|
||||
import androidx.wear.compose.material.Text
|
||||
|
||||
@Composable
|
||||
fun ControlDashboard(controlDashboardUiState: ControlDashboardUiState, onMicClicked: () -> Unit, modifier: Modifier = Modifier) {
|
||||
fun ControlDashboard(controlDashboardUiState: ControlDashboardUiState,
|
||||
onMicClicked: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
navController: NavHostController) {
|
||||
Box(contentAlignment = Alignment.Center, modifier = modifier.fillMaxSize()) {
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
|
||||
@@ -35,22 +39,17 @@ private fun ControlDashboardButton(buttonState: ControlDashboardButtonUiState,
|
||||
onClick: () -> Unit,
|
||||
labelText: String,
|
||||
modifier: Modifier = Modifier) {
|
||||
CompactChip(
|
||||
modifier = Modifier,
|
||||
onClick = onClick ,
|
||||
CompactChip(modifier = Modifier,
|
||||
onClick = onClick,
|
||||
enabled = true,
|
||||
contentPadding = PaddingValues(5.dp, 1.dp, 5.dp, 1.dp),
|
||||
shape = MaterialTheme.shapes.small,
|
||||
label = {
|
||||
Text(
|
||||
text = labelText
|
||||
)
|
||||
}
|
||||
)
|
||||
Text(text = labelText)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Button(modifier = modifier, enabled = buttonState.enabled && buttonState.visible, onClick = onClick) {
|
||||
// Text(contentDescription);
|
||||
//// Icon(imageVector = imageVector, contentDescription = contentDescription)
|
||||
|
||||
@@ -15,19 +15,39 @@ import androidx.activity.compose.ManagedActivityResultLauncher
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.result.contract.ActivityResultContracts.RequestPermission
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.wear.compose.material.Text
|
||||
import androidx.wear.compose.navigation.SwipeDismissableNavHost
|
||||
import androidx.wear.compose.navigation.composable
|
||||
import androidx.wear.compose.navigation.rememberSwipeDismissableNavController
|
||||
import androidx.wear.compose.ui.tooling.preview.WearPreviewDevices
|
||||
import androidx.wear.compose.ui.tooling.preview.WearPreviewFontScales
|
||||
import com.birdsounds.identify.presentation.theme.IdentifyTheme
|
||||
import com.google.android.horologist.annotations.ExperimentalHorologistApi
|
||||
import com.google.android.horologist.audio.ui.VolumeViewModel
|
||||
import com.google.android.horologist.compose.layout.ScalingLazyColumn
|
||||
import com.google.android.horologist.compose.layout.ScalingLazyColumnDefaults
|
||||
import com.google.android.horologist.compose.layout.ScreenScaffold
|
||||
import com.google.android.horologist.compose.layout.rememberResponsiveColumnState
|
||||
import com.google.android.horologist.compose.material.Chip
|
||||
import com.google.android.horologist.compose.material.ListHeaderDefaults.firstItemPadding
|
||||
import com.google.android.horologist.compose.material.ResponsiveListHeader
|
||||
import com.google.android.horologist.compose.rotaryinput.rotaryWithScroll
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@@ -40,11 +60,9 @@ val Any.TAG: String
|
||||
}
|
||||
|
||||
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
|
||||
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
installSplashScreen()
|
||||
|
||||
@@ -69,61 +87,148 @@ fun WearApp() {
|
||||
|
||||
|
||||
val volumeViewModel: VolumeViewModel = viewModel(factory = VolumeViewModel.Factory)
|
||||
val navController = rememberSwipeDismissableNavController()
|
||||
|
||||
val mainState = remember(activity) {
|
||||
MainState(
|
||||
activity = activity,
|
||||
requestPermission = {
|
||||
requestPermissionLauncher.launch(Manifest.permission.RECORD_AUDIO)
|
||||
}
|
||||
)
|
||||
MainState(activity = activity, requestPermission = {
|
||||
requestPermissionLauncher.launch(Manifest.permission.RECORD_AUDIO)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
requestPermissionLauncher = rememberLauncherForActivityResult(RequestPermission()) {
|
||||
scope.launch {
|
||||
mainState.permissionResultReturned()
|
||||
}
|
||||
}
|
||||
|
||||
val lifecycleOwner = androidx.lifecycle.compose.LocalLifecycleOwner.current
|
||||
val navController: NavHostController = rememberSwipeDismissableNavController()
|
||||
mainState.setNavController(navController);
|
||||
SwipeDismissableNavHost(navController = navController, startDestination = "speaker") {
|
||||
|
||||
// AppScaffold {
|
||||
// DisposableEffect(mainState, scope, lifecycleOwner) {
|
||||
// val lifecycleObserver = object : DefaultLifecycleObserver {
|
||||
// override fun onStop(owner: LifecycleOwner) {
|
||||
// super.onStop(owner)
|
||||
// }
|
||||
// }
|
||||
// lifecycleOwner.lifecycle.addObserver(lifecycleObserver)
|
||||
//
|
||||
// onDispose {
|
||||
// lifecycleOwner.lifecycle.removeObserver(lifecycleObserver)
|
||||
// }
|
||||
// }
|
||||
var sdnv = SwipeDismissableNavHost(navController = navController, startDestination = "speaker") {
|
||||
composable("speaker") {
|
||||
StartRecordingScreen(
|
||||
context = context,
|
||||
appState = mainState.appState,
|
||||
isPermissionDenied = mainState.isPermissionDenied,
|
||||
onMicClicked = {
|
||||
scope.launch {
|
||||
mainState.onMicClicked()
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
// }
|
||||
composable("speaker") {
|
||||
StartRecordingScreen(
|
||||
context = context,
|
||||
navController = navController,
|
||||
appState = mainState.appState,
|
||||
isPermissionDenied = mainState.isPermissionDenied,
|
||||
onMicClicked = {
|
||||
scope.launch {
|
||||
mainState.onMicClicked()
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
composable("species_list") {
|
||||
SpeciesListView(context = context)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// var sdnv = SwipeDismissableNavHost(navController = navController, startDestination = "list") {
|
||||
// composable("speaker") {
|
||||
// StartRecordingScreen(
|
||||
// context = context,
|
||||
// appState = mainState.appState,
|
||||
// isPermissionDenied = mainState.isPermissionDenied,
|
||||
// onMicClicked = {
|
||||
// scope.launch {
|
||||
// mainState.onMicClicked()
|
||||
// }
|
||||
// },
|
||||
// )
|
||||
// }
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
tailrec fun Context.findActivity(): Activity = when (this) {
|
||||
is Activity -> this
|
||||
is ContextWrapper -> baseContext.findActivity()
|
||||
else -> throw IllegalStateException("findActivity should be called in the context of an Activity")
|
||||
}
|
||||
|
||||
|
||||
@OptIn(ExperimentalHorologistApi::class)
|
||||
@Composable
|
||||
fun MessageDetail(id: String) {
|
||||
val scrollState = rememberScrollState()
|
||||
|
||||
ScreenScaffold(scrollState = scrollState) {
|
||||
val padding =
|
||||
ScalingLazyColumnDefaults.padding(first = ScalingLazyColumnDefaults.ItemType.Text, last = ScalingLazyColumnDefaults.ItemType.Text)()
|
||||
Column(modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.verticalScroll(scrollState)
|
||||
.rotaryWithScroll(scrollState)
|
||||
.padding(padding),
|
||||
verticalArrangement = Arrangement.Center) {
|
||||
Text(text = id, textAlign = TextAlign.Center, modifier = Modifier.fillMaxSize())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tailrec fun Context.findActivity(): Activity =
|
||||
when (this) {
|
||||
is Activity -> this
|
||||
is ContextWrapper -> baseContext.findActivity()
|
||||
else -> throw IllegalStateException(
|
||||
"findActivity should be called in the context of an Activity"
|
||||
)
|
||||
@OptIn(ExperimentalHorologistApi::class)
|
||||
@Composable
|
||||
fun MessageList(onMessageClick: (String) -> Unit) {
|
||||
val columnState =
|
||||
rememberResponsiveColumnState(contentPadding = ScalingLazyColumnDefaults.padding(first = ScalingLazyColumnDefaults.ItemType.Text,
|
||||
last = ScalingLazyColumnDefaults.ItemType.Chip))
|
||||
|
||||
ScreenScaffold(scrollState = columnState) {
|
||||
ScalingLazyColumn(columnState = columnState, modifier = Modifier.fillMaxSize()) {
|
||||
item {
|
||||
ResponsiveListHeader(contentPadding = firstItemPadding()) {
|
||||
Text(text = "Hey hey hey")
|
||||
}
|
||||
}
|
||||
item {
|
||||
Chip(label = "Message 1", onClick = { onMessageClick("message1") })
|
||||
}
|
||||
item {
|
||||
Chip(label = "Message 2", onClick = { onMessageClick("message2") })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@OptIn(ExperimentalHorologistApi::class)
|
||||
@Composable
|
||||
fun MessageList2(onMessageClick: (String) -> Unit) {
|
||||
val columnState =
|
||||
rememberResponsiveColumnState(contentPadding = ScalingLazyColumnDefaults.padding(first = ScalingLazyColumnDefaults.ItemType.Text,
|
||||
last = ScalingLazyColumnDefaults.ItemType.Chip))
|
||||
|
||||
ScreenScaffold(scrollState = columnState) {
|
||||
ScalingLazyColumn(columnState = columnState, modifier = Modifier.fillMaxSize()) {
|
||||
item {
|
||||
ResponsiveListHeader(contentPadding = firstItemPadding()) {
|
||||
Text(text = "Hey hey hey")
|
||||
}
|
||||
}
|
||||
item {
|
||||
Chip(label = "Message 3", onClick = { onMessageClick("message3") })
|
||||
}
|
||||
item {
|
||||
Chip(label = "Message 4", onClick = { onMessageClick("message4") })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@WearPreviewDevices
|
||||
@WearPreviewFontScales
|
||||
@Composable
|
||||
fun MessageDetailPreview() {
|
||||
MessageDetail("test")
|
||||
}
|
||||
|
||||
@WearPreviewDevices
|
||||
@WearPreviewFontScales
|
||||
@Composable
|
||||
fun MessageListPreview() {
|
||||
MessageList(onMessageClick = {})
|
||||
}
|
||||
@@ -1,9 +1,7 @@
|
||||
package com.birdsounds.identify.presentation
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.util.Log
|
||||
import androidx.annotation.RequiresPermission
|
||||
@@ -11,24 +9,13 @@ import androidx.compose.foundation.MutatorMutex
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.core.content.ContextCompat
|
||||
import co.touchlab.stately.collections.ConcurrentMutableCollection
|
||||
import com.google.android.gms.tasks.Tasks
|
||||
import androidx.navigation.NavHostController
|
||||
import com.google.android.gms.wearable.ChannelClient
|
||||
import com.google.android.gms.wearable.ChannelClient.ChannelCallback
|
||||
import com.google.android.gms.wearable.Wearable
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.tasks.await
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.time.Duration
|
||||
import java.time.LocalDateTime
|
||||
import java.util.concurrent.ExecutionException
|
||||
|
||||
|
||||
class MainState(private val activity: Activity, private val requestPermission: () -> Unit) {
|
||||
@@ -40,7 +27,10 @@ class MainState(private val activity: Activity, private val requestPermission: (
|
||||
var isPermissionDenied by mutableStateOf(false)
|
||||
private set
|
||||
private val soundRecorder = SoundRecorder(activity, "audiorecord.opus")
|
||||
|
||||
private var navController: NavHostController? = null
|
||||
public fun setNavController(_navController: NavHostController) {
|
||||
navController = _navController
|
||||
}
|
||||
suspend fun onMicClicked() {
|
||||
playbackStateMutatorMutex.mutate {
|
||||
when (appState) {
|
||||
@@ -48,8 +38,7 @@ class MainState(private val activity: Activity, private val requestPermission: (
|
||||
(ContextCompat.checkSelfPermission(activity, Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) -> {
|
||||
Log.e(TAG, "Permissions granted, continuing to record")
|
||||
appState = AppState.Recording
|
||||
|
||||
|
||||
navController?.navigate("species_list")
|
||||
record(activity = activity, soundRecorder = soundRecorder, setProgress = { progress -> recordingProgress = progress })
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ package com.birdsounds.identify.presentation
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import co.touchlab.stately.collections.ConcurrentMutableSet
|
||||
import com.google.android.gms.tasks.Tasksx
|
||||
import com.google.android.gms.tasks.Tasks
|
||||
import com.google.android.gms.wearable.Wearable
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
package com.birdsounds.identify.presentation
|
||||
|
||||
import android.util.Log
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.snapshots.SnapshotStateList
|
||||
import java.time.Instant
|
||||
|
||||
|
||||
class AScore(
|
||||
_species: String,
|
||||
_score: Float,
|
||||
_timestamp: Long
|
||||
_timestamp: Long,
|
||||
|
||||
) {
|
||||
) {
|
||||
|
||||
var split_stuff = _species.split("_")
|
||||
val species = split_stuff[0]
|
||||
@@ -31,32 +33,46 @@ class AScore(
|
||||
object SpeciesList {
|
||||
var internal_list = mutableListOf<AScore>()
|
||||
var do_add_observation = false
|
||||
var _list_on_ui: SnapshotStateList<MutableState<String>>? = null
|
||||
fun setSpeciecsShow_list(list_in: SnapshotStateList<MutableState<String>>) {
|
||||
_list_on_ui = list_in;
|
||||
}
|
||||
|
||||
fun add_observation(species_in: AScore) {
|
||||
Log.w(TAG,"In add obsergation")
|
||||
do_add_observation = false
|
||||
var idx = 0
|
||||
var idx_replace = -1
|
||||
for (i in internal_list)
|
||||
{
|
||||
if (i.species == species_in.species)
|
||||
{
|
||||
for (i in internal_list) {
|
||||
if (i.species == species_in.species) {
|
||||
do_add_observation = false
|
||||
idx_replace = idx
|
||||
}
|
||||
idx+=1
|
||||
idx += 1
|
||||
}
|
||||
if (idx_replace >= 0)
|
||||
{
|
||||
if (idx_replace >= 0) {
|
||||
Log.w(TAG, "Replacing")
|
||||
internal_list[idx_replace] = species_in
|
||||
internal_list[idx_replace] = species_in // _list_on_ui?.removeAt(idx_replace)
|
||||
// _list_on_ui?.add(species_in);
|
||||
// if (_list_on_ui != null) {
|
||||
// _list_on_ui?.removeAt(idx_replace)
|
||||
// _list_on_ui.add(idx_replace, species_in);
|
||||
// }
|
||||
|
||||
} else {
|
||||
internal_list.add(species_in)
|
||||
|
||||
|
||||
}
|
||||
// val list_reranked = internal_list.withIndex().sortedBy { it -> it.value.age() }
|
||||
|
||||
internal_list = internal_list.sortedBy({ (it.age()) }).toMutableList()
|
||||
|
||||
for ((index, value) in internal_list.withIndex()) {
|
||||
_list_on_ui?.get(index)?.value = value.common_name;
|
||||
}
|
||||
|
||||
Log.w(TAG, internal_list.toString())
|
||||
// internal_list.add(species_in)
|
||||
Log.w(TAG, internal_list.size.toString())
|
||||
Log.w(TAG, _list_on_ui?.size.toString()) // internal_list.add(species_in)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.birdsounds.identify.presentation
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.snapshots.SnapshotStateList
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.wear.compose.foundation.lazy.items
|
||||
import androidx.wear.compose.material.Text
|
||||
import com.google.android.horologist.annotations.ExperimentalHorologistApi
|
||||
import com.google.android.horologist.compose.layout.ScalingLazyColumn
|
||||
import com.google.android.horologist.compose.layout.ScalingLazyColumnDefaults
|
||||
import com.google.android.horologist.compose.layout.ScreenScaffold
|
||||
import com.google.android.horologist.compose.layout.rememberResponsiveColumnState
|
||||
|
||||
|
||||
@OptIn(ExperimentalHorologistApi::class)
|
||||
@Composable
|
||||
fun SpeciesListView(context: Context,
|
||||
) {
|
||||
val text: MutableState<String> = mutableStateOf("text")
|
||||
//text.toString()
|
||||
val species_list_show = mutableStateListOf<MutableState<String>>()
|
||||
for (i in 1..10)
|
||||
{
|
||||
val hi = mutableStateOf("hi")
|
||||
species_list_show.add(hi);
|
||||
}
|
||||
SpeciesList.setSpeciecsShow_list(species_list_show)
|
||||
val species_show: SnapshotStateList<MutableState<String>> = remember { species_list_show }
|
||||
|
||||
val columnState =
|
||||
rememberResponsiveColumnState(contentPadding = ScalingLazyColumnDefaults.padding(first = ScalingLazyColumnDefaults.ItemType.Text,
|
||||
last = ScalingLazyColumnDefaults.ItemType.Chip))
|
||||
|
||||
ScreenScaffold(scrollState = columnState) {
|
||||
ScalingLazyColumn(columnState = columnState, modifier = Modifier.fillMaxSize()) {
|
||||
items(species_show) { aSpec -> Text(text = aSpec.value)
|
||||
} // Dynamically display the chips
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,49 +3,40 @@ package com.birdsounds.identify.presentation
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
import androidx.wear.compose.ui.tooling.preview.WearPreviewDevices
|
||||
import androidx.wear.compose.ui.tooling.preview.WearPreviewFontScales
|
||||
import androidx.navigation.NavHostController
|
||||
import com.google.android.horologist.compose.layout.ScreenScaffold
|
||||
|
||||
@Composable
|
||||
fun StartRecordingScreen(
|
||||
context: Context,
|
||||
appState: AppState,
|
||||
navController: NavHostController,
|
||||
isPermissionDenied: Boolean,
|
||||
onMicClicked: () -> Unit
|
||||
) {
|
||||
ScreenScaffold {
|
||||
val controlDashboardUiState = computeControlDashboardUiState(
|
||||
appState = appState,
|
||||
isPermissionDenied = isPermissionDenied
|
||||
)
|
||||
ControlDashboard(
|
||||
controlDashboardUiState = controlDashboardUiState,
|
||||
onMicClicked = onMicClicked
|
||||
onMicClicked = onMicClicked,
|
||||
navController = navController
|
||||
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun computeControlDashboardUiState(
|
||||
appState: AppState,
|
||||
isPermissionDenied: Boolean
|
||||
): ControlDashboardUiState =
|
||||
when (appState) {
|
||||
AppState.Ready -> ControlDashboardUiState(
|
||||
micState = ControlDashboardButtonUiState(
|
||||
expanded = false,
|
||||
enabled = !isPermissionDenied,
|
||||
visible = true
|
||||
),
|
||||
micState = ControlDashboardButtonUiState(expanded = false, visible = true, enabled = true),
|
||||
)
|
||||
AppState.Recording -> ControlDashboardUiState(
|
||||
micState = ControlDashboardButtonUiState(
|
||||
expanded = true,
|
||||
enabled = true,
|
||||
visible = true
|
||||
),
|
||||
micState = ControlDashboardButtonUiState(expanded = true, visible = true, enabled = true),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user