TASK-061: edge tab for the side pane, and a new app icon

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
최민영 2026-09-28 16:31:27 +09:00
parent 023fa0b728
commit 17fa248065
8 changed files with 169 additions and 31 deletions

View File

@ -147,6 +147,7 @@ private enum class ViewerLayout {
private val CompactHeightBreakpoint = 480.dp
private val SidePaneWidth = 288.dp
private val TreeIndent = 14.dp
private val EdgeTabTouchWidth = 28.dp
private val NarrowSidePaneWidth = 220.dp
private val NarrowWideBreakpoint = 700.dp
@ -376,8 +377,9 @@ fun CodeViewerScreen(
LocationStrip(enclosingSymbols(document.symbols, firstVisibleLine))
}
Box(Modifier.weight(1f).fillMaxWidth()) {
Row(
Modifier.weight(1f).fillMaxWidth().openFromLeftEdge(enabled = !sidePaneIsShown && drawerState.isClosed) {
Modifier.fillMaxSize().openFromLeftEdge(enabled = !sidePaneIsShown && drawerState.isClosed) {
scope.launch { drawerState.open() }
},
) {
@ -448,6 +450,12 @@ fun CodeViewerScreen(
}
}
}
// Says that there is something to draw out from this edge; without it nothing on the
// screen does.
if (!sidePaneIsShown) {
EdgeTab(Modifier.align(Alignment.CenterStart)) { scope.launch { drawerState.open() } }
}
}
if (layout != ViewerLayout.LANDSCAPE) Toolbar(tools)
}
}
@ -835,6 +843,34 @@ private fun JumpToCounterpart(counterpart: RepositoryPath, modifier: Modifier =
}
}
/**
* A small tab on the left edge, where the side pane is drawn out from. It can be tapped as well:
* a swipe from the edge is not available to everyone.
*/
@Composable
private fun EdgeTab(modifier: Modifier = Modifier, onOpen: () -> Unit) {
val description = stringResource(R.string.codeviewer_edge_tab)
Box(
modifier
.size(width = EdgeTabTouchWidth, height = 72.dp)
.clickable(role = Role.Button, onClickLabel = description, onClick = onOpen)
.semantics { contentDescription = description },
contentAlignment = Alignment.CenterStart,
) {
Box(
Modifier
.size(width = 14.dp, height = 56.dp)
.background(
MaterialTheme.colorScheme.primary.copy(alpha = 0.85f),
RoundedCornerShape(topEnd = 12.dp, bottomEnd = 12.dp),
),
contentAlignment = Alignment.Center,
) {
UBIcon(R.drawable.ic_ub_chevron_right, null, size = 14.dp, tint = MaterialTheme.colorScheme.onPrimary)
}
}
}
/**
* A header and its source, side by side, header on the left whichever of the two was opened. The
* bar between them is dragged to give one side more of the width.

View File

@ -1,14 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- App icon background layer: a solid fill in the same sky blue used as this app's Material 3
primary color (ui/theme/Color.kt's SkyPrimaryLight), so the home-screen icon and the in-app
theme read as the same deliberate color rather than drifting apart after the sky-blue redesign
(this used to match the earlier "Gitea green" theme's primary before that changed). -->
<!-- App icon, back layer (TASK-061): the bright sky blue of the app (BrandSky in ui/theme/Color.kt) running to its deeper primary, with two faint circles so the flat color has some depth -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M0,0h108v108h-108z">
<aapt:attr name="android:fillColor">
<gradient
android:type="linear"
android:startX="14"
android:startY="8"
android:endX="94"
android:endY="100">
<item android:offset="0" android:color="#FF4DB0FF" />
<item android:offset="0.55" android:color="#FF2F98F9" />
<item android:offset="1" android:color="#FF0A6FD8" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#0369A1"
android:pathData="M0,0h108v108h-108z" />
android:fillColor="#1FFFFFFF"
android:pathData="M58,88 a34,34 0 1,0 68,0 a34,34 0 1,0 -68,0 Z" />
<path
android:fillColor="#14FFFFFF"
android:pathData="M-14,16 a26,26 0 1,0 52,0 a26,26 0 1,0 -52,0 Z" />
</vector>

View File

@ -1,35 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- A simple git-branch glyph (trunk node, a straight line up to a main-branch node, a curved line
out to a second branch node), reading immediately as "a git tool" without reproducing Gitea's
own trademarked logo. Every coordinate stays within the adaptive-icon safe zone (the centered
66dp-diameter circle on this 108dp canvas), since the system mask crops outside it on some
launchers. This app has no icon library (see CLAUDE.md's established convention), so this is
hand-drawn geometry, circles for nodes and stroked paths for the connecting branch lines,
matching the same plain-vector approach already used for the notification small icon. -->
<!-- App icon, front layer (TASK-061): a branch that leaves the trunk, its commits drawn as rings. It says "Git" without using Gitea's own logo. Everything stays inside the 66dp safe circle of the 108dp canvas, which is all that some launchers show -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<!-- Drawn large, then brought inside the safe circle. -->
<group
android:pivotX="54"
android:pivotY="54"
android:scaleX="0.85"
android:scaleY="0.85"
android:translateX="-2">
<path
android:pathData="M40,78 L40,30"
android:pathData="M41,74 L41,34"
android:strokeColor="#FFFFFFFF"
android:strokeWidth="6"
android:strokeWidth="6.5"
android:strokeLineCap="round"
android:fillColor="#00000000" />
<path
android:pathData="M40,78 C40,60 74,64 74,46"
android:pathData="M41,74 C41,57 72,61 72,45"
android:strokeColor="#FFFFFFFF"
android:strokeWidth="6"
android:strokeWidth="6.5"
android:strokeLineCap="round"
android:fillColor="#00000000" />
<!-- Each node is a ring: the outer circle with the inner one cut out of it. -->
<path
android:fillColor="#FFFFFFFF"
android:pathData="M33,78 A7,7 0 1,0 47,78 A7,7 0 1,0 33,78 Z" />
android:fillType="evenOdd"
android:pathData="M31.5,76 a9.5,9.5 0 1,0 19,0 a9.5,9.5 0 1,0 -19,0 Z M36.5,76 a4.5,4.5 0 1,0 9,0 a4.5,4.5 0 1,0 -9,0 Z" />
<path
android:fillColor="#FFFFFFFF"
android:pathData="M33,30 A7,7 0 1,0 47,30 A7,7 0 1,0 33,30 Z" />
android:fillType="evenOdd"
android:pathData="M31.5,32 a9.5,9.5 0 1,0 19,0 a9.5,9.5 0 1,0 -19,0 Z M36.5,32 a4.5,4.5 0 1,0 9,0 a4.5,4.5 0 1,0 -9,0 Z" />
<path
android:fillColor="#FFFFFFFF"
android:pathData="M67,46 A7,7 0 1,0 81,46 A7,7 0 1,0 67,46 Z" />
android:fillType="evenOdd"
android:pathData="M62.5,43 a9.5,9.5 0 1,0 19,0 a9.5,9.5 0 1,0 -19,0 Z M67.5,43 a4.5,4.5 0 1,0 9,0 a4.5,4.5 0 1,0 -9,0 Z" />
</group>
</vector>

View File

@ -1,31 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Android 13+ themed-icon layer. The system re-tints this to match the device wallpaper theme,
so (like the notification small icon) only the shape/alpha matters, not this fill color.
Same glyph as ic_launcher_foreground.xml. -->
<!-- App icon, themed layer (Android 13+): the same shape as the front layer. The system colors it, so only the shape matters -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<!-- Drawn large, then brought inside the safe circle. -->
<group
android:pivotX="54"
android:pivotY="54"
android:scaleX="0.85"
android:scaleY="0.85"
android:translateX="-2">
<path
android:pathData="M40,78 L40,30"
android:pathData="M41,74 L41,34"
android:strokeColor="#FF000000"
android:strokeWidth="6"
android:strokeWidth="6.5"
android:strokeLineCap="round"
android:fillColor="#00000000" />
<path
android:pathData="M40,78 C40,60 74,64 74,46"
android:pathData="M41,74 C41,57 72,61 72,45"
android:strokeColor="#FF000000"
android:strokeWidth="6"
android:strokeWidth="6.5"
android:strokeLineCap="round"
android:fillColor="#00000000" />
<!-- Each node is a ring: the outer circle with the inner one cut out of it. -->
<path
android:fillColor="#FF000000"
android:pathData="M33,78 A7,7 0 1,0 47,78 A7,7 0 1,0 33,78 Z" />
android:fillType="evenOdd"
android:pathData="M31.5,76 a9.5,9.5 0 1,0 19,0 a9.5,9.5 0 1,0 -19,0 Z M36.5,76 a4.5,4.5 0 1,0 9,0 a4.5,4.5 0 1,0 -9,0 Z" />
<path
android:fillColor="#FF000000"
android:pathData="M33,30 A7,7 0 1,0 47,30 A7,7 0 1,0 33,30 Z" />
android:fillType="evenOdd"
android:pathData="M31.5,32 a9.5,9.5 0 1,0 19,0 a9.5,9.5 0 1,0 -19,0 Z M36.5,32 a4.5,4.5 0 1,0 9,0 a4.5,4.5 0 1,0 -9,0 Z" />
<path
android:fillColor="#FF000000"
android:pathData="M67,46 A7,7 0 1,0 81,46 A7,7 0 1,0 67,46 Z" />
android:fillType="evenOdd"
android:pathData="M62.5,43 a9.5,9.5 0 1,0 19,0 a9.5,9.5 0 1,0 -19,0 Z M67.5,43 a4.5,4.5 0 1,0 9,0 a4.5,4.5 0 1,0 -9,0 Z" />
</group>
</vector>

View File

@ -69,6 +69,7 @@
<string name="codeviewer_files_title">폴더 구조</string>
<string name="codeviewer_symbols_title">클래스 · 함수</string>
<string name="codeviewer_symbols_empty">이 파일에는 표시할 클래스나 함수가 없습니다.</string>
<string name="codeviewer_edge_tab">폴더 구조와 클래스 · 함수 열기</string>
<string name="codeviewer_pane_swap">위아래 바꾸기</string>
<string name="codeviewer_folder_open">펼쳐짐</string>
<string name="codeviewer_folder_closed">접힘</string>

Binary file not shown.

View File

@ -1410,3 +1410,13 @@ This is the append-only implementation and handoff record shared by Codex and Cl
- Checks and results: the required checks pass; 437 unit tests, 0 failures; lint 0 errors.
- Live verification: installed on the SM-F966N; not seen on a screen by the implementer.
- Next owner: the product owner, to confirm on the device.
## 2026-09-28 (continued) — TASK-061: a tab on the left edge, and a new app icon
- Request: the human product owner asked for a mark showing that the side pane can be drawn out
from the left edge of the code, and for a more fitting app icon.
- What changed: see `tasks/061-edge-tab-and-app-icon.md`.
- Checks and results: the required checks pass; 437 unit tests, 0 failures; lint 0 errors.
- Live verification: installed on the SM-F966N; neither change was seen on the device by the
implementer.
- Next owner: the product owner, to confirm on the device.

View File

@ -0,0 +1,60 @@
# TASK-061: A tab on the left edge, and a new app icon
Status: implemented; required checks pass; installed on the product owner's Z Fold7, awaiting their confirmation
Owner: Claude
Reviewer: human product owner
## Outcome
Requested by the human product owner, 2026-09-28: nothing on the code screen said that the side
pane could be drawn out from the left edge, and the app icon should be changed to suit the app.
## Scope
- Included:
1. A small tab at the middle of the code's left edge, with an arrow. It marks where the pane is
drawn out from, and tapping it opens the pane as well. It is not shown where the pane is
already beside the code.
2. App icon: the background is the app's bright sky blue running to its deeper primary (it was
a flat darker blue from before the redesign); the branch glyph's commits are drawn as rings.
The themed (monochrome) layer has the same shape.
- Excluded: using the UbiSam logo in the icon. It is a wordmark, and unreadable at icon size.
## Writable paths
- `app/src/main/java/com/ubisam/ubgitea/feature/codebrowser/CodeViewerScreen.kt`
- `app/src/main/res/drawable/ic_launcher_*.xml`
- `app/src/main/res/values/strings_codebrowser.xml`
- `tasks/`, `docs/`
## Acceptance criteria
- [x] The tab has a spoken description and a touch area wider than what is drawn.
- [x] The icon's glyph stays inside the 66dp safe circle of the adaptive icon.
## Security and privacy
No additional concerns.
## Required checks
```text
./gradlew compileDebugKotlin compileDebugUnitTestKotlin testDebugUnitTest assembleDebug lintDebug
```
## Evidence
- Required checks pass: 437 unit tests, 0 failures; lint 0 errors.
- Installed on the SM-F966N over wireless `adb`.
- The icon was looked at only as a rough drawing made on a PC from the same coordinates, before
the glyph was made smaller to fit the safe circle; not on a launcher. The tab has not been seen
on a screen by the implementer.
## Known limitations
- The tab covers a strip 14dp wide and 56dp tall of the line numbers behind it.
- A launcher may keep showing the old icon until it refreshes its cache.
## Review findings
None yet.