The release build type is signed with the key the published builds have had,
so it installs over them.
Agent: main (opus)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
What loaded during a push was held 80 ms past it and then took a frame to
build, so the screen stood there still loading. It is now released 40 ms
before the push ends, where the screen has almost no way left to go.
Agent: main (opus)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pressing a card under 활동 중인 저장소 hitched: the file list was built in one
long frame while the screen was still pushing in, and Back began with a frame
of about 120 ms because the four tab screens were built again.
PushedOver keeps the tab pager composed under a pushed screen, moved off to the
left with the push; heldWhilePushedIn shows what loaded during the push once
the screen stands still.
Agent: main (opus)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Going between the two repository tabs sent every row back to "checking"
and then to its branch chip, which changed each row's height and the
lines of its text twice per move. The view model keeps the branch last
found for each repository and starts a reloaded list with it, still
checking for a newer one.
Agent: main (opus)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Measured on the product owner's phone over adb. The code workbench value,
provided through a static composition local, was rebuilt on each root
recomposition, which turned skipping off for all four tab screens on every
move. It is remembered now. Looping animations stop while their page is off
screen, the two repository lists stay composed side by side, and a
repository's branches open beside the list instead of replacing it.
First frame of a bottom tab move: 80-118 ms to 23-34 ms. The branches
slide has not been measured on the device yet.
Agent: main (opus)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Opening a screen pushes it in from the right and Back reverses it, in place
of a 90 ms fade that read as a flicker. The repository tabs keep each tab's
last list through a reload, so nothing settles after the glide. The four
bottom tabs stay composed; only the one shown answers Back.
Agent: main (opus)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A selected filter chip is outlined; the loading cup waits 450 ms before it
shows; Back on 홈 asks before leaving; long lists offer a button back to the
top; AnimatedContent no longer animates its own size, which made sideways
moves drift diagonally.
Agent: main (opus), implementer (sonnet) for Chips.kt and ExitConfirmDialog.kt
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The four tab screens are pages of one pager that a tab press scrolls, so 홈
to 알림 passes 저장소 and 작업 instead of sliding straight there. Swiping is
off; entering and leaving other screens is unchanged.
Agent: main (opus)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Until the session is known the route shown is the repository list; when it
becomes Home the change played the full-width tab glide just as the launch
cover was fading. That hand-over is now a plain fade, and the cover waits for
it (at most 1.5 s longer) before it leaves.
Agent: main (opus)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
"업데이트" streams the published APK into a system install session instead of
opening the browser, so nothing is saved to the phone. Progress, cancel and
retry are shown. Android 12+ is asked to skip its confirmation, which it does
once this app is the installer of the copy being replaced.
Adds REQUEST_INSTALL_PACKAGES and UPDATE_PACKAGES_WITHOUT_USER_ACTION.
Not run on a device.
Agent: main (opus)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The repository list (all / favourites) and a repository's issues and pull
requests keep their header and tab row still while the list under them moves
the whole width. TabGlide in Motion.kt holds the movement.
A repository tab change reloads through Loading, which names no tab, so the
screen remembers the tab that was tapped and keeps the tab row up meanwhile.
Agent: main (opus)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The old GitHub site is no longer used; releases and the version file
live on the apk branch of the team's Gitea.
Agent: main (opus)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The old download page asked for a password and is no longer used. The
app now reads version.json and fetches UBGitea.apk from the apk branch.
Agent: main (opus)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Splash, cup loader, list skeleton, empty-screen cup, pull to refresh
indicator, star and tab icon spring, screen and tab transitions, and a
row by row diff intro. Compose animation APIs only.
Agent: main (opus)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A wrong password fetched the encrypted APK before being refused, and a
phone browser can keep that fetch as a download. A small sealed check is
opened first; nothing is fetched when it fails.
Agent: main (opus)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- version 0.2.0 (versionCode 2)
- The app reads version.json from the download page once at launch and
offers the page when a newer build is out; settings shows the version
and a check button.
- tools/publish-download.py encrypts an APK under the download password
and writes the page that decrypts it in the browser.
Agent: main (opus)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Up to five code files saved as tabs in a strip above the bottom tabs.
- Compare a file with one from another ref, commit or place; the
current file goes left or right, then the other is chosen.
- The side pane on a wide screen is dragged to size and snaps back to
its default; the header/source split snaps to the middle.
- A tapped name is marked everywhere in the file, with previous/next.
- The Repositories tab pressed again goes back to the list page the
repository came from, then to the first page.
Agent: main (opus)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
No task waits on a Codex review; the redesign tasks are confirmed on the
product owner's Z Fold7; TASK-016's leftovers are on hold; no biometric
reauthentication.
Agent: main (opus)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The viewer's side pane is two cards: folder structure, and classes and
functions. A button swaps them and the choice is kept.
- Folders open in place; files inside them open from the tree.
- Unfolded Home: the headline is a card and the columns are equal.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
- Code viewer: the outline opens with a swipe from the left edge and closes
with a swipe left, with one pane or two.
- Side-by-side .h/.cpp: a draggable handle resizes the panes (20% to 80%).
- Directory listing reads Git tree objects instead of the contents endpoint,
which looked up the last commit of every entry.
- A listing that needs more than one request shows percent and count.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Repository names get a line to themselves; the repository, work and notification tabs lose their title; a today count on Home opens today's activity of that kind; the outline is a foldable tree of classes and methods without fields; Home can show only starred repositories and remembers the choice; settings has a light/dark/system theme choice.
Whether the app is dark is now the app's decision (UBGiteaTheme.isDark), so the logo moved off a -night drawable. 420 unit tests pass, lint reports 0 errors. Installed on the product owner's Z Fold7.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Four tabs in an app shell that becomes a rail from 600dp, a brighter sky-blue palette with the real UbiSam logo, a Home tab built on Gitea's activity feeds, a Work tab that searches issues and pull requests across repositories, a full-screen code viewer with search, outline and Visual Studio colors, C/C++ header/source pairing, and two-pane layouts for wide windows.
The five tasks were built and checked together, so they are one commit: MainActivity, the routes and the shared components belong to all of them. 409 unit tests pass, lint reports 0 errors. Verified on an emulator up to the sign-in screen only; no physical device was available.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
assetlinks.json is the Digital Asset Links statement served from the Gitea host for the OAuth App Link; it holds only the package name and public certificate fingerprints. The deck is rebuilt for the redesign (TASK-050 to TASK-054).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude becomes implementer; review moves to a separate Claude session or the product owner. README and product brief now describe the application as it is: the starring write scope, the removed compare view, and the C#/C++ focus.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Adds a CPP language, preprocessor coloring, hex and digit-separator numbers, and block-comment state carried across lines. CodeBlock now highlights a file once instead of on every recomposition.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Includes the two same-day follow-ups that fixed horizontal scrolling. See tasks/048-code-viewer-readability.md.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Rebuilds the Material3 light/dark palette around a sky-blue primary, adds the UBGiteaTopBar wordmark to the repository list, and recolors the launcher icon background to match.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Closes one of docs/product.md's open product decisions ("whether
repositories must be cached for offline browsing"), at the human product
owner's explicit request.
A new file-backed RepositoryListCache persists the ALL/no-organization-
filter repository list after every successful load, using a dedicated
plain DTO (not the domain RepositorySummary directly, since
RepositoryCoordinates/RepositoryRef validate through a private-constructor
factory Gson's reflection would otherwise bypass). RepositoryListViewModel
falls back to it whenever a live fetch of that view fails with a
network-classified error (cold start or mid-session), seeding
repositorySnapshots so pagination keeps working from the cache. A
page-level banner makes the fallback impossible to mistake for a live
view. The cache is cleared on logout.
Deliberately scoped to just the landing list -- not favorites,
organization filters, or repository internals (branches/files/history) --
confirmed with the human product owner after they live-tested the
fallback via airplane mode and asked about extending it further; decided
to hold that off.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The FAVORITES-mode empty state ("nothing starred yet") shared its
MessageState call with the ALL-mode empty state ("account has zero
repositories"), inheriting a hardcoded 로그아웃 action that only made sense
for the latter. Gives FAVORITES-mode its own action: "전체 저장소 보기",
wired to the same onShowAllRepositories the tab row already uses.
Live bug report: "현재 화면 즐겨찾기가 안되어있는데 로그아웃할거냐는
버튼이 왜 있지?" Live-verified the fix on-device.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Reviewed the text/image/PDF/CSV file-viewer implementations in
CodeBrowserScreen.kt as part of the ongoing design-review pass; live
spot-checked the text viewer on a real .gitignore. No bug or design gap
found.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Closes the known limitation from the previous commit: NotificationsScreen
had the identical plain-text state-label gap, in a separate screen/enum
(NotificationSubjectState, which also has an UNKNOWN case). Adds its own
StatusBadge composable with the same color roles, mapping UNKNOWN to the
neutral surfaceVariant treatment VisibilityBadge already uses for private.
Live-verified on-device: notifications 전체 list shows all three real
colors side by side (닫힘/병합됨/열림).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Replaces the plain-text 열림/닫힘/병합됨 label on issue/PR list rows and
detail headers with a compact colored badge, reusing the VisibilityBadge
pattern TASK-039 established for 공개/비공개. OPEN reuses the app's green
primaryContainer, CLOSED reuses the baseline errorContainer, MERGED reuses
the teal tertiaryContainer -- all existing theme roles, so dark mode is
handled automatically with no new hardcoded colors.
Found while verifying issue/PR body rendering for real content (confirmed
correct, no bug) during the design-review pass. Live-verified on-device in
both light and dark mode.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>