Add keyboard-first accessibility behavior
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"strings"
|
||||
|
||||
"gioui.org/layout"
|
||||
"gioui.org/op/clip"
|
||||
"gioui.org/op/paint"
|
||||
"gioui.org/unit"
|
||||
)
|
||||
|
||||
type focusAppearance struct {
|
||||
BorderColor color.NRGBA
|
||||
OutlineColor color.NRGBA
|
||||
OutlineWidth int
|
||||
MinHeight int
|
||||
}
|
||||
|
||||
func fieldFocusAppearance(metric unit.Metric, focused bool) focusAppearance {
|
||||
appearance := focusAppearance{
|
||||
BorderColor: color.NRGBA{R: 202, G: 194, B: 180, A: 255},
|
||||
OutlineColor: color.NRGBA{A: 0},
|
||||
OutlineWidth: max(1, metric.Dp(unit.Dp(1))),
|
||||
MinHeight: metric.Dp(unit.Dp(44)),
|
||||
}
|
||||
if focused {
|
||||
appearance.BorderColor = accentColor
|
||||
appearance.OutlineColor = color.NRGBA{R: 28, G: 83, B: 63, A: 72}
|
||||
appearance.OutlineWidth = max(2, metric.Dp(unit.Dp(2)))
|
||||
}
|
||||
return appearance
|
||||
}
|
||||
|
||||
func buttonFocusColors(focused bool) (background color.NRGBA, text color.NRGBA) {
|
||||
background = color.NRGBA{R: 231, G: 239, B: 235, A: 255}
|
||||
text = accentColor
|
||||
if focused {
|
||||
background = color.NRGBA{R: 214, G: 229, B: 221, A: 255}
|
||||
}
|
||||
return background, text
|
||||
}
|
||||
|
||||
func (u *ui) accessibilityLabel(id focusID) string {
|
||||
switch {
|
||||
case id == focusSearch:
|
||||
return "Search vault"
|
||||
case strings.HasPrefix(string(id), "breadcrumb:"):
|
||||
index := focusIndex(id)
|
||||
crumbs := u.breadcrumbLabels()
|
||||
if index >= 0 && index < len(crumbs) {
|
||||
return fmt.Sprintf("Navigate to %s", crumbs[index])
|
||||
}
|
||||
case strings.HasPrefix(string(id), "list:"):
|
||||
index := focusIndex(id)
|
||||
if index >= 0 && index < len(u.visible) {
|
||||
return fmt.Sprintf("Select entry %s", u.visible[index].Title)
|
||||
}
|
||||
case strings.HasPrefix(string(id), "detail:"):
|
||||
name := strings.TrimPrefix(string(id), "detail:")
|
||||
return fmt.Sprintf("Edit %s", detailFieldLabel(detailField(name)))
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func drawFocusOutline(gtx layout.Context, appearance focusAppearance, size image.Point) layout.Dimensions {
|
||||
if appearance.OutlineColor.A == 0 || appearance.OutlineWidth <= 0 {
|
||||
return layout.Dimensions{Size: size}
|
||||
}
|
||||
|
||||
width := appearance.OutlineWidth
|
||||
paint.FillShape(gtx.Ops, appearance.OutlineColor, clip.Rect{Max: image.Pt(size.X, width)}.Op())
|
||||
paint.FillShape(gtx.Ops, appearance.OutlineColor, clip.Rect{Min: image.Pt(0, size.Y-width), Max: image.Pt(size.X, size.Y)}.Op())
|
||||
paint.FillShape(gtx.Ops, appearance.OutlineColor, clip.Rect{Max: image.Pt(width, size.Y)}.Op())
|
||||
paint.FillShape(gtx.Ops, appearance.OutlineColor, clip.Rect{Min: image.Pt(size.X-width, 0), Max: image.Pt(size.X, size.Y)}.Op())
|
||||
return layout.Dimensions{Size: size}
|
||||
}
|
||||
|
||||
func (u *ui) isFocused(id focusID) bool {
|
||||
return u.keyboardFocus == id
|
||||
}
|
||||
|
||||
func detailFieldLabel(field detailField) string {
|
||||
switch field {
|
||||
case detailFieldID:
|
||||
return "ID"
|
||||
case detailFieldTitle:
|
||||
return "Title"
|
||||
case detailFieldUsername:
|
||||
return "Username"
|
||||
case detailFieldPassword:
|
||||
return "Password"
|
||||
case detailFieldURL:
|
||||
return "URL"
|
||||
case detailFieldPath:
|
||||
return "Path"
|
||||
case detailFieldTags:
|
||||
return "Tags"
|
||||
case detailFieldPasswordProfile:
|
||||
return "Password Profile"
|
||||
case detailFieldNotes:
|
||||
return "Notes"
|
||||
case detailFieldFields:
|
||||
return "Custom Fields"
|
||||
case detailFieldHistoryIndex:
|
||||
return "History Index"
|
||||
default:
|
||||
return strings.ReplaceAll(string(field), "-", " ")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user