Single-action recording rows, S.H.O.N.A.R. header branding, drop storage pill
This commit is contained in:
parent
47f7cb9336
commit
1f46d2a0e4
2 changed files with 50 additions and 66 deletions
|
|
@ -26,7 +26,6 @@ import androidx.compose.material.icons.filled.Delete
|
||||||
import androidx.compose.material.icons.filled.Mic
|
import androidx.compose.material.icons.filled.Mic
|
||||||
import androidx.compose.material.icons.filled.MoreVert
|
import androidx.compose.material.icons.filled.MoreVert
|
||||||
import androidx.compose.material.icons.filled.Pause
|
import androidx.compose.material.icons.filled.Pause
|
||||||
import androidx.compose.material.icons.filled.PhoneAndroid
|
|
||||||
import androidx.compose.material.icons.filled.PlayArrow
|
import androidx.compose.material.icons.filled.PlayArrow
|
||||||
import androidx.compose.material.icons.filled.Settings
|
import androidx.compose.material.icons.filled.Settings
|
||||||
import androidx.compose.material3.AlertDialog
|
import androidx.compose.material3.AlertDialog
|
||||||
|
|
@ -190,7 +189,7 @@ fun HomeScreen(
|
||||||
ShonarSearchField(
|
ShonarSearchField(
|
||||||
value = query,
|
value = query,
|
||||||
onValueChange = { query = it },
|
onValueChange = { query = it },
|
||||||
placeholder = "Search saved recordings…",
|
placeholder = "Search recordings…",
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -200,7 +199,6 @@ fun HomeScreen(
|
||||||
onSort = { sort = it },
|
onSort = { sort = it },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
item { StorageChip() }
|
|
||||||
if (storageOk == false) {
|
if (storageOk == false) {
|
||||||
item {
|
item {
|
||||||
val ctx = context
|
val ctx = context
|
||||||
|
|
@ -227,6 +225,9 @@ fun HomeScreen(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Section break between the controls above and the library:
|
||||||
|
// list spacing (10dp) + this spacer = a deliberate 20dp pause.
|
||||||
|
item { Spacer(Modifier.height(10.dp)) }
|
||||||
if (recordings.isNotEmpty()) {
|
if (recordings.isNotEmpty()) {
|
||||||
item {
|
item {
|
||||||
Row(
|
Row(
|
||||||
|
|
@ -315,31 +316,32 @@ private fun HeaderBlock(recording: Boolean, onOpenSettings: () -> Unit) {
|
||||||
) {
|
) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(44.dp)
|
.size(76.dp)
|
||||||
.background(
|
.background(
|
||||||
cs.primary.copy(alpha = 0.14f),
|
androidx.compose.ui.graphics.Color(0xFF0B1220),
|
||||||
RoundedCornerShape(12.dp),
|
RoundedCornerShape(16.dp),
|
||||||
)
|
)
|
||||||
.border(1.dp, cs.primary.copy(alpha = 0.45f), RoundedCornerShape(12.dp)),
|
.border(1.dp, cs.primary.copy(alpha = 0.45f), RoundedCornerShape(16.dp)),
|
||||||
contentAlignment = Alignment.Center,
|
contentAlignment = Alignment.Center,
|
||||||
) {
|
) {
|
||||||
Icon(
|
androidx.compose.foundation.Image(
|
||||||
Icons.Filled.Mic,
|
painter = androidx.compose.ui.res.painterResource(
|
||||||
|
id = com.shonar.R.drawable.ic_launcher_foreground,
|
||||||
|
),
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = cs.primary,
|
modifier = Modifier.size(58.dp),
|
||||||
modifier = Modifier.size(22.dp),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Spacer(Modifier.width(12.dp))
|
Spacer(Modifier.width(12.dp))
|
||||||
Column(Modifier.weight(1f)) {
|
Column(Modifier.weight(1f)) {
|
||||||
Text(
|
Text(
|
||||||
"Recordings",
|
"S.H.O.N.A.R.",
|
||||||
style = MaterialTheme.typography.headlineSmall,
|
style = MaterialTheme.typography.headlineSmall,
|
||||||
color = cs.onBackground,
|
color = cs.onBackground,
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
if (recording) "Recording in progress — stays on this phone"
|
if (recording) "Recording in progress — stays on this phone"
|
||||||
else "Your saved recordings stay on this phone",
|
else "Self Hosted Oral Notes and Audio Recording",
|
||||||
style = MaterialTheme.typography.bodySmall,
|
style = MaterialTheme.typography.bodySmall,
|
||||||
color = cs.onSurfaceVariant,
|
color = cs.onSurfaceVariant,
|
||||||
)
|
)
|
||||||
|
|
@ -522,59 +524,62 @@ private fun RecordingRow(
|
||||||
Modifier.fillMaxWidth().padding(12.dp),
|
Modifier.fillMaxWidth().padding(12.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
Box(
|
// Single primary action: large play/pause. No mic tile here —
|
||||||
|
// the mic icon lives only on the Record button, where it
|
||||||
|
// unambiguously means "record".
|
||||||
|
IconButton(
|
||||||
|
onClick = onPlay,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(44.dp)
|
.size(52.dp)
|
||||||
.background(
|
.background(
|
||||||
if (selected) cs.primary.copy(alpha = 0.16f) else cs.surfaceVariant,
|
cs.primary.copy(alpha = if (playing) 0.22f else 0.14f),
|
||||||
RoundedCornerShape(10.dp),
|
androidx.compose.foundation.shape.CircleShape,
|
||||||
)
|
)
|
||||||
.border(
|
.border(
|
||||||
1.dp,
|
1.dp,
|
||||||
if (selected) cs.primary.copy(alpha = 0.5f) else cs.outline.copy(alpha = 0.4f),
|
cs.primary.copy(alpha = 0.55f),
|
||||||
RoundedCornerShape(10.dp),
|
androidx.compose.foundation.shape.CircleShape,
|
||||||
),
|
),
|
||||||
contentAlignment = Alignment.Center,
|
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
Icons.Filled.Mic,
|
if (playing) Icons.Filled.Pause else Icons.Filled.PlayArrow,
|
||||||
contentDescription = null,
|
contentDescription = if (playing) "Pause ${recording.title}" else "Play ${recording.title}",
|
||||||
tint = if (selected) cs.primary else cs.onSurfaceVariant,
|
tint = cs.primary,
|
||||||
modifier = Modifier.size(22.dp),
|
modifier = Modifier.size(24.dp),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Spacer(Modifier.width(12.dp))
|
Spacer(Modifier.width(12.dp))
|
||||||
Column(Modifier.weight(1f)) {
|
Column(Modifier.weight(1f)) {
|
||||||
Text(
|
Text(
|
||||||
recording.title,
|
recording.title,
|
||||||
style = MaterialTheme.typography.titleSmall,
|
style = MaterialTheme.typography.titleMedium,
|
||||||
color = cs.onSurface,
|
color = cs.onSurface,
|
||||||
maxLines = 2,
|
maxLines = 2,
|
||||||
)
|
)
|
||||||
Spacer(Modifier.height(2.dp))
|
Spacer(Modifier.height(4.dp))
|
||||||
Text(
|
Text(
|
||||||
"${formatBytes(recording.sizeBytes)} • ${formatDuration(recording.durationMs)} • ${formatDate(recording.createdAtEpochMs)}",
|
"${formatBytes(recording.sizeBytes)} • ${formatDuration(recording.durationMs)} • ${formatDate(recording.createdAtEpochMs)}",
|
||||||
style = MaterialTheme.typography.bodySmall,
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
color = cs.onSurfaceVariant,
|
color = cs.onSurfaceVariant,
|
||||||
maxLines = 1,
|
maxLines = 2,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
// Secondary action: visually quieter — muted tone inside a
|
||||||
|
// subtle outline so it reads as "more options", not primary.
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = onPlay,
|
onClick = { menu = true },
|
||||||
modifier = Modifier.size(48.dp),
|
modifier = Modifier
|
||||||
|
.size(48.dp)
|
||||||
|
.border(
|
||||||
|
1.dp,
|
||||||
|
cs.outline.copy(alpha = 0.5f),
|
||||||
|
androidx.compose.foundation.shape.CircleShape,
|
||||||
|
),
|
||||||
) {
|
) {
|
||||||
Icon(
|
|
||||||
if (playing) Icons.Filled.Pause else Icons.Filled.PlayArrow,
|
|
||||||
contentDescription = if (playing) "Pause preview" else "Play preview",
|
|
||||||
tint = cs.primary,
|
|
||||||
modifier = Modifier.size(24.dp),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
IconButton(onClick = { menu = true }, modifier = Modifier.size(48.dp)) {
|
|
||||||
Icon(
|
Icon(
|
||||||
Icons.Filled.MoreVert,
|
Icons.Filled.MoreVert,
|
||||||
contentDescription = "More actions for ${recording.title}",
|
contentDescription = "More actions for ${recording.title}",
|
||||||
tint = cs.onSurfaceVariant,
|
tint = LocalShonarExtras.current.muted,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
androidx.compose.material3.DropdownMenu(
|
androidx.compose.material3.DropdownMenu(
|
||||||
|
|
@ -683,32 +688,9 @@ private fun StorageAccessCard(onGrant: () -> Unit) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Fixed on-phone storage indicator — no selection, nothing leaves the phone. */
|
/** Fixed on-phone storage indicator — no selection, nothing leaves the phone. */
|
||||||
@Composable
|
/* StorageChip removed per design review (2026-09-18): the "Stored: on this
|
||||||
private fun StorageChip() {
|
phone" pill, text, icon, background, and reserved space are gone. The
|
||||||
val cs = MaterialTheme.colorScheme
|
section spacer above keeps the layout rhythm intentional. */
|
||||||
Card(
|
|
||||||
shape = RoundedCornerShape(50),
|
|
||||||
colors = CardDefaults.cardColors(containerColor = cs.surfaceVariant),
|
|
||||||
border = androidx.compose.foundation.BorderStroke(1.dp, cs.outline.copy(alpha = 0.6f)),
|
|
||||||
) {
|
|
||||||
Row(
|
|
||||||
Modifier.padding(horizontal = 14.dp, vertical = 8.dp),
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
Icons.Filled.PhoneAndroid, contentDescription = null,
|
|
||||||
modifier = Modifier.size(18.dp),
|
|
||||||
tint = cs.onSurfaceVariant,
|
|
||||||
)
|
|
||||||
Spacer(Modifier.size(8.dp))
|
|
||||||
Text(
|
|
||||||
"Stored: on this phone",
|
|
||||||
style = MaterialTheme.typography.labelLarge,
|
|
||||||
color = cs.onSurfaceVariant,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun EmptyState(text: String) {
|
private fun EmptyState(text: String) {
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,8 @@ import androidx.compose.material3.TextButton
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.semantics.contentDescription
|
||||||
|
import androidx.compose.ui.semantics.semantics
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -63,7 +65,7 @@ fun ShonarSearchField(
|
||||||
focusedTextColor = MaterialTheme.colorScheme.onSurface,
|
focusedTextColor = MaterialTheme.colorScheme.onSurface,
|
||||||
unfocusedTextColor = MaterialTheme.colorScheme.onSurface,
|
unfocusedTextColor = MaterialTheme.colorScheme.onSurface,
|
||||||
),
|
),
|
||||||
modifier = modifier,
|
modifier = modifier.semantics { contentDescription = placeholder },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue