Merge branch 'main' into filter-analytics-events
This commit is contained in:
commit
b4d3d398fd
39 changed files with 1436 additions and 1532 deletions
|
|
@ -50,10 +50,7 @@ class _SpaceViewState extends State<SpaceView> {
|
|||
|
||||
final String _chatCountsKey = 'chatCounts';
|
||||
Map<String, int> get chatCounts => Map.from(
|
||||
widget.controller.pangeaController.pStoreService.read(
|
||||
_chatCountsKey,
|
||||
local: true,
|
||||
) ??
|
||||
widget.controller.pangeaController.pStoreService.read(_chatCountsKey) ??
|
||||
{},
|
||||
);
|
||||
// Pangea#
|
||||
|
|
@ -550,7 +547,6 @@ class _SpaceViewState extends State<SpaceView> {
|
|||
await widget.controller.pangeaController.pStoreService.save(
|
||||
_chatCountsKey,
|
||||
updatedChatCounts,
|
||||
local: true,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,14 @@
|
|||
import 'dart:developer';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
import 'package:fluffychat/pangea/choreographer/controllers/choreographer.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/controllers/error_service.dart';
|
||||
import 'package:fluffychat/pangea/repo/full_text_translation_repo.dart';
|
||||
import 'package:fluffychat/pangea/utils/error_handler.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
import '../../repo/similarity_repo.dart';
|
||||
|
||||
class AlternativeTranslator {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import 'package:fluffychat/pangea/models/it_step.dart';
|
|||
import 'package:fluffychat/pangea/models/representation_content_model.dart';
|
||||
import 'package:fluffychat/pangea/models/space_model.dart';
|
||||
import 'package:fluffychat/pangea/models/tokens_event_content_model.dart';
|
||||
import 'package:fluffychat/pangea/models/user_model.dart';
|
||||
import 'package:fluffychat/pangea/utils/any_state_holder.dart';
|
||||
import 'package:fluffychat/pangea/utils/error_handler.dart';
|
||||
import 'package:fluffychat/pangea/utils/overlay.dart';
|
||||
|
|
@ -514,11 +513,9 @@ class Choreographer {
|
|||
chatController.room,
|
||||
);
|
||||
|
||||
bool get itAutoPlayEnabled =>
|
||||
pangeaController.pStoreService.read(
|
||||
MatrixProfile.itAutoPlay.title,
|
||||
) ??
|
||||
false;
|
||||
bool get itAutoPlayEnabled {
|
||||
return pangeaController.userController.profile.userSettings.itAutoPlay;
|
||||
}
|
||||
|
||||
bool get definitionsEnabled =>
|
||||
pangeaController.permissionsController.isToolEnabled(
|
||||
|
|
|
|||
|
|
@ -197,7 +197,7 @@ class TranslateButton extends StatelessWidget {
|
|||
return TextButton(
|
||||
onPressed: loading ? null : onPress,
|
||||
style: ButtonStyle(
|
||||
backgroundColor: MaterialStateProperty.all<Color>(
|
||||
backgroundColor: WidgetStateProperty.all<Color>(
|
||||
AppConfig.primaryColor.withOpacity(0.1),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,16 +1,8 @@
|
|||
class PLocalKey {
|
||||
static const String user = 'user';
|
||||
|
||||
static const String classes = 'classes';
|
||||
|
||||
static const String access = "access";
|
||||
static const String cachedClassCodeToJoin = "cachedclasscodetojoin";
|
||||
static const String beganWebPayment = "beganWebPayment";
|
||||
|
||||
// making this a random string so that it's harder to guess
|
||||
static const String activatedTrialKey = '7C4EuKIsph';
|
||||
static const String dismissedPaywall = 'dismissedPaywall';
|
||||
static const String paywallBackoff = 'paywallBackoff';
|
||||
static const String autoPlayMessages = 'autoPlayMessages';
|
||||
static const String itAutoPlay = 'itAutoPlay';
|
||||
static const String messagesSinceUpdate = 'messagesSinceLastUpdate';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,15 @@ class ModelKey {
|
|||
static const String l1LanguageKey = 'source_language';
|
||||
static const String publicProfile = 'public';
|
||||
static const String userId = 'user_id';
|
||||
static const String toolSettings = 'tool_settings';
|
||||
static const String userSettings = 'user_settings';
|
||||
static const String instructionsSettings = 'instructions_settings';
|
||||
|
||||
// matrix profile keys
|
||||
// making this a random string so that it's harder to guess
|
||||
static const String activatedTrialKey = '7C4EuKIsph';
|
||||
static const String autoPlayMessages = 'autoPlayMessages';
|
||||
static const String itAutoPlay = 'itAutoPlay';
|
||||
|
||||
static const String clientClassCity = "city";
|
||||
static const String clientClassCountry = "country";
|
||||
|
|
|
|||
|
|
@ -48,15 +48,13 @@ class ClassController extends BaseController {
|
|||
Future<void> checkForClassCodeAndSubscription(BuildContext context) async {
|
||||
final String? classCode = _pangeaController.pStoreService.read(
|
||||
PLocalKey.cachedClassCodeToJoin,
|
||||
addClientIdToKey: false,
|
||||
local: true,
|
||||
isAccountData: false,
|
||||
);
|
||||
|
||||
if (classCode != null) {
|
||||
await _pangeaController.pStoreService.delete(
|
||||
PLocalKey.cachedClassCodeToJoin,
|
||||
addClientIdToKey: false,
|
||||
local: true,
|
||||
isAccountData: false,
|
||||
);
|
||||
await joinClasswithCode(
|
||||
context,
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:http/http.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/config/environment.dart';
|
||||
import 'package:fluffychat/pangea/utils/error_handler.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:http/http.dart';
|
||||
|
||||
import '../constants/model_keys.dart';
|
||||
import '../network/requests.dart';
|
||||
import '../network/urls.dart';
|
||||
|
|
|
|||
|
|
@ -1,12 +1,8 @@
|
|||
import 'dart:developer';
|
||||
|
||||
import 'package:fluffychat/pangea/constants/language_constants.dart';
|
||||
import 'package:fluffychat/pangea/controllers/language_list_controller.dart';
|
||||
import 'package:fluffychat/pangea/controllers/pangea_controller.dart';
|
||||
import 'package:fluffychat/pangea/models/language_model.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||
|
||||
import '../widgets/user_settings/p_language_dialog.dart';
|
||||
|
||||
|
|
@ -18,15 +14,6 @@ class LanguageController {
|
|||
}
|
||||
//show diloag when user does not have languages selected
|
||||
showDialogOnEmptyLanguage(BuildContext dialogContext, Function callback) {
|
||||
if (_pangeaController.userController.userModel?.profile == null) {
|
||||
debugger(when: kDebugMode);
|
||||
Sentry.addBreadcrumb(
|
||||
Breadcrumb(
|
||||
message: 'calling showDialogOnEmptyLanguagae with empty user',
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (!languagesSet) {
|
||||
pLanguageDialog(dialogContext, callback);
|
||||
}
|
||||
|
|
@ -42,13 +29,13 @@ class LanguageController {
|
|||
|
||||
String? get _userL1Code {
|
||||
final source =
|
||||
_pangeaController.userController.userModel?.profile?.sourceLanguage;
|
||||
_pangeaController.userController.profile.userSettings.sourceLanguage;
|
||||
return source == null || source.isEmpty ? null : source;
|
||||
}
|
||||
|
||||
String? get _userL2Code {
|
||||
final target =
|
||||
_pangeaController.userController.userModel?.profile?.targetLanguage;
|
||||
_pangeaController.userController.profile.userSettings.targetLanguage;
|
||||
return target == null || target.isEmpty ? null : target;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,34 +0,0 @@
|
|||
import 'package:fluffychat/pangea/controllers/pangea_controller.dart';
|
||||
import 'package:fluffychat/pangea/models/space_model.dart';
|
||||
|
||||
class LocalSettings {
|
||||
late PangeaController _pangeaController;
|
||||
|
||||
LocalSettings(PangeaController pangeaController) : super() {
|
||||
_pangeaController = pangeaController;
|
||||
}
|
||||
|
||||
bool userLanguageToolSetting(ToolSetting setting) {
|
||||
final profileSetting =
|
||||
_pangeaController.pStoreService.read(setting.toString());
|
||||
if (profileSetting != null) {
|
||||
return profileSetting;
|
||||
}
|
||||
return setting == ToolSetting.immersionMode ? false : true;
|
||||
}
|
||||
|
||||
// bool get userEnableIT =>
|
||||
// _pangeaController.pStoreService.read(ToolSetting.interactiveTranslator.toString()) ?? true;
|
||||
|
||||
// bool get userEnableIGC =>
|
||||
// _pangeaController.pStoreService.read(ToolSetting.interactiveGrammar.toString()) ?? true;
|
||||
|
||||
// bool get userImmersionMode =>
|
||||
// _pangeaController.pStoreService.read(ToolSetting.immersionMode.toString()) ?? true;
|
||||
|
||||
// bool get userTranslationsTool =>
|
||||
// _pangeaController.pStoreService.read(ToolSetting.translations.toString()) ?? true;
|
||||
|
||||
// bool get userDefinitionsTool =>
|
||||
// _pangeaController.pStoreService.read(ToolSetting.definitions.toString()) ?? true;
|
||||
}
|
||||
|
|
@ -42,7 +42,6 @@ class AnalyticsController extends BaseController {
|
|||
try {
|
||||
final String? str = _pangeaController.pStoreService.read(
|
||||
_analyticsTimeSpanKey,
|
||||
local: true,
|
||||
);
|
||||
return str != null
|
||||
? TimeSpan.values.firstWhere((e) {
|
||||
|
|
@ -60,7 +59,6 @@ class AnalyticsController extends BaseController {
|
|||
await _pangeaController.pStoreService.save(
|
||||
_analyticsTimeSpanKey,
|
||||
timeSpan.toString(),
|
||||
local: true,
|
||||
);
|
||||
setState();
|
||||
}
|
||||
|
|
@ -72,7 +70,6 @@ class AnalyticsController extends BaseController {
|
|||
try {
|
||||
final String? str = _pangeaController.pStoreService.read(
|
||||
_analyticsSpaceLangKey,
|
||||
local: true,
|
||||
);
|
||||
return str != null
|
||||
? PangeaLanguage.byLangCode(str)
|
||||
|
|
@ -88,7 +85,6 @@ class AnalyticsController extends BaseController {
|
|||
await _pangeaController.pStoreService.save(
|
||||
_analyticsSpaceLangKey,
|
||||
lang.langCode,
|
||||
local: true,
|
||||
);
|
||||
setState();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,7 +121,6 @@ class MyAnalyticsController {
|
|||
_pangeaController.pStoreService.save(
|
||||
PLocalKey.messagesSinceUpdate,
|
||||
currentCache,
|
||||
local: true,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -155,7 +154,6 @@ class MyAnalyticsController {
|
|||
_pangeaController.pStoreService.save(
|
||||
PLocalKey.messagesSinceUpdate,
|
||||
[],
|
||||
local: true,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -167,14 +165,12 @@ class MyAnalyticsController {
|
|||
Logs().d('Reading messages since update from local storage');
|
||||
final dynamic locallySaved = _pangeaController.pStoreService.read(
|
||||
PLocalKey.messagesSinceUpdate,
|
||||
local: true,
|
||||
);
|
||||
if (locallySaved == null) {
|
||||
Logs().d('No locally saved messages found, initializing empty list.');
|
||||
_pangeaController.pStoreService.save(
|
||||
PLocalKey.messagesSinceUpdate,
|
||||
[],
|
||||
local: true,
|
||||
);
|
||||
return [];
|
||||
}
|
||||
|
|
@ -201,7 +197,6 @@ class MyAnalyticsController {
|
|||
_pangeaController.pStoreService.save(
|
||||
PLocalKey.messagesSinceUpdate,
|
||||
[],
|
||||
local: true,
|
||||
);
|
||||
return [];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import 'package:fluffychat/pangea/controllers/contextual_definition_controller.d
|
|||
import 'package:fluffychat/pangea/controllers/language_controller.dart';
|
||||
import 'package:fluffychat/pangea/controllers/language_detection_controller.dart';
|
||||
import 'package:fluffychat/pangea/controllers/language_list_controller.dart';
|
||||
import 'package:fluffychat/pangea/controllers/local_settings.dart';
|
||||
import 'package:fluffychat/pangea/controllers/message_data_controller.dart';
|
||||
import 'package:fluffychat/pangea/controllers/my_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/controllers/permissions_controller.dart';
|
||||
|
|
@ -47,7 +46,6 @@ class PangeaController {
|
|||
late AnalyticsController analytics;
|
||||
late MyAnalyticsController myAnalytics;
|
||||
late WordController wordNet;
|
||||
late LocalSettings localSettings;
|
||||
late MessageDataController messageData;
|
||||
late ContextualDefinitionController definitions;
|
||||
late ITFeedbackController itFeedback;
|
||||
|
|
@ -60,7 +58,7 @@ class PangeaController {
|
|||
late PracticeGenerationController practiceGenerationController;
|
||||
|
||||
///store Services
|
||||
late PLocalStore pStoreService;
|
||||
late PStore pStoreService;
|
||||
final pLanguageStore = PangeaLanguage();
|
||||
|
||||
///Matrix Variables
|
||||
|
|
@ -89,10 +87,9 @@ class PangeaController {
|
|||
|
||||
/// Initialize controllers
|
||||
_addRefInObjects() {
|
||||
pStoreService = PLocalStore(pangeaController: this);
|
||||
pStoreService = PStore(pangeaController: this);
|
||||
userController = UserController(this);
|
||||
languageController = LanguageController(this);
|
||||
localSettings = LocalSettings(this);
|
||||
classController = ClassController(this);
|
||||
permissionsController = PermissionsController(this);
|
||||
analytics = AnalyticsController(this);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import 'package:fluffychat/pangea/controllers/base_controller.dart';
|
|||
import 'package:fluffychat/pangea/controllers/pangea_controller.dart';
|
||||
import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_extension.dart';
|
||||
import 'package:fluffychat/pangea/models/space_model.dart';
|
||||
import 'package:fluffychat/pangea/models/user_model.dart';
|
||||
import 'package:fluffychat/pangea/utils/p_extension.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
|
|
@ -32,12 +31,9 @@ class PermissionsController extends BaseController {
|
|||
|
||||
/// Returns false if user is null
|
||||
bool isUser18() {
|
||||
final dob = _pangeaController.pStoreService.read(
|
||||
MatrixProfile.dateOfBirth.title,
|
||||
);
|
||||
return dob != null
|
||||
? DateTime.parse(dob).isAtLeastYearsOld(AgeLimits.toAccessFeatures)
|
||||
: false;
|
||||
final DateTime? dob =
|
||||
_pangeaController.userController.profile.userSettings.dateOfBirth;
|
||||
return dob?.isAtLeastYearsOld(AgeLimits.toAccessFeatures) ?? false;
|
||||
}
|
||||
|
||||
/// A user can private chat if
|
||||
|
|
@ -99,8 +95,26 @@ class PermissionsController extends BaseController {
|
|||
return classPermission == 0;
|
||||
}
|
||||
|
||||
bool userToolSetting(ToolSetting setting) =>
|
||||
_pangeaController.localSettings.userLanguageToolSetting(setting);
|
||||
bool userToolSetting(ToolSetting setting) {
|
||||
switch (setting) {
|
||||
case ToolSetting.interactiveTranslator:
|
||||
return _pangeaController
|
||||
.userController.profile.toolSettings.interactiveTranslator;
|
||||
case ToolSetting.interactiveGrammar:
|
||||
return _pangeaController
|
||||
.userController.profile.toolSettings.interactiveGrammar;
|
||||
case ToolSetting.immersionMode:
|
||||
return _pangeaController
|
||||
.userController.profile.toolSettings.immersionMode;
|
||||
case ToolSetting.definitions:
|
||||
return _pangeaController
|
||||
.userController.profile.toolSettings.definitions;
|
||||
case ToolSetting.autoIGC:
|
||||
return _pangeaController.userController.profile.toolSettings.autoIGC;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool isToolEnabled(ToolSetting setting, Room? room) {
|
||||
if (room?.isSpaceAdmin ?? false) {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import 'package:fluffychat/pangea/controllers/base_controller.dart';
|
|||
import 'package:fluffychat/pangea/controllers/pangea_controller.dart';
|
||||
import 'package:fluffychat/pangea/models/base_subscription_info.dart';
|
||||
import 'package:fluffychat/pangea/models/mobile_subscriptions.dart';
|
||||
import 'package:fluffychat/pangea/models/user_model.dart';
|
||||
import 'package:fluffychat/pangea/models/web_subscriptions.dart';
|
||||
import 'package:fluffychat/pangea/network/requests.dart';
|
||||
import 'package:fluffychat/pangea/network/urls.dart';
|
||||
|
|
@ -97,12 +96,10 @@ class SubscriptionController extends BaseController {
|
|||
} else {
|
||||
final bool? beganWebPayment = _pangeaController.pStoreService.read(
|
||||
PLocalKey.beganWebPayment,
|
||||
local: true,
|
||||
);
|
||||
if (beganWebPayment ?? false) {
|
||||
await _pangeaController.pStoreService.delete(
|
||||
PLocalKey.beganWebPayment,
|
||||
local: true,
|
||||
);
|
||||
if (_pangeaController.subscriptionController.isSubscribed) {
|
||||
subscriptionStream.add(true);
|
||||
|
|
@ -142,7 +139,6 @@ class SubscriptionController extends BaseController {
|
|||
await _pangeaController.pStoreService.save(
|
||||
PLocalKey.beganWebPayment,
|
||||
true,
|
||||
local: true,
|
||||
);
|
||||
setState();
|
||||
launchUrlString(
|
||||
|
|
@ -182,37 +178,35 @@ class SubscriptionController extends BaseController {
|
|||
}
|
||||
}
|
||||
|
||||
bool get _activatedNewUserTrial =>
|
||||
_pangeaController.userController.inTrialWindow &&
|
||||
(_pangeaController.pStoreService.read(
|
||||
MatrixProfile.activatedFreeTrial.title,
|
||||
) ??
|
||||
false);
|
||||
bool get _activatedNewUserTrial {
|
||||
final bool activated = _pangeaController
|
||||
.userController.profile.userSettings.activatedFreeTrial;
|
||||
return _pangeaController.userController.inTrialWindow && activated;
|
||||
}
|
||||
|
||||
void activateNewUserTrial() {
|
||||
_pangeaController.pStoreService
|
||||
.save(
|
||||
MatrixProfile.activatedFreeTrial.title,
|
||||
true,
|
||||
)
|
||||
.then((_) {
|
||||
setNewUserTrial();
|
||||
trialActivationStream.add(true);
|
||||
});
|
||||
_pangeaController.userController.updateProfile(
|
||||
(profile) {
|
||||
profile.userSettings.activatedFreeTrial = true;
|
||||
return profile;
|
||||
},
|
||||
);
|
||||
setNewUserTrial();
|
||||
trialActivationStream.add(true);
|
||||
}
|
||||
|
||||
void setNewUserTrial() {
|
||||
if (_pangeaController.userController.userModel?.profile == null) {
|
||||
final DateTime? createdAt =
|
||||
_pangeaController.userController.profile.userSettings.createdAt;
|
||||
if (createdAt == null) {
|
||||
ErrorHandler.logError(
|
||||
m: "Null user profile in subscription settings",
|
||||
m: "Null user profile createAt in subscription settings",
|
||||
s: StackTrace.current,
|
||||
);
|
||||
return;
|
||||
}
|
||||
final String profileCreatedAt =
|
||||
_pangeaController.userController.userModel!.profile!.createdAt;
|
||||
final DateTime creationTimestamp = DateTime.parse(profileCreatedAt);
|
||||
final DateTime expirationDate = creationTimestamp.add(
|
||||
|
||||
final DateTime expirationDate = createdAt.add(
|
||||
const Duration(days: 7),
|
||||
);
|
||||
subscription?.setTrial(expirationDate);
|
||||
|
|
@ -242,7 +236,6 @@ class SubscriptionController extends BaseController {
|
|||
DateTime? get _lastDismissedPaywall {
|
||||
final lastDismissed = _pangeaController.pStoreService.read(
|
||||
PLocalKey.dismissedPaywall,
|
||||
local: true,
|
||||
);
|
||||
if (lastDismissed == null) return null;
|
||||
return DateTime.tryParse(lastDismissed);
|
||||
|
|
@ -251,7 +244,6 @@ class SubscriptionController extends BaseController {
|
|||
int? get _paywallBackoff {
|
||||
final backoff = _pangeaController.pStoreService.read(
|
||||
PLocalKey.paywallBackoff,
|
||||
local: true,
|
||||
);
|
||||
if (backoff == null) return null;
|
||||
return backoff;
|
||||
|
|
@ -269,20 +261,17 @@ class SubscriptionController extends BaseController {
|
|||
await _pangeaController.pStoreService.save(
|
||||
PLocalKey.dismissedPaywall,
|
||||
DateTime.now().toString(),
|
||||
local: true,
|
||||
);
|
||||
|
||||
if (_paywallBackoff == null) {
|
||||
await _pangeaController.pStoreService.save(
|
||||
PLocalKey.paywallBackoff,
|
||||
1,
|
||||
local: true,
|
||||
);
|
||||
} else {
|
||||
await _pangeaController.pStoreService.save(
|
||||
PLocalKey.paywallBackoff,
|
||||
_paywallBackoff! + 1,
|
||||
local: true,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@ import 'dart:async';
|
|||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:fluffychat/pangea/constants/language_constants.dart';
|
||||
import 'package:fluffychat/pangea/constants/model_keys.dart';
|
||||
import 'package:fluffychat/pangea/controllers/base_controller.dart';
|
||||
import 'package:fluffychat/pangea/controllers/pangea_controller.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:fluffychat/pangea/extensions/client_extension/client_extension.dart';
|
||||
import 'package:fluffychat/pangea/utils/error_handler.dart';
|
||||
import 'package:jwt_decode/jwt_decode.dart';
|
||||
import 'package:matrix/matrix.dart' as matrix;
|
||||
|
||||
|
|
@ -13,447 +13,247 @@ import '../constants/local.key.dart';
|
|||
import '../models/user_model.dart';
|
||||
import '../repo/user_repo.dart';
|
||||
|
||||
/// Controller that manages saving and reading of user/profile information
|
||||
class UserController extends BaseController {
|
||||
late PangeaController _pangeaController;
|
||||
final Completer _completer = Completer();
|
||||
UserController(PangeaController pangeaController) : super() {
|
||||
_pangeaController = pangeaController;
|
||||
}
|
||||
|
||||
Future<void> createPangeaUser({required String dob}) async {
|
||||
final PUserModel newUserModel = await PUserRepo.repoCreatePangeaUser(
|
||||
userID: userId!,
|
||||
fullName: fullname,
|
||||
dob: dob,
|
||||
matrixAccessToken: _matrixAccessToken!,
|
||||
);
|
||||
newUserModel.save(_pangeaController);
|
||||
await updateMatrixProfile(dateOfBirth: dob);
|
||||
/// Convenience function that returns the user ID currently stored in the client.
|
||||
String? get userId => _pangeaController.matrixState.client.userID;
|
||||
|
||||
/// Convenience function that returns the accessToken currently stored in the client.
|
||||
String? get _matrixAccessToken =>
|
||||
_pangeaController.matrixState.client.accessToken;
|
||||
|
||||
/// Cached version of the user profile, so it doesn't have
|
||||
/// to be read in from client's account data each time it is accessed.
|
||||
Profile? _cachedProfile;
|
||||
|
||||
/// Listens for account updates and updates the cached profile
|
||||
StreamSubscription? _profileListener;
|
||||
|
||||
/// Listen for updates to account data in syncs and update the cached profile
|
||||
void addProfileListener() {
|
||||
_profileListener ??= _pangeaController.matrixState.client.onSync.stream
|
||||
.where((sync) => sync.accountData != null)
|
||||
.listen((sync) {
|
||||
final Profile? fromAccountData = Profile.fromAccountData();
|
||||
if (fromAccountData != null) {
|
||||
_cachedProfile = fromAccountData;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<PUserModel?> fetchUserModel() async {
|
||||
try {
|
||||
if (_matrixAccessToken == null) {
|
||||
throw Exception(
|
||||
"calling fetchUserModel with matrixAccesstoken == null",
|
||||
);
|
||||
}
|
||||
/// The user's profile. Will be empty if the client's accountData hasn't
|
||||
/// been loaded yet (if the first sync hasn't gone through yet)
|
||||
/// or if the user hasn't yer set their date of birth.
|
||||
Profile get profile {
|
||||
/// if the profile is cached, return it
|
||||
if (_cachedProfile != null) return _cachedProfile!;
|
||||
|
||||
final PUserModel? newUserModel = await PUserRepo.fetchPangeaUserInfo(
|
||||
/// if account data is empty, return an empty profile
|
||||
if (_pangeaController.matrixState.client.accountData.isEmpty) {
|
||||
return Profile.emptyProfile;
|
||||
}
|
||||
|
||||
/// try to get the account data in the up-to-date format
|
||||
final Profile? fromAccountData = Profile.fromAccountData();
|
||||
if (fromAccountData != null) {
|
||||
_cachedProfile = fromAccountData;
|
||||
return fromAccountData;
|
||||
}
|
||||
|
||||
_cachedProfile = Profile.migrateFromAccountData();
|
||||
_cachedProfile?.saveProfileData();
|
||||
return _cachedProfile ?? Profile.emptyProfile;
|
||||
}
|
||||
|
||||
/// Updates the user's profile with the given [update] function and saves it.
|
||||
void updateProfile(Profile Function(Profile) update) {
|
||||
final Profile updatedProfile = update(profile);
|
||||
updatedProfile.saveProfileData();
|
||||
}
|
||||
|
||||
/// Creates a new profile for the user with the given date of birth.
|
||||
Future<void> createProfile({required DateTime dob}) async {
|
||||
final userSettings = UserSettings(
|
||||
dateOfBirth: dob,
|
||||
createdAt: DateTime.now(),
|
||||
);
|
||||
final newProfile = Profile(userSettings: userSettings);
|
||||
await newProfile.saveProfileData(waitForDataInSync: true);
|
||||
}
|
||||
|
||||
/// A completer for the profile model of a user.
|
||||
Completer<void>? _profileCompleter;
|
||||
|
||||
/// Initializes the user's profile. Runs a function to wait for account data to load,
|
||||
/// read account data into profile, and migrate any missing info from the pangea profile.
|
||||
/// Finally, it adds a listen to update the profile data when new account data comes in.
|
||||
Future<void> initialize() async {
|
||||
if (_profileCompleter?.isCompleted ?? false) {
|
||||
return _profileCompleter!.future;
|
||||
}
|
||||
|
||||
if (_profileCompleter != null) {
|
||||
await _profileCompleter!.future;
|
||||
return _profileCompleter!.future;
|
||||
}
|
||||
|
||||
_profileCompleter = Completer<void>();
|
||||
|
||||
try {
|
||||
await _initialize();
|
||||
addProfileListener();
|
||||
} catch (err, s) {
|
||||
ErrorHandler.logError(e: err, s: s);
|
||||
} finally {
|
||||
_profileCompleter!.complete();
|
||||
}
|
||||
|
||||
return _profileCompleter!.future;
|
||||
}
|
||||
|
||||
/// Initializes the user's profile by waiting for account data to load, reading in account
|
||||
/// data to profile, and migrating from the pangea profile if the account data is not present.
|
||||
Future<void> _initialize() async {
|
||||
await _pangeaController.matrixState.client.waitForAccountData();
|
||||
if (profile.userSettings.dateOfBirth != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final PangeaProfileResponse? resp = await PUserRepo.fetchPangeaUserInfo(
|
||||
userID: userId!,
|
||||
matrixAccessToken: _matrixAccessToken!,
|
||||
);
|
||||
if (resp?.profile == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final userSetting = UserSettings.fromJson(resp!.profile.toJson());
|
||||
final newProfile = Profile(userSettings: userSetting);
|
||||
await newProfile.saveProfileData(waitForDataInSync: true);
|
||||
}
|
||||
|
||||
/// Reinitializes the user's profile
|
||||
/// This method should be called whenever the user's login status changes
|
||||
Future<void> reinitialize() async {
|
||||
_profileCompleter = null;
|
||||
_cachedProfile = null;
|
||||
await initialize();
|
||||
}
|
||||
|
||||
/// Returns a boolean value indicating whether a new JWT (JSON Web Token) is needed.
|
||||
bool needNewJWT(String token) => Jwt.isExpired(token);
|
||||
|
||||
/// Retrieves the access token for the user. Looks for it locally,
|
||||
/// and if it's not found or expired, fetches it from the server.
|
||||
Future<String> get accessToken async {
|
||||
final localAccessToken =
|
||||
_pangeaController.pStoreService.read(PLocalKey.access);
|
||||
|
||||
if (localAccessToken == null || needNewJWT(localAccessToken)) {
|
||||
final PangeaProfileResponse? userModel =
|
||||
await PUserRepo.fetchPangeaUserInfo(
|
||||
userID: userId!,
|
||||
matrixAccessToken: _matrixAccessToken!,
|
||||
);
|
||||
newUserModel?.save(_pangeaController);
|
||||
await migrateMatrixProfile();
|
||||
_completeCompleter();
|
||||
|
||||
return newUserModel;
|
||||
} catch (err) {
|
||||
debugPrint(
|
||||
"User model not found. Probably first signup and needs Pangea account",
|
||||
if (userModel?.access == null) {
|
||||
throw ("Trying to get accessToken with null userModel");
|
||||
}
|
||||
_pangeaController.pStoreService.save(
|
||||
PLocalKey.access,
|
||||
userModel!.access,
|
||||
);
|
||||
rethrow;
|
||||
return userModel.access;
|
||||
}
|
||||
|
||||
return localAccessToken;
|
||||
}
|
||||
|
||||
dynamic migratedProfileInfo(MatrixProfile key) {
|
||||
final dynamic localValue = _pangeaController.pStoreService.read(
|
||||
key.title,
|
||||
local: true,
|
||||
);
|
||||
final dynamic matrixValue = _pangeaController.pStoreService.read(
|
||||
key.title,
|
||||
);
|
||||
return localValue != null && matrixValue != localValue ? localValue : null;
|
||||
}
|
||||
|
||||
Future<void> migrateMatrixProfile() async {
|
||||
final Profile? pangeaProfile = userModel?.profile;
|
||||
|
||||
final String? pangeaDob = pangeaProfile?.dateOfBirth;
|
||||
final String? matrixDob = _pangeaController.pStoreService.read(
|
||||
ModelKey.userDateOfBirth,
|
||||
);
|
||||
final String? dob =
|
||||
pangeaDob != null && matrixDob != pangeaDob ? pangeaDob : null;
|
||||
|
||||
final pangeaCreatedAt = pangeaProfile?.createdAt;
|
||||
final matrixCreatedAt = _pangeaController.pStoreService.read(
|
||||
MatrixProfile.createdAt.title,
|
||||
);
|
||||
final String? createdAt =
|
||||
pangeaCreatedAt != null && matrixCreatedAt != pangeaCreatedAt
|
||||
? pangeaCreatedAt
|
||||
: null;
|
||||
|
||||
final String? pangeaTargetLanguage = pangeaProfile?.targetLanguage;
|
||||
final String? matrixTargetLanguage = _pangeaController.pStoreService.read(
|
||||
MatrixProfile.targetLanguage.title,
|
||||
);
|
||||
final String? targetLanguage = pangeaTargetLanguage != null &&
|
||||
matrixTargetLanguage != pangeaTargetLanguage
|
||||
? pangeaTargetLanguage
|
||||
: null;
|
||||
|
||||
final String? pangeaSourceLanguage = pangeaProfile?.sourceLanguage;
|
||||
final String? matrixSourceLanguage = _pangeaController.pStoreService.read(
|
||||
MatrixProfile.sourceLanguage.title,
|
||||
);
|
||||
final String? sourceLanguage = pangeaSourceLanguage != null &&
|
||||
matrixSourceLanguage != pangeaSourceLanguage
|
||||
? pangeaSourceLanguage
|
||||
: null;
|
||||
|
||||
final String? pangeaCountry = pangeaProfile?.country;
|
||||
final String? matrixCountry = _pangeaController.pStoreService.read(
|
||||
MatrixProfile.country.title,
|
||||
);
|
||||
final String? country =
|
||||
pangeaCountry != null && matrixCountry != pangeaCountry
|
||||
? pangeaCountry
|
||||
: null;
|
||||
|
||||
final bool? pangeaPublicProfile = pangeaProfile?.publicProfile;
|
||||
final bool? matrixPublicProfile = _pangeaController.pStoreService.read(
|
||||
MatrixProfile.publicProfile.title,
|
||||
);
|
||||
final bool? publicProfile = pangeaPublicProfile != null &&
|
||||
matrixPublicProfile != pangeaPublicProfile
|
||||
? pangeaPublicProfile
|
||||
: null;
|
||||
|
||||
final bool? autoPlay = migratedProfileInfo(MatrixProfile.autoPlayMessages);
|
||||
final bool? itAutoPlay = migratedProfileInfo(MatrixProfile.itAutoPlay);
|
||||
final bool? trial = migratedProfileInfo(MatrixProfile.activatedFreeTrial);
|
||||
final bool? interactiveTranslator =
|
||||
migratedProfileInfo(MatrixProfile.interactiveTranslator);
|
||||
final bool? interactiveGrammar =
|
||||
migratedProfileInfo(MatrixProfile.interactiveGrammar);
|
||||
final bool? immersionMode =
|
||||
migratedProfileInfo(MatrixProfile.immersionMode);
|
||||
final bool? definitions = migratedProfileInfo(MatrixProfile.definitions);
|
||||
// final bool? translations = migratedProfileInfo(MatrixProfile.translations);
|
||||
final bool? showItInstructions =
|
||||
migratedProfileInfo(MatrixProfile.showedItInstructions);
|
||||
final bool? showClickMessage =
|
||||
migratedProfileInfo(MatrixProfile.showedClickMessage);
|
||||
final bool? showBlurMeansTranslate =
|
||||
migratedProfileInfo(MatrixProfile.showedBlurMeansTranslate);
|
||||
|
||||
await updateMatrixProfile(
|
||||
dateOfBirth: dob,
|
||||
autoPlayMessages: autoPlay,
|
||||
itAutoPlay: itAutoPlay,
|
||||
activatedFreeTrial: trial,
|
||||
interactiveTranslator: interactiveTranslator,
|
||||
interactiveGrammar: interactiveGrammar,
|
||||
immersionMode: immersionMode,
|
||||
definitions: definitions,
|
||||
// translations: translations,
|
||||
showedItInstructions: showItInstructions,
|
||||
showedClickMessage: showClickMessage,
|
||||
showedBlurMeansTranslate: showBlurMeansTranslate,
|
||||
createdAt: createdAt,
|
||||
targetLanguage: targetLanguage,
|
||||
sourceLanguage: sourceLanguage,
|
||||
country: country,
|
||||
publicProfile: publicProfile,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> updateUserProfile({
|
||||
String? dateOfBirth,
|
||||
String? targetLanguage,
|
||||
String? sourceLanguage,
|
||||
String? country,
|
||||
List<String>? interests,
|
||||
List<String>? speaks,
|
||||
bool? publicProfile,
|
||||
}) async {
|
||||
if (userModel == null) throw Exception("Local userModel not defined");
|
||||
final profileJson = userModel!.profile!.toJson();
|
||||
|
||||
if (dateOfBirth != null) {
|
||||
profileJson[ModelKey.userDateOfBirth] = dateOfBirth;
|
||||
}
|
||||
if (targetLanguage != null) {
|
||||
profileJson[ModelKey.userTargetLanguage] = targetLanguage;
|
||||
}
|
||||
if (sourceLanguage != null) {
|
||||
profileJson[ModelKey.userSourceLanguage] = sourceLanguage;
|
||||
}
|
||||
if (interests != null) {
|
||||
profileJson[ModelKey.userInterests] = interests.toString();
|
||||
}
|
||||
if (speaks != null) {
|
||||
profileJson[ModelKey.userSpeaks] = speaks.toString();
|
||||
}
|
||||
if (country != null) {
|
||||
profileJson[ModelKey.userCountry] = country;
|
||||
}
|
||||
if (publicProfile != null) {
|
||||
profileJson[ModelKey.publicProfile] = publicProfile;
|
||||
}
|
||||
final Profile updatedUserProfile = await PUserRepo.updateUserProfile(
|
||||
Profile.fromJson(profileJson),
|
||||
await accessToken,
|
||||
);
|
||||
|
||||
PUserModel(
|
||||
access: await accessToken,
|
||||
refresh: userModel!.refresh,
|
||||
profile: updatedUserProfile,
|
||||
).save(_pangeaController);
|
||||
|
||||
await updateMatrixProfile(
|
||||
dateOfBirth: dateOfBirth,
|
||||
targetLanguage: targetLanguage,
|
||||
sourceLanguage: sourceLanguage,
|
||||
country: country,
|
||||
publicProfile: publicProfile,
|
||||
);
|
||||
}
|
||||
|
||||
PUserModel? get userModel {
|
||||
final data = _pangeaController.pStoreService.read(
|
||||
PLocalKey.user,
|
||||
local: true,
|
||||
);
|
||||
return data != null ? PUserModel.fromJson(data) : null;
|
||||
}
|
||||
|
||||
Future<void> updateMatrixProfile({
|
||||
String? dateOfBirth,
|
||||
bool? autoPlayMessages,
|
||||
bool? itAutoPlay,
|
||||
bool? activatedFreeTrial,
|
||||
bool? interactiveTranslator,
|
||||
bool? interactiveGrammar,
|
||||
bool? immersionMode,
|
||||
bool? definitions,
|
||||
// bool? translations,
|
||||
bool? showedItInstructions,
|
||||
bool? showedClickMessage,
|
||||
bool? showedBlurMeansTranslate,
|
||||
bool? showedTooltipInstructions,
|
||||
String? createdAt,
|
||||
String? targetLanguage,
|
||||
String? sourceLanguage,
|
||||
String? country,
|
||||
bool? publicProfile,
|
||||
}) async {
|
||||
if (dateOfBirth != null) {
|
||||
await _pangeaController.pStoreService.save(
|
||||
MatrixProfile.dateOfBirth.title,
|
||||
dateOfBirth,
|
||||
);
|
||||
}
|
||||
if (autoPlayMessages != null) {
|
||||
await _pangeaController.pStoreService.save(
|
||||
MatrixProfile.autoPlayMessages.title,
|
||||
autoPlayMessages,
|
||||
);
|
||||
}
|
||||
if (itAutoPlay != null) {
|
||||
await _pangeaController.pStoreService.save(
|
||||
MatrixProfile.itAutoPlay.title,
|
||||
itAutoPlay,
|
||||
);
|
||||
}
|
||||
if (activatedFreeTrial != null) {
|
||||
await _pangeaController.pStoreService.save(
|
||||
MatrixProfile.activatedFreeTrial.title,
|
||||
activatedFreeTrial,
|
||||
);
|
||||
}
|
||||
if (interactiveTranslator != null) {
|
||||
await _pangeaController.pStoreService.save(
|
||||
MatrixProfile.interactiveTranslator.title,
|
||||
interactiveTranslator,
|
||||
);
|
||||
}
|
||||
if (interactiveGrammar != null) {
|
||||
await _pangeaController.pStoreService.save(
|
||||
MatrixProfile.interactiveGrammar.title,
|
||||
interactiveGrammar,
|
||||
);
|
||||
}
|
||||
if (immersionMode != null) {
|
||||
await _pangeaController.pStoreService.save(
|
||||
MatrixProfile.immersionMode.title,
|
||||
immersionMode,
|
||||
);
|
||||
}
|
||||
if (definitions != null) {
|
||||
await _pangeaController.pStoreService.save(
|
||||
MatrixProfile.definitions.title,
|
||||
definitions,
|
||||
);
|
||||
}
|
||||
// if (translations != null) {
|
||||
// await _pangeaController.pStoreService.save(
|
||||
// MatrixProfile.translations.title,
|
||||
// translations,
|
||||
// );
|
||||
// }
|
||||
if (showedItInstructions != null) {
|
||||
await _pangeaController.pStoreService.save(
|
||||
MatrixProfile.showedItInstructions.title,
|
||||
showedItInstructions,
|
||||
);
|
||||
}
|
||||
if (showedClickMessage != null) {
|
||||
await _pangeaController.pStoreService.save(
|
||||
MatrixProfile.showedClickMessage.title,
|
||||
showedClickMessage,
|
||||
);
|
||||
}
|
||||
if (showedBlurMeansTranslate != null) {
|
||||
await _pangeaController.pStoreService.save(
|
||||
MatrixProfile.showedBlurMeansTranslate.title,
|
||||
showedBlurMeansTranslate,
|
||||
);
|
||||
}
|
||||
if (showedTooltipInstructions != null) {
|
||||
await _pangeaController.pStoreService.save(
|
||||
MatrixProfile.showedTooltipInstructions.title,
|
||||
showedTooltipInstructions,
|
||||
);
|
||||
}
|
||||
if (createdAt != null) {
|
||||
await _pangeaController.pStoreService.save(
|
||||
MatrixProfile.createdAt.title,
|
||||
createdAt,
|
||||
);
|
||||
}
|
||||
if (targetLanguage != null) {
|
||||
await _pangeaController.pStoreService.save(
|
||||
MatrixProfile.targetLanguage.title,
|
||||
targetLanguage,
|
||||
);
|
||||
}
|
||||
if (sourceLanguage != null) {
|
||||
await _pangeaController.pStoreService.save(
|
||||
MatrixProfile.sourceLanguage.title,
|
||||
sourceLanguage,
|
||||
);
|
||||
}
|
||||
if (country != null) {
|
||||
await _pangeaController.pStoreService.save(
|
||||
MatrixProfile.country.title,
|
||||
country,
|
||||
);
|
||||
}
|
||||
if (publicProfile != null) {
|
||||
await _pangeaController.pStoreService.save(
|
||||
MatrixProfile.publicProfile.title,
|
||||
publicProfile,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void _completeCompleter() {
|
||||
if (!_completer.isCompleted) {
|
||||
_completer.complete(null);
|
||||
}
|
||||
}
|
||||
|
||||
Future<Completer> get completer async {
|
||||
if (await isPUserDataAvailable) {
|
||||
_completeCompleter();
|
||||
}
|
||||
return _completer;
|
||||
}
|
||||
|
||||
bool get needNewJWT =>
|
||||
userModel?.access != null ? Jwt.isExpired(userModel!.access) : true;
|
||||
|
||||
Future<String> get accessToken async {
|
||||
await (await completer).future;
|
||||
// if userModel null or access token expired then fetchUserModel
|
||||
final PUserModel? useThisOne =
|
||||
needNewJWT ? await fetchUserModel() : userModel;
|
||||
|
||||
if (useThisOne == null) {
|
||||
//debugger(when: kDebugMode);
|
||||
throw Exception("trying to get accessToken with userModel = null");
|
||||
}
|
||||
return useThisOne.access;
|
||||
}
|
||||
|
||||
String? get userId {
|
||||
return _pangeaController.matrixState.client.userID;
|
||||
}
|
||||
|
||||
String get fullname {
|
||||
final String? userID = userId;
|
||||
if (userID == null) {
|
||||
throw Exception('User ID not found');
|
||||
}
|
||||
return userID.substring(0, userID.indexOf(":")).replaceAll("@", "");
|
||||
}
|
||||
|
||||
Future<bool> get isPUserDataAvailable async {
|
||||
try {
|
||||
final PUserModel? toCheck = userModel ?? (await fetchUserModel());
|
||||
return toCheck != null ? true : false;
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
/// Returns the full name of the user.
|
||||
/// If the [userId] is null, an error will be logged and null will be returned.
|
||||
/// The full name is obtained by extracting the substring before the first occurrence of ":" in the [userId]
|
||||
/// and then replacing all occurrences of "@" with an empty string.
|
||||
String? get fullname {
|
||||
if (userId == null) {
|
||||
ErrorHandler.logError(
|
||||
e: "calling fullname with userId == null",
|
||||
);
|
||||
return null;
|
||||
}
|
||||
return userId!.substring(0, userId!.indexOf(":")).replaceAll("@", "");
|
||||
}
|
||||
|
||||
/// Checks if user data is available and the date of birth is set.
|
||||
/// Returns a [Future] that completes with a [bool] value indicating
|
||||
/// whether the user data is available and the date of birth is set.
|
||||
Future<bool> get isUserDataAvailableAndDateOfBirthSet async {
|
||||
try {
|
||||
final client = _pangeaController.matrixState.client;
|
||||
if (client.prevBatch == null) {
|
||||
await client.onSync.stream.first;
|
||||
}
|
||||
await fetchUserModel();
|
||||
final localAccountData = _pangeaController.pStoreService.read(
|
||||
ModelKey.userDateOfBirth,
|
||||
);
|
||||
return localAccountData != null;
|
||||
} catch (err) {
|
||||
// the function fetchUserModel() uses a completer, so it shouldn't
|
||||
// re-call the endpoint if it has already been called
|
||||
await initialize();
|
||||
return profile.userSettings.dateOfBirth != null;
|
||||
} catch (err, s) {
|
||||
ErrorHandler.logError(e: err, s: s);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a boolean value indicating whether the user is currently in the trial window.
|
||||
bool get inTrialWindow {
|
||||
final String? createdAt = userModel?.profile?.createdAt;
|
||||
final DateTime? createdAt = profile.userSettings.createdAt;
|
||||
if (createdAt == null) {
|
||||
return false;
|
||||
}
|
||||
return DateTime.parse(createdAt).isAfter(
|
||||
return createdAt.isAfter(
|
||||
DateTime.now().subtract(const Duration(days: 7)),
|
||||
);
|
||||
}
|
||||
|
||||
/// Checks if the user's languages are set.
|
||||
/// Returns a [Future] that completes with a [bool] value
|
||||
/// indicating whether the user's languages are set.
|
||||
///
|
||||
/// A user's languages are considered set if the source and target languages
|
||||
/// are not null, not empty, and not equal to the [LanguageKeys.unknownLanguage] constant.
|
||||
///
|
||||
/// If an error occurs during the process, it logs the error and returns `false`.
|
||||
Future<bool> get areUserLanguagesSet async {
|
||||
try {
|
||||
final PUserModel? toCheck = userModel ?? (await fetchUserModel());
|
||||
if (toCheck?.profile == null) {
|
||||
return false;
|
||||
}
|
||||
final String? srcLang = toCheck!.profile!.sourceLanguage;
|
||||
final String? tgtLang = toCheck.profile!.targetLanguage;
|
||||
final String? srcLang = profile.userSettings.sourceLanguage;
|
||||
final String? tgtLang = profile.userSettings.targetLanguage;
|
||||
return srcLang != null &&
|
||||
tgtLang != null &&
|
||||
srcLang.isNotEmpty &&
|
||||
tgtLang.isNotEmpty &&
|
||||
srcLang != LanguageKeys.unknownLanguage &&
|
||||
tgtLang != LanguageKeys.unknownLanguage;
|
||||
} catch (err) {
|
||||
} catch (err, s) {
|
||||
ErrorHandler.logError(e: err, s: s);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
String? get _matrixAccessToken =>
|
||||
_pangeaController.matrixState.client.accessToken;
|
||||
|
||||
bool get isPublic =>
|
||||
_pangeaController.userController.userModel?.profile?.publicProfile ??
|
||||
false;
|
||||
/// Returns a boolean value indicating whether the user's profile is public.
|
||||
bool get isPublic {
|
||||
return profile.userSettings.publicProfile;
|
||||
}
|
||||
|
||||
/// Retrieves the user's email address.
|
||||
///
|
||||
/// This method fetches the user's email address by making a request to the
|
||||
/// Matrix server. It uses the `_pangeaController` instance to access the
|
||||
/// Matrix client and retrieve the account's third-party identifiers. It then
|
||||
/// filters the identifiers to find the first one with the medium set to
|
||||
/// `ThirdPartyIdentifierMedium.email`. Finally, it returns the email address
|
||||
/// associated with the identifier, or `null` if no email address is found.
|
||||
///
|
||||
/// Returns:
|
||||
/// - The user's email address as a [String], or `null` if no email address
|
||||
/// is found.
|
||||
Future<String?> get userEmail async {
|
||||
final List<matrix.ThirdPartyIdentifier>? identifiers =
|
||||
await _pangeaController.matrixState.client.getAccount3PIDs();
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import 'package:collection/collection.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
import 'package:fluffychat/pangea/constants/language_constants.dart';
|
||||
import 'package:fluffychat/pangea/repo/word_repo.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
import '../models/word_data_model.dart';
|
||||
import 'base_controller.dart';
|
||||
import 'pangea_controller.dart';
|
||||
|
|
|
|||
|
|
@ -80,4 +80,6 @@ extension PangeaClient on Client {
|
|||
|
||||
String? powerLevelName(int powerLevel, L10n l10n) =>
|
||||
_powerLevelName(powerLevel, l10n);
|
||||
|
||||
Future<void> waitForAccountData() async => await _waitForAccountData();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,4 +78,11 @@ extension GeneralInfoClientExtension on Client {
|
|||
50: l10n.moderator,
|
||||
100: l10n.admin,
|
||||
}[powerLevel];
|
||||
|
||||
/// Account data comes through in the first sync, so wait for that
|
||||
Future<void> _waitForAccountData() async {
|
||||
if (prevBatch == null) {
|
||||
await onSync.stream.first;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,46 +109,6 @@ class PangeaRoomRules {
|
|||
this.autoIGC = ClassDefaultValues.languageToolPermissions,
|
||||
});
|
||||
|
||||
updatePermission(String key, bool value) {
|
||||
switch (key) {
|
||||
case 'isPublic':
|
||||
isPublic = value;
|
||||
break;
|
||||
case 'isOpenEnrollment':
|
||||
isOpenEnrollment = value;
|
||||
break;
|
||||
case 'oneToOneChatClass':
|
||||
oneToOneChatClass = value;
|
||||
break;
|
||||
case 'isCreateRooms':
|
||||
isCreateRooms = value;
|
||||
break;
|
||||
case 'isShareVideo':
|
||||
isShareVideo = value;
|
||||
break;
|
||||
case 'isSharePhoto':
|
||||
isSharePhoto = value;
|
||||
break;
|
||||
case 'isShareFiles':
|
||||
isShareFiles = value;
|
||||
break;
|
||||
case 'isShareLocation':
|
||||
isShareLocation = value;
|
||||
break;
|
||||
case 'isCreateStories':
|
||||
isCreateStories = value;
|
||||
break;
|
||||
case 'isVoiceNotes':
|
||||
isVoiceNotes = value;
|
||||
break;
|
||||
case 'isInviteOnlyStudents':
|
||||
isInviteOnlyStudents = value;
|
||||
break;
|
||||
default:
|
||||
throw Exception('Invalid key for setting permissions - $key');
|
||||
}
|
||||
}
|
||||
|
||||
setLanguageToolSetting(ToolSetting setting, int value) {
|
||||
switch (setting) {
|
||||
case ToolSetting.interactiveTranslator:
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -4,7 +4,7 @@ class UserProfileSearchResponse {
|
|||
int count;
|
||||
String? next;
|
||||
String? previous;
|
||||
List<Profile> results;
|
||||
List<PangeaProfile> results;
|
||||
|
||||
UserProfileSearchResponse({
|
||||
required this.count,
|
||||
|
|
@ -19,9 +19,9 @@ class UserProfileSearchResponse {
|
|||
next: json["next"],
|
||||
previous: json["previous"],
|
||||
results: json["results"]
|
||||
.map((p) => Profile.fromJson(p))
|
||||
.map((p) => PangeaProfile.fromJson(p))
|
||||
.toList()
|
||||
.cast<Profile>(),
|
||||
.cast<PangeaProfile>(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@ import 'dart:async';
|
|||
import 'package:country_picker/country_picker.dart';
|
||||
import 'package:fluffychat/pangea/models/language_model.dart';
|
||||
import 'package:fluffychat/pangea/models/user_model.dart';
|
||||
import 'package:fluffychat/pangea/utils/error_handler.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
import '../../../widgets/matrix.dart';
|
||||
import '../../controllers/pangea_controller.dart';
|
||||
|
|
@ -35,9 +37,10 @@ class FindPartnerController extends State<FindPartner> {
|
|||
|
||||
Timer? coolDown;
|
||||
|
||||
final List<Profile> _userProfilesCache = [];
|
||||
final List<PangeaProfile> _userProfilesCache = [];
|
||||
|
||||
final scrollController = ScrollController();
|
||||
String? error;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
|
|
@ -66,10 +69,21 @@ class FindPartnerController extends State<FindPartner> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (error != null && error!.isNotEmpty) {
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(L10n.of(context)!.oopsSomethingWentWrong),
|
||||
Text(L10n.of(context)!.errorPleaseRefresh),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
return FindPartnerView(this);
|
||||
}
|
||||
|
||||
List<Profile> get userProfiles => _userProfilesCache.where((p) {
|
||||
List<PangeaProfile> get userProfiles => _userProfilesCache.where((p) {
|
||||
return (p.targetLanguage != null &&
|
||||
targetLanguageSearch.langCode == p.targetLanguage) &&
|
||||
(p.sourceLanguage != null &&
|
||||
|
|
@ -91,21 +105,29 @@ class FindPartnerController extends State<FindPartner> {
|
|||
if (loading || nextUrl == null) return;
|
||||
setState(() => loading = true);
|
||||
|
||||
final UserProfileSearchResponse response =
|
||||
await PUserRepo.searchUserProfiles(
|
||||
accessToken: await pangeaController.userController.accessToken,
|
||||
targetLanguage: targetLanguageSearch.langCode,
|
||||
sourceLanguage: sourceLanguageSearch.langCode,
|
||||
country: countrySearch,
|
||||
limit: 15,
|
||||
pageNumber: nextPage.toString(),
|
||||
);
|
||||
UserProfileSearchResponse response;
|
||||
try {
|
||||
final String accessToken =
|
||||
await pangeaController.userController.accessToken;
|
||||
response = await PUserRepo.searchUserProfiles(
|
||||
accessToken: accessToken,
|
||||
targetLanguage: targetLanguageSearch.langCode,
|
||||
sourceLanguage: sourceLanguageSearch.langCode,
|
||||
country: countrySearch,
|
||||
limit: 15,
|
||||
pageNumber: nextPage.toString(),
|
||||
);
|
||||
} catch (err, s) {
|
||||
error = err.toString();
|
||||
setState(() => loading = false);
|
||||
ErrorHandler.logError(e: err, s: s);
|
||||
return;
|
||||
}
|
||||
|
||||
nextUrl = response.next;
|
||||
nextPage++;
|
||||
|
||||
final String? currentUserId =
|
||||
pangeaController.userController.userModel?.profile?.pangeaUserId;
|
||||
final String? currentUserId = pangeaController.matrixState.client.userID;
|
||||
_userProfilesCache.addAll(
|
||||
response.results.where(
|
||||
(p) =>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import 'package:country_picker/country_picker.dart';
|
|||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/config/themes.dart';
|
||||
import 'package:fluffychat/pangea/models/user_model.dart';
|
||||
import 'package:fluffychat/pangea/utils/country_display.dart';
|
||||
import 'package:fluffychat/pangea/widgets/common/list_placeholder.dart';
|
||||
import 'package:fluffychat/pangea/widgets/common/pangea_logo_svg.dart';
|
||||
import 'package:fluffychat/pangea/widgets/user_settings/p_language_dropdown.dart';
|
||||
|
|
@ -244,7 +245,7 @@ class LanguageSelectionRow extends StatelessWidget {
|
|||
}
|
||||
|
||||
class UserProfileEntry extends StatelessWidget {
|
||||
final Profile pangeaProfile;
|
||||
final PangeaProfile pangeaProfile;
|
||||
final FindPartnerController controller;
|
||||
|
||||
const UserProfileEntry({
|
||||
|
|
@ -287,7 +288,7 @@ class UserProfileEntry extends StatelessWidget {
|
|||
const SizedBox(width: 20),
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
text: pangeaProfile.flagEmoji,
|
||||
text: CountryDisplayUtil.flagEmoji(pangeaProfile.country),
|
||||
style: const TextStyle(fontSize: 15),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import 'package:fluffychat/widgets/matrix.dart';
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
import '../../utils/bot_name.dart';
|
||||
import '../../utils/error_handler.dart';
|
||||
|
|
@ -73,26 +72,24 @@ class PUserAgeController extends State<PUserAge> {
|
|||
}
|
||||
|
||||
//Note: used linear progress bar (also used in fluffychat signup button) for consistency
|
||||
createUserInPangea() async {
|
||||
Future<void> createUserInPangea() async {
|
||||
try {
|
||||
setState(() {
|
||||
error = dobValidator();
|
||||
});
|
||||
|
||||
setState(() => error = dobValidator());
|
||||
if (error?.isNotEmpty == true) return;
|
||||
setState(() => loading = true);
|
||||
|
||||
setState(() {
|
||||
loading = true;
|
||||
});
|
||||
final DateTime? dob =
|
||||
pangeaController.userController.profile.userSettings.dateOfBirth;
|
||||
|
||||
final String date = DateFormat('yyyy-MM-dd').format(selectedDate!);
|
||||
|
||||
if (pangeaController.userController.userModel?.access == null) {
|
||||
await pangeaController.userController.createPangeaUser(dob: date);
|
||||
} else {
|
||||
await pangeaController.userController.updateUserProfile(
|
||||
dateOfBirth: date,
|
||||
if (dob == null) {
|
||||
await pangeaController.userController.createProfile(
|
||||
dob: selectedDate!,
|
||||
);
|
||||
} else {
|
||||
pangeaController.userController.updateProfile((profile) {
|
||||
profile.userSettings.dateOfBirth = selectedDate!;
|
||||
return profile;
|
||||
});
|
||||
}
|
||||
FluffyChatApp.router.go('/rooms');
|
||||
} catch (err, s) {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ import 'dart:async';
|
|||
|
||||
import 'package:country_picker/country_picker.dart';
|
||||
import 'package:fluffychat/pangea/controllers/pangea_controller.dart';
|
||||
import 'package:fluffychat/pangea/models/space_model.dart';
|
||||
import 'package:fluffychat/pangea/models/user_model.dart';
|
||||
import 'package:fluffychat/pangea/pages/settings_learning/settings_learning_view.dart';
|
||||
import 'package:fluffychat/pangea/widgets/user_settings/p_language_dialog.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
|
@ -18,31 +20,55 @@ class SettingsLearningController extends State<SettingsLearning> {
|
|||
late StreamSubscription _userSubscription;
|
||||
PangeaController pangeaController = MatrixState.pangeaController;
|
||||
|
||||
setPublicProfile(bool b) async {
|
||||
await pangeaController.userController.updateUserProfile(publicProfile: b);
|
||||
setState(() {});
|
||||
Future<void> changeLanguage() async {
|
||||
await pLanguageDialog(context, () {});
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
_userSubscription =
|
||||
pangeaController.userController.stateStream.listen((event) {
|
||||
setState(() {});
|
||||
Future<void> setPublicProfile(bool isPublic) async {
|
||||
pangeaController.userController.updateProfile((profile) {
|
||||
profile.userSettings.publicProfile = isPublic;
|
||||
return profile;
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> changeLanguage() async {
|
||||
await pLanguageDialog(context, () {});
|
||||
setState(() {});
|
||||
Future<void> changeCountry(Country country) async {
|
||||
pangeaController.userController.updateProfile((profile) {
|
||||
profile.userSettings.country = country.displayNameNoCountryCode;
|
||||
return profile;
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> changeCountry(Country country) async {
|
||||
await pangeaController.userController.updateUserProfile(
|
||||
country: country.displayNameNoCountryCode,
|
||||
);
|
||||
setState(() {});
|
||||
void updateToolSetting(ToolSetting toolSetting, bool value) {
|
||||
pangeaController.userController.updateProfile((Profile profile) {
|
||||
switch (toolSetting) {
|
||||
case ToolSetting.interactiveTranslator:
|
||||
return profile..toolSettings.interactiveTranslator = value;
|
||||
case ToolSetting.interactiveGrammar:
|
||||
return profile..toolSettings.interactiveGrammar = value;
|
||||
case ToolSetting.immersionMode:
|
||||
return profile..toolSettings.immersionMode = value;
|
||||
case ToolSetting.definitions:
|
||||
return profile..toolSettings.definitions = value;
|
||||
case ToolSetting.autoIGC:
|
||||
return profile..toolSettings.autoIGC = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool getToolSetting(ToolSetting toolSetting) {
|
||||
final toolSettings = pangeaController.userController.profile.toolSettings;
|
||||
switch (toolSetting) {
|
||||
case ToolSetting.interactiveTranslator:
|
||||
return toolSettings.interactiveTranslator;
|
||||
case ToolSetting.interactiveGrammar:
|
||||
return toolSettings.interactiveGrammar;
|
||||
case ToolSetting.immersionMode:
|
||||
return toolSettings.immersionMode;
|
||||
case ToolSetting.definitions:
|
||||
return toolSettings.definitions;
|
||||
case ToolSetting.autoIGC:
|
||||
return toolSettings.autoIGC;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import 'package:fluffychat/pangea/constants/local.key.dart';
|
||||
import 'package:fluffychat/pangea/models/space_model.dart';
|
||||
import 'package:fluffychat/pangea/pages/settings_learning/settings_learning.dart';
|
||||
import 'package:fluffychat/pangea/utils/error_handler.dart';
|
||||
|
|
@ -18,73 +17,97 @@ class SettingsLearningView extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
centerTitle: true,
|
||||
title: Text(
|
||||
L10n.of(context)!.learningSettings,
|
||||
),
|
||||
// rebuild this page each time a sync comes through with new account data
|
||||
// this prevents having to call setState each time an individual setting is changed
|
||||
return StreamBuilder(
|
||||
stream:
|
||||
controller.pangeaController.matrixState.client.onSync.stream.where(
|
||||
(update) => update.accountData != null,
|
||||
),
|
||||
body: ListTileTheme(
|
||||
iconColor: Theme.of(context).textTheme.bodyLarge!.color,
|
||||
child: MaxWidthBody(
|
||||
withScrolling: true,
|
||||
child: Column(
|
||||
children: [
|
||||
LanguageTile(controller),
|
||||
CountryPickerTile(controller),
|
||||
const SizedBox(height: 8),
|
||||
const Divider(height: 1),
|
||||
const SizedBox(height: 8),
|
||||
if (controller.pangeaController.permissionsController.isUser18())
|
||||
SwitchListTile.adaptive(
|
||||
activeColor: AppConfig.activeToggleColor,
|
||||
title: Text(L10n.of(context)!.publicProfileTitle),
|
||||
subtitle: Text(L10n.of(context)!.publicProfileDesc),
|
||||
value: controller.pangeaController.userController.isPublic,
|
||||
onChanged: (bool isPublicProfile) => showFutureLoadingDialog(
|
||||
context: context,
|
||||
future: () => controller.setPublicProfile(isPublicProfile),
|
||||
onError: (err) =>
|
||||
ErrorHandler.logError(e: err, s: StackTrace.current),
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
subtitle: Text(L10n.of(context)!.toggleToolSettingsDescription),
|
||||
),
|
||||
for (final setting in ToolSetting.values)
|
||||
PSettingsSwitchListTile.adaptive(
|
||||
defaultValue: controller.pangeaController.localSettings
|
||||
.userLanguageToolSetting(setting),
|
||||
title: setting.toolName(context),
|
||||
subtitle: setting.toolDescription(context),
|
||||
pStoreKey: setting.toString(),
|
||||
local: false,
|
||||
),
|
||||
PSettingsSwitchListTile.adaptive(
|
||||
defaultValue: controller.pangeaController.pStoreService.read(
|
||||
PLocalKey.itAutoPlay,
|
||||
) ??
|
||||
false,
|
||||
title: L10n.of(context)!.interactiveTranslatorAutoPlaySliderHeader,
|
||||
subtitle: L10n.of(context)!.interactiveTranslatorAutoPlayDesc,
|
||||
pStoreKey: PLocalKey.itAutoPlay,
|
||||
local: false,
|
||||
),
|
||||
PSettingsSwitchListTile.adaptive(
|
||||
defaultValue: controller.pangeaController.pStoreService.read(
|
||||
PLocalKey.autoPlayMessages,
|
||||
) ??
|
||||
false,
|
||||
title: L10n.of(context)!.autoPlayTitle,
|
||||
subtitle: L10n.of(context)!.autoPlayDesc,
|
||||
pStoreKey: PLocalKey.autoPlayMessages,
|
||||
local: false,
|
||||
),
|
||||
],
|
||||
builder: (context, snapshot) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
centerTitle: true,
|
||||
title: Text(
|
||||
L10n.of(context)!.learningSettings,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
body: ListTileTheme(
|
||||
iconColor: Theme.of(context).textTheme.bodyLarge!.color,
|
||||
child: MaxWidthBody(
|
||||
withScrolling: true,
|
||||
child: Column(
|
||||
children: [
|
||||
LanguageTile(controller),
|
||||
CountryPickerTile(controller),
|
||||
const SizedBox(height: 8),
|
||||
const Divider(height: 1),
|
||||
const SizedBox(height: 8),
|
||||
if (controller.pangeaController.permissionsController
|
||||
.isUser18())
|
||||
SwitchListTile.adaptive(
|
||||
activeColor: AppConfig.activeToggleColor,
|
||||
title: Text(L10n.of(context)!.publicProfileTitle),
|
||||
subtitle: Text(L10n.of(context)!.publicProfileDesc),
|
||||
value:
|
||||
controller.pangeaController.userController.isPublic,
|
||||
onChanged: (bool isPublicProfile) =>
|
||||
showFutureLoadingDialog(
|
||||
context: context,
|
||||
future: () =>
|
||||
controller.setPublicProfile(isPublicProfile),
|
||||
onError: (err) => ErrorHandler.logError(
|
||||
e: err,
|
||||
s: StackTrace.current,
|
||||
),
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
subtitle:
|
||||
Text(L10n.of(context)!.toggleToolSettingsDescription),
|
||||
),
|
||||
for (final toolSetting in ToolSetting.values)
|
||||
ProfileSettingsSwitchListTile.adaptive(
|
||||
defaultValue: controller.getToolSetting(toolSetting),
|
||||
title: toolSetting.toolName(context),
|
||||
subtitle: toolSetting.toolDescription(context),
|
||||
onChange: (bool value) => controller.updateToolSetting(
|
||||
toolSetting,
|
||||
value,
|
||||
),
|
||||
),
|
||||
ProfileSettingsSwitchListTile.adaptive(
|
||||
defaultValue: controller.pangeaController.userController
|
||||
.profile.userSettings.itAutoPlay,
|
||||
title: L10n.of(context)!
|
||||
.interactiveTranslatorAutoPlaySliderHeader,
|
||||
subtitle:
|
||||
L10n.of(context)!.interactiveTranslatorAutoPlayDesc,
|
||||
onChange: (bool value) => controller
|
||||
.pangeaController.userController
|
||||
.updateProfile((profile) {
|
||||
profile.userSettings.itAutoPlay = value;
|
||||
return profile;
|
||||
}),
|
||||
),
|
||||
ProfileSettingsSwitchListTile.adaptive(
|
||||
defaultValue: controller.pangeaController.userController
|
||||
.profile.userSettings.autoPlayMessages,
|
||||
title: L10n.of(context)!.autoPlayTitle,
|
||||
subtitle: L10n.of(context)!.autoPlayDesc,
|
||||
onChange: (bool value) => controller
|
||||
.pangeaController.userController
|
||||
.updateProfile((profile) {
|
||||
profile.userSettings.autoPlayMessages = value;
|
||||
return profile;
|
||||
}),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -150,4 +150,4 @@ SpanDetailsRepoReqAndRes get mockReponseWithChoices {
|
|||
// res.span.choices![1].selected = true;
|
||||
// res.span.message = "Conjugation error";
|
||||
// return res;
|
||||
// }
|
||||
// }
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'package:http/http.dart';
|
||||
|
||||
import '../config/environment.dart';
|
||||
|
|
|
|||
|
|
@ -4,37 +4,13 @@ import 'dart:developer';
|
|||
import 'package:fluffychat/pangea/constants/model_keys.dart';
|
||||
import 'package:http/http.dart';
|
||||
|
||||
import '../../widgets/matrix.dart';
|
||||
import '../models/user_model.dart';
|
||||
import '../models/user_profile_search_model.dart';
|
||||
import '../network/requests.dart';
|
||||
import '../network/urls.dart';
|
||||
|
||||
class PUserRepo {
|
||||
static Future<PUserModel> repoCreatePangeaUser({
|
||||
required String userID,
|
||||
required String dob,
|
||||
required fullName,
|
||||
required String matrixAccessToken,
|
||||
}) async {
|
||||
final Requests req = Requests(
|
||||
baseUrl: PApiUrls.baseAPI,
|
||||
matrixAccessToken: matrixAccessToken,
|
||||
);
|
||||
|
||||
final Map<String, dynamic> body = {
|
||||
ModelKey.userFullName: fullName,
|
||||
ModelKey.userPangeaUserId: userID,
|
||||
ModelKey.userDateOfBirth: dob,
|
||||
};
|
||||
final Response res = await req.post(
|
||||
url: PApiUrls.createUser,
|
||||
body: body,
|
||||
);
|
||||
return PUserModel.fromJson(jsonDecode(res.body));
|
||||
}
|
||||
|
||||
static Future<PUserModel?> fetchPangeaUserInfo({
|
||||
static Future<PangeaProfileResponse?> fetchPangeaUserInfo({
|
||||
required String userID,
|
||||
required String matrixAccessToken,
|
||||
}) async {
|
||||
|
|
@ -49,7 +25,7 @@ class PUserRepo {
|
|||
objectId: userID,
|
||||
);
|
||||
|
||||
return PUserModel.fromJson(jsonDecode(res.body));
|
||||
return PangeaProfileResponse.fromJson(jsonDecode(res.body));
|
||||
} catch (err) {
|
||||
//status code should be 400 - PTODO - check ffor this.
|
||||
log("Most likely a first signup and needs to make an account");
|
||||
|
|
@ -57,32 +33,6 @@ class PUserRepo {
|
|||
}
|
||||
}
|
||||
|
||||
//notes for jordan - only replace non-null fields, return whole profile
|
||||
//Jordan - should return pangeaUserId as well
|
||||
static Future<Profile> updateUserProfile(
|
||||
Profile userProfile,
|
||||
String accessToken,
|
||||
) async {
|
||||
final Requests req = Requests(
|
||||
baseUrl: PApiUrls.baseAPI,
|
||||
accessToken: accessToken,
|
||||
);
|
||||
final Response res = await req.put(
|
||||
url: PApiUrls.updateUserProfile,
|
||||
body: userProfile.toJson(),
|
||||
);
|
||||
|
||||
//temp fix
|
||||
final content = jsonDecode(res.body);
|
||||
//PTODO - try taking this out and see where bug occurs
|
||||
if (content[ModelKey.userPangeaUserId] == null) {
|
||||
content[ModelKey.userPangeaUserId] =
|
||||
MatrixState.pangeaController.matrixState.client.userID;
|
||||
}
|
||||
|
||||
return Profile.fromJson(content);
|
||||
}
|
||||
|
||||
static Future<UserProfileSearchResponse> searchUserProfiles({
|
||||
// List<String>? interests,
|
||||
String? targetLanguage,
|
||||
|
|
|
|||
515
lib/pangea/utils/country_display.dart
Normal file
515
lib/pangea/utils/country_display.dart
Normal file
|
|
@ -0,0 +1,515 @@
|
|||
import 'package:country_picker/country_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
class CountryDisplayUtil {
|
||||
/// used in find a partner page for display partner's country
|
||||
static String flagEmoji(String? countryName) {
|
||||
countryName = countryName?.split(' (')[0];
|
||||
final Country? country = CountryService().findByName(countryName);
|
||||
return country?.flagEmoji ?? "";
|
||||
}
|
||||
|
||||
static String? countryDisplayName(String? countryName, BuildContext context) {
|
||||
countryName = countryName?.split(' (')[0];
|
||||
final Country? country = CountryService().findByName(countryName);
|
||||
if (country?.countryCode == null) return null;
|
||||
switch (country!.countryCode) {
|
||||
case 'WW':
|
||||
return L10n.of(context)!.wwCountryDisplayName;
|
||||
case 'AF':
|
||||
return L10n.of(context)!.afCountryDisplayName;
|
||||
case 'AX':
|
||||
return L10n.of(context)!.axCountryDisplayName;
|
||||
case 'AL':
|
||||
return L10n.of(context)!.alCountryDisplayName;
|
||||
case 'DZ':
|
||||
return L10n.of(context)!.dzCountryDisplayName;
|
||||
case 'AS':
|
||||
return L10n.of(context)!.asCountryDisplayName;
|
||||
case 'AD':
|
||||
return L10n.of(context)!.adCountryDisplayName;
|
||||
case 'AO':
|
||||
return L10n.of(context)!.aoCountryDisplayName;
|
||||
case 'AI':
|
||||
return L10n.of(context)!.aiCountryDisplayName;
|
||||
case 'AG':
|
||||
return L10n.of(context)!.agCountryDisplayName;
|
||||
case 'AR':
|
||||
return L10n.of(context)!.arCountryDisplayName;
|
||||
case 'AM':
|
||||
return L10n.of(context)!.amCountryDisplayName;
|
||||
case 'AW':
|
||||
return L10n.of(context)!.awCountryDisplayName;
|
||||
case 'AC':
|
||||
return L10n.of(context)!.acCountryDisplayName;
|
||||
case 'AU':
|
||||
return L10n.of(context)!.auCountryDisplayName;
|
||||
case 'AT':
|
||||
return L10n.of(context)!.atCountryDisplayName;
|
||||
case 'AZ':
|
||||
return L10n.of(context)!.azCountryDisplayName;
|
||||
case 'BS':
|
||||
return L10n.of(context)!.bsCountryDisplayName;
|
||||
case 'BH':
|
||||
return L10n.of(context)!.bhCountryDisplayName;
|
||||
case 'BD':
|
||||
return L10n.of(context)!.bdCountryDisplayName;
|
||||
case 'BB':
|
||||
return L10n.of(context)!.bbCountryDisplayName;
|
||||
case 'BY':
|
||||
return L10n.of(context)!.byCountryDisplayName;
|
||||
case 'BE':
|
||||
return L10n.of(context)!.beCountryDisplayName;
|
||||
case 'BZ':
|
||||
return L10n.of(context)!.bzCountryDisplayName;
|
||||
case 'BJ':
|
||||
return L10n.of(context)!.bjCountryDisplayName;
|
||||
case 'BM':
|
||||
return L10n.of(context)!.bmCountryDisplayName;
|
||||
case 'BT':
|
||||
return L10n.of(context)!.btCountryDisplayName;
|
||||
case 'BO':
|
||||
return L10n.of(context)!.boCountryDisplayName;
|
||||
case 'BA':
|
||||
return L10n.of(context)!.baCountryDisplayName;
|
||||
case 'BW':
|
||||
return L10n.of(context)!.bwCountryDisplayName;
|
||||
case 'BR':
|
||||
return L10n.of(context)!.brCountryDisplayName;
|
||||
case 'IO':
|
||||
return L10n.of(context)!.ioCountryDisplayName;
|
||||
case 'VG':
|
||||
return L10n.of(context)!.vgCountryDisplayName;
|
||||
case 'BN':
|
||||
return L10n.of(context)!.bnCountryDisplayName;
|
||||
case 'BG':
|
||||
return L10n.of(context)!.bgCountryDisplayName;
|
||||
case 'BF':
|
||||
return L10n.of(context)!.bfCountryDisplayName;
|
||||
case 'BI':
|
||||
return L10n.of(context)!.biCountryDisplayName;
|
||||
case 'KH':
|
||||
return L10n.of(context)!.khCountryDisplayName;
|
||||
case 'CM':
|
||||
return L10n.of(context)!.cmCountryDisplayName;
|
||||
case 'CA':
|
||||
return L10n.of(context)!.caCountryDisplayName;
|
||||
case 'CV':
|
||||
return L10n.of(context)!.cvCountryDisplayName;
|
||||
case 'BQ':
|
||||
return L10n.of(context)!.bqCountryDisplayName;
|
||||
case 'KY':
|
||||
return L10n.of(context)!.kyCountryDisplayName;
|
||||
case 'CF':
|
||||
return L10n.of(context)!.cfCountryDisplayName;
|
||||
case 'TD':
|
||||
return L10n.of(context)!.tdCountryDisplayName;
|
||||
case 'CL':
|
||||
return L10n.of(context)!.clCountryDisplayName;
|
||||
case 'CN':
|
||||
return L10n.of(context)!.cnCountryDisplayName;
|
||||
case 'CX':
|
||||
return L10n.of(context)!.cxCountryDisplayName;
|
||||
case 'CC':
|
||||
return L10n.of(context)!.ccCountryDisplayName;
|
||||
case 'CO':
|
||||
return L10n.of(context)!.coCountryDisplayName;
|
||||
case 'KM':
|
||||
return L10n.of(context)!.kmCountryDisplayName;
|
||||
case 'CD':
|
||||
return L10n.of(context)!.cdCountryDisplayName;
|
||||
case 'CG':
|
||||
return L10n.of(context)!.cgCountryDisplayName;
|
||||
case 'CK':
|
||||
return L10n.of(context)!.ckCountryDisplayName;
|
||||
case 'CR':
|
||||
return L10n.of(context)!.crCountryDisplayName;
|
||||
case 'CI':
|
||||
return L10n.of(context)!.ciCountryDisplayName;
|
||||
case 'HR':
|
||||
return L10n.of(context)!.hrCountryDisplayName;
|
||||
case 'CU':
|
||||
return L10n.of(context)!.cuCountryDisplayName;
|
||||
case 'CW':
|
||||
return L10n.of(context)!.cwCountryDisplayName;
|
||||
case 'CY':
|
||||
return L10n.of(context)!.cyCountryDisplayName;
|
||||
case 'CZ':
|
||||
return L10n.of(context)!.czCountryDisplayName;
|
||||
case 'DK':
|
||||
return L10n.of(context)!.dkCountryDisplayName;
|
||||
case 'DJ':
|
||||
return L10n.of(context)!.djCountryDisplayName;
|
||||
case 'DM':
|
||||
return L10n.of(context)!.dmCountryDisplayName;
|
||||
case 'DO':
|
||||
return L10n.of(context)!.doCountryDisplayName;
|
||||
case 'TL':
|
||||
return L10n.of(context)!.tlCountryDisplayName;
|
||||
case 'EC':
|
||||
return L10n.of(context)!.ecCountryDisplayName;
|
||||
case 'EG':
|
||||
return L10n.of(context)!.egCountryDisplayName;
|
||||
case 'SV':
|
||||
return L10n.of(context)!.svCountryDisplayName;
|
||||
case 'GQ':
|
||||
return L10n.of(context)!.gqCountryDisplayName;
|
||||
case 'ER':
|
||||
return L10n.of(context)!.erCountryDisplayName;
|
||||
case 'EE':
|
||||
return L10n.of(context)!.eeCountryDisplayName;
|
||||
case 'SZ':
|
||||
return L10n.of(context)!.szCountryDisplayName;
|
||||
case 'ET':
|
||||
return L10n.of(context)!.etCountryDisplayName;
|
||||
case 'FK':
|
||||
return L10n.of(context)!.fkCountryDisplayName;
|
||||
case 'FO':
|
||||
return L10n.of(context)!.foCountryDisplayName;
|
||||
case 'FJ':
|
||||
return L10n.of(context)!.fjCountryDisplayName;
|
||||
case 'FI':
|
||||
return L10n.of(context)!.fiCountryDisplayName;
|
||||
case 'FR':
|
||||
return L10n.of(context)!.frCountryDisplayName;
|
||||
case 'GF':
|
||||
return L10n.of(context)!.gfCountryDisplayName;
|
||||
case 'PF':
|
||||
return L10n.of(context)!.pfCountryDisplayName;
|
||||
case 'GA':
|
||||
return L10n.of(context)!.gaCountryDisplayName;
|
||||
case 'GM':
|
||||
return L10n.of(context)!.gmCountryDisplayName;
|
||||
case 'GE':
|
||||
return L10n.of(context)!.geCountryDisplayName;
|
||||
case 'DE':
|
||||
return L10n.of(context)!.deCountryDisplayName;
|
||||
case 'GH':
|
||||
return L10n.of(context)!.ghCountryDisplayName;
|
||||
case 'GI':
|
||||
return L10n.of(context)!.giCountryDisplayName;
|
||||
case 'GR':
|
||||
return L10n.of(context)!.grCountryDisplayName;
|
||||
case 'GL':
|
||||
return L10n.of(context)!.glCountryDisplayName;
|
||||
case 'GD':
|
||||
return L10n.of(context)!.gdCountryDisplayName;
|
||||
case 'GP':
|
||||
return L10n.of(context)!.gpCountryDisplayName;
|
||||
case 'GU':
|
||||
return L10n.of(context)!.guCountryDisplayName;
|
||||
case 'GT':
|
||||
return L10n.of(context)!.gtCountryDisplayName;
|
||||
case 'GG':
|
||||
return L10n.of(context)!.ggCountryDisplayName;
|
||||
case 'GN':
|
||||
return L10n.of(context)!.gnCountryDisplayName;
|
||||
case 'GW':
|
||||
return L10n.of(context)!.gwCountryDisplayName;
|
||||
case 'GY':
|
||||
return L10n.of(context)!.gyCountryDisplayName;
|
||||
case 'HT':
|
||||
return L10n.of(context)!.htCountryDisplayName;
|
||||
case 'HM':
|
||||
return L10n.of(context)!.hmCountryDisplayName;
|
||||
case 'HN':
|
||||
return L10n.of(context)!.hnCountryDisplayName;
|
||||
case 'HK':
|
||||
return L10n.of(context)!.hkCountryDisplayName;
|
||||
case 'HU':
|
||||
return L10n.of(context)!.huCountryDisplayName;
|
||||
case 'IS':
|
||||
return L10n.of(context)!.isCountryDisplayName;
|
||||
case 'IN':
|
||||
return L10n.of(context)!.inCountryDisplayName;
|
||||
case 'ID':
|
||||
return L10n.of(context)!.idCountryDisplayName;
|
||||
case 'IR':
|
||||
return L10n.of(context)!.irCountryDisplayName;
|
||||
case 'IQ':
|
||||
return L10n.of(context)!.iqCountryDisplayName;
|
||||
case 'IE':
|
||||
return L10n.of(context)!.ieCountryDisplayName;
|
||||
case 'IM':
|
||||
return L10n.of(context)!.imCountryDisplayName;
|
||||
case 'IL':
|
||||
return L10n.of(context)!.ilCountryDisplayName;
|
||||
case 'IT':
|
||||
return L10n.of(context)!.itCountryDisplayName;
|
||||
case 'JM':
|
||||
return L10n.of(context)!.jmCountryDisplayName;
|
||||
case 'JP':
|
||||
return L10n.of(context)!.jpCountryDisplayName;
|
||||
case 'JE':
|
||||
return L10n.of(context)!.jeCountryDisplayName;
|
||||
case 'JO':
|
||||
return L10n.of(context)!.joCountryDisplayName;
|
||||
case 'KZ':
|
||||
return L10n.of(context)!.kzCountryDisplayName;
|
||||
case 'KE':
|
||||
return L10n.of(context)!.keCountryDisplayName;
|
||||
case 'KI':
|
||||
return L10n.of(context)!.kiCountryDisplayName;
|
||||
case 'XK':
|
||||
return L10n.of(context)!.xkCountryDisplayName;
|
||||
case 'KW':
|
||||
return L10n.of(context)!.kwCountryDisplayName;
|
||||
case 'KG':
|
||||
return L10n.of(context)!.kgCountryDisplayName;
|
||||
case 'LA':
|
||||
return L10n.of(context)!.laCountryDisplayName;
|
||||
case 'LV':
|
||||
return L10n.of(context)!.lvCountryDisplayName;
|
||||
case 'LB':
|
||||
return L10n.of(context)!.lbCountryDisplayName;
|
||||
case 'LS':
|
||||
return L10n.of(context)!.lsCountryDisplayName;
|
||||
case 'LR':
|
||||
return L10n.of(context)!.lrCountryDisplayName;
|
||||
case 'LY':
|
||||
return L10n.of(context)!.lyCountryDisplayName;
|
||||
case 'LI':
|
||||
return L10n.of(context)!.liCountryDisplayName;
|
||||
case 'LT':
|
||||
return L10n.of(context)!.ltCountryDisplayName;
|
||||
case 'LU':
|
||||
return L10n.of(context)!.luCountryDisplayName;
|
||||
case 'MO':
|
||||
return L10n.of(context)!.moCountryDisplayName;
|
||||
case 'MK':
|
||||
return L10n.of(context)!.mkCountryDisplayName;
|
||||
case 'MG':
|
||||
return L10n.of(context)!.mgCountryDisplayName;
|
||||
case 'MW':
|
||||
return L10n.of(context)!.mwCountryDisplayName;
|
||||
case 'MY':
|
||||
return L10n.of(context)!.myCountryDisplayName;
|
||||
case 'MV':
|
||||
return L10n.of(context)!.mvCountryDisplayName;
|
||||
case 'ML':
|
||||
return L10n.of(context)!.mlCountryDisplayName;
|
||||
case 'MT':
|
||||
return L10n.of(context)!.mtCountryDisplayName;
|
||||
case 'MH':
|
||||
return L10n.of(context)!.mhCountryDisplayName;
|
||||
case 'MQ':
|
||||
return L10n.of(context)!.mqCountryDisplayName;
|
||||
case 'MR':
|
||||
return L10n.of(context)!.mrCountryDisplayName;
|
||||
case 'MU':
|
||||
return L10n.of(context)!.muCountryDisplayName;
|
||||
case 'YT':
|
||||
return L10n.of(context)!.ytCountryDisplayName;
|
||||
case 'MX':
|
||||
return L10n.of(context)!.mxCountryDisplayName;
|
||||
case 'FM':
|
||||
return L10n.of(context)!.fmCountryDisplayName;
|
||||
case 'MD':
|
||||
return L10n.of(context)!.mdCountryDisplayName;
|
||||
case 'MC':
|
||||
return L10n.of(context)!.mcCountryDisplayName;
|
||||
case 'MN':
|
||||
return L10n.of(context)!.mnCountryDisplayName;
|
||||
case 'ME':
|
||||
return L10n.of(context)!.meCountryDisplayName;
|
||||
case 'MS':
|
||||
return L10n.of(context)!.msCountryDisplayName;
|
||||
case 'MA':
|
||||
return L10n.of(context)!.maCountryDisplayName;
|
||||
case 'MZ':
|
||||
return L10n.of(context)!.mzCountryDisplayName;
|
||||
case 'MM':
|
||||
return L10n.of(context)!.mmCountryDisplayName;
|
||||
case 'NA':
|
||||
return L10n.of(context)!.naCountryDisplayName;
|
||||
case 'NR':
|
||||
return L10n.of(context)!.nrCountryDisplayName;
|
||||
case 'NP':
|
||||
return L10n.of(context)!.npCountryDisplayName;
|
||||
case 'NL':
|
||||
return L10n.of(context)!.nlCountryDisplayName;
|
||||
case 'NC':
|
||||
return L10n.of(context)!.ncCountryDisplayName;
|
||||
case 'NZ':
|
||||
return L10n.of(context)!.nzCountryDisplayName;
|
||||
case 'NI':
|
||||
return L10n.of(context)!.niCountryDisplayName;
|
||||
case 'NE':
|
||||
return L10n.of(context)!.neCountryDisplayName;
|
||||
case 'NG':
|
||||
return L10n.of(context)!.ngCountryDisplayName;
|
||||
case 'NU':
|
||||
return L10n.of(context)!.nuCountryDisplayName;
|
||||
case 'NF':
|
||||
return L10n.of(context)!.nfCountryDisplayName;
|
||||
case 'KP':
|
||||
return L10n.of(context)!.kpCountryDisplayName;
|
||||
case 'MP':
|
||||
return L10n.of(context)!.mpCountryDisplayName;
|
||||
case 'NO':
|
||||
return L10n.of(context)!.noCountryDisplayName;
|
||||
case 'OM':
|
||||
return L10n.of(context)!.omCountryDisplayName;
|
||||
case 'PK':
|
||||
return L10n.of(context)!.pkCountryDisplayName;
|
||||
case 'PW':
|
||||
return L10n.of(context)!.pwCountryDisplayName;
|
||||
case 'PS':
|
||||
return L10n.of(context)!.psCountryDisplayName;
|
||||
case 'PA':
|
||||
return L10n.of(context)!.paCountryDisplayName;
|
||||
case 'PG':
|
||||
return L10n.of(context)!.pgCountryDisplayName;
|
||||
case 'PY':
|
||||
return L10n.of(context)!.pyCountryDisplayName;
|
||||
case 'PE':
|
||||
return L10n.of(context)!.peCountryDisplayName;
|
||||
case 'PH':
|
||||
return L10n.of(context)!.phCountryDisplayName;
|
||||
case 'PL':
|
||||
return L10n.of(context)!.plCountryDisplayName;
|
||||
case 'PT':
|
||||
return L10n.of(context)!.ptCountryDisplayName;
|
||||
case 'PR':
|
||||
return L10n.of(context)!.prCountryDisplayName;
|
||||
case 'QA':
|
||||
return L10n.of(context)!.qaCountryDisplayName;
|
||||
case 'RE':
|
||||
return L10n.of(context)!.reCountryDisplayName;
|
||||
case 'RO':
|
||||
return L10n.of(context)!.roCountryDisplayName;
|
||||
case 'RU':
|
||||
return L10n.of(context)!.ruCountryDisplayName;
|
||||
case 'RW':
|
||||
return L10n.of(context)!.rwCountryDisplayName;
|
||||
case 'BL':
|
||||
return L10n.of(context)!.blCountryDisplayName;
|
||||
case 'SH':
|
||||
return L10n.of(context)!.shCountryDisplayName;
|
||||
case 'KN':
|
||||
return L10n.of(context)!.knCountryDisplayName;
|
||||
case 'LC':
|
||||
return L10n.of(context)!.lcCountryDisplayName;
|
||||
case 'MF':
|
||||
return L10n.of(context)!.mfCountryDisplayName;
|
||||
case 'PM':
|
||||
return L10n.of(context)!.pmCountryDisplayName;
|
||||
case 'VC':
|
||||
return L10n.of(context)!.vcCountryDisplayName;
|
||||
case 'WS':
|
||||
return L10n.of(context)!.wsCountryDisplayName;
|
||||
case 'SM':
|
||||
return L10n.of(context)!.smCountryDisplayName;
|
||||
case 'ST':
|
||||
return L10n.of(context)!.stCountryDisplayName;
|
||||
case 'SA':
|
||||
return L10n.of(context)!.saCountryDisplayName;
|
||||
case 'SN':
|
||||
return L10n.of(context)!.snCountryDisplayName;
|
||||
case 'RS':
|
||||
return L10n.of(context)!.rsCountryDisplayName;
|
||||
case 'SC':
|
||||
return L10n.of(context)!.scCountryDisplayName;
|
||||
case 'SL':
|
||||
return L10n.of(context)!.slCountryDisplayName;
|
||||
case 'SG':
|
||||
return L10n.of(context)!.sgCountryDisplayName;
|
||||
case 'SX':
|
||||
return L10n.of(context)!.sxCountryDisplayName;
|
||||
case 'SK':
|
||||
return L10n.of(context)!.skCountryDisplayName;
|
||||
case 'SI':
|
||||
return L10n.of(context)!.siCountryDisplayName;
|
||||
case 'SB':
|
||||
return L10n.of(context)!.sbCountryDisplayName;
|
||||
case 'SO':
|
||||
return L10n.of(context)!.soCountryDisplayName;
|
||||
case 'ZA':
|
||||
return L10n.of(context)!.zaCountryDisplayName;
|
||||
case 'GS':
|
||||
return L10n.of(context)!.gsCountryDisplayName;
|
||||
case 'KR':
|
||||
return L10n.of(context)!.krCountryDisplayName;
|
||||
case 'SS':
|
||||
return L10n.of(context)!.ssCountryDisplayName;
|
||||
case 'ES':
|
||||
return L10n.of(context)!.esCountryDisplayName;
|
||||
case 'LK':
|
||||
return L10n.of(context)!.lkCountryDisplayName;
|
||||
case 'SD':
|
||||
return L10n.of(context)!.sdCountryDisplayName;
|
||||
case 'SR':
|
||||
return L10n.of(context)!.srCountryDisplayName;
|
||||
case 'SJ':
|
||||
return L10n.of(context)!.sjCountryDisplayName;
|
||||
case 'SE':
|
||||
return L10n.of(context)!.seCountryDisplayName;
|
||||
case 'CH':
|
||||
return L10n.of(context)!.chCountryDisplayName;
|
||||
case 'SY':
|
||||
return L10n.of(context)!.syCountryDisplayName;
|
||||
case 'TW':
|
||||
return L10n.of(context)!.twCountryDisplayName;
|
||||
case 'TJ':
|
||||
return L10n.of(context)!.tjCountryDisplayName;
|
||||
case 'TZ':
|
||||
return L10n.of(context)!.tzCountryDisplayName;
|
||||
case 'TH':
|
||||
return L10n.of(context)!.thCountryDisplayName;
|
||||
case 'TG':
|
||||
return L10n.of(context)!.tgCountryDisplayName;
|
||||
case 'TK':
|
||||
return L10n.of(context)!.tkCountryDisplayName;
|
||||
case 'TO':
|
||||
return L10n.of(context)!.toCountryDisplayName;
|
||||
case 'TT':
|
||||
return L10n.of(context)!.ttCountryDisplayName;
|
||||
case 'TN':
|
||||
return L10n.of(context)!.tnCountryDisplayName;
|
||||
case 'TR':
|
||||
return L10n.of(context)!.trCountryDisplayName;
|
||||
case 'TM':
|
||||
return L10n.of(context)!.tmCountryDisplayName;
|
||||
case 'TC':
|
||||
return L10n.of(context)!.tcCountryDisplayName;
|
||||
case 'TV':
|
||||
return L10n.of(context)!.tvCountryDisplayName;
|
||||
case 'VI':
|
||||
return L10n.of(context)!.viCountryDisplayName;
|
||||
case 'UG':
|
||||
return L10n.of(context)!.ugCountryDisplayName;
|
||||
case 'UA':
|
||||
return L10n.of(context)!.uaCountryDisplayName;
|
||||
case 'AE':
|
||||
return L10n.of(context)!.aeCountryDisplayName;
|
||||
case 'GB':
|
||||
return L10n.of(context)!.gbCountryDisplayName;
|
||||
case 'US':
|
||||
return L10n.of(context)!.usCountryDisplayName;
|
||||
case 'UY':
|
||||
return L10n.of(context)!.uyCountryDisplayName;
|
||||
case 'UZ':
|
||||
return L10n.of(context)!.uzCountryDisplayName;
|
||||
case 'VU':
|
||||
return L10n.of(context)!.vuCountryDisplayName;
|
||||
case 'VA':
|
||||
return L10n.of(context)!.vaCountryDisplayName;
|
||||
case 'VE':
|
||||
return L10n.of(context)!.veCountryDisplayName;
|
||||
case 'VN':
|
||||
return L10n.of(context)!.vnCountryDisplayName;
|
||||
case 'WF':
|
||||
return L10n.of(context)!.wfCountryDisplayName;
|
||||
case 'EH':
|
||||
return L10n.of(context)!.ehCountryDisplayName;
|
||||
case 'YE':
|
||||
return L10n.of(context)!.yeCountryDisplayName;
|
||||
case 'ZM':
|
||||
return L10n.of(context)!.zmCountryDisplayName;
|
||||
case 'ZW':
|
||||
return L10n.of(context)!.zwCountryDisplayName;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,133 +1,71 @@
|
|||
import 'package:fluffychat/pangea/controllers/pangea_controller.dart';
|
||||
import 'package:fluffychat/pangea/utils/error_handler.dart';
|
||||
import 'package:get_storage/get_storage.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
class PLocalStore {
|
||||
/// Utility to save and read data both in the matrix profile (this is the default
|
||||
/// behavior) and in the local storage (local needs to be specificied). An
|
||||
/// instance of this class is created in the PangeaController.
|
||||
class PStore {
|
||||
final GetStorage _box = GetStorage();
|
||||
final PangeaController pangeaController;
|
||||
|
||||
PLocalStore({required this.pangeaController});
|
||||
PStore({required this.pangeaController});
|
||||
|
||||
/// save data in local
|
||||
/// Saves the provided [data] with the specified [key] in the local storage.
|
||||
///
|
||||
/// By default, the [data] is considered as account data, but you can set
|
||||
/// [isAccountData] to false if it's not account-related data.
|
||||
///
|
||||
/// Example usage:
|
||||
/// ```dart
|
||||
/// await save('user', {'name': 'John Doe', 'age': 25});
|
||||
/// ```
|
||||
Future<void> save(
|
||||
String key,
|
||||
dynamic data, {
|
||||
bool addClientIdToKey = true,
|
||||
bool local = false,
|
||||
bool isAccountData = true,
|
||||
}) async {
|
||||
local
|
||||
? await saveLocal(
|
||||
key,
|
||||
data,
|
||||
addClientIdToKey: addClientIdToKey,
|
||||
)
|
||||
: await saveProfile(key, data);
|
||||
await _box.write(_key(key, isAccountData: isAccountData), data);
|
||||
}
|
||||
|
||||
/// fetch data from local
|
||||
dynamic read(
|
||||
String key, {
|
||||
bool addClientIdToKey = true,
|
||||
local = false,
|
||||
}) {
|
||||
return local
|
||||
? readLocal(
|
||||
key,
|
||||
addClientIdToKey: addClientIdToKey,
|
||||
)
|
||||
: readProfile(key);
|
||||
}
|
||||
|
||||
/// delete data from local
|
||||
Future<void> delete(
|
||||
String key, {
|
||||
bool addClientIdToKey = true,
|
||||
local = false,
|
||||
}) async {
|
||||
return local
|
||||
? deleteLocal(
|
||||
key,
|
||||
addClientIdToKey: addClientIdToKey,
|
||||
)
|
||||
: deleteProfile(key);
|
||||
}
|
||||
|
||||
/// save data in local
|
||||
Future<void> saveLocal(
|
||||
String key,
|
||||
dynamic data, {
|
||||
bool addClientIdToKey = true,
|
||||
}) async {
|
||||
await _box.write(_key(key, addClientIdToKey: addClientIdToKey), data);
|
||||
}
|
||||
|
||||
Future<void> saveProfile(
|
||||
String key,
|
||||
dynamic data,
|
||||
) async {
|
||||
final waitForAccountSync =
|
||||
pangeaController.matrixState.client.onSync.stream.firstWhere(
|
||||
(sync) =>
|
||||
sync.accountData != null &&
|
||||
sync.accountData!.any(
|
||||
(event) => event.content.keys.any(
|
||||
(k) => k == key,
|
||||
),
|
||||
),
|
||||
);
|
||||
await pangeaController.matrixState.client.setAccountData(
|
||||
pangeaController.matrixState.client.userID!,
|
||||
key,
|
||||
{key: data},
|
||||
);
|
||||
await waitForAccountSync;
|
||||
await pangeaController.matrixState.client.onSyncStatus.stream.firstWhere(
|
||||
(syncStatus) => syncStatus.status == SyncStatus.finished,
|
||||
);
|
||||
}
|
||||
|
||||
/// fetch data from local
|
||||
dynamic readLocal(String key, {bool addClientIdToKey = true}) {
|
||||
/// Reads the value associated with the given [key] from the local store.
|
||||
///
|
||||
/// If [isAccountData] is true, tries to find key assosiated with the logged in user.
|
||||
/// Otherwise, it is read from the general store.
|
||||
///
|
||||
/// Returns the value associated with the [key], or
|
||||
/// null if the user ID is null or value hasn't been set.
|
||||
dynamic read(String key, {bool isAccountData = true}) {
|
||||
return pangeaController.matrixState.client.userID != null
|
||||
? _box.read(_key(key, addClientIdToKey: addClientIdToKey))
|
||||
? _box.read(_key(key, isAccountData: isAccountData))
|
||||
: null;
|
||||
}
|
||||
|
||||
dynamic readProfile(String key) {
|
||||
try {
|
||||
return pangeaController.matrixState.client.accountData[key]?.content[key];
|
||||
} catch (err) {
|
||||
ErrorHandler.logError(e: err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// delete data from local
|
||||
Future<void> deleteLocal(String key, {bool addClientIdToKey = true}) async {
|
||||
/// Deletes the value associated with the given [key] from the local store.
|
||||
///
|
||||
/// If [isAccountData] is true (default), will try to use key assosiated with the logged in user's ID
|
||||
///
|
||||
/// Returns a [Future] that completes when the value is successfully deleted.
|
||||
/// If the user is not logged in, the value will not be deleted and the [Future] will complete with null.
|
||||
Future<void> delete(String key, {bool isAccountData = true}) async {
|
||||
return pangeaController.matrixState.client.userID != null
|
||||
? _box.remove(_key(key, addClientIdToKey: addClientIdToKey))
|
||||
? _box.remove(_key(key, isAccountData: isAccountData))
|
||||
: null;
|
||||
}
|
||||
|
||||
Future<void> deleteProfile(key) async {
|
||||
return pangeaController.matrixState.client.userID != null
|
||||
? pangeaController.matrixState.client.setAccountData(
|
||||
pangeaController.matrixState.client.userID!,
|
||||
key,
|
||||
{key: null},
|
||||
)
|
||||
: null;
|
||||
}
|
||||
|
||||
_key(String key, {bool addClientIdToKey = true}) {
|
||||
return addClientIdToKey
|
||||
/// Returns the key for storing data in the pangea store.
|
||||
///
|
||||
/// The [key] parameter represents the base key for the data.
|
||||
/// The [isAccountData] parameter indicates whether the data is account-specific.
|
||||
/// If [isAccountData] is true, the account-specific key is returned by appending the user ID to the base key.
|
||||
/// If [isAccountData] is false, the base key is returned as is.
|
||||
String _key(String key, {bool isAccountData = true}) {
|
||||
return isAccountData
|
||||
? pangeaController.matrixState.client.userID! + key
|
||||
: key;
|
||||
}
|
||||
|
||||
/// clear all local storage
|
||||
clearStorage() {
|
||||
/// Clears the storage by erasing all data in the box.
|
||||
void clearStorage() {
|
||||
_box.erase();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import 'dart:developer';
|
|||
|
||||
import 'package:fluffychat/config/themes.dart';
|
||||
import 'package:fluffychat/pages/chat/chat.dart';
|
||||
import 'package:fluffychat/pangea/constants/local.key.dart';
|
||||
import 'package:fluffychat/pangea/enum/message_mode_enum.dart';
|
||||
import 'package:fluffychat/pangea/matrix_event_wrappers/pangea_message_event.dart';
|
||||
import 'package:fluffychat/pangea/utils/any_state_holder.dart';
|
||||
|
|
@ -329,17 +328,13 @@ class MessageToolbarState extends State<MessageToolbar> {
|
|||
});
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
||||
final bool autoplay = MatrixState.pangeaController.pStoreService.read(
|
||||
PLocalKey.autoPlayMessages,
|
||||
) ??
|
||||
false;
|
||||
|
||||
if (widget.pangeaMessageEvent.isAudioMessage) {
|
||||
updateMode(MessageMode.speechToText);
|
||||
return;
|
||||
}
|
||||
|
||||
autoplay
|
||||
MatrixState.pangeaController.userController.profile.userSettings
|
||||
.autoPlayMessages
|
||||
? updateMode(MessageMode.textToSpeech)
|
||||
: updateMode(MessageMode.translation);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -43,8 +43,7 @@ class _JoinClassWithLinkState extends State<JoinClassWithLink> {
|
|||
await _pangeaController.pStoreService.save(
|
||||
PLocalKey.cachedClassCodeToJoin,
|
||||
classCode,
|
||||
addClientIdToKey: false,
|
||||
local: true,
|
||||
isAccountData: false,
|
||||
);
|
||||
context.go("/home");
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import 'dart:developer';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/pangea/constants/local.key.dart';
|
||||
import 'package:fluffychat/pangea/enum/span_data_type.dart';
|
||||
import 'package:fluffychat/pangea/models/span_data.dart';
|
||||
import 'package:fluffychat/pangea/utils/bot_style.dart';
|
||||
|
|
@ -154,21 +153,18 @@ class WordMatchContent extends StatelessWidget {
|
|||
.selected = true;
|
||||
|
||||
controller.setState(
|
||||
() => (
|
||||
controller.currentExpression =
|
||||
controller
|
||||
.widget
|
||||
.scm
|
||||
.choreographer
|
||||
.igc
|
||||
.igcTextData
|
||||
!.matches[controller.widget.scm.matchIndex]
|
||||
.match
|
||||
.choices![index]
|
||||
.isBestCorrection
|
||||
() => (controller.currentExpression = controller
|
||||
.widget
|
||||
.scm
|
||||
.choreographer
|
||||
.igc
|
||||
.igcTextData!
|
||||
.matches[controller.widget.scm.matchIndex]
|
||||
.match
|
||||
.choices![index]
|
||||
.isBestCorrection
|
||||
? BotExpression.gold
|
||||
: BotExpression.surprised
|
||||
),
|
||||
: BotExpression.surprised),
|
||||
);
|
||||
// if (controller.widget.scm.pangeaMatch.match.choices![index].type ==
|
||||
// SpanChoiceType.distractor) {
|
||||
|
|
@ -344,6 +340,12 @@ class WordMatchContent extends StatelessWidget {
|
|||
if (controller.widget.scm.pangeaMatch!.isITStart)
|
||||
DontShowSwitchListTile(
|
||||
controller: pangeaController,
|
||||
onSwitch: (bool value) {
|
||||
pangeaController.userController.updateProfile((profile) {
|
||||
profile.userSettings.itAutoPlay = value;
|
||||
return profile;
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
|
|
@ -486,10 +488,12 @@ class StartITButton extends StatelessWidget {
|
|||
|
||||
class DontShowSwitchListTile extends StatefulWidget {
|
||||
final PangeaController controller;
|
||||
final Function(bool) onSwitch;
|
||||
|
||||
const DontShowSwitchListTile({
|
||||
super.key,
|
||||
required this.controller,
|
||||
required this.onSwitch,
|
||||
});
|
||||
|
||||
@override
|
||||
|
|
@ -510,12 +514,9 @@ class DontShowSwitchListTileState extends State<DontShowSwitchListTile> {
|
|||
activeColor: AppConfig.activeToggleColor,
|
||||
title: Text(L10n.of(context)!.interactiveTranslatorAutoPlaySliderHeader),
|
||||
value: switchValue,
|
||||
onChanged: (value) => {
|
||||
widget.controller.pStoreService.save(
|
||||
PLocalKey.itAutoPlay.toString(),
|
||||
value,
|
||||
),
|
||||
setState(() => switchValue = value),
|
||||
onChanged: (value) {
|
||||
widget.onSwitch(value);
|
||||
setState(() => switchValue = value);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import 'dart:developer';
|
|||
import 'package:country_picker/country_picker.dart';
|
||||
import 'package:fluffychat/pangea/controllers/pangea_controller.dart';
|
||||
import 'package:fluffychat/pangea/pages/settings_learning/settings_learning.dart';
|
||||
import 'package:fluffychat/pangea/utils/country_display.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
|
@ -19,10 +20,13 @@ class CountryPickerTile extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final Profile? profile = pangeaController.userController.userModel?.profile;
|
||||
final Profile profile = pangeaController.userController.profile;
|
||||
return ListTile(
|
||||
title: Text(
|
||||
"${L10n.of(context)!.countryInformation}: ${profile?.countryDisplayName(context) ?? ''} ${profile?.flagEmoji}",
|
||||
"${L10n.of(context)!.countryInformation}: ${CountryDisplayUtil.countryDisplayName(
|
||||
profile.userSettings.country,
|
||||
context,
|
||||
) ?? ''} ${CountryDisplayUtil.flagEmoji(profile.userSettings.country)}",
|
||||
),
|
||||
trailing: const Icon(Icons.edit_outlined),
|
||||
onTap: () => showCountryPicker(
|
||||
|
|
|
|||
|
|
@ -88,13 +88,14 @@ pLanguageDialog(BuildContext parentContext, Function callback) async {
|
|||
context: context,
|
||||
future: () async {
|
||||
try {
|
||||
await pangeaController.userController
|
||||
.updateUserProfile(
|
||||
sourceLanguage:
|
||||
selectedSourceLanguage.langCode,
|
||||
targetLanguage:
|
||||
selectedTargetLanguage.langCode,
|
||||
);
|
||||
pangeaController.userController
|
||||
.updateProfile((profile) {
|
||||
profile.userSettings.sourceLanguage =
|
||||
selectedSourceLanguage.langCode;
|
||||
profile.userSettings.targetLanguage =
|
||||
selectedTargetLanguage.langCode;
|
||||
return profile;
|
||||
});
|
||||
Navigator.pop(context);
|
||||
} catch (err, s) {
|
||||
debugger(when: kDebugMode);
|
||||
|
|
|
|||
|
|
@ -1,45 +1,37 @@
|
|||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/pangea/controllers/pangea_controller.dart';
|
||||
import 'package:fluffychat/pangea/utils/error_handler.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class PSettingsSwitchListTile extends StatefulWidget {
|
||||
class ProfileSettingsSwitchListTile extends StatefulWidget {
|
||||
final bool defaultValue;
|
||||
final String pStoreKey;
|
||||
final String title;
|
||||
final String? subtitle;
|
||||
final bool local;
|
||||
final Function(bool) onChange;
|
||||
|
||||
const PSettingsSwitchListTile.adaptive({
|
||||
const ProfileSettingsSwitchListTile.adaptive({
|
||||
super.key,
|
||||
this.defaultValue = false,
|
||||
required this.pStoreKey,
|
||||
required this.defaultValue,
|
||||
required this.title,
|
||||
required this.onChange,
|
||||
this.subtitle,
|
||||
this.local = false,
|
||||
});
|
||||
|
||||
@override
|
||||
PSettingsSwitchListTileState createState() => PSettingsSwitchListTileState();
|
||||
}
|
||||
|
||||
class PSettingsSwitchListTileState extends State<PSettingsSwitchListTile> {
|
||||
class PSettingsSwitchListTileState
|
||||
extends State<ProfileSettingsSwitchListTile> {
|
||||
bool currentValue = true;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
currentValue = MatrixState.pangeaController.pStoreService.read(
|
||||
widget.pStoreKey,
|
||||
local: widget.local,
|
||||
) ??
|
||||
widget.defaultValue;
|
||||
currentValue = widget.defaultValue;
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final PangeaController pangeaController = MatrixState.pangeaController;
|
||||
return SwitchListTile.adaptive(
|
||||
value: currentValue,
|
||||
title: Text(widget.title),
|
||||
|
|
@ -47,20 +39,15 @@ class PSettingsSwitchListTileState extends State<PSettingsSwitchListTile> {
|
|||
subtitle: widget.subtitle != null ? Text(widget.subtitle!) : null,
|
||||
onChanged: (bool newValue) async {
|
||||
try {
|
||||
await pangeaController.pStoreService.save(
|
||||
widget.pStoreKey,
|
||||
newValue,
|
||||
local: widget.local,
|
||||
);
|
||||
currentValue = newValue;
|
||||
widget.onChange(newValue);
|
||||
setState(() => currentValue = newValue);
|
||||
} catch (err, s) {
|
||||
ErrorHandler.logError(
|
||||
e: err,
|
||||
m: "Failed to updates user setting ${widget.pStoreKey}",
|
||||
m: "Failed to updates user setting",
|
||||
s: s,
|
||||
);
|
||||
}
|
||||
setState(() {});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -342,8 +342,11 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
|
|||
} else {
|
||||
// #Pangea
|
||||
if (state == LoginState.loggedIn) {
|
||||
await (await pangeaController.userController.completer).future;
|
||||
await pangeaController.subscriptionController.reinitialize();
|
||||
final futures = [
|
||||
pangeaController.userController.reinitialize(),
|
||||
pangeaController.subscriptionController.reinitialize(),
|
||||
];
|
||||
await Future.wait(futures);
|
||||
}
|
||||
String routeDestination;
|
||||
if (state == LoginState.loggedIn) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue