Skip to content

Commit 57eb7bb

Browse files
Merge branch 'master' into feat/trezor-hardware-support
2 parents 209eacc + d60467a commit 57eb7bb

204 files changed

Lines changed: 17225 additions & 1056 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.
Lines changed: 58 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -122,31 +122,72 @@ This PR adds support for...
122122
When the user provides custom instructions after `--`:
123123
- Parse any referenced commit SHAs and read their full messages
124124
- Focus the description content on areas the user emphasizes
125-
- Structure QA Notes according to user's specific testing instructions
125+
- Structure QA Notes according to user's specific manual testing instructions and automated coverage notes
126126
- Custom instructions take priority over default generation rules for sections they address
127-
- Preserve exact testing steps provided by the user (don't summarize or omit details)
128-
129-
**QA Notes / Testing Scenarios:**
130-
- Structure with numbered headings and steps
131-
- Make steps easily referenceable
132-
- Be specific about what to test and expected outcomes
127+
- Preserve exact manual testing steps provided by the user (don't summarize or omit details)
128+
- If custom instructions include automated checks or coverage notes, place them under `#### Automated Checks`
129+
130+
**QA Notes / Validation:**
131+
- QA Notes separate actionable human QA instructions from automated verification coverage.
132+
- Always use this structure:
133+
```md
134+
### QA Notes
135+
#### Manual Tests
136+
#### Automated Checks
137+
```
138+
- Keep local verification commands, Gradle tasks, detekt, lint, unit tests, build passes, cargo test, cargo clippy, npm test, typecheck, CI coverage, or similar automated checks out of `#### Manual Tests`; summarize them under `#### Automated Checks` when they add useful context.
139+
- Use `#### Automated Checks` to summarize automated verification evidence, prioritizing coverage added, modified, or removed with file paths and a short explanation.
140+
- For removed automated coverage, state why it was removed.
141+
- Do not list standard CI or PR bot commands as checkbox items just because they run for every PR. If standard CI coverage is worth mentioning, summarize it in one sentence.
142+
- List raw commands only when they were run locally, are non-standard, use special flags or environment values, validate workflow behavior, or explain a meaningful verification gap.
143+
- For workflow behavior validation, include `(after merge)` in the automated check item because workflow changes only take effect for PRs opened after the workflow update merges.
144+
- If no actionable manual validation exists, write `N/A` under `#### Manual Tests`.
145+
- If no automated checks were run and no automated coverage changed, write `N/A` under `#### Automated Checks`.
146+
- Write manual tests using this template:
147+
```md
148+
- [ ] **{numbering}.** {optional_condition + →} {screen_action} → {next_screen_action}: expectation
149+
```
150+
- Use a list of unchecked checkboxes for each individual test.
151+
- Use a numbered prefix for each test, in bold, for example `**1.**`, `**2.**`.
152+
- Use `regression:` for regression checks, positioned after the numbering.
153+
- Use sub-lists for variations of the same test.
154+
- Use letter suffixes in numbering for each variation when a test has a sub-list, for example `**3a.**`, `**3b.**`.
155+
- Always use `` to denote navigation, for example `Send → Amount`.
156+
- Use screen names from code, formatted as separate words without the `Screen` suffix, for example `SendAmountScreen` becomes `Send Amount`.
157+
- Use short-form wording like `in-sheet` for sheet screens, `nav` for navigation, `back` for back nav, and `LN` for Lightning Network.
133158

134159
**For library repos (has `bindings/` directory or `Cargo.toml`):**
135-
Structure QA Notes around testing and integration:
160+
Structure manual QA around integration validation only. Automated checks belong under `#### Automated Checks`.
136161

137162
Example:
138163
```
139164
### QA Notes
165+
#### Manual Tests
166+
- [ ] **1.** Consumer app → exercise updated binding flow: behavior matches previous release.
167+
- [ ] **2.** `regression:` Android integration screen → trigger changed API path: no crash or stale data.
168+
#### Automated Checks
169+
- Binding tests added: cover updated Android API path in `bindings/android/...`.
170+
- CI: standard cargo and binding checks run by the PR bot.
171+
```
140172

141-
#### Testing
142-
- [ ] `cargo test` passes
143-
- [ ] `cargo clippy` clean
144-
- [ ] Android bindings: `./build_android.sh`
145-
- [ ] iOS bindings: `./build_ios.sh`
146-
147-
#### Integration
148-
- Tested in: [bitkit-android#XXX](link)
149-
- Or N/A if internal refactor with no API changes
173+
Concrete style target:
174+
```md
175+
### QA Notes
176+
#### Manual Tests
177+
- [ ] **1.** No usable channels/spending balance → scan LN invoice: error shows immediately, not after 15s.
178+
- [ ] **2.** Scanner → scan fixed amount LN invoice: Send Confirm or QuickPay opens directly.
179+
- [ ] **3a.** `regression:` Send → scanner/paste fixed amount LN invoice: in-sheet nav to Confirm or QuickPay.
180+
- [ ] **3b.** `regression:` Variable amount LN invoice/LNURL-pay: lands on Amount view.
181+
- [ ] **4a.** Activity Detail of LN transfer → tap Connection: lands on Channel Detail.
182+
- [ ] **4b.** back: returns to Activity Detail.
183+
- [ ] **5a.** Settings → Lightning Connections → tap channel: still opens Channel Detail.
184+
- [ ] **5b.** back: returns to Connections List.
185+
- [ ] **6.** `regression:` Channel Detail → tap Close Connection: works.
186+
#### Automated Checks
187+
- Unit tests added: cover invoice timeout handling in `app/src/test/.../SendInvoiceTest.kt`.
188+
- Unit tests modified: update channel navigation assertions in `app/src/test/.../ChannelDetailTest.kt`.
189+
- Test coverage removed: delete stale mock-only assertions from `app/src/test/.../OldFlowTest.kt` because the flow no longer exists.
190+
- CI: standard compile, unit test, and detekt checks run by the PR bot.
150191
```
151192

152193
**Preview Section (conditional):**
Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -53,18 +53,9 @@ If "Previous tag": ask `"Which tag?"` with a text input (default: `v{oldVersionN
5353

5454
If "master" or if the release is minor/major: `{baseRef} = master`.
5555

56-
### 2c. Finalize Changelog
57-
58-
Read `CHANGELOG.md` and check whether `## [Unreleased]` has any entries beneath it.
59-
60-
**If entries exist:**
61-
1. Replace `## [Unreleased]` with `## [{newVersionName}] - {YYYY-MM-DD}` (today's date)
62-
2. Insert a fresh empty `## [Unreleased]` section above the new version heading
63-
3. Update the compare link references at the bottom of the file:
64-
- Change `[Unreleased]` link to compare from `v{newVersionName}...HEAD`
65-
- Add a new `[{newVersionName}]` link comparing `v{oldVersionName}...v{newVersionName}`
66-
67-
**If no entries:** Print `⚠ CHANGELOG.md has no unreleased entries — continuing without changelog update.` and proceed.
56+
Set `{changelogTarget}`:
57+
- If `{baseRef}` is `master`: `next`
58+
- Otherwise: `hotfix`
6859

6960
### 3. Create Release Branch & Bump Version
7061

@@ -86,18 +77,34 @@ Cherry-pick the commits you need onto this branch now, then continue.
8677
```
8778
Wait for the user to confirm they are done cherry-picking before proceeding.
8879

80+
Finalize changelog after the release branch contains all release commits:
81+
82+
```bash
83+
scripts/collect-changelog.sh --target {changelogTarget}
84+
```
85+
86+
Read `CHANGELOG.md` and check whether `## [Unreleased]` has any entries beneath it after collecting fragments.
87+
88+
**If entries exist:**
89+
1. Replace `## [Unreleased]` with `## [{newVersionName}] - {YYYY-MM-DD}` (today's date)
90+
2. Insert a fresh empty `## [Unreleased]` section above the new version heading
91+
3. Update the compare link references at the bottom of the file:
92+
- Change `[Unreleased]` link to compare from `v{newVersionName}...HEAD`
93+
- Add a new `[{newVersionName}]` link comparing `v{oldVersionName}...v{newVersionName}`
94+
95+
**If no entries:** Print `⚠ CHANGELOG.md has no unreleased entries — continuing without changelog update.` and proceed.
96+
8997
Edit `app/build.gradle.kts`:
9098
- Change `versionCode = {old}` to `versionCode = {newVersionCode}`
9199
- Change `versionName = "{old}"` to `versionName = "{newVersionName}"`
92100

93101
```bash
94102
git add app/build.gradle.kts
95-
# Only stage CHANGELOG.md if step 2c modified it (i.e. unreleased entries were found)
96103
git commit -m "chore: version {newVersionName}"
97104
git push -u origin release-{newVersionName}
98105
```
99106

100-
If step 2c updated `CHANGELOG.md`, also `git add CHANGELOG.md` before the commit.
107+
If changelog collection updated `CHANGELOG.md` or deleted consumed fragments, run `git add CHANGELOG.md changelog.d` before the commit.
101108

102109
### 4. Create Version Bump PR
103110

.claude/commands

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../.agents/commands

.cursor/rules/rules.main.mdc

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,14 @@ alwaysApply: true
6363
---
6464

6565
## Changelog rules:
66-
- add an entry under `## [Unreleased]` in `CHANGELOG.md` for `feat:` and `fix:` PRs; skip for `chore:`, `ci:`, `refactor:`, `test:`, `docs:` unless the change is user-facing
67-
- use standard Keep a Changelog categories: `### Added`, `### Changed`, `### Deprecated`, `### Removed`, `### Fixed`, `### Security`
68-
- append `#PR_NUMBER` at the end of each changelog entry when the PR number is known
69-
- place new entries at the top of their category section (newest first)
70-
- never modify released version sections — only edit `## [Unreleased]`
71-
- create category headings on demand (don't add empty stubs)
66+
- never edit `CHANGELOG.md` in normal feature/fix PRs; release automation collects changelog fragments into it
67+
- add exactly one changelog fragment for user-facing `feat:` and `fix:` PRs; skip for `chore:`, `ci:`, `refactor:`, `test:`, `docs:` unless the change is user-facing
68+
- put normal release fragments in `changelog.d/next/` and hotfix fragments in `changelog.d/hotfix/`
69+
- name fragments `<issue-or-pr>.<category>.md`, where category is one of `added`, `changed`, `deprecated`, `removed`, `fixed`, or `security`
70+
- write the fragment as one polished user-facing sentence without a leading bullet and without a PR number
71+
- never add multiple changelog fragments for the same PR — summarize all changes in one concise fragment
72+
- release commits consume fragments with `scripts/collect-changelog.sh --target next|hotfix`, update `CHANGELOG.md`, and delete consumed fragment files
73+
- never modify released version sections manually
7274

7375
---
7476

.github/pull_request_template.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!-- Closes | Fixes | Resolves #ISSUE_ID -->
2-
<!-- Changelog: Add an entry under ## [Unreleased] in CHANGELOG.md for user-facing changes (skip for chores/CI/refactors). -->
2+
<!-- Changelog: For user-facing changes, add one fragment in changelog.d/next/ or changelog.d/hotfix/. Do not edit CHANGELOG.md in normal PRs. -->
33
<!-- Brief summary of the PR changes, linking to the related resources (issue/design/bug/etc) if applicable. -->
44

55
### Description

AGENTS.md

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
# CLAUDE.md
22

3-
This file provides guidance to AI agents like Cursor/Claude Code/Codex/WARP when working with code in this repository.
3+
This file provides guidance to Codex, Claude Code, and Cursor when working with code in this repository.
4+
5+
## Agent Commands
6+
7+
Durable shared agent command specs live in `.agents/commands/`. For PR creation, follow `.agents/commands/pr.md`; `.claude/commands` is a compatibility symlink to the same files.
48

59
## Build Commands
610

@@ -194,7 +198,7 @@ suspend fun getData(): Result<Data> = withContext(Dispatchers.IO) {
194198
- ALWAYS use `remember` for expensive Compose computations
195199
- ALWAYS declare `modifier: Modifier = Modifier,` as the FIRST optional parameter in composable declarations
196200
- 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
201+
- ALWAYS add trailing commas in multi-line declarations, EXCEPT after a `modifier = ...` last argument — never add a trailing comma there, whether the modifier is a single call (`modifier = Modifier.weight(1f)`) or a chain (`modifier = Modifier.fillMaxWidth().testTag("foo")`)
198202
- ALWAYS use `navController.navigateTo(route)` for simple navigation; NEVER use raw `navController.navigate(route)``navigateTo` prevents duplicate destinations
199203
- ALWAYS prefer `VerticalSpacer`, `HorizontalSpacer`, `FillHeight` and `FillWidth` over `Spacer` when applicable
200204
- PREFER declaring small dependant classes, constants, interfaces or top-level functions in the same file with the core class where these are used
@@ -240,13 +244,14 @@ suspend fun getData(): Result<Data> = withContext(Dispatchers.IO) {
240244

241245
### Changelog
242246

243-
- ALWAYS add exactly ONE entry per PR under `## [Unreleased]` in `CHANGELOG.md` for `feat:` and `fix:` PRs; skip for `chore:`, `ci:`, `refactor:`, `test:`, `docs:` unless the change is user-facing
244-
- NEVER add multiple changelog lines for the same PR — summarize all changes in a single concise entry
245-
- USE standard Keep a Changelog categories: `### Added`, `### Changed`, `### Deprecated`, `### Removed`, `### Fixed`, `### Security`
246-
- ALWAYS append `#PR_NUMBER` at the end of each changelog entry when the PR number is known
247-
- ALWAYS place new entries at the top of their category section (newest first)
248-
- NEVER modify released version sections — only edit `## [Unreleased]`
249-
- ALWAYS create category headings on demand (don't add empty stubs)
247+
- NEVER edit `CHANGELOG.md` in normal feature/fix PRs; release automation collects changelog fragments into it
248+
- ALWAYS add exactly ONE changelog fragment for user-facing `feat:` and `fix:` PRs; skip for `chore:`, `ci:`, `refactor:`, `test:`, `docs:` unless the change is user-facing
249+
- PUT normal release fragments in `changelog.d/next/` and hotfix fragments in `changelog.d/hotfix/`
250+
- NAME fragments `<issue-or-pr>.<category>.md`, where category is one of `added`, `changed`, `deprecated`, `removed`, `fixed`, or `security`
251+
- WRITE the fragment as one polished user-facing sentence without a leading bullet and without a PR number
252+
- NEVER add multiple changelog fragments for the same PR — summarize all changes in one concise fragment
253+
- Release commits consume fragments with `scripts/collect-changelog.sh --target next|hotfix`, update `CHANGELOG.md`, and delete consumed fragment files
254+
- NEVER modify released version sections manually
250255

251256
### Device Debugging (adb)
252257

CHANGELOG.md

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

88
## [Unreleased]
99

10+
### Changed
11+
- Improve Pubky profile restore, contact editing, and contact routing flows #905
12+
13+
### Fixed
14+
- Fix probe results and add keysend probes #920
15+
- Align top bar back arrow and passphrase input cursor/placeholder with iOS #906
16+
- Polish Terms of Use screen padding to match iOS #903
17+
1018
## [2.2.0] - 2026-04-07
1119

1220
### Fixed
@@ -17,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1725
- Show loading state on Spending tab when node is not running #875
1826

1927
### Added
28+
- Pubky profile onboarding with contact sync, import, and editing #824
2029
- Lightning Connections empty state with onboarding screen #857
2130
- Unified PIN management screen (enable/disable/change in one place) #857
2231
- Support entry in drawer menu #857

app/build.gradle.kts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ val bcp47Locales = listOf(
4747
"en", "ar", "es-419", "ca", "cs", "de", "el", "es", "es-ES", "fr", "it", "nl", "pl", "pt", "pt-BR", "ru"
4848
)
4949
val e2eBackendEnv = System.getenv("E2E_BACKEND") ?: "local"
50+
val e2eHomegateUrlEnv = System.getenv("E2E_HOMEGATE_URL") ?: "http://127.0.0.1:6288"
5051

5152
android {
5253
namespace = "to.bitkit"
@@ -63,6 +64,7 @@ android {
6364
}
6465
buildConfigField("boolean", "E2E", System.getenv("E2E")?.toBoolean()?.toString() ?: "false")
6566
buildConfigField("String", "E2E_BACKEND", "\"$e2eBackendEnv\"")
67+
buildConfigField("String", "E2E_HOMEGATE_URL", "\"$e2eHomegateUrlEnv\"")
6668
buildConfigField("boolean", "GEO", System.getenv("GEO")?.toBoolean()?.toString() ?: "true")
6769
buildConfigField("String", "LOCALES", "\"${bcp47Locales.joinToString(",")}\"")
6870
}
@@ -237,6 +239,7 @@ dependencies {
237239
implementation(libs.bouncycastle.provider.jdk)
238240
implementation(libs.ldk.node.android) { exclude(group = "net.java.dev.jna", module = "jna") }
239241
implementation(libs.bitkit.core)
242+
implementation(libs.paykit)
240243
implementation(libs.vss.client)
241244
// Firebase
242245
implementation(platform(libs.firebase.bom))
@@ -267,6 +270,9 @@ dependencies {
267270
implementation(libs.charts)
268271
implementation(libs.haze)
269272
implementation(libs.haze.materials)
273+
// Image Loading
274+
implementation(platform(libs.coil.bom))
275+
implementation(libs.coil.compose)
270276
// Compose Navigation
271277
implementation(libs.navigation.compose)
272278
androidTestImplementation(libs.navigation.testing)
@@ -280,6 +286,9 @@ dependencies {
280286
// WorkManager
281287
implementation(libs.hilt.work)
282288
implementation(libs.work.runtime.ktx)
289+
// Glance - AppWidgets
290+
implementation(libs.glance.appwidget)
291+
implementation(libs.glance.material3)
283292
// Ktor - Networking
284293
implementation(libs.ktor.client.core)
285294
implementation(libs.ktor.client.okhttp)

app/src/main/AndroidManifest.xml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,14 @@
33
xmlns:tools="http://schemas.android.com/tools">
44

55
<queries>
6+
<package android:name="to.pubky.ring" />
67
<intent>
78
<action android:name="android.settings.APPLICATION_DETAILS_SETTINGS" />
89
</intent>
10+
<intent>
11+
<action android:name="android.intent.action.VIEW" />
12+
<data android:scheme="pubkyauth" />
13+
</intent>
914
</queries>
1015

1116
<uses-feature
@@ -119,6 +124,7 @@
119124
<data android:scheme="lnurlw" />
120125
<data android:scheme="lnurlc" />
121126
<data android:scheme="lnurlp" />
127+
<data android:scheme="pubkyauth" />
122128
</intent-filter>
123129

124130
<!-- NFC -->
@@ -198,6 +204,33 @@
198204
android:name="android.support.FILE_PROVIDER_PATHS"
199205
android:resource="@xml/provider_paths" />
200206
</provider>
207+
208+
<!-- AppWidget Config Activity -->
209+
<activity
210+
android:name=".appwidget.config.AppWidgetConfigActivity"
211+
android:exported="true"
212+
android:excludeFromRecents="true"
213+
android:screenOrientation="portrait"
214+
android:taskAffinity=""
215+
android:theme="@style/Theme.App">
216+
<intent-filter>
217+
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
218+
</intent-filter>
219+
</activity>
220+
221+
<!-- Price Widget -->
222+
<receiver
223+
android:name=".appwidget.ui.price.PriceGlanceReceiver"
224+
android:exported="true"
225+
android:label="@string/widgets__price__name">
226+
<intent-filter>
227+
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
228+
</intent-filter>
229+
<meta-data
230+
android:name="android.appwidget.provider"
231+
android:resource="@xml/appwidget_info_price" />
232+
</receiver>
233+
201234
</application>
202235

203236
</manifest>

app/src/main/java/to/bitkit/App.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import android.app.Application.ActivityLifecycleCallbacks
77
import android.os.Bundle
88
import androidx.hilt.work.HiltWorkerFactory
99
import androidx.work.Configuration
10+
import coil3.ImageLoader
11+
import coil3.SingletonImageLoader
1012
import dagger.hilt.android.HiltAndroidApp
1113
import to.bitkit.env.Env
1214
import to.bitkit.services.BluetoothInit
@@ -17,13 +19,17 @@ internal open class App : Application(), Configuration.Provider {
1719
@Inject
1820
lateinit var workerFactory: HiltWorkerFactory
1921

22+
@Inject
23+
lateinit var imageLoader: ImageLoader
24+
2025
override val workManagerConfiguration
2126
get() = Configuration.Builder()
2227
.setWorkerFactory(workerFactory)
2328
.build()
2429

2530
override fun onCreate() {
2631
super.onCreate()
32+
SingletonImageLoader.setSafe { imageLoader }
2733
currentActivity = CurrentActivity().also { registerActivityLifecycleCallbacks(it) }
2834
Env.initAppStoragePath(filesDir.absolutePath)
2935
// Initialize btleplug for Bluetooth support (required before any BLE usage)

0 commit comments

Comments
 (0)