diff --git a/CHANGELOG.md b/CHANGELOG.md index 61a4afd..35612fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ và dự án tuân theo [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ## [Unreleased] +### Added / Feature +- **Motivation Quote UI**: Triển khai hiển thị câu chữ truyền động lực (Motivation Quote) bên dưới đồng hồ đếm ngược. UI tự động gọi AI lấy câu quote (theo database hoặc fallback) dựa trên các cột mốc chiến lược: `PreFocus` (bắt đầu ngẫu nhiên), `MidFocus` (qua 50% thời gian), và `PostFocus` (gần hoàn thành, vượt 90%). Khi khôi phục phiên sẽ hiển thị quote giữ lửa cố định. + --- ## [1.0.3] - 2026-04-17 diff --git a/src/DontBeLazy.WPF/ViewModels/FocusSessionViewModel.cs b/src/DontBeLazy.WPF/ViewModels/FocusSessionViewModel.cs index 5e57c63..88e0c56 100644 --- a/src/DontBeLazy.WPF/ViewModels/FocusSessionViewModel.cs +++ b/src/DontBeLazy.WPF/ViewModels/FocusSessionViewModel.cs @@ -44,6 +44,10 @@ public partial class FocusSessionViewModel : ObservableObject public bool CanConfirmAbandon => FrictionInput.Trim() == FrictionPhrase; private int _totalSeconds; + private bool _hasShownMidFocus; + private bool _hasShownPostFocus; + + [ObservableProperty] private string _currentMotivationQuote = string.Empty; partial void OnSelectedTaskChanged(FocusTaskDto? value) { @@ -93,6 +97,10 @@ public void LoadRestoredSession(SessionHistoryDto restoredSession) TimerDisplay = $"{RemainingSeconds / 60:D2}:{RemainingSeconds % 60:D2}"; TimerProgress = ((double)restoredSession.ActualSeconds / _totalSeconds) * 100; + CurrentMotivationQuote = "Hãy tiếp tục hoàn thành mục tiêu dang dở của bạn!"; + _hasShownMidFocus = TimerProgress >= 50; + _hasShownPostFocus = TimerProgress >= 90; + _timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1) }; _timer.Tick += OnTimerTick; _timer.Start(); @@ -135,6 +143,11 @@ private async Task StartSessionAsync() IsSessionActive = true; IsPaused = false; + + _hasShownMidFocus = false; + _hasShownPostFocus = false; + var q = await _quoteUseCase.GetQuoteForEventAsync(QuoteEventTypeDto.PreFocus, "vi"); + CurrentMotivationQuote = q?.Content ?? "Hãy tập trung hết sức cho mục tiêu của bạn!"; _timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1) }; _timer.Tick += OnTimerTick; @@ -147,6 +160,20 @@ private async void OnTimerTick(object? sender, EventArgs e) RemainingSeconds--; TimerProgress = ((double)(_totalSeconds - RemainingSeconds) / _totalSeconds) * 100; UpdateTimerDisplay(); + + if (TimerProgress >= 50 && !_hasShownMidFocus) + { + _hasShownMidFocus = true; + var q = await _quoteUseCase.GetQuoteForEventAsync(QuoteEventTypeDto.MidFocus, "vi"); + if (q != null) CurrentMotivationQuote = q.Content; + } + else if (TimerProgress >= 90 && !_hasShownPostFocus) + { + _hasShownPostFocus = true; + var q = await _quoteUseCase.GetQuoteForEventAsync(QuoteEventTypeDto.PostFocus, "vi"); + if (q != null) CurrentMotivationQuote = q.Content; + } + await _sessionUseCase.SyncSessionTimeAsync(_currentSession.Id, 1); if (RemainingSeconds <= 0) await CompleteSessionAsync(); } diff --git a/src/DontBeLazy.WPF/Views/FocusSessionView.xaml b/src/DontBeLazy.WPF/Views/FocusSessionView.xaml index c681a28..b0ffab4 100644 --- a/src/DontBeLazy.WPF/Views/FocusSessionView.xaml +++ b/src/DontBeLazy.WPF/Views/FocusSessionView.xaml @@ -141,8 +141,16 @@ + + + -