Add search button to top bar, move cursor info to bottom bar
StatusBar (top bar): - Added Search icon (always visible, toggles search bar) - Removed cursor position from top bar (moved to bottom bar) - Fixed icon slots: Cut, Copy, Search, Paste (left to right) - File size between Paste and Conflict icons BottomBar (new element): - Always visible at bottom of editor page (24 DP fixed height) - Left: cursor position (Ln X, Col Y) - Right: word wrap status (On/Off) - Cursor position updated on every cursor movement - Word wrap status persisted to .pad/state.json Search button: - Tap toggles search bar visible/invisible - When active: shows SearchBar element, focuses text field, shows keyboard - When inactive: hides SearchBar, clears query, hides keyboard - Primary search activation method on Android (Ctrl+F still works as secondary) Layout: - Top: StatusBar (filename + action icons) - Middle: SearchBar (when active) + TextField (editor) - Bottom: BottomBar (cursor position + word wrap status) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
parent
c210f9a2f1
commit
8b09697e6b
|
|
@ -215,10 +215,10 @@ type StatusBar struct {
|
||||||
/* region, visible, id — unexported */
|
/* region, visible, id — unexported */
|
||||||
Filename string // e.g., "notes.txt" (truncated with ellipsis if too long)
|
Filename string // e.g., "notes.txt" (truncated with ellipsis if too long)
|
||||||
FilenameExp bool // true = show full filename (multi-line), false = truncated
|
FilenameExp bool // true = show full filename (multi-line), false = truncated
|
||||||
Left string // e.g., "Ln 10, Col 5"
|
|
||||||
Right string // e.g., "1024 / 50000 bytes"
|
Right string // e.g., "1024 / 50000 bytes"
|
||||||
CutCopy bool // true = show cut icon in left slot
|
CutCopy bool // true = show cut icon in left slot
|
||||||
Copy bool // true = show copy icon in left slot (next to cut)
|
Copy bool // true = show copy icon in left slot (next to cut)
|
||||||
|
Search bool // true = show search icon (toggle search bar)
|
||||||
Paste bool // true = show paste icon in right slot
|
Paste bool // true = show paste icon in right slot
|
||||||
ConflictIcon bool // true = show conflict warning icon (rightmost)
|
ConflictIcon bool // true = show conflict warning icon (rightmost)
|
||||||
}
|
}
|
||||||
|
|
@ -227,19 +227,44 @@ type StatusBar struct {
|
||||||
The status bar appears at the top of the editor page. It has a **two-line layout**:
|
The status bar appears at the top of the editor page. It has a **two-line layout**:
|
||||||
|
|
||||||
- **Line 1**: Filename (truncated with ellipsis if too long). Tapping the ellipsis toggles between truncated and full multi-line view.
|
- **Line 1**: Filename (truncated with ellipsis if too long). Tapping the ellipsis toggles between truncated and full multi-line view.
|
||||||
- **Line 2**: Action icons (Cut, Copy, Paste) + line/col info + file size + conflict icon.
|
- **Line 2**: Action icons (Cut, Copy, Search, Paste) + file size + conflict icon.
|
||||||
|
|
||||||
**Fixed icon slots** (24×24 DP each, fixed positions):
|
**Fixed icon slots** (24×24 DP each, fixed positions):
|
||||||
- **Cut icon**: leftmost action icon
|
- **Cut icon**: leftmost action icon
|
||||||
- **Copy icon**: second from left (36 DP from Cut icon)
|
- **Copy icon**: second from left (36 DP from Cut icon)
|
||||||
- **Paste icon**: second from right
|
- **Search icon**: third from left (36 DP from Copy icon)
|
||||||
|
- **Paste icon**: fourth from left (36 DP from Search icon)
|
||||||
- **Conflict icon**: rightmost
|
- **Conflict icon**: rightmost
|
||||||
|
|
||||||
Icons appear/disappear without reflowing other elements. The StatusBar's `Region.H` is computed dynamically based on whether the filename is truncated (2 lines) or expanded (3+ lines).
|
Icons appear/disappear without reflowing other elements. The StatusBar's `Region.H` is computed dynamically based on whether the filename is truncated (2 lines) or expanded (3+ lines).
|
||||||
|
|
||||||
When a sync conflict is detected for the active file, `ConflictIcon` is set to true. Tapping the icon navigates to the merge resolution page. The icon persists across process death — if a conflict file exists for the active file on restore, the icon appears.
|
When a sync conflict is detected for the active file, `ConflictIcon` is set to true. Tapping the icon navigates to the merge resolution page. The icon persists across process death — if a conflict file exists for the active file on restore, the icon appears.
|
||||||
|
|
||||||
### 3.10 Toast / Notification
|
### 3.10 Bottom Bar
|
||||||
|
|
||||||
|
```go
|
||||||
|
type BottomBar struct {
|
||||||
|
/* region, visible, id — unexported */
|
||||||
|
CursorPos string // e.g., "Ln 10, Col 5"
|
||||||
|
WordWrap bool // true = word wrap is enabled (shown for reference)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The bottom bar appears at the bottom of the editor page. It displays cursor position and editor state information. It is always visible (no icons, just text).
|
||||||
|
|
||||||
|
**Layout**:
|
||||||
|
```
|
||||||
|
┌──────────────────────────────────────────────────────────────┐
|
||||||
|
│ Ln 10, Col 5 Word Wrap: On │
|
||||||
|
└──────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Left**: Cursor position (line number, column number)
|
||||||
|
- **Right**: Word wrap status (On/Off)
|
||||||
|
|
||||||
|
The BottomBar's `Region.H` is fixed (24 DP). It sits below the editor content.
|
||||||
|
|
||||||
|
### 3.11 Toast / Notification
|
||||||
|
|
||||||
```go
|
```go
|
||||||
type Toast struct {
|
type Toast struct {
|
||||||
|
|
@ -318,11 +343,11 @@ Elements are rendered in slice order. Later elements draw on top of earlier ones
|
||||||
|
|
||||||
```
|
```
|
||||||
1. Background (full screen)
|
1. Background (full screen)
|
||||||
2. Header / Label
|
2. Status bar (top)
|
||||||
3. Search bar or main content
|
3. Search bar or main content
|
||||||
4. List or text area
|
4. List or text area
|
||||||
5. Overlay elements (cursor, selection highlight, toast)
|
5. Overlay elements (cursor, selection highlight)
|
||||||
6. Status bar (bottom)
|
6. Bottom bar
|
||||||
```
|
```
|
||||||
|
|
||||||
## 7. Theme
|
## 7. Theme
|
||||||
|
|
@ -356,12 +381,13 @@ Elements that don't specify explicit colors/sizes use theme defaults. The theme
|
||||||
[]Element{
|
[]Element{
|
||||||
StatusBar{
|
StatusBar{
|
||||||
Filename: "notes.txt", FilenameExp: false,
|
Filename: "notes.txt", FilenameExp: false,
|
||||||
Left: "Ln 47, Col 12", Right: "1024 / 50000",
|
Right: "1024 / 50000",
|
||||||
CutCopy: true, Copy: false, Paste: true, ConflictIcon: false,
|
CutCopy: true, Copy: false, Search: false, Paste: true, ConflictIcon: false,
|
||||||
},
|
},
|
||||||
SearchBar{Query: "foo", Match: 1, Total: 3}, // search (when active)
|
SearchBar{Query: "foo", Match: 1, Total: 3}, // search (when active)
|
||||||
TextField{Multiline: true, VisibleLines: [...], ScrollOffset: 420, WordWrap: true},
|
TextField{Multiline: true, VisibleLines: [...], ScrollOffset: 420, WordWrap: true},
|
||||||
Cursor{Line: 5, Column: 12, Selection: &Selection{...}},
|
Cursor{Line: 5, Column: 12, Selection: &Selection{...}},
|
||||||
|
BottomBar{CursorPos: "Ln 47, Col 12", WordWrap: true},
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -369,10 +395,13 @@ The search bar is only present when the user has activated search. When visible,
|
||||||
|
|
||||||
The StatusBar contains:
|
The StatusBar contains:
|
||||||
- **Filename** on line 1 (truncated with ellipsis if too long)
|
- **Filename** on line 1 (truncated with ellipsis if too long)
|
||||||
- **Action icons** (Cut, Copy, Paste) on line 2, fixed positions
|
- **Action icons** (Cut, Copy, Search, Paste) on line 2, fixed positions
|
||||||
- **Line/col info** between Cut/Copy and Paste icons
|
|
||||||
- **File size** between Paste and Conflict icons
|
- **File size** between Paste and Conflict icons
|
||||||
|
|
||||||
|
The BottomBar contains:
|
||||||
|
- **Cursor position** on the left (e.g., "Ln 47, Col 12")
|
||||||
|
- **Word wrap status** on the right (e.g., "Word Wrap: On")
|
||||||
|
|
||||||
### 8.3 Merge Page
|
### 8.3 Merge Page
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
|
||||||
71
doc/touch.md
71
doc/touch.md
|
|
@ -303,17 +303,24 @@ The StatusBar (top bar) has **fixed icon slots** for cut, copy, and paste. Icons
|
||||||
```
|
```
|
||||||
┌──────────────────────────────────────────────────────────────┐
|
┌──────────────────────────────────────────────────────────────┐
|
||||||
│ filename.txt │ ← Line 1: filename (truncated with ellipsis)
|
│ filename.txt │ ← Line 1: filename (truncated with ellipsis)
|
||||||
│ [Cut] [Copy] Ln 10, Col 5 [Paste] 1024 / 50000 [Conf] │ ← Line 2: action icons + info
|
│ [Cut] [Copy] [Search] [Paste] 1024 / 50000 [Conf] │ ← Line 2: action icons + file size
|
||||||
|
└──────────────────────────────────────────────────────────────┘
|
||||||
|
StatusBar (top bar)
|
||||||
|
┌──────────────────────────────────────────────────────────────┐
|
||||||
|
│ TextField (editor content) │
|
||||||
|
└──────────────────────────────────────────────────────────────┘
|
||||||
|
┌──────────────────────────────────────────────────────────────┐
|
||||||
|
│ Ln 10, Col 5 Word Wrap: On │ ← BottomBar
|
||||||
└──────────────────────────────────────────────────────────────┘
|
└──────────────────────────────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
**Fixed slot positions** (in Dp, from the edges):
|
**Fixed slot positions** (in Dp, from the edges):
|
||||||
- **Cut icon**: leftmost action icon (24×24 DP, fixed position)
|
- **Cut icon**: leftmost action icon (24×24 DP, fixed position)
|
||||||
- **Copy icon**: second from left (24×24 DP, fixed position, 36 DP from Cut icon)
|
- **Copy icon**: second from left (24×24 DP, fixed position, 36 DP from Cut icon)
|
||||||
- **Paste icon**: second from right (24×24 DP, fixed position)
|
- **Search icon**: third from left (24×24 DP, fixed position, 36 DP from Copy icon)
|
||||||
|
- **Paste icon**: fourth from left (24×24 DP, fixed position, 36 DP from Search icon)
|
||||||
- **Conflict icon**: rightmost (24×24 DP, fixed position)
|
- **Conflict icon**: rightmost (24×24 DP, fixed position)
|
||||||
- **Filename**: top line, truncated with ellipsis if too long
|
- **Filename**: top line, truncated with ellipsis if too long
|
||||||
- **Line/col info**: between Cut/Copy and Paste icons
|
|
||||||
- **File size**: between Paste and Conflict icons
|
- **File size**: between Paste and Conflict icons
|
||||||
|
|
||||||
**Visibility rules**:
|
**Visibility rules**:
|
||||||
|
|
@ -322,6 +329,7 @@ The StatusBar (top bar) has **fixed icon slots** for cut, copy, and paste. Icons
|
||||||
|---|---|
|
|---|---|
|
||||||
| **Cut** | `selection_start != selection_end` |
|
| **Cut** | `selection_start != selection_end` |
|
||||||
| **Copy** | `selection_start != selection_end` |
|
| **Copy** | `selection_start != selection_end` |
|
||||||
|
| **Search** | Always visible (toggle search bar) |
|
||||||
| **Paste** | `clipboard != ""` |
|
| **Paste** | `clipboard != ""` |
|
||||||
| **Conflict** | sync conflict detected for active file |
|
| **Conflict** | sync conflict detected for active file |
|
||||||
|
|
||||||
|
|
@ -344,6 +352,25 @@ Icons are rendered as `Button` elements with fixed sizes. The StatusBar's `Regio
|
||||||
4. Selection is **not** cleared (text remains in buffer).
|
4. Selection is **not** cleared (text remains in buffer).
|
||||||
5. Logic produces a new frame (Cut/Copy icons still visible, Paste icon appears).
|
5. Logic produces a new frame (Cut/Copy icons still visible, Paste icon appears).
|
||||||
|
|
||||||
|
### 5.6.4a Search Button
|
||||||
|
|
||||||
|
The Search button toggles the search bar visible/invisible.
|
||||||
|
|
||||||
|
1. User taps the Search icon.
|
||||||
|
2. Logic toggles `search_active` state field.
|
||||||
|
3. If `search_active` is true:
|
||||||
|
- Show `SearchBar` element below the StatusBar.
|
||||||
|
- Set focus to the search bar's text field.
|
||||||
|
- Show the soft keyboard (`key.SoftKeyboardOp(true)`).
|
||||||
|
4. If `search_active` is false:
|
||||||
|
- Hide `SearchBar` element.
|
||||||
|
- Clear search query.
|
||||||
|
- Remove focus from search bar.
|
||||||
|
- Hide soft keyboard (`key.SoftKeyboardOp(false)`).
|
||||||
|
5. Logic produces a new frame.
|
||||||
|
|
||||||
|
The Search button is always visible in the StatusBar (unlike Cut/Copy/Paste which are conditional). It serves as the primary way to activate search on Android (where Ctrl+F may not be available).
|
||||||
|
|
||||||
### 5.6.5 Paste Operation
|
### 5.6.5 Paste Operation
|
||||||
|
|
||||||
1. User taps the Paste icon.
|
1. User taps the Paste icon.
|
||||||
|
|
@ -406,16 +433,48 @@ This field is **not** persisted to disk — it is reset on app restart (same as
|
||||||
In the truncated view, the StatusBar has 2 lines:
|
In the truncated view, the StatusBar has 2 lines:
|
||||||
```
|
```
|
||||||
Line 1: filename.txt...
|
Line 1: filename.txt...
|
||||||
Line 2: [Cut] [Copy] Ln 10, Col 5 [Paste] 1024 / 50000 [Conf]
|
Line 2: [Cut] [Copy] [Search] [Paste] 1024 / 50000 [Conf]
|
||||||
```
|
```
|
||||||
|
|
||||||
In the full view, the StatusBar has 3+ lines (depending on filename length):
|
In the full view, the StatusBar has 3+ lines (depending on filename length):
|
||||||
```
|
```
|
||||||
Line 1: very_long_filename_that_does_not_fit_on_a_single_line.txt
|
Line 1: very_long_filename_that_does_not_fit_on_a_single_line.txt
|
||||||
Line 2: [Cut] [Copy] Ln 10, Col 5 [Paste] 1024 / 50000 [Conf]
|
Line 2: [Cut] [Copy] [Search] [Paste] 1024 / 50000 [Conf]
|
||||||
```
|
```
|
||||||
|
|
||||||
The `Region.H` of the StatusBar is computed dynamically based on the number of lines.
|
The `Region.H` of the StatusBar is computed dynamically based on the number of lines. The BottomBar is always at the bottom of the screen (24 DP fixed height).
|
||||||
|
|
||||||
|
## 5.8 Bottom Bar
|
||||||
|
|
||||||
|
The Bottom Bar appears at the bottom of the editor page. It displays cursor position and editor state information. It is always visible (no icons, just text).
|
||||||
|
|
||||||
|
### 5.8.1 Layout
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────────────────────────────────────────────────────────┐
|
||||||
|
│ Ln 10, Col 5 Word Wrap: On │
|
||||||
|
└──────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Left**: Cursor position (e.g., "Ln 10, Col 5")
|
||||||
|
- **Right**: Word wrap status (e.g., "Word Wrap: On")
|
||||||
|
|
||||||
|
The BottomBar's `Region.H` is fixed at 24 DP. It sits below the editor content.
|
||||||
|
|
||||||
|
### 5.8.2 Cursor Position
|
||||||
|
|
||||||
|
The cursor position is computed from the current byte offset:
|
||||||
|
1. Logic converts byte offset to (line, column) using the **Line Index**.
|
||||||
|
2. The `CursorPos` field is set to `"Ln {line}, Col {column}"`.
|
||||||
|
3. The field is updated on every cursor movement (tap, arrow keys, backspace, etc.).
|
||||||
|
|
||||||
|
### 5.8.3 Word Wrap Status
|
||||||
|
|
||||||
|
The word wrap status is a simple boolean field (`word_wrap_enabled`):
|
||||||
|
- `true` → "Word Wrap: On"
|
||||||
|
- `false` → "Word Wrap: Off"
|
||||||
|
|
||||||
|
This field is persisted to `.pad/state.json` and restored on app start. Toggling word wrap is done via a settings screen (not yet implemented).
|
||||||
|
|
||||||
## 6. Scroll Momentum
|
## 6. Scroll Momentum
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user