Skip to content

Commit 6713961

Browse files
authored
Merge branch 'master' into ai/lsp-skill
2 parents 95f9c90 + fd1f24b commit 6713961

111 files changed

Lines changed: 3874 additions & 2409 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

AGENTS.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,9 @@ suspend fun getData(): Result<Data> = withContext(Dispatchers.IO) {
192192
- NEVER hardcode strings and always preserve string resources
193193
- ALWAYS localize in ViewModels using injected `@ApplicationContext`, e.g. `context.getString()`
194194
- ALWAYS use `remember` for expensive Compose computations
195-
- ALWAYS add modifiers to the last place in the argument list when calling composable functions
196-
- NEVER add parameters with default values BEFORE the `modifier` parameter in composable functions - modifier must be the FIRST optional parameter
195+
- ALWAYS declare `modifier: Modifier = Modifier,` as the FIRST optional parameter in composable declarations
196+
- ALWAYS pass `modifier = ...` as the LAST argument in composable calls
197+
- ALWAYS add trailing commas in multi-line declarations; NEVER add a trailing comma to `modifier = ...` at call sites
197198
- ALWAYS use `navController.navigateTo(route)` for simple navigation; NEVER use raw `navController.navigate(route)``navigateTo` prevents duplicate destinations
198199
- ALWAYS prefer `VerticalSpacer`, `HorizontalSpacer`, `FillHeight` and `FillWidth` over `Spacer` when applicable
199200
- PREFER declaring small dependant classes, constants, interfaces or top-level functions in the same file with the core class where these are used

CHANGELOG.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Fixed
11+
- Fix ANR on RGS server settings screen caused by catastrophic regex backtracking #880
12+
- Fix crash when returning app to foreground on Receive screen #875
13+
- Show loading state on Spending tab when node is not running #875
14+
15+
### Added
16+
- Lightning Connections empty state with onboarding screen #857
17+
- Unified PIN management screen (enable/disable/change in one place) #857
18+
- Support entry in drawer menu #857
19+
- Brand endorsement row (Synonym + Tether logos) in Support screen #857
20+
- Reset Widgets and Reset Suggestions Cards options in Widgets settings #857
21+
- Diagonal orange footer background in Support screen #857
22+
- Mnemonic warning text transitions on reveal #857
23+
24+
### Changed
25+
- Settings redesigned with tabbed navigation (General/Security/Advanced) with swipe support #857
26+
- Icons added to all settings rows for faster scanning #857
27+
- Selected values displayed on right side of settings rows #857
28+
- Support screen redesigned with About content merged in #857
29+
- Backup and Reset moved into Security tab #857
30+
- PIN flow reworked into sheet-based enable/disable/change #857
31+
- Social links simplified with Brand tint #857
32+
- Mnemonic warning updated with new copy and red styling #857
33+
- Security title changed from "Security and Privacy" to "Security" #857
34+
- Language model updated to use string resources for "System Settings" #857
35+
36+
### Removed
37+
- About screen (content merged into Support) #857
38+
- Standalone General, Security, and Advanced settings screens (merged into tabs) #857
39+
1040
[Unreleased]: https://github.com/synonymdev/bitkit-android/compare/v2.1.2...HEAD

app/src/main/java/to/bitkit/di/HttpModule.kt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,14 @@ import io.ktor.client.plugins.defaultRequest
1212
import io.ktor.client.plugins.logging.LogLevel
1313
import io.ktor.client.plugins.logging.Logging
1414
import io.ktor.client.plugins.logging.LoggingConfig
15+
import io.ktor.client.request.head
1516
import io.ktor.http.ContentType
1617
import io.ktor.http.contentType
18+
import io.ktor.http.isSuccess
1719
import io.ktor.serialization.kotlinx.json.json
1820
import kotlinx.serialization.json.Json
21+
import to.bitkit.utils.UrlValidator
22+
import to.bitkit.utils.AppError
1923
import to.bitkit.utils.Logger
2024
import javax.inject.Singleton
2125
import io.ktor.client.plugins.logging.Logger as KtorLogger
@@ -43,6 +47,17 @@ object HttpModule {
4347
}
4448
}
4549

50+
@Provides
51+
@Singleton
52+
fun provideUrlValidator(httpClient: HttpClient) = UrlValidator { url ->
53+
runCatching {
54+
val response = httpClient.head(url)
55+
if (!response.status.isSuccess()) {
56+
throw AppError("Server returned '${response.status}'")
57+
}
58+
}
59+
}
60+
4661
@Suppress("MagicNumber")
4762
private fun HttpTimeoutConfig.defaultTimeoutConfig() {
4863
requestTimeoutMillis = 60_000

app/src/main/java/to/bitkit/models/Language.kt

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,38 @@
11
package to.bitkit.models
22

3+
import androidx.annotation.StringRes
34
import kotlinx.serialization.Serializable
5+
import to.bitkit.R
46
import java.util.Locale
57

68
@Serializable
79
enum class Language(
8-
val displayName: String,
10+
@StringRes val displayNameResId: Int? = null,
11+
val nativeName: String? = null,
912
val languageCode: String,
1013
val countryCode: String? = null,
1114
val isSystemDefault: Boolean = false,
1215
) {
1316
SYSTEM_DEFAULT(
14-
displayName = "System Default",
17+
displayNameResId = R.string.settings__language_system_default,
1518
languageCode = "system",
1619
countryCode = null,
1720
isSystemDefault = true
1821
),
19-
ARABIC("العربية", "ar"),
20-
CATALAN("Català", "ca"),
21-
CZECH("Čeština", "cs"),
22-
DUTCH("Nederlands", "nl"),
23-
ENGLISH("English", "en", "US"),
24-
FRENCH("Français", "fr", "FR"),
25-
GERMAN("Deutsch", "de"),
26-
GREEK("Ελληνικά", "el"),
27-
ITALIAN("Italiano", "it"),
28-
POLISH("Polski", "pl"),
29-
PORTUGUESE("Português", "pt", "BR"),
30-
RUSSIAN("Русский", "ru"),
31-
SPANISH("Español", "es", "ES"),
32-
SPANISH_LATIN_AMERICA("Español (Latinoamérica)", "es", "419");
22+
ARABIC(nativeName = "العربية", languageCode = "ar"),
23+
CATALAN(nativeName = "Català", languageCode = "ca"),
24+
CZECH(nativeName = "Čeština", languageCode = "cs"),
25+
DUTCH(nativeName = "Nederlands", languageCode = "nl"),
26+
ENGLISH(nativeName = "English", languageCode = "en", countryCode = "US"),
27+
FRENCH(nativeName = "Français", languageCode = "fr", countryCode = "FR"),
28+
GERMAN(nativeName = "Deutsch", languageCode = "de"),
29+
GREEK(nativeName = "Ελληνικά", languageCode = "el"),
30+
ITALIAN(nativeName = "Italiano", languageCode = "it"),
31+
POLISH(nativeName = "Polski", languageCode = "pl"),
32+
PORTUGUESE(nativeName = "Português", languageCode = "pt", countryCode = "BR"),
33+
RUSSIAN(nativeName = "Русский", languageCode = "ru"),
34+
SPANISH(nativeName = "Español", languageCode = "es", countryCode = "ES"),
35+
SPANISH_LATIN_AMERICA(nativeName = "Español (Latinoamérica)", languageCode = "es", countryCode = "419");
3336

3437
companion object {
3538
fun fromLanguageCode(languageCode: String, countryCode: String? = null): Language? {

app/src/main/java/to/bitkit/repositories/LightningRepo.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ import to.bitkit.services.NodeEventHandler
7979
import to.bitkit.utils.AppError
8080
import to.bitkit.utils.Logger
8181
import to.bitkit.utils.ServiceError
82+
import to.bitkit.utils.UrlValidator
8283
import java.io.File
8384
import java.util.concurrent.ConcurrentHashMap
8485
import java.util.concurrent.atomic.AtomicBoolean
@@ -105,6 +106,7 @@ class LightningRepo @Inject constructor(
105106
private val preActivityMetadataRepo: PreActivityMetadataRepo,
106107
private val connectivityRepo: ConnectivityRepo,
107108
private val vssBackupClientLdk: VssBackupClientLdk,
109+
private val urlValidator: UrlValidator,
108110
) {
109111
private val _lightningState = MutableStateFlow(LightningState())
110112
val lightningState = _lightningState.asStateFlow()
@@ -619,6 +621,11 @@ class LightningRepo @Inject constructor(
619621
suspend fun restartWithRgsServer(newRgsUrl: String): Result<Unit> = withContext(bgDispatcher) {
620622
Logger.info("Changing ldk-node RGS server to: '$newRgsUrl'", context = TAG)
621623

624+
validateRgsUrl(newRgsUrl).onFailure {
625+
Logger.warn("RGS server unreachable at '$newRgsUrl'", it, context = TAG)
626+
return@withContext Result.failure(it)
627+
}
628+
622629
waitForNodeToStop().onFailure { return@withContext Result.failure(it) }
623630
stop().onFailure {
624631
Logger.error("Failed to stop node during RGS server change", it, context = TAG)
@@ -640,6 +647,12 @@ class LightningRepo @Inject constructor(
640647
}
641648
}
642649

650+
private suspend fun validateRgsUrl(url: String): Result<Unit> = withContext(bgDispatcher) {
651+
val initialTimestamp = 0
652+
val testUrl = "${url.trimEnd('/')}/$initialTimestamp"
653+
urlValidator.validate(testUrl)
654+
}
655+
643656
suspend fun getBalanceForAddressType(addressType: AddressType): Result<ULong> = withContext(bgDispatcher) {
644657
executeWhenNodeRunning("getBalanceForAddressType") {
645658
runCatching {

0 commit comments

Comments
 (0)