import 'dart:async'; import 'dart:convert'; import 'package:crypto/crypto.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/cupertino.dart'; import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'accountModel.dart'; class AccountData { static const _usernameField = 'username'; static const _passwordField = 'password'; static final AccountData _instance = AccountData._construct(); final Future _storage = SharedPreferences.getInstance(); Completer _populated = Completer(); factory AccountData() { return _instance; } AccountData._construct() { _updateFromStorage(); } String? _username; String? _password; String getUsername() { if(_username == null) throw Exception('Username not initialized'); return _username!; } String getPassword() { if(_password == null) throw Exception('Password not initialized'); return _password!; } String getUserSecret() { return sha512.convert(utf8.encode('${AccountData().getUsername()}:${AccountData().getPassword()}')).toString(); } Future getDeviceId() async { return sha512.convert(utf8.encode('${getUserSecret()}@${await FirebaseMessaging.instance.getToken()}')).toString(); } Future setData(String username, String password) async { SharedPreferences storage = await _storage; storage.setString(_usernameField, username); storage.setString(_passwordField, password); await _updateFromStorage(); } Future removeData({BuildContext? context}) async { _populated = Completer(); if(context != null) Provider.of(context, listen: false).setState(AccountModelState.loggedOut); SharedPreferences storage = await _storage; await storage.remove(_usernameField); await storage.remove(_passwordField); } Future _updateFromStorage() async { SharedPreferences storage = await _storage; //await storage.reload(); // This line was the cause of the first rejected google play upload :( if(storage.containsKey(_usernameField) && storage.containsKey(_passwordField)) { _username = storage.getString(_usernameField); _password = storage.getString(_passwordField); } if(!_populated.isCompleted) _populated.complete(); } Future waitForPopulation() async { await _populated.future; return isPopulated(); } bool isPopulated() { return _username != null && _password != null; } String buildHttpAuthString() { if(!isPopulated()) throw Exception('AccountData (e.g. username or password) is not initialized!'); return '$_username:$_password'; } }