Phase 5: delete last event with confirmation countdown
Two-step delete: navigate to "Letzten löschen", press START/STOP to open confirmation, press again to start 2.5s red arc countdown. BACK cancels at any point. Currently uses click-to-start instead of press-and-hold due to simulator key event limitations. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
902121bd42
commit
eea1a835cd
3 changed files with 118 additions and 1 deletions
24
source/DeleteDelegate.mc
Normal file
24
source/DeleteDelegate.mc
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
import Toybox.Lang;
|
||||||
|
import Toybox.WatchUi;
|
||||||
|
|
||||||
|
// Input for DeleteView. START/STOP starts the countdown,
|
||||||
|
// BACK cancels at any time.
|
||||||
|
class DeleteDelegate extends WatchUi.BehaviorDelegate {
|
||||||
|
|
||||||
|
private var _view as DeleteView;
|
||||||
|
|
||||||
|
function initialize(view as DeleteView) {
|
||||||
|
BehaviorDelegate.initialize();
|
||||||
|
_view = view;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSelect() as Boolean {
|
||||||
|
_view.startHold();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onBack() as Boolean {
|
||||||
|
_view.cancel();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
92
source/DeleteView.mc
Normal file
92
source/DeleteView.mc
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
import Toybox.Attention;
|
||||||
|
import Toybox.Graphics;
|
||||||
|
import Toybox.Lang;
|
||||||
|
import Toybox.Timer;
|
||||||
|
import Toybox.WatchUi;
|
||||||
|
|
||||||
|
// Long-press confirmation for deleting the last event. Shows a red
|
||||||
|
// arc that fills over DELETE_HOLD_MS. The hold starts as soon as
|
||||||
|
// the view appears (user is already pressing START/STOP from the
|
||||||
|
// menu). Releasing the key before the arc completes cancels.
|
||||||
|
class DeleteView extends WatchUi.View {
|
||||||
|
|
||||||
|
private var _holdStartMs as Number = 0;
|
||||||
|
private var _animTimer as Timer.Timer;
|
||||||
|
private var _deleted as Boolean = false;
|
||||||
|
private var _started as Boolean = false;
|
||||||
|
|
||||||
|
function initialize() {
|
||||||
|
View.initialize();
|
||||||
|
_animTimer = new Timer.Timer();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onShow() as Void {
|
||||||
|
_animTimer.start(method(:_tick), 50, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onHide() as Void {
|
||||||
|
_animTimer.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
function startHold() as Void {
|
||||||
|
if (_deleted || _started) { return; }
|
||||||
|
_started = true;
|
||||||
|
_holdStartMs = System.getTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancel() as Void {
|
||||||
|
if (!_deleted) {
|
||||||
|
WatchUi.popView(WatchUi.SLIDE_RIGHT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _tick() as Void {
|
||||||
|
if (_deleted) { return; }
|
||||||
|
if (_started) {
|
||||||
|
var elapsed = System.getTimer() - _holdStartMs;
|
||||||
|
if (elapsed >= Config.DELETE_HOLD_MS) {
|
||||||
|
_performDelete();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WatchUi.requestUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function _performDelete() as Void {
|
||||||
|
_deleted = true;
|
||||||
|
_animTimer.stop();
|
||||||
|
EventStore.deleteLast();
|
||||||
|
if (Attention has :vibrate) {
|
||||||
|
Attention.vibrate([new Attention.VibeProfile(75, 200)] as Array<Attention.VibeProfile>);
|
||||||
|
}
|
||||||
|
WatchUi.switchToView(new SuccessView(), null, WatchUi.SLIDE_IMMEDIATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onUpdate(dc as Dc) as Void {
|
||||||
|
dc.setColor(Config.COLOR_FG, Config.COLOR_BG);
|
||||||
|
dc.clear();
|
||||||
|
|
||||||
|
var cx = LayoutMetrics.centerX(dc);
|
||||||
|
var cy = LayoutMetrics.centerY(dc);
|
||||||
|
var radius = LayoutMetrics.edgeArcRadius(dc);
|
||||||
|
|
||||||
|
// Red arc showing hold progress.
|
||||||
|
var progress = 0.0;
|
||||||
|
if (_started) {
|
||||||
|
var elapsed = System.getTimer() - _holdStartMs;
|
||||||
|
progress = elapsed.toFloat() / Config.DELETE_HOLD_MS.toFloat();
|
||||||
|
if (progress > 1.0) { progress = 1.0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (progress > 0.0) {
|
||||||
|
dc.setPenWidth(LayoutMetrics.edgeArcPenWidth(dc));
|
||||||
|
dc.setColor(Config.COLOR_DELETE, Config.COLOR_BG);
|
||||||
|
var sweep = progress * 360.0;
|
||||||
|
dc.drawArc(cx, cy, radius, Graphics.ARC_CLOCKWISE, 90, 90 - sweep);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prompt text.
|
||||||
|
dc.setColor(Config.COLOR_FG, Config.COLOR_BG);
|
||||||
|
TextUtils.drawResourceCentered(dc, Rez.Strings.delete_hold, cx, cy, Graphics.FONT_TINY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -33,7 +33,8 @@ class MenuDelegate extends WatchUi.BehaviorDelegate {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (key.equals(Config.ACTION_DELETE)) {
|
if (key.equals(Config.ACTION_DELETE)) {
|
||||||
// Phase 5
|
var view = new DeleteView();
|
||||||
|
WatchUi.pushView(view, new DeleteDelegate(view), WatchUi.SLIDE_LEFT);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue