mirror of
https://github.com/rt-bishop/Look4Sat.git
synced 2026-10-05 04:07:29 +00:00
Added AOS/LOS timer to each pass and a SearchBar filter
This commit is contained in:
1 parent
782b438a07
commit
83ce7229f6
9 files changed
+396
-249
No files matched your search
@@ -39,6 +39,7 @@ import androidx.compose.foundation.layout.statusBars
|
||||
import androidx.compose.foundation.layout.statusBarsPadding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.BasicTextField
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
@@ -46,21 +47,32 @@ import androidx.compose.material3.ElevatedButton
|
||||
import androidx.compose.material3.ElevatedCard
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.LocalTextStyle
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.ModalBottomSheet
|
||||
import androidx.compose.material3.ProgressIndicatorDefaults
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.rememberModalBottomSheetState
|
||||
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfoV2
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.compositionLocalOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.drawWithCache
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.geometry.Size
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Path
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.addOutline
|
||||
import androidx.compose.ui.graphics.drawscope.Stroke
|
||||
import androidx.compose.ui.graphics.drawscope.clipRect
|
||||
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
|
||||
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
@@ -428,6 +440,55 @@ private fun DialogShell(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SearchBar(onQueryChange: (String) -> Unit, modifier: Modifier = Modifier) {
|
||||
val currentQuery = rememberSaveable { mutableStateOf("") }
|
||||
val updateQuery = { newValue: String ->
|
||||
currentQuery.value = newValue
|
||||
onQueryChange(newValue)
|
||||
}
|
||||
ElevatedCard(modifier = modifier.height(48.dp)) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.Start,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.padding(start = 12.dp)
|
||||
) {
|
||||
Icon(painter = painterResource(id = R.drawable.ic_search), contentDescription = null)
|
||||
BasicTextField(
|
||||
value = currentQuery.value,
|
||||
onValueChange = updateQuery,
|
||||
singleLine = true,
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(start = 12.dp),
|
||||
textStyle = TextStyle(
|
||||
fontSize = 16.sp,
|
||||
lineHeight = 20.sp,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = MaterialTheme.colorScheme.onSurface
|
||||
),
|
||||
decorationBox = { innerTextField ->
|
||||
if (currentQuery.value.isEmpty()) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.sat_search_hint),
|
||||
fontSize = 16.sp,
|
||||
lineHeight = 20.sp,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
}
|
||||
innerTextField()
|
||||
},
|
||||
cursorBrush = SolidColor(MaterialTheme.colorScheme.onSurface)
|
||||
)
|
||||
IconButton(onClick = { updateQuery("") }) {
|
||||
val clearCd = stringResource(R.string.sat_search_clear)
|
||||
Icon(painter = painterResource(id = R.drawable.ic_close), contentDescription = clearCd)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun hasEnoughHeight(): Boolean =
|
||||
currentWindowAdaptiveInfoV2().windowSizeClass.isHeightAtLeastBreakpoint(480)
|
||||
@@ -580,3 +641,30 @@ fun formatFrequency(frequencyHz: Long): String {
|
||||
val hz = frequencyHz % 1_000
|
||||
return String.format(Locale.ENGLISH, "%d.%03d.%03d", mhz, khz, hz)
|
||||
}
|
||||
|
||||
/**
|
||||
* Strokes the [shape] outline as a track, then reveals it left to right up to the [progress]
|
||||
* fraction of the width, so the top and bottom edges fill in sync.
|
||||
*/
|
||||
@Composable
|
||||
fun Modifier.progressOutline(
|
||||
progress: Float,
|
||||
shape: Shape = RoundedCornerShape(12.dp),
|
||||
width: Dp = 0.5.dp,
|
||||
trackColor: Color = ProgressIndicatorDefaults.linearTrackColor,
|
||||
progressColor: Color = ProgressIndicatorDefaults.linearColor
|
||||
) = this.drawWithCache {
|
||||
val widthPx = width.toPx()
|
||||
val outline = shape.createOutline(Size(size.width - widthPx, size.height - widthPx), layoutDirection, this)
|
||||
val outlinePath = Path().apply {
|
||||
addOutline(outline)
|
||||
translate(Offset(widthPx / 2f, widthPx / 2f))
|
||||
}
|
||||
val stroke = Stroke(width = widthPx)
|
||||
val revealWidth = size.width * progress.coerceIn(0f, 1f)
|
||||
onDrawWithContent {
|
||||
drawContent()
|
||||
drawPath(outlinePath, trackColor, style = stroke)
|
||||
clipRect(right = revealWidth) { drawPath(outlinePath, progressColor, style = stroke) }
|
||||
}
|
||||
}
|
||||
+5
-2
@@ -39,6 +39,7 @@ fun SwipeableItem(onSwipeRight: () -> Unit, onSwipeLeft: () -> Unit, content: @C
|
||||
val dismissThresholdPx = with(LocalDensity.current) { 120.dp.toPx() }
|
||||
val dismissState = rememberSwipeToDismissBoxState { dismissThresholdPx }
|
||||
val willTrigger by remember { derivedStateOf { dismissState.targetValue != SwipeToDismissBoxValue.Settled } }
|
||||
val isSwiping by remember { derivedStateOf { dismissState.dismissDirection != SwipeToDismissBoxValue.Settled } }
|
||||
val hapticFeedback = LocalHapticFeedback.current
|
||||
LaunchedEffect(willTrigger) {
|
||||
val feedbackType = if (willTrigger) HapticFeedbackType.LongPress else HapticFeedbackType.SegmentTick
|
||||
@@ -49,8 +50,10 @@ fun SwipeableItem(onSwipeRight: () -> Unit, onSwipeLeft: () -> Unit, content: @C
|
||||
enableDismissFromStartToEnd = true,
|
||||
enableDismissFromEndToStart = true,
|
||||
backgroundContent = {
|
||||
val isSwipeRight = dismissState.dismissDirection == SwipeToDismissBoxValue.StartToEnd
|
||||
SwipeBackground(isSwipeRight, willTrigger, MaterialTheme.colorScheme.primary)
|
||||
if (isSwiping) {
|
||||
val isSwipeRight = dismissState.dismissDirection == SwipeToDismissBoxValue.StartToEnd
|
||||
SwipeBackground(isSwipeRight, willTrigger, MaterialTheme.colorScheme.primary)
|
||||
}
|
||||
},
|
||||
content = { content() },
|
||||
onDismiss = {
|
||||
|
||||
@@ -47,8 +47,13 @@
|
||||
<string name="pass_deep_space" translatable="false">DeepSpace</string>
|
||||
<string name="pass_altitude">Altitude: %d km</string>
|
||||
<string name="pass_aosLos" translatable="false">%03d° - %03d°</string>
|
||||
<string name="pass_azimuth" translatable="false">%03d°</string>
|
||||
<string name="pass_duration_placeholder" translatable="false">--m --s</string>
|
||||
<string name="pass_timer_aos" translatable="false">AOS %s</string>
|
||||
<string name="pass_timer_los" translatable="false">LOS %s</string>
|
||||
<string name="pass_empty_list_message">
|
||||
Make sure your filters are correct and you have selected satellites</string>
|
||||
<string name="pass_empty_search_message">No upcoming passes match your search</string>
|
||||
<string name="pass_error_message">There are no upcoming satellite passes to display</string>
|
||||
<string name="pass_welcome_title">Welcome to Look4Sat\!</string>
|
||||
<string name="pass_welcome_message">
|
||||
|
||||
Reference in new issue
Block a user