Skip to content
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
9e25ee4
Automated update of relay data - Sun Sep 21 06:21:05 UTC 2025
actions-user Sep 21, 2025
6cccaae
Merge remote-tracking branch 'origin/main'
yet300 Sep 24, 2025
95358ac
Automated update of relay data - Sun Sep 28 06:20:40 UTC 2025
actions-user Sep 28, 2025
696f698
refactor: new close button like ios(but not liquid glass)
yet300 Sep 30, 2025
e0c7240
Merge remote-tracking branch 'origin/main'
yet300 Sep 30, 2025
776d6c5
Automated update of relay data - Sun Oct 5 06:20:09 UTC 2025
actions-user Oct 5, 2025
ce31b85
Automated update of relay data - Sun Oct 12 06:20:12 UTC 2025
actions-user Oct 12, 2025
2703c52
Merge branch 'main' into main
yet300 Oct 13, 2025
19f6473
Automated update of relay data - Sun Oct 19 06:21:51 UTC 2025
actions-user Oct 19, 2025
f24d170
Merge remote-tracking branch 'origin/main'
yet300 Oct 25, 2025
cd02bc8
Automated update of relay data - Sun Oct 26 06:21:31 UTC 2025
actions-user Oct 26, 2025
4b84db0
Automated update of relay data - Sun Nov 2 06:22:16 UTC 2025
actions-user Nov 2, 2025
bb3dd9c
Automated update of relay data - Sun Nov 9 06:21:43 UTC 2025
actions-user Nov 9, 2025
cae1e3d
Automated update of relay data - Sun Nov 16 06:22:37 UTC 2025
actions-user Nov 16, 2025
1143e49
Merge remote-tracking branch 'upstream/main'
yet300 Nov 19, 2025
57f4c03
Merge remote-tracking branch 'origin/main'
yet300 Nov 19, 2025
0bd034b
Automated update of relay data - Sun Nov 23 06:22:51 UTC 2025
actions-user Nov 23, 2025
205cc3c
Automated update of relay data - Sun Nov 30 06:24:08 UTC 2025
actions-user Nov 30, 2025
a8e9715
Chore: Remove unused `lifecycle-livedata-ktx` dependency
yet300 Nov 30, 2025
904f377
Refactor: Remove unused `runtime-livedata` dependency
yet300 Nov 30, 2025
eb1d0bc
Refactor: Migrate `LocationChannelManager` and `GeohashBookmarksStore…
yet300 Nov 30, 2025
fd9aae5
Refactor: Migrate from LiveData to StateFlow for Nostr components
yet300 Nov 30, 2025
5699887
Refactor: Migrate ChatState from LiveData to StateFlow
yet300 Nov 30, 2025
ff71bab
Refactor: Migrate UI from LiveData to StateFlow
yet300 Nov 30, 2025
9eb1c91
Refactor: Use `collectAsStateWithLifecycle` for UI state collection
yet300 Dec 1, 2025
a35c8fc
Refactor: move CloseButton to core/ui/component
yet300 Dec 1, 2025
cf7f2e4
Refactor: remove AI generated comments
yet300 Dec 1, 2025
8e631f2
Refactor: fix combine to map and use WhileSubscribed
yet300 Dec 1, 2025
f541d30
Refactor: Pass CoroutineScope to ChatState
yet300 Dec 1, 2025
4aaf996
Test: Use `TestScope` for coroutines in `CommandProcessorTest`
yet300 Dec 1, 2025
2fcc079
Merge branch 'main' into feature/livedata-to-flow
yet300 Dec 12, 2025
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
502 changes: 245 additions & 257 deletions app/src/main/assets/nostr_relays.csv

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.bitchat.android.core.ui.component.button

import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Close
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.IconButtonDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp

@Composable
fun CloseButton(
onClick: () -> Unit,
modifier: Modifier = Modifier.Companion
) {
IconButton(
onClick = onClick,
modifier = modifier
.size(32.dp),
colors = IconButtonDefaults.iconButtonColors(
contentColor = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.6f),
containerColor = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.1f)
)
) {
Icon(
imageVector = Icons.Default.Close,
contentDescription = "Close",
modifier = Modifier.Companion.size(18.dp)
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ import android.location.Geocoder
import android.location.Location
import android.location.LocationManager
import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import java.util.Locale

/**
Expand Down Expand Up @@ -46,11 +47,11 @@ class GeohashBookmarksStore private constructor(private val context: Context) {

private val membership = mutableSetOf<String>()

private val _bookmarks = MutableLiveData<List<String>>(emptyList())
val bookmarks: LiveData<List<String>> = _bookmarks
private val _bookmarks = MutableStateFlow<List<String>>(emptyList())
val bookmarks: StateFlow<List<String>> = _bookmarks.asStateFlow()

private val _bookmarkNames = MutableLiveData<Map<String, String>>(emptyMap())
val bookmarkNames: LiveData<Map<String, String>> = _bookmarkNames
private val _bookmarkNames = MutableStateFlow<Map<String, String>>(emptyMap())
val bookmarkNames: StateFlow<Map<String, String>> = _bookmarkNames.asStateFlow()

// For throttling / preventing duplicate geocode lookups
private val resolving = mutableSetOf<String>()
Expand All @@ -68,8 +69,8 @@ class GeohashBookmarksStore private constructor(private val context: Context) {
val gh = normalize(geohash)
if (gh.isEmpty() || membership.contains(gh)) return
membership.add(gh)
val updated = listOf(gh) + (_bookmarks.value ?: emptyList())
_bookmarks.postValue(updated)
val updated = listOf(gh) + (_bookmarks.value)
_bookmarks.value = updated
persist(updated)
// Resolve friendly name asynchronously
resolveNameIfNeeded(gh)
Expand All @@ -79,12 +80,12 @@ class GeohashBookmarksStore private constructor(private val context: Context) {
val gh = normalize(geohash)
if (!membership.contains(gh)) return
membership.remove(gh)
val updated = (_bookmarks.value ?: emptyList()).filterNot { it == gh }
_bookmarks.postValue(updated)
val updated = (_bookmarks.value).filterNot { it == gh }
_bookmarks.value = updated
// Remove stored name to avoid stale cache growth
val names = _bookmarkNames.value?.toMutableMap() ?: mutableMapOf()
val names = _bookmarkNames.value.toMutableMap()
if (names.remove(gh) != null) {
_bookmarkNames.postValue(names)
_bookmarkNames.value = names
persistNames(names)
}
persist(updated)
Expand All @@ -108,7 +109,7 @@ class GeohashBookmarksStore private constructor(private val context: Context) {
}
}
membership.clear(); membership.addAll(seen)
_bookmarks.postValue(ordered)
_bookmarks.value = ordered
}
} catch (e: Exception) {
Log.e(TAG, "Failed to load bookmarks: ${e.message}")
Expand All @@ -118,7 +119,7 @@ class GeohashBookmarksStore private constructor(private val context: Context) {
if (!namesJson.isNullOrEmpty()) {
val mapType = object : TypeToken<Map<String, String>>() {}.type
val dict = gson.fromJson<Map<String, String>>(namesJson, mapType)
_bookmarkNames.postValue(dict)
_bookmarkNames.value = dict
}
} catch (e: Exception) {
Log.e(TAG, "Failed to load bookmark names: ${e.message}")
Expand All @@ -127,14 +128,14 @@ class GeohashBookmarksStore private constructor(private val context: Context) {

private fun persist() {
try {
val json = gson.toJson(_bookmarks.value ?: emptyList<String>())
val json = gson.toJson(_bookmarks.value)
prefs.edit().putString(STORE_KEY, json).apply()
} catch (_: Exception) {}
}

private fun persistNames() {
try {
val json = gson.toJson(_bookmarkNames.value ?: emptyMap<String, String>())
val json = gson.toJson(_bookmarkNames.value)
prefs.edit().putString(NAMES_STORE_KEY, json).apply()
} catch (_: Exception) {}
}
Expand All @@ -144,8 +145,8 @@ class GeohashBookmarksStore private constructor(private val context: Context) {
fun clearAll() {
try {
membership.clear()
_bookmarks.postValue(emptyList())
_bookmarkNames.postValue(emptyMap())
_bookmarks.value = emptyList()
_bookmarkNames.value = emptyMap()
prefs.edit()
.remove(STORE_KEY)
.remove(NAMES_STORE_KEY)
Expand Down Expand Up @@ -209,9 +210,9 @@ class GeohashBookmarksStore private constructor(private val context: Context) {
}

if (!name.isNullOrEmpty()) {
val current = _bookmarkNames.value?.toMutableMap() ?: mutableMapOf()
val current = _bookmarkNames.value.toMutableMap()
current[gh] = name
_bookmarkNames.postValue(current)
_bookmarkNames.value = current
persistNames(current)
}
} catch (e: Exception) {
Expand Down
Loading
Loading