138 lines
3.6 KiB
Dart
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());
|
|
}
|
|
}
|