概要

連続トレーニング日数(ストリーク)の計算と、各種実績バッジの判定機能。 継続のモチベーション維持を狙う。

関連画面

AchievementService API

@MainActor
final class AchievementService {
    func calculateStreak(sessions: [WorkoutSession]) -> Int
    func checkAchievements(sessions: [WorkoutSession]) -> [Achievement]
}

バッジ一覧

バッジ名条件
First Step初回セッション完了
Consistency10セッション完了
Half Century50セッション完了
Centurion100セッション完了
Streak 33日連続
Streak 77日連続
Streak 1414日連続
Streak 3030日連続
First PR初回PR達成
PR Machine10PR達成
Goal Achieved目標達成
Monthly Perfect月間目標 4週連続達成

ストリーク計算ロジック

// 昨日トレーニングしていれば streak +1
// 当日のみなら 1 開始
// 2日以上空いていれば 0 リセット
func calculateStreak(sessions: [WorkoutSession]) -> Int {
    let sortedDates = sessions.map { $0.date }.sorted()
    var streak = 0
    var prev = Date.distantPast
    for date in sortedDates {
        if Calendar.current.isDate(date, inSameDayAs: prev) { continue }
        if Calendar.current.isDate(date, inSameDayAs: prev.advanced(by: 86400)) {
            streak += 1
        } else {
            streak = 1
        }
        prev = date
    }
    return streak
}

ビジネスルール

変更履歴

バージョン日付変更内容
1.02026-05-09初版作成