diff --git a/lib/services/entitlements/entitlement_state.dart b/lib/services/entitlements/entitlement_state.dart new file mode 100644 index 0000000..3ad7643 --- /dev/null +++ b/lib/services/entitlements/entitlement_state.dart @@ -0,0 +1,66 @@ +import 'package:flutter/foundation.dart'; + +enum MotorSignalPlan { + free, + proMonthly, + proLifetime, +} + +enum MotorSignalEntitlementStatus { + free, + proMonthlyActive, + proMonthlyGrace, + proMonthlyAccountHold, + proMonthlyExpired, + proLifetime, + unknown, + syncPending, +} + +/// Central capability model. UI and services should depend on capabilities, +/// not Google Play product IDs or scattered `isPro` checks. +@immutable +class EntitlementState { + final MotorSignalPlan plan; + final MotorSignalEntitlementStatus status; + final DateTime? expiresAt; + + const EntitlementState({ + this.plan = MotorSignalPlan.free, + this.status = MotorSignalEntitlementStatus.free, + this.expiresAt, + }); + + bool get isPro => plan != MotorSignalPlan.free && + status != MotorSignalEntitlementStatus.proMonthlyExpired; + + bool get canCloudBackup => true; + bool get canUnlimitedCloudHistory => isPro; + bool get canMultiDeviceRestore => isPro; + bool get canAdvancedTelemetry => isPro; + bool get canAdvancedAcceleration => isPro; + bool get canAdvancedBraking => isPro; + bool get canAdvancedLean => isPro; + bool get canAdvancedAnalytics => isPro; + bool get canUnlimitedHistory => isPro; + bool get canExportCsv => isPro; + bool get canExportPdf => isPro; + bool get canUseMultipleMotorcycles => isPro; + bool get canPlanTrips => isPro; + bool get canCreateGroupRides => isPro; + bool get canUseAdvancedGroupRideFeatures => isPro; + + /// The Free cloud allowance is intentionally not hard-coded here. Product + /// economics will define the exact quota before launch. + int? get cloudRideAllowance => isPro ? null : null; + + EntitlementState copyWith({ + MotorSignalPlan? plan, + MotorSignalEntitlementStatus? status, + DateTime? expiresAt, + }) => EntitlementState( + plan: plan ?? this.plan, + status: status ?? this.status, + expiresAt: expiresAt ?? this.expiresAt, + ); +}