Skip to content

Commit a85c845

Browse files
committed
Implemented visual mode for mangadesk
1 parent 67511a5 commit a85c845

File tree

3 files changed

+80
-5
lines changed

3 files changed

+80
-5
lines changed

app/ui/manga_page.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,8 @@ func newMangaPage(manga *mangodex.Manga) *MangaPage {
108108
Info: info,
109109
Table: table,
110110
sWrap: &utils.SelectorWrapper{
111-
Selection: map[int]struct{}{},
111+
Selection: map[int]struct{}{},
112+
VisualStart: -1,
112113
},
113114
cWrap: &utils.ContextWrapper{
114115
Ctx: ctx,

app/ui/page_inputs.go

+63-1
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ package ui
22

33
import (
44
"context"
5-
"github.com/darylhjd/mangadesk/app/ui/utils"
65
"log"
76
"math"
87

8+
"github.com/darylhjd/mangadesk/app/ui/utils"
9+
910
"github.com/darylhjd/mangodex"
1011
"github.com/gdamore/tcell/v2"
1112
"github.com/rivo/tview"
@@ -188,6 +189,12 @@ func (p *MangaPage) setHandlers(cancel context.CancelFunc) {
188189
return event
189190
})
190191

192+
p.Table.SetSelectionChangedFunc(func(row, _column int) {
193+
if p.sWrap.IsInVisualMode() {
194+
p.selectRange(min(row, p.sWrap.VisualStart), max(row, p.sWrap.VisualStart))
195+
}
196+
})
197+
191198
// Set table selected function.
192199
p.Table.SetSelectedFunc(func(row, _ int) {
193200
log.Println("Creating and showing confirm download modal...")
@@ -202,16 +209,26 @@ func (p *MangaPage) setHandlers(cancel context.CancelFunc) {
202209

203210
// Set table input captures.
204211
p.Table.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
212+
205213
switch event.Key() {
206214
case tcell.KeyCtrlE: // User selects this manga row.
207215
p.ctrlEInput()
216+
return event
208217
case tcell.KeyCtrlA: // User wants to toggle select All.
209218
p.ctrlAInput()
219+
return event
210220
case tcell.KeyCtrlR: // User wants to toggle read status for Selection.
211221
p.ctrlRInput()
222+
return event
212223
case tcell.KeyCtrlQ:
213224
p.ctrlQInput()
225+
return event
214226
}
227+
228+
if event.Rune() == 'v' || event.Rune() == 'V' {
229+
p.shiftVInput()
230+
}
231+
215232
return event
216233
})
217234
}
@@ -233,6 +250,51 @@ func (p *MangaPage) ctrlAInput() {
233250
p.markAll()
234251
}
235252

253+
func (p *MangaPage) selectRange(from, to int) {
254+
start := min(from, to)
255+
end := max(from, to)
256+
257+
for row := 1; row < p.Table.GetRowCount(); row++ {
258+
if row < start || row > end {
259+
if p.sWrap.HasSelection(row) {
260+
p.markUnselected(row)
261+
}
262+
} else {
263+
if !p.sWrap.HasSelection(row) {
264+
p.markSelected(row)
265+
}
266+
}
267+
}
268+
}
269+
270+
func min(a, b int) int {
271+
if a < b {
272+
return a
273+
}
274+
return b
275+
}
276+
277+
func max(a, b int) int {
278+
if a > b {
279+
return a
280+
}
281+
return b
282+
}
283+
284+
func (p *MangaPage) shiftVInput() {
285+
if p.sWrap.IsInVisualMode() {
286+
p.sWrap.StopVisualSelection()
287+
for row := 1; row < p.Table.GetRowCount(); row++ {
288+
if p.sWrap.HasSelection(row) {
289+
p.markUnselected(row)
290+
}
291+
}
292+
} else {
293+
row, _ := p.Table.GetSelection()
294+
p.sWrap.StartVisualSelection(row)
295+
}
296+
}
297+
236298
// ctrlRInput : Allows user to toggle read status for a chapter.
237299
func (p *MangaPage) ctrlRInput() {
238300
modal := confirmModal(utils.ToggleReadChapterModalID,

app/ui/utils/selector.go

+15-3
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ package utils
33
// SelectorWrapper : A wrapper to store selections. Used by the manga page to
44
// keep track of selections.
55
type SelectorWrapper struct {
6-
Selection map[int]struct{} // Keep track of which chapters have been selected by user.
7-
All bool // Keep track of whether user has selected All or not.
6+
Selection map[int]struct{} // Keep track of which chapters have been selected by user.
7+
All bool // Keep track of whether user has selected All or not.
8+
VisualStart int // Keeps track of the start of the visual selection. -1 If none.
89
}
910

1011
// HasSelections : Checks whether there are currently selections.
@@ -24,7 +25,6 @@ func (s *SelectorWrapper) CopySelection(row int) map[int]struct{} {
2425
if !s.HasSelections() {
2526
s.AddSelection(row)
2627
}
27-
2828
selection := map[int]struct{}{}
2929
for se := range s.Selection {
3030
selection[se] = struct{}{}
@@ -47,3 +47,15 @@ func (s *SelectorWrapper) AddSelection(row int) {
4747
func (s *SelectorWrapper) RemoveSelection(row int) {
4848
delete(s.Selection, row)
4949
}
50+
51+
func (s *SelectorWrapper) IsInVisualMode() bool {
52+
return s.VisualStart != -1
53+
}
54+
55+
func (s *SelectorWrapper) StartVisualSelection(row int) {
56+
s.VisualStart = row
57+
}
58+
59+
func (s *SelectorWrapper) StopVisualSelection() {
60+
s.VisualStart = -1
61+
}

0 commit comments

Comments
 (0)