diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml
index 6d0ee1c..d4b7acc 100644
--- a/.idea/kotlinc.xml
+++ b/.idea/kotlinc.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 74dd639..b2c751a 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,4 +1,3 @@
-
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index bf4b227..637db1f 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -55,6 +55,6 @@ litert = { group = "com.google.ai.edge.litert", name = "litert", version.ref = "
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
+kotlin-android = { id = "org.jetbrains.kotlin.android", version = "2.0.20" }
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
diff --git a/mobile/src/main/java/com/birdsounds/identify/SoundClassifier.kt b/mobile/src/main/java/com/birdsounds/identify/SoundClassifier.kt
index c6f1f2c..73f2d4a 100644
--- a/mobile/src/main/java/com/birdsounds/identify/SoundClassifier.kt
+++ b/mobile/src/main/java/com/birdsounds/identify/SoundClassifier.kt
@@ -359,7 +359,8 @@ class SoundClassifier(
return
}
val sharedPref = PreferenceManager.getDefaultSharedPreferences(mContext)
- val highPass = sharedPref.getInt("high_pass", 0)
+// val highPass = sharedPref.getInt("high_pass", 0)
+ val highPass = 300;
val butterworth = Butterworth()
butterworth.highPass(6, 48000.0, highPass.toDouble())
diff --git a/wear/TileService.kt b/wear/TileService.kt
new file mode 100644
index 0000000..c11fe49
--- /dev/null
+++ b/wear/TileService.kt
@@ -0,0 +1 @@
+class TileService {}
\ No newline at end of file
diff --git a/wear/src/main/java/com/birdsounds/identify/presentation/ControlDashboard.kt b/wear/src/main/java/com/birdsounds/identify/presentation/ControlDashboard.kt
index 925b096..afc61c6 100644
--- a/wear/src/main/java/com/birdsounds/identify/presentation/ControlDashboard.kt
+++ b/wear/src/main/java/com/birdsounds/identify/presentation/ControlDashboard.kt
@@ -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)
diff --git a/wear/src/main/java/com/birdsounds/identify/presentation/MainActivity.kt b/wear/src/main/java/com/birdsounds/identify/presentation/MainActivity.kt
index 71f40af..8d50df8 100644
--- a/wear/src/main/java/com/birdsounds/identify/presentation/MainActivity.kt
+++ b/wear/src/main/java/com/birdsounds/identify/presentation/MainActivity.kt
@@ -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 = {})
+}
\ No newline at end of file
diff --git a/wear/src/main/java/com/birdsounds/identify/presentation/MainState.kt b/wear/src/main/java/com/birdsounds/identify/presentation/MainState.kt
index 135d40d..f9c1253 100644
--- a/wear/src/main/java/com/birdsounds/identify/presentation/MainState.kt
+++ b/wear/src/main/java/com/birdsounds/identify/presentation/MainState.kt
@@ -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 })
}
diff --git a/wear/src/main/java/com/birdsounds/identify/presentation/MessageSender.kt b/wear/src/main/java/com/birdsounds/identify/presentation/MessageSender.kt
index 98025b3..d22165d 100644
--- a/wear/src/main/java/com/birdsounds/identify/presentation/MessageSender.kt
+++ b/wear/src/main/java/com/birdsounds/identify/presentation/MessageSender.kt
@@ -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
diff --git a/wear/src/main/java/com/birdsounds/identify/presentation/SpeciesList.kt b/wear/src/main/java/com/birdsounds/identify/presentation/SpeciesList.kt
index b5f6767..8e1c589 100644
--- a/wear/src/main/java/com/birdsounds/identify/presentation/SpeciesList.kt
+++ b/wear/src/main/java/com/birdsounds/identify/presentation/SpeciesList.kt
@@ -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()
var do_add_observation = false
+ var _list_on_ui: SnapshotStateList>? = null
+ fun setSpeciecsShow_list(list_in: SnapshotStateList>) {
+ _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)
}
}
\ No newline at end of file
diff --git a/wear/src/main/java/com/birdsounds/identify/presentation/SpeciesListView.kt b/wear/src/main/java/com/birdsounds/identify/presentation/SpeciesListView.kt
new file mode 100644
index 0000000..081f75d
--- /dev/null
+++ b/wear/src/main/java/com/birdsounds/identify/presentation/SpeciesListView.kt
@@ -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 = mutableStateOf("text")
+//text.toString()
+ val species_list_show = mutableStateListOf>()
+ for (i in 1..10)
+ {
+ val hi = mutableStateOf("hi")
+ species_list_show.add(hi);
+ }
+ SpeciesList.setSpeciecsShow_list(species_list_show)
+ val species_show: SnapshotStateList> = 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
+
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/wear/src/main/java/com/birdsounds/identify/presentation/StartRecordingScreen.kt b/wear/src/main/java/com/birdsounds/identify/presentation/StartRecordingScreen.kt
index 17198e4..2d753e6 100644
--- a/wear/src/main/java/com/birdsounds/identify/presentation/StartRecordingScreen.kt
+++ b/wear/src/main/java/com/birdsounds/identify/presentation/StartRecordingScreen.kt
@@ -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),
)
}