mirror of
https://github.com/kuhyx/screen-locker.git
synced 2026-07-04 13:23:13 +02:00
195 lines
6.9 KiB
Python
195 lines
6.9 KiB
Python
|
|
"""Verify-workout and relaxed-day UI flow methods mixin."""
|
||
|
|
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
from concurrent.futures import ThreadPoolExecutor # pylint: disable=no-name-in-module
|
||
|
|
|
||
|
|
from screen_locker._weekly_check import (
|
||
|
|
WEEKLY_WORKOUT_MINIMUM,
|
||
|
|
count_weekly_workouts,
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
class UIFlowsRelaxedMixin:
|
||
|
|
"""Mixin providing verify-workout and relaxed-day UI flow logic."""
|
||
|
|
|
||
|
|
# ------------------------------------------------------------------
|
||
|
|
# Verify-workout flow (post-sick-day)
|
||
|
|
# ------------------------------------------------------------------
|
||
|
|
|
||
|
|
def _start_verify_workout_check(self) -> None:
|
||
|
|
"""Start phone check for post-sick-day workout verification."""
|
||
|
|
self.clear_container()
|
||
|
|
self._label(
|
||
|
|
"Verifying Workout",
|
||
|
|
font_size=36,
|
||
|
|
color="#ffaa00",
|
||
|
|
pady=30,
|
||
|
|
)
|
||
|
|
self._text(
|
||
|
|
"Checking phone for today's workout...",
|
||
|
|
font_size=18,
|
||
|
|
)
|
||
|
|
executor = ThreadPoolExecutor(max_workers=1)
|
||
|
|
self._phone_future = executor.submit(self._verify_phone_workout)
|
||
|
|
executor.shutdown(wait=False)
|
||
|
|
self._poll_verify_workout_check()
|
||
|
|
|
||
|
|
def _poll_verify_workout_check(self) -> None:
|
||
|
|
"""Poll background phone check for verify-workout mode."""
|
||
|
|
if self._phone_future is not None and self._phone_future.done():
|
||
|
|
status, message = self._phone_future.result()
|
||
|
|
self._handle_verify_workout_result(status, message)
|
||
|
|
else:
|
||
|
|
self.root.after(500, self._poll_verify_workout_check)
|
||
|
|
|
||
|
|
def _handle_verify_workout_result(
|
||
|
|
self,
|
||
|
|
status: str,
|
||
|
|
message: str,
|
||
|
|
) -> None:
|
||
|
|
"""Route phone check result in verify-workout mode."""
|
||
|
|
if status == "verified":
|
||
|
|
self.workout_data["type"] = "phone_verified"
|
||
|
|
self.workout_data["source"] = message
|
||
|
|
self.workout_data["after_sick_day"] = "true"
|
||
|
|
adjusted = self._adjust_shutdown_time_later()
|
||
|
|
self.save_workout_log()
|
||
|
|
self.clear_container()
|
||
|
|
self._label(
|
||
|
|
"✓ Workout Verified!",
|
||
|
|
font_size=42,
|
||
|
|
color="#00cc44",
|
||
|
|
pady=30,
|
||
|
|
)
|
||
|
|
self._text(message, font_size=20, color="#aaffaa")
|
||
|
|
if adjusted:
|
||
|
|
self._text(
|
||
|
|
"Shutdown time moved later!",
|
||
|
|
font_size=20,
|
||
|
|
color="#ffaa00",
|
||
|
|
)
|
||
|
|
self.root.after(2000, self.close)
|
||
|
|
else:
|
||
|
|
self._show_verify_retry(message)
|
||
|
|
|
||
|
|
def _show_verify_retry(self, message: str) -> None:
|
||
|
|
"""Show retry/close buttons when workout not found in verify mode."""
|
||
|
|
self.clear_container()
|
||
|
|
self._label(
|
||
|
|
"Workout Not Found",
|
||
|
|
font_size=36,
|
||
|
|
color="#ff4444",
|
||
|
|
pady=20,
|
||
|
|
)
|
||
|
|
self._text(message, color="#ffaa00")
|
||
|
|
frame = self._button_row()
|
||
|
|
self._button(
|
||
|
|
frame,
|
||
|
|
"TRY AGAIN",
|
||
|
|
bg="#0066cc",
|
||
|
|
command=self._start_verify_workout_check,
|
||
|
|
width=12,
|
||
|
|
).pack(side="left", padx=10)
|
||
|
|
self._button(
|
||
|
|
frame,
|
||
|
|
"Close",
|
||
|
|
bg="#aa0000",
|
||
|
|
command=self.close,
|
||
|
|
width=12,
|
||
|
|
).pack(side="left", padx=10)
|
||
|
|
|
||
|
|
# ------------------------------------------------------------------
|
||
|
|
# Relaxed-day flow (Tue/Wed/Thu — optional, no penalty for skipping)
|
||
|
|
# ------------------------------------------------------------------
|
||
|
|
|
||
|
|
def _start_relaxed_day_flow(self) -> None:
|
||
|
|
"""Show optional workout prompt for relaxed days (Tue-Thu).
|
||
|
|
|
||
|
|
The screen is not locked — the user can skip freely or voluntarily
|
||
|
|
import a Stronglift workout that counts toward the weekly minimum.
|
||
|
|
"""
|
||
|
|
count = count_weekly_workouts(self.log_file)
|
||
|
|
self.clear_container()
|
||
|
|
self._label(
|
||
|
|
"Optional Day (Tue / Wed / Thu)",
|
||
|
|
font_size=30,
|
||
|
|
color="#ffaa00",
|
||
|
|
pady=20,
|
||
|
|
)
|
||
|
|
self._text(
|
||
|
|
f"Weekly workouts: {count} / {WEEKLY_WORKOUT_MINIMUM}\n"
|
||
|
|
"No penalty for skipping today.",
|
||
|
|
font_size=20,
|
||
|
|
color="#aaaaaa",
|
||
|
|
pady=10,
|
||
|
|
)
|
||
|
|
frame = self._button_row()
|
||
|
|
self._button(
|
||
|
|
frame,
|
||
|
|
"Skip — No Penalty",
|
||
|
|
bg="#006600",
|
||
|
|
command=self.close,
|
||
|
|
width=18,
|
||
|
|
).pack(side="left", padx=10)
|
||
|
|
self._button(
|
||
|
|
frame,
|
||
|
|
"Log Stronglift Workout",
|
||
|
|
bg="#0066cc",
|
||
|
|
command=self._start_relaxed_phone_check,
|
||
|
|
width=20,
|
||
|
|
).pack(side="left", padx=10)
|
||
|
|
|
||
|
|
def _start_relaxed_phone_check(self) -> None:
|
||
|
|
"""Run Stronglift check in relaxed mode (no screen grab, no sick option)."""
|
||
|
|
self.clear_container()
|
||
|
|
self._label("Checking phone...", font_size=36, color="#ffaa00", pady=30)
|
||
|
|
self._text("Looking for today's workout in StrongLifts...", font_size=18)
|
||
|
|
executor = ThreadPoolExecutor(max_workers=1)
|
||
|
|
self._phone_future = executor.submit(self._verify_phone_workout)
|
||
|
|
executor.shutdown(wait=False)
|
||
|
|
self._poll_relaxed_phone_check()
|
||
|
|
|
||
|
|
def _poll_relaxed_phone_check(self) -> None:
|
||
|
|
"""Poll background phone check in relaxed-day mode."""
|
||
|
|
if self._phone_future is not None and self._phone_future.done():
|
||
|
|
status, message = self._phone_future.result()
|
||
|
|
self._handle_relaxed_phone_result(status, message)
|
||
|
|
else:
|
||
|
|
self.root.after(500, self._poll_relaxed_phone_check)
|
||
|
|
|
||
|
|
def _handle_relaxed_phone_result(self, status: str, message: str) -> None:
|
||
|
|
"""Route phone check result in relaxed-day mode.
|
||
|
|
|
||
|
|
On success saves the workout (counts toward weekly total) then closes.
|
||
|
|
On failure shows retry and close — no sick option since skipping is free.
|
||
|
|
"""
|
||
|
|
if status == "verified":
|
||
|
|
self.workout_data["type"] = "phone_verified"
|
||
|
|
self.workout_data["source"] = message
|
||
|
|
unlock_delay = 1500 if self.demo_mode else 2000
|
||
|
|
self.root.after(unlock_delay, self.unlock_screen)
|
||
|
|
else:
|
||
|
|
self._show_relaxed_retry(message, status)
|
||
|
|
|
||
|
|
def _show_relaxed_retry(self, message: str, status: str) -> None:
|
||
|
|
"""Show retry and skip-close when workout not found in relaxed mode."""
|
||
|
|
self.clear_container()
|
||
|
|
self._label("No Workout Found", font_size=36, color="#ff4444", pady=20)
|
||
|
|
self._text(f"❌ {message}\n\nReason: {status}", color="#ffaa00")
|
||
|
|
frame = self._button_row()
|
||
|
|
self._button(
|
||
|
|
frame,
|
||
|
|
"TRY AGAIN",
|
||
|
|
bg="#0066cc",
|
||
|
|
command=self._start_relaxed_phone_check,
|
||
|
|
width=12,
|
||
|
|
).pack(side="left", padx=10)
|
||
|
|
self._button(
|
||
|
|
frame,
|
||
|
|
"Close (Skip)",
|
||
|
|
bg="#006600",
|
||
|
|
command=self.close,
|
||
|
|
width=14,
|
||
|
|
).pack(side="left", padx=10)
|