Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .devcontainer/on-start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@ sudo /usr/local/bin/init-firewall.sh

# Configure git to use gh for authentication (if logged in)
gh auth setup-git 2>/dev/null || true

# Install lefthook git hooks
lefthook install
282 changes: 0 additions & 282 deletions TODO-flipper-dumps.md

This file was deleted.

2 changes: 2 additions & 0 deletions app/src/commonMain/composeResources/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<string name="view_sample">Sample card</string>
<string name="card_type">Card Type</string>
<string name="copy">Copy</string>
<string name="copied_to_clipboard">Copied to clipboard</string>
<string name="delete">Delete</string>
<string name="delete_selected_cards">Delete %1$d selected cards?</string>
<string name="delete_selected_keys">Delete %1$d selected keys?</string>
Expand All @@ -33,6 +34,7 @@
<string name="locked_card">Locked Card</string>
<string name="menu">Menu</string>
<string name="n_selected">%1$d selected</string>
<string name="select_all">Select all</string>
<string name="nfc">NFC</string>
<string name="nfc_disabled">NFC is disabled</string>
<string name="nfc_listening_title">Ready to scan</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ fun FareBotApp(
},
onToggleSelection = { itemId -> historyViewModel.toggleSelection(itemId) },
onClearSelection = { historyViewModel.clearSelection() },
onSelectAll = { historyViewModel.selectAll() },
onDeleteSelected = { historyViewModel.deleteSelected() },
supportedCards = supportedCards,
supportedCardTypes = supportedCardTypes,
Expand Down Expand Up @@ -294,6 +295,7 @@ fun FareBotApp(
onDeleteKey = { keyId -> viewModel.deleteKey(keyId) },
onToggleSelection = { keyId -> viewModel.toggleSelection(keyId) },
onClearSelection = { viewModel.clearSelection() },
onSelectAll = { viewModel.selectAll() },
onDeleteSelected = { viewModel.deleteSelected() },
)
}
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.codebutler.farebot.shared.ui.screen

import com.codebutler.farebot.base.ui.FareBotUiTree
import com.codebutler.farebot.base.util.FormattedString
import com.codebutler.farebot.transit.CardInfo
import com.codebutler.farebot.transit.Trip

data class CardUiState(
Expand All @@ -20,6 +21,8 @@ data class CardUiState(
val currentScanLabel: String? = null,
val scanHistory: List<ScanHistoryEntry> = emptyList(),
val showScanHistory: Boolean = false,
val brandColor: Int? = null,
val cardInfo: CardInfo? = null,
)

data class ScanHistoryEntry(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -471,14 +471,15 @@ private fun CardImageTile(

@OptIn(ExperimentalLayoutApi::class)
@Composable
private fun CardDetailSheet(
internal fun CardDetailSheet(
card: CardInfo,
cardName: String,
cardLocation: String,
isSupported: Boolean,
isKeysRequired: Boolean,
onStatusChipTap: (String) -> Unit = {},
onSampleCardTap: (() -> Unit)? = null,
showImage: Boolean = true,
) {
Column(
modifier =
Expand All @@ -487,40 +488,41 @@ private fun CardDetailSheet(
.padding(horizontal = 16.dp),
) {
// Card image
Box(
modifier =
Modifier
.fillMaxWidth()
.aspectRatio(1.586f)
.clip(RoundedCornerShape(12.dp)),
) {
val imageRes = card.imageRes
if (imageRes != null) {
Image(
painter = painterResource(imageRes),
contentDescription = cardName,
modifier = Modifier.fillMaxSize(),
contentScale = ContentScale.Crop,
)
} else {
Box(
modifier =
Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.surfaceVariant),
contentAlignment = Alignment.Center,
) {
Text(
text = cardName,
style = MaterialTheme.typography.titleMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
if (showImage) {
Box(
modifier =
Modifier
.fillMaxWidth()
.aspectRatio(1.586f)
.clip(RoundedCornerShape(12.dp)),
) {
val imageRes = card.imageRes
if (imageRes != null) {
Image(
painter = painterResource(imageRes),
contentDescription = cardName,
modifier = Modifier.fillMaxSize(),
contentScale = ContentScale.Crop,
)
} else {
Box(
modifier =
Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.surfaceVariant),
contentAlignment = Alignment.Center,
) {
Text(
text = cardName,
style = MaterialTheme.typography.titleMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
}
}
Spacer(Modifier.height(12.dp))
}

Spacer(Modifier.height(12.dp))

// Card name
Text(
text = cardName,
Expand Down Expand Up @@ -669,7 +671,7 @@ private fun CardDetailSheet(
}

@Composable
private fun NonInteractiveChip(content: @Composable () -> Unit) {
internal fun NonInteractiveChip(content: @Composable () -> Unit) {
Box(
modifier =
Modifier.pointerInput(Unit) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import androidx.compose.material.icons.filled.Nfc
import androidx.compose.material.icons.filled.RadioButtonChecked
import androidx.compose.material.icons.filled.RadioButtonUnchecked
import androidx.compose.material.icons.filled.Search
import androidx.compose.material.icons.filled.SelectAll
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Badge
import androidx.compose.material3.Button
Expand Down Expand Up @@ -105,6 +106,7 @@ import farebot.app.generated.resources.ok
import farebot.app.generated.resources.reading_card
import farebot.app.generated.resources.scan
import farebot.app.generated.resources.search_supported_cards
import farebot.app.generated.resources.select_all
import farebot.app.generated.resources.show
import farebot.app.generated.resources.show_all_scans
import farebot.app.generated.resources.show_experimental_cards
Expand All @@ -130,6 +132,7 @@ fun HomeScreen(
onImportFile: () -> Unit,
onToggleSelection: (String) -> Unit,
onClearSelection: () -> Unit,
onSelectAll: () -> Unit,
onDeleteSelected: () -> Unit,
supportedCards: List<CardInfo>,
supportedCardTypes: Set<CardType>,
Expand Down Expand Up @@ -255,6 +258,9 @@ fun HomeScreen(
}
},
actions = {
IconButton(onClick = onSelectAll) {
Icon(Icons.Default.SelectAll, contentDescription = stringResource(Res.string.select_all))
}
IconButton(onClick = { showDeleteConfirmation = true }) {
Icon(Icons.Default.Delete, contentDescription = stringResource(Res.string.delete))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.SelectAll
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Checkbox
import androidx.compose.material3.CircularProgressIndicator
Expand Down Expand Up @@ -47,6 +48,7 @@ import farebot.app.generated.resources.delete_selected_keys
import farebot.app.generated.resources.keys
import farebot.app.generated.resources.n_selected
import farebot.app.generated.resources.no_keys
import farebot.app.generated.resources.select_all
import org.jetbrains.compose.resources.stringResource

@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
Expand All @@ -58,6 +60,7 @@ fun KeysScreen(
onDeleteKey: (String) -> Unit,
onToggleSelection: (String) -> Unit = {},
onClearSelection: () -> Unit = {},
onSelectAll: () -> Unit = {},
onDeleteSelected: () -> Unit = {},
) {
var showDeleteConfirmation by remember { mutableStateOf(false) }
Expand Down Expand Up @@ -94,6 +97,9 @@ fun KeysScreen(
}
},
actions = {
IconButton(onClick = onSelectAll) {
Icon(Icons.Default.SelectAll, contentDescription = stringResource(Res.string.select_all))
}
IconButton(onClick = { showDeleteConfirmation = true }) {
Icon(Icons.Default.Delete, contentDescription = stringResource(Res.string.delete))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ class CardViewModel(
viewModelScope.launch {
try {
val card = rawCard.parse()
val brandColor = transitFactoryRegistry.findBrandColor(card)
val cardInfo = transitFactoryRegistry.findCardInfo(card)
val transitInfo = transitFactoryRegistry.parseTransitInfo(card)

// Build scan history entries
Expand Down Expand Up @@ -121,6 +123,8 @@ class CardViewModel(
scanCount = currentScanIds.size.coerceAtLeast(1),
currentScanLabel = currentScanLabel,
scanHistory = scanHistory,
brandColor = brandColor,
cardInfo = cardInfo,
)
} else {
val tagIdHex =
Expand All @@ -145,6 +149,8 @@ class CardViewModel(
scanCount = currentScanIds.size.coerceAtLeast(1),
currentScanLabel = currentScanLabel,
scanHistory = scanHistory,
brandColor = brandColor,
cardInfo = cardInfo,
)
}
} catch (ex: Exception) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,16 @@ class HistoryViewModel(
)
}

fun selectAll() {
val current = _uiState.value
val allIds = current.items.map { it.id }.toSet()
_uiState.value =
current.copy(
selectedIds = allIds,
isSelectionMode = allIds.isNotEmpty(),
)
}

fun clearSelection() {
_uiState.value =
_uiState.value.copy(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,16 @@ class KeysViewModel(
)
}

fun selectAll() {
val current = _uiState.value
val allIds = current.keys.map { it.id }.toSet()
_uiState.value =
current.copy(
selectedIds = allIds,
isSelectionMode = allIds.isNotEmpty(),
)
}

fun clearSelection() {
_uiState.value =
_uiState.value.copy(
Expand Down