git.iko.soy/parseable-android
on master help sign in
Sort all datasets deterministically to ensure constant ordering (#21)

- Streams: sort by name (case-insensitive) after API fetch - Alerts: sort by name/title (case-insensitive) after API fetch - Schema columns: sort alphabetically for consistent filter/column lists - Saved filters: sort by filter name (case-insensitive) - FavoriteStreamDao.getAllNames(): add ORDER BY addedAt DESC to match getAll() https://claude.ai/code/session_01GgwJRmPpvfiUNAv2yUW87h Co-authored-by: Claude <noreply@anthropic.com>

commitd49d52d3353f219804e7c83b87c24d171f895f66 authoriko <mail@iko.soy> dateMon 16 Feb 2026, 02:40 (8 months ago) parenta02f8b3
4 files changed+10−5
app/src/main/java/com/parseable/android/data/local/FavoriteStreamDao.kt+1−1 app/src/main/java/com/parseable/android/ui/screens/alerts/AlertsViewModel.kt+4−1 app/src/main/java/com/parseable/android/ui/screens/logviewer/LogViewerViewModel.kt+4−2 app/src/main/java/com/parseable/android/ui/screens/streams/StreamsViewModel.kt+1−1
app/src/main/java/com/parseable/android/data/local/FavoriteStreamDao.kt+1−1
@@ -12,7 +12,7 @@ interface FavoriteStreamDao {
1212 @Query("SELECT * FROM favorite_streams ORDER BY addedAt DESC")
1313 fun getAll(): Flow<List<FavoriteStream>>
1414
15− @Query("SELECT streamName FROM favorite_streams")
15+ @Query("SELECT streamName FROM favorite_streams ORDER BY addedAt DESC")
1616 fun getAllNames(): Flow<List<String>>
1717
1818 @Insert(onConflict = OnConflictStrategy.REPLACE)
app/src/main/java/com/parseable/android/ui/screens/alerts/AlertsViewModel.kt+4−1
@@ -33,7 +33,10 @@ class AlertsViewModel @Inject constructor(
3333 _state.update { it.copy(isLoading = true, error = null) }
3434 when (val result = repository.listAlerts()) {
3535 is ApiResult.Success -> {
36− _state.update { it.copy(alerts = result.data, isLoading = false) }
36+ val sorted = result.data.sortedBy { a ->
37+ (a.name ?: a.title ?: "").lowercase()
38+ }
39+ _state.update { it.copy(alerts = sorted, isLoading = false) }
3740 }
3841 is ApiResult.Error -> {
3942 _state.update { it.copy(isLoading = false, error = result.userMessage) }
app/src/main/java/com/parseable/android/ui/screens/logviewer/LogViewerViewModel.kt+4−2
@@ -123,7 +123,7 @@ class LogViewerViewModel @Inject constructor(
123123 schemaJob = viewModelScope.launch {
124124 when (val result = repository.getStreamSchema(streamName)) {
125125 is ApiResult.Success -> {
126− val columns = result.data.fields.map { it.name }
126+ val columns = result.data.fields.map { it.name }.sorted()
127127 _state.update { it.copy(columns = columns) }
128128 }
129129 is ApiResult.Error -> { /* Schema loading failure is non-fatal */ }
@@ -486,7 +486,9 @@ class LogViewerViewModel @Inject constructor(
486486 _state.update { it.copy(savedFilters = it.savedFilters.copy(isLoading = true, error = null)) }
487487 when (val result = repository.listFilters()) {
488488 is ApiResult.Success -> {
489− val streamFilters = result.data.filter { it.streamName == _state.value.streamName }
489+ val streamFilters = result.data
490+ .filter { it.streamName == _state.value.streamName }
491+ .sortedBy { it.filterName.lowercase() }
490492 _state.update {
491493 it.copy(savedFilters = it.savedFilters.copy(filters = streamFilters, isLoading = false))
492494 }
app/src/main/java/com/parseable/android/ui/screens/streams/StreamsViewModel.kt+1−1
@@ -95,7 +95,7 @@ class StreamsViewModel @Inject constructor(
9595 is ApiResult.Success -> {
9696 _state.update {
9797 it.copy(
98− streams = streamsResult.data,
98+ streams = streamsResult.data.sortedBy { s -> s.name.lowercase() },
9999 isLoading = false,
100100 )
101101 }