mirror of
https://github.com/we-promise/sure.git
synced 2026-04-07 14:31:25 +00:00
Intro mode in Flutter client fixes
This commit is contained in:
@@ -23,15 +23,42 @@ class User {
|
||||
email: json['email'] as String,
|
||||
firstName: json['first_name'] as String?,
|
||||
lastName: json['last_name'] as String?,
|
||||
uiLayout: (json['ui_layout'] as String?) ?? 'dashboard',
|
||||
// Default to true when key is absent (legacy payloads from older app versions).
|
||||
// Avoids regressing existing users who would otherwise be incorrectly gated.
|
||||
aiEnabled: json.containsKey('ai_enabled')
|
||||
? (json['ai_enabled'] == true)
|
||||
: true,
|
||||
uiLayout: _coerceUiLayout(json['ui_layout'] ?? json['uiLayout']),
|
||||
aiEnabled: _coerceBool(json['ai_enabled'] ?? json['aiEnabled'], defaultValue: false),
|
||||
);
|
||||
}
|
||||
|
||||
static String _coerceUiLayout(dynamic value) {
|
||||
if (value is String) {
|
||||
final layout = value.trim();
|
||||
if (layout.isNotEmpty) return layout;
|
||||
}
|
||||
return 'dashboard';
|
||||
}
|
||||
|
||||
static bool _coerceBool(dynamic value, {required bool defaultValue}) {
|
||||
if (value == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
if (value is bool) return value;
|
||||
if (value is num) return value != 0;
|
||||
if (value is String) {
|
||||
switch (value.trim().toLowerCase()) {
|
||||
case "true":
|
||||
case "1":
|
||||
case "yes":
|
||||
return true;
|
||||
case "false":
|
||||
case "0":
|
||||
case "no":
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
User copyWith({
|
||||
String? id,
|
||||
String? email,
|
||||
|
||||
@@ -52,7 +52,7 @@ class _MainNavigationScreenState extends State<MainNavigationScreen> {
|
||||
const NavigationDestination(
|
||||
icon: Icon(Icons.chat_bubble_outline),
|
||||
selectedIcon: Icon(Icons.chat_bubble),
|
||||
label: 'AI Chat',
|
||||
label: 'Assistant',
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
@@ -180,10 +180,17 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
),
|
||||
|
||||
// App version
|
||||
const ListTile(
|
||||
leading: Icon(Icons.info_outline),
|
||||
title: Text('App Version'),
|
||||
subtitle: Text('1.0.0'),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.info_outline),
|
||||
title: const Text('App Version: 0.6.8'),
|
||||
subtitle: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(' > ui_layout: ${authProvider.user?.uiLayout}'),
|
||||
Text(' > ai_enabled: ${authProvider.user?.aiEnabled}'),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
const Divider(),
|
||||
|
||||
@@ -56,7 +56,9 @@ class AuthService {
|
||||
// Store user data - parse once and reuse
|
||||
User? user;
|
||||
if (responseData['user'] != null) {
|
||||
user = User.fromJson(responseData['user']);
|
||||
final rawUser = responseData['user'];
|
||||
_logRawUserPayload('login', rawUser);
|
||||
user = User.fromJson(rawUser);
|
||||
await _saveUser(user);
|
||||
}
|
||||
|
||||
@@ -160,7 +162,9 @@ class AuthService {
|
||||
// Store user data - parse once and reuse
|
||||
User? user;
|
||||
if (responseData['user'] != null) {
|
||||
user = User.fromJson(responseData['user']);
|
||||
final rawUser = responseData['user'];
|
||||
_logRawUserPayload('signup', rawUser);
|
||||
user = User.fromJson(rawUser);
|
||||
await _saveUser(user);
|
||||
}
|
||||
|
||||
@@ -406,6 +410,7 @@ class AuthService {
|
||||
});
|
||||
await _saveTokens(tokens);
|
||||
|
||||
_logRawUserPayload('sso_exchange', data['user']);
|
||||
final user = User.fromJson(data['user']);
|
||||
await _saveUser(user);
|
||||
|
||||
@@ -451,6 +456,7 @@ class AuthService {
|
||||
final responseData = jsonDecode(response.body);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
_logRawUserPayload('enable_ai', responseData['user']);
|
||||
final user = User.fromJson(responseData['user']);
|
||||
await _saveUser(user);
|
||||
return {
|
||||
@@ -514,6 +520,23 @@ class AuthService {
|
||||
);
|
||||
}
|
||||
|
||||
void _logRawUserPayload(String source, dynamic userPayload) {
|
||||
if (userPayload == null) {
|
||||
LogService.instance.debug('AuthService', '$source user payload: <missing>');
|
||||
return;
|
||||
}
|
||||
|
||||
if (userPayload is Map<String, dynamic>) {
|
||||
try {
|
||||
LogService.instance.debug('AuthService', '$source user payload: ${jsonEncode(userPayload)}');
|
||||
} catch (_) {
|
||||
LogService.instance.debug('AuthService', '$source user payload: $userPayload');
|
||||
}
|
||||
} else {
|
||||
LogService.instance.debug('AuthService', '$source user payload type: ${userPayload.runtimeType}');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _saveApiKey(String apiKey) async {
|
||||
await _storage.write(key: _apiKeyKey, value: apiKey);
|
||||
await _storage.write(key: _authModeKey, value: 'api_key');
|
||||
|
||||
Reference in New Issue
Block a user