aboutsummaryrefslogtreecommitdiff
path: root/source/ui/InfoView.mc
blob: cab4b52170267cbec255abc53795c31291fd5654 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// Author:  cirakg & claude ai
// Summary: A scrollable text screen with a title: settings results, entry IDs, clock status, about, errors.

import Toybox.Graphics;
import Toybox.Lang;
import Toybox.WatchUi;

class InfoView extends WatchUi.View {

    private var _title as String;
    private var _text as Array<String>;
    private var _screen as String;
    private var _lines as Array<String>? = null; // wrapped, on first draw
    // For each wrapped line: true when it starts one of the text items.
    private var _starts as Array<Boolean> = [] as Array<Boolean>;
    private var _first as Number = 0;
    private var _visible as Number = 1;
    private var _shownLogged as Boolean = false;

    // screen names the view in "DIAG shown" lines for UI scripts.
    function initialize(title as String, text as Array<String>, screen as String) {
        View.initialize();
        _title = title;
        _text = text;
        _screen = screen;
    }

    function onShow() as Void {
        _shownLogged = false;
    }

    // Scroll by delta lines; returns false when already at that end.
    function scroll(delta as Number) as Boolean {
        var lines = _lines;
        if (lines == null) {
            return false;
        }
        var max = lines.size() - _visible > 0 ? lines.size() - _visible : 0;
        var next = _first + delta;
        next = next < 0 ? 0 : (next > max ? max : next);
        if (next == _first) {
            return false;
        }
        _first = next;
        WatchUi.requestUpdate();
        return true;
    }

    function onUpdate(dc as Graphics.Dc) as Void {
        Ui.clear(dc);
        var w = dc.getWidth();
        var h = dc.getHeight();
        var font = Graphics.FONT_XTINY;
        var lineH = dc.getFontHeight(font);
        var y = Ui.isRound() ? h / 8 : 6;
        dc.setColor(Ui.accent(), Graphics.COLOR_TRANSPARENT);
        dc.drawText(w / 2, y, Graphics.FONT_SMALL, Ui.fit(dc, _title, Graphics.FONT_SMALL, 2 * Ui.halfWidthAt(dc, y)),
            Graphics.TEXT_JUSTIFY_CENTER);
        y += dc.getFontHeight(Graphics.FONT_SMALL) + 4;
        var bottom = Ui.isRound() ? h - h / 10 : h - 4;
        var lines = _lines;
        if (lines == null) {
            // Wrap to the narrowest width the text area has.
            var width = 2 * Ui.halfWidthBetween(dc, y, bottom) - 8;
            lines = [] as Array<String>;
            for (var i = 0; i < _text.size(); i++) {
                var wrapped = Ui.wrap(dc, _text[i], font, width);
                for (var k = 0; k < wrapped.size(); k++) {
                    _starts.add(k == 0);
                }
                lines.addAll(wrapped);
            }
            _lines = lines;
        }
        dc.setColor(Ui.fg(), Graphics.COLOR_TRANSPARENT);
        // A third of a line between items, so wrapped items stay apart.
        var gap = lineH / 3;
        var shown = 0;
        for (var i = _first; i < lines.size() && y + lineH <= bottom; i++) {
            if (_starts[i] && i != _first) {
                y += gap;
                if (y + lineH > bottom) {
                    break;
                }
            }
            dc.drawText(w / 2, y, font, lines[i], Graphics.TEXT_JUSTIFY_CENTER);
            y += lineH;
            shown++;
        }
        _visible = shown > 0 ? shown : 1;
        if (_first + shown < lines.size()) {
            var cx = w / 2;
            dc.setColor(Ui.dim(), Graphics.COLOR_TRANSPARENT);
            dc.fillPolygon([[cx - 6, bottom], [cx + 6, bottom], [cx, bottom + 6]] as Array<Graphics.Point2D>);
        }
        if (!_shownLogged) {
            _shownLogged = true;
            Diag.shown(_screen);
        }
    }
}

// Input on a text screen: scroll, BACK closes (and leaves the app when this
// is the only screen, as for start-up errors).
class InfoDelegate extends WatchUi.BehaviorDelegate {

    function initialize() {
        BehaviorDelegate.initialize();
    }

    private function view() as InfoView? {
        var current = WatchUi.getCurrentView()[0];
        return current instanceof InfoView ? current : null;
    }

    function onNextPage() as Boolean {
        AppState.activity();
        var v = view();
        if (v != null) {
            v.scroll(3);
        }
        return true;
    }

    function onPreviousPage() as Boolean {
        AppState.activity();
        var v = view();
        if (v != null) {
            v.scroll(-3);
        }
        return true;
    }

    function onBack() as Boolean {
        AppState.activity();
        return false;
    }
}