Ocideck/lib/state/consent_provider.dart
Brenno de Winter c6190dc31b Add consent/privacy screen at startup and license display
Implement three privacy features:
1. Consent gate at app startup - users must accept privacy terms before using OciDeck
2. License visibility - MIT license displayed in consent dialog
3. Consent revocation - privacy settings tab allows users to withdraw consent and return to consent screen

Changes:
- New ConsentProvider for managing consent state with SharedPreferences persistence
- New ConsentDialog with privacy explanation and MIT license (expandable)
- Added Privacy tab to settings dialog with revoke consent button
- Updated localization strings for Dutch/English consent screens

Consent flow:
- On first launch or after revocation, consent screen blocks app access
- Users can read privacy terms, view license, and accept to proceed
- Consent can be revoked anytime from Settings → Privacy tab
- After revocation, app returns to consent screen on next launch

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-06-11 14:01:06 +02:00

67 lines
1.7 KiB
Dart

import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:shared_preferences/shared_preferences.dart';
const _consentKey = 'app_consent_accepted';
final consentProvider =
NotifierProvider<ConsentNotifier, ConsentState>(() {
return ConsentNotifier();
});
class ConsentState {
final bool hasAccepted;
final bool isLoading;
const ConsentState({
required this.hasAccepted,
this.isLoading = false,
});
ConsentState copyWith({
bool? hasAccepted,
bool? isLoading,
}) {
return ConsentState(
hasAccepted: hasAccepted ?? this.hasAccepted,
isLoading: isLoading ?? this.isLoading,
);
}
}
class ConsentNotifier extends Notifier<ConsentState> {
@override
ConsentState build() {
_initialize();
return const ConsentState(hasAccepted: false, isLoading: true);
}
Future<void> _initialize() async {
try {
final prefs = await SharedPreferences.getInstance();
final hasAccepted = prefs.getBool(_consentKey) ?? false;
state = state.copyWith(hasAccepted: hasAccepted, isLoading: false);
} catch (e) {
state = state.copyWith(isLoading: false);
}
}
Future<void> acceptConsent() async {
try {
final prefs = await SharedPreferences.getInstance();
await prefs.setBool(_consentKey, true);
state = state.copyWith(hasAccepted: true);
} catch (e) {
state = state.copyWith(hasAccepted: true);
}
}
Future<void> revokeConsent() async {
try {
final prefs = await SharedPreferences.getInstance();
await prefs.setBool(_consentKey, false);
state = state.copyWith(hasAccepted: false);
} catch (e) {
state = state.copyWith(hasAccepted: false);
}
}
}