Files
kickkings_admin_app/lib/session.dart
T
2026-10-16 01:25:50 +05:30

138 lines
3.6 KiB
Dart

import 'dart:async';
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'api/support_api.dart';
import 'models/account.dart';
import 'models/api_exception.dart';
class SessionStore {
SessionStore({FlutterSecureStorage? storage})
: _storage = storage ?? const FlutterSecureStorage();
static const tokenKey = 'auth_token';
static const accountKey = 'account_json';
static const fcmTokenKey = 'fcm_token';
final FlutterSecureStorage _storage;
Future<String?> readToken() => _storage.read(key: tokenKey);
Future<Account?> readAccount() async {
final raw = await _storage.read(key: accountKey);
if (raw == null || raw.isEmpty) {
return null;
}
final decoded = jsonDecode(raw);
if (decoded is! Map) {
return null;
}
return Account.fromJson(Map<String, dynamic>.from(decoded));
}
Future<String?> readFcmToken() => _storage.read(key: fcmTokenKey);
Future<void> writeSession(String token, Account account) async {
await _storage.write(key: tokenKey, value: token);
await _storage.write(key: accountKey, value: jsonEncode(account.toJson()));
}
Future<void> writeFcmToken(String token) {
return _storage.write(key: fcmTokenKey, value: token);
}
Future<void> clear() async {
await _storage.delete(key: tokenKey);
await _storage.delete(key: accountKey);
await _storage.delete(key: fcmTokenKey);
}
}
class SessionController extends ChangeNotifier {
SessionController({required this.store, required this.api});
final SessionStore store;
final SupportApi api;
Account? account;
String? token;
String? fcmToken;
String? pendingTicketId;
bool ready = false;
bool get isSignedIn =>
token != null && account != null && account!.canReadSupport;
Future<void> restore() async {
try {
token = await store.readToken();
account = await store.readAccount();
fcmToken = await store.readFcmToken();
if (token == null || account == null || !account!.canReadSupport) {
token = null;
account = null;
}
api.authToken = token;
} finally {
ready = true;
notifyListeners();
}
}
/// Returns an error message, or null when the inbox can open.
Future<String?> signIn(String username, String password) async {
try {
final result = await api.login(username.trim(), password);
if (!result.account.canReadSupport) {
return 'This account does not have support access';
}
await store.writeSession(result.token, result.account);
token = result.token;
account = result.account;
api.authToken = token;
notifyListeners();
return null;
} on ApiException catch (error) {
return error.message;
} on Object {
return 'Could not save this session.';
}
}
Future<void> saveFcmToken(String value) async {
fcmToken = value;
await store.writeFcmToken(value);
}
Future<void> signOut() async {
final deviceToken = fcmToken;
if (deviceToken != null && deviceToken.isNotEmpty && token != null) {
try {
await api.unregisterDevice(deviceToken);
} on ApiException {
// Local logout still proceeds when the device delete fails.
}
}
token = null;
account = null;
fcmToken = null;
api.authToken = null;
await store.clear();
notifyListeners();
}
void handleUnauthorized() {
if (token == null && account == null) {
return;
}
token = null;
account = null;
fcmToken = null;
api.authToken = null;
notifyListeners();
unawaited(store.clear());
}
}