Update Saqel Platform: 2026-09-08 17:51:07
This commit is contained in:
@@ -6,6 +6,9 @@ import '../utils/app_logger.dart';
|
||||
|
||||
/// Enterprise Storage Service with Device-Bound Payload Obfuscation & Secure KeyStore/Keychain
|
||||
class StorageService {
|
||||
// Keeps a newly issued session available during this app run if the macOS
|
||||
// debug runner has no Keychain entitlement. Production still uses Keychain.
|
||||
static final Map<String, String> _volatileStore = <String, String>{};
|
||||
final FlutterSecureStorage _secureStorage;
|
||||
|
||||
StorageService({FlutterSecureStorage? secureStorage})
|
||||
@@ -26,6 +29,7 @@ class StorageService {
|
||||
static const String _keyDeviceId = 'saqel_device_id';
|
||||
|
||||
Future<void> _writeSafe(String key, String value) async {
|
||||
_volatileStore[key] = value;
|
||||
try {
|
||||
await _secureStorage.write(key: key, value: value);
|
||||
} on PlatformException catch (e) {
|
||||
@@ -38,10 +42,11 @@ class StorageService {
|
||||
final val = await _secureStorage.read(key: key);
|
||||
if (val != null && val.isNotEmpty) return val;
|
||||
} catch (_) {}
|
||||
return null;
|
||||
return _volatileStore[key];
|
||||
}
|
||||
|
||||
Future<void> _deleteSafe(String key) async {
|
||||
_volatileStore.remove(key);
|
||||
try {
|
||||
await _secureStorage.delete(key: key);
|
||||
} catch (_) {}
|
||||
|
||||
@@ -88,7 +88,7 @@ class AuthRepository {
|
||||
required String identityToken,
|
||||
required String fullName,
|
||||
required String nationalId,
|
||||
String gradeLevel = 'tawjihi_2008',
|
||||
String gradeLevel = 'grade_10',
|
||||
String stream = 'scientific',
|
||||
}) async {
|
||||
final res = await _api.post(
|
||||
|
||||
@@ -148,7 +148,7 @@ class AuthCubit extends Cubit<AuthState> {
|
||||
required String identityToken,
|
||||
required String fullName,
|
||||
required String nationalId,
|
||||
String gradeLevel = 'tawjihi_2008',
|
||||
String gradeLevel = 'grade_10',
|
||||
String stream = 'scientific',
|
||||
}) async {
|
||||
AppLogger.log('Setting up profile for $fullName ($nationalId)...', tag: 'AUTH_CUBIT');
|
||||
|
||||
@@ -23,7 +23,7 @@ class _AuthScreenState extends State<AuthScreen> {
|
||||
final TextEditingController _fullNameController = TextEditingController();
|
||||
|
||||
String _selectedRole = 'student';
|
||||
final String _selectedGrade = 'tawjihi_2008';
|
||||
String _selectedGrade = 'grade_10';
|
||||
String _selectedStream = 'scientific';
|
||||
|
||||
@override
|
||||
@@ -440,7 +440,30 @@ class _AuthScreenState extends State<AuthScreen> {
|
||||
),
|
||||
const SizedBox(height: 18),
|
||||
|
||||
// Stream Selector (العلمي / الأدبي)
|
||||
Text(
|
||||
'الصف الدراسي',
|
||||
style: AppTypography.titleMedium.copyWith(color: AppColors.textSecondaryDark, fontSize: 13),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Wrap(
|
||||
spacing: 8,
|
||||
children: [
|
||||
('grade_10', 'الصف العاشر'),
|
||||
('grade_11', 'الأول ثانوي'),
|
||||
('grade_12', 'الثاني ثانوي'),
|
||||
].map((grade) => ChoiceChip(
|
||||
label: Text(grade.$2),
|
||||
selected: _selectedGrade == grade.$1,
|
||||
onSelected: isLoading ? null : (_) => setState(() {
|
||||
_selectedGrade = grade.$1;
|
||||
if (_selectedGrade == 'grade_10') _selectedStream = 'general';
|
||||
}),
|
||||
)).toList(),
|
||||
),
|
||||
const SizedBox(height: 18),
|
||||
|
||||
// Stream Selector (only secondary grades have a stream)
|
||||
if (_selectedGrade != 'grade_10') ...[
|
||||
Text(
|
||||
'الفرع الأكاديمي',
|
||||
style: AppTypography.titleMedium.copyWith(color: AppColors.textSecondaryDark, fontSize: 13),
|
||||
@@ -501,6 +524,7 @@ class _AuthScreenState extends State<AuthScreen> {
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 24),
|
||||
|
||||
LuxuryButton(
|
||||
|
||||
Reference in New Issue
Block a user