feat: allow users on staging to switch their environment (#2799)

pull/2245/head
ggurdin 6 months ago committed by GitHub
parent 6c3de08019
commit 33425f4406
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -1,3 +1,4 @@
ENVIRONMENT = 'staging'
CHOREO_API = 'https://api.staging.pangea.chat'
FRONTEND_URL='https://app.staging.pangea.chat'
SYNAPSE_URL = 'matrix.staging.pangea.chat'

@ -47,6 +47,8 @@ jobs:
touch public/.env
echo "$WEB_APP_ENV" >> public/.env
cp public/.env public/assets/.env
touch public/assets/envs.json
echo "$ENV_OVERRIDES" >> public/assets/envs.json
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v4
with:

@ -45,6 +45,8 @@ jobs:
rm assets/.env
echo "$WEB_APP_ENV" >> .env
cp .env assets/.env
touch assets/envs.json
echo "$ENV_OVERRIDES" >> assets/envs.json
- name: Apply .env patch
run: git apply ./scripts/enable_mobile_env.patch
- name: Install Fastlane

1
.gitignore vendored

@ -18,6 +18,7 @@ keys.json
!/public/.env
*.env.local_choreo
*.env.prod
envs.json
# libolm package
/assets/js/package

@ -1,3 +1,4 @@
ENVIRONMENT = 'staging'
CHOREO_API = 'https://api.staging.pangea.chat'
FRONTEND_URL = 'https://app.staging.pangea.chat'

@ -4934,5 +4934,7 @@
"joinSpaceOnboardingDesc": "Do you have an invite code or link to a learning community?",
"skipForNow": "Skip for now",
"permissions": "Permissions",
"spaceChildPermission": "Who can add new chats and subspaces to this space"
"spaceChildPermission": "Who can add new chats and subspaces to this space",
"addEnvironmentOverride": "Add environment override",
"defaultOption": "Default"
}

@ -15,7 +15,7 @@ abstract class AppConfig {
static String? get applicationWelcomeMessage => _applicationWelcomeMessage;
// #Pangea
// static String _defaultHomeserver = 'matrix.org';
static String _defaultHomeserver = Environment.synapseURL;
static String get _defaultHomeserver => Environment.synapseURL;
// #Pangea
static String get defaultHomeserver => _defaultHomeserver;
static double fontSizeFactor = 1;
@ -206,9 +206,11 @@ abstract class AppConfig {
if (json['application_welcome_message'] is String) {
_applicationWelcomeMessage = json['application_welcome_message'];
}
if (json['default_homeserver'] is String) {
_defaultHomeserver = json['default_homeserver'];
}
// #Pangea
// if (json['default_homeserver'] is String) {
// _defaultHomeserver = json['default_homeserver'];
// }
// Pangea#
if (json['privacy_url'] is String) {
_privacyUrl = json['privacy_url'];
}

@ -110,7 +110,7 @@ Future<void> startGui(List<Client> clients, SharedPreferences store) async {
// staging or vice versa, logout.
if (firstClient?.userID?.domain != null) {
final isStagingUser = firstClient!.userID!.domain!.contains("staging");
final isStagingServer = Environment.isStaging;
final isStagingServer = Environment.synapseURL.contains("staging");
if (isStagingServer != isStagingUser) {
await firstClient.logout();
}

@ -330,7 +330,7 @@ class SettingsView extends StatelessWidget {
},
),
// Conditional ListTile based on the environment (staging or not)
if (Environment.isStaging)
if (Environment.isStagingEnvironment)
ListTile(
leading: const Icon(Icons.bug_report_outlined),
title: Text(L10n.of(context).connectedToStaging),

@ -25,7 +25,7 @@ import 'package:fluffychat/pangea/practice_activities/practice_selection_repo.da
/// A minimized version of AnalyticsController that get the logged in user's analytics
class GetAnalyticsController extends BaseController {
final GetStorage analyticsBox = GetStorage("analytics_storage");
static final GetStorage analyticsBox = GetStorage("analytics_storage");
late PangeaController _pangeaController;
late PracticeSelectionRepo perMessage;
@ -276,6 +276,15 @@ class GetAnalyticsController extends BaseController {
}
}
Future<void> clearMessagesCache() async =>
analyticsBox.remove(PLocalKey.messagesSinceUpdate);
Future<void> setMessagesCache(Map<dynamic, dynamic> cacheValue) async =>
analyticsBox.write(
PLocalKey.messagesSinceUpdate,
cacheValue,
);
/// A flat list of all locally cached construct uses
List<OneConstructUse> get _locallyCachedConstructs =>
messagesSinceUpdate.values.expand((e) => e).toList();

@ -174,7 +174,7 @@ class LevelUpBannerState extends State<LevelUpBanner>
}
Future<void> _toggleDetails() async {
if (!Environment.isStaging) return;
if (!Environment.isStagingEnvironment) return;
if (mounted) {
setState(() {
@ -282,7 +282,7 @@ class LevelUpBannerState extends State<LevelUpBanner>
),
Row(
children: [
if (Environment.isStaging)
if (Environment.isStagingEnvironment)
AnimatedSize(
duration: FluffyThemes.animationDuration,
child: _error == null

@ -8,7 +8,6 @@ import 'package:fluffychat/pangea/analytics_misc/client_analytics_extension.dart
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
import 'package:fluffychat/pangea/analytics_misc/construct_use_type_enum.dart';
import 'package:fluffychat/pangea/analytics_misc/constructs_model.dart';
import 'package:fluffychat/pangea/common/constants/local.key.dart';
import 'package:fluffychat/pangea/common/controllers/base_controller.dart';
import 'package:fluffychat/pangea/common/controllers/pangea_controller.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
@ -319,16 +318,14 @@ class PutAnalyticsController extends BaseController<AnalyticsStream> {
/// Clears the local cache of recently sent constructs. Called before updating analytics
void clearMessagesSinceUpdate({clearDrafts = false}) {
if (clearDrafts) {
MatrixState.pangeaController.getAnalytics.analyticsBox
.remove(PLocalKey.messagesSinceUpdate);
MatrixState.pangeaController.getAnalytics.clearMessagesCache();
return;
}
final localCache = _pangeaController.getAnalytics.messagesSinceUpdate;
final draftKeys = localCache.keys.where((key) => key.startsWith('draft'));
if (draftKeys.isEmpty) {
MatrixState.pangeaController.getAnalytics.analyticsBox
.remove(PLocalKey.messagesSinceUpdate);
MatrixState.pangeaController.getAnalytics.clearMessagesCache();
return;
}
@ -348,10 +345,8 @@ class PutAnalyticsController extends BaseController<AnalyticsStream> {
final constructJsons = entry.value.map((e) => e.toJson()).toList();
formattedCache[entry.key] = constructJsons;
}
await MatrixState.pangeaController.getAnalytics.analyticsBox.write(
PLocalKey.messagesSinceUpdate,
formattedCache,
);
await MatrixState.pangeaController.getAnalytics
.setMessagesCache(formattedCache);
}
/// Prevent concurrent updates to analytics

@ -3,7 +3,7 @@ import 'package:fluffychat/pangea/common/config/environment.dart';
class BotName {
static String get byEnvironment => Environment.botName != null
? Environment.botName!
: Environment.isStaging
: Environment.isStagingEnvironment
? "@bot:staging.pangea.chat"
: "@bot:pangea.chat";
static String get localBot => "@matrix-bot-test:staging.pangea.chat";

@ -22,7 +22,6 @@ Map<String, dynamic> defaultPowerLevels(String userID) => {
"m.room.tombstone": 100,
},
"users": {
"@bot:staging.pangea.chat": 50,
userID: 100,
},
};

@ -1,25 +1,35 @@
import 'dart:convert';
import 'package:flutter/services.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:get_storage/get_storage.dart';
import 'package:fluffychat/pangea/common/constants/local.key.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
class Environment {
static bool get itIsTime =>
DateTime.utc(2023, 1, 25).isBefore(DateTime.now());
static String get fileName {
return ".env";
}
static bool get isStaging => synapseURL.contains("staging");
static bool get isStagingEnvironment =>
dotenv.env["ENVIRONMENT"] == "staging";
static String get frontendURL {
return dotenv.env["FRONTEND_URL"] ?? "Frontend URL NOT FOUND";
return appConfigOverride?.frontendURL ??
dotenv.env["FRONTEND_URL"] ??
"Frontend URL NOT FOUND";
}
static String get synapseURL {
return dotenv.env['SYNAPSE_URL'] ?? 'Synapse Url not found';
return appConfigOverride?.synapseURL ??
dotenv.env['SYNAPSE_URL'] ??
'Synapse Url not found';
}
static String get homeServer {
String? homeServerFromSynapseURL = dotenv.env['SYNAPSE_URL'];
String? homeServerFromSynapseURL =
appConfigOverride?.synapseURL ?? dotenv.env['SYNAPSE_URL'];
if (homeServerFromSynapseURL != null) {
if (homeServerFromSynapseURL.startsWith("http://")) {
homeServerFromSynapseURL =
@ -34,13 +44,14 @@ class Environment {
homeServerFromSynapseURL.replaceFirst("matrix.", "");
}
}
return dotenv.env["HOME_SERVER"] ??
return appConfigOverride?.homeServer ??
dotenv.env["HOME_SERVER"] ??
homeServerFromSynapseURL ??
'Home Server not found';
}
static String get choreoApi {
final envEntry = dotenv.env['CHOREO_API'];
final envEntry = appConfigOverride?.choreoApi ?? dotenv.env['CHOREO_API'];
if (envEntry == null) {
return "Not found";
}
@ -54,48 +65,214 @@ class Environment {
}
static String get choreoApiKey {
return dotenv.env['CHOREO_API_KEY'] ??
return appConfigOverride?.choreoApiKey ??
dotenv.env['CHOREO_API_KEY'] ??
'e6fa9fa97031ba0c852efe78457922f278a2fbc109752fe18e465337699e9873';
}
static String get sentryDsn {
return dotenv.env["SENTRY_DSN"] ??
return appConfigOverride?.sentryDsn ??
dotenv.env["SENTRY_DSN"] ??
'https://c2fd19ab2cdc4ebb939a32d01c0e9fa1@o225078.ingest.sentry.io/1376295';
}
static String get rcGoogleKey {
return dotenv.env["RC_GOOGLE_KEY"] ?? 'goog_paQMrzFKGzuWZvcMTPkkvIsifJe';
return appConfigOverride?.rcGoogleKey ??
dotenv.env["RC_GOOGLE_KEY"] ??
'goog_paQMrzFKGzuWZvcMTPkkvIsifJe';
}
static String get rcIosKey {
return dotenv.env["RC_IOS_KEY"] ?? 'appl_DUPqnxuLjkBLzhBPTWeDjqNENuv';
}
// This is a public key
static String get rcStripeKey {
return dotenv.env["RC_STRIPE_KEY"] ?? 'strp_YWZxWUeEfvagiefDNoofinaRCOl';
return appConfigOverride?.rcIosKey ??
dotenv.env["RC_IOS_KEY"] ??
'appl_DUPqnxuLjkBLzhBPTWeDjqNENuv';
}
static String get rcOfferingName {
return dotenv.env["RC_OFFERING_NAME"] ?? 'default';
return appConfigOverride?.rcOfferingName ??
dotenv.env["RC_OFFERING_NAME"] ??
'default';
}
static String get stripeManagementUrl {
return dotenv.env["STRIPE_MANAGEMENT_LINK"] ??
return appConfigOverride?.stripeManagementUrl ??
dotenv.env["STRIPE_MANAGEMENT_LINK"] ??
'https://billing.stripe.com/p/login/dR6dSkf5p6rBc4EcMM';
}
static String get supportSpaceId {
return isStaging
? '!gqSNSkvwTpgumyjLsV:staging.pangea.chat'
: '!MvJoWwKJErvFuTYOdq:pangea.chat';
}
static String get supportUserId {
return isStaging ? '@support:staging.pangea.chat' : '@support:pangea.chat';
return synapseURL.contains('staging')
? '@support:staging.pangea.chat'
: '@support:pangea.chat';
}
static String? get botName {
return dotenv.env["BOT_NAME"];
return appConfigOverride?.botName ?? dotenv.env["BOT_NAME"];
}
static final GetStorage appConfigurationStorage = GetStorage('env_override');
static Future<List<AppConfigOverride>> getAppConfigOverrides() async {
if (!isStagingEnvironment) {
return [];
}
List<dynamic> data = [];
try {
final String jsonString = await rootBundle.loadString('assets/envs.json');
data = jsonDecode(jsonString);
} catch (e, s) {
ErrorHandler.logError(
e: e,
s: s,
data: {},
);
return [];
}
final List<AppConfigOverride> overrides = [];
for (final entry in data) {
if (entry is! Map<String, dynamic>) {
ErrorHandler.logError(
e: Exception("Invalid entry in envs.json"),
s: StackTrace.current,
data: entry,
);
continue;
}
try {
final override = AppConfigOverride.fromJson(entry);
overrides.add(override);
} catch (e, s) {
ErrorHandler.logError(
e: e,
s: s,
data: entry,
);
continue;
}
}
return overrides;
}
static AppConfigOverride? get appConfigOverride {
final entry = appConfigurationStorage.read(PLocalKey.appConfigOverride);
if (entry == null) return null;
try {
return AppConfigOverride.fromJson(entry);
} catch (e) {
ErrorHandler.logError(
e: e,
s: StackTrace.current,
data: entry,
);
return null;
}
}
static Future<void> setAppConfigOverride(AppConfigOverride? override) async {
appConfigurationStorage.write(
PLocalKey.appConfigOverride,
override?.toJson(),
);
}
}
class AppConfigOverride {
final String? environment;
final String? frontendURL;
final String? synapseURL;
final String? homeServer;
final String? choreoApi;
final String? choreoApiKey;
final String? sentryDsn;
final String? rcGoogleKey;
final String? rcIosKey;
final String? rcOfferingName;
final String? stripeManagementUrl;
final String? botName;
const AppConfigOverride({
this.environment,
this.frontendURL,
this.synapseURL,
this.homeServer,
this.choreoApi,
this.choreoApiKey,
this.sentryDsn,
this.rcGoogleKey,
this.rcIosKey,
this.rcOfferingName,
this.stripeManagementUrl,
this.botName,
});
static AppConfigOverride fromJson(Map<String, dynamic> json) {
return AppConfigOverride(
environment: json['environment'] as String?,
frontendURL: json['frontendURL'] as String?,
synapseURL: json['synapseURL'] as String?,
homeServer: json['homeServer'] as String?,
choreoApi: json['choreoApi'] as String?,
choreoApiKey: json['choreoApiKey'] as String?,
sentryDsn: json['sentryDsn'] as String?,
rcGoogleKey: json['rcGoogleKey'] as String?,
rcIosKey: json['rcIosKey'] as String?,
rcOfferingName: json['rcOfferingName'] as String?,
stripeManagementUrl: json['stripeManagementUrl'] as String?,
botName: json['botName'] as String?,
);
}
Map<String, dynamic> toJson() {
return {
'environment': environment,
'frontendURL': frontendURL,
'synapseURL': synapseURL,
'homeServer': homeServer,
'choreoApi': choreoApi,
'choreoApiKey': choreoApiKey,
'sentryDsn': sentryDsn,
'rcGoogleKey': rcGoogleKey,
'rcIosKey': rcIosKey,
'rcOfferingName': rcOfferingName,
'stripeManagementUrl': stripeManagementUrl,
'botName': botName,
};
}
@override
int get hashCode {
return environment.hashCode ^
frontendURL.hashCode ^
synapseURL.hashCode ^
homeServer.hashCode ^
choreoApi.hashCode ^
choreoApiKey.hashCode ^
sentryDsn.hashCode ^
rcGoogleKey.hashCode ^
rcIosKey.hashCode ^
rcOfferingName.hashCode ^
stripeManagementUrl.hashCode ^
botName.hashCode;
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
if (other is! AppConfigOverride) return false;
return environment == other.environment &&
frontendURL == other.frontendURL &&
synapseURL == other.synapseURL &&
homeServer == other.homeServer &&
choreoApi == other.choreoApi &&
choreoApiKey == other.choreoApiKey &&
sentryDsn == other.sentryDsn &&
rcGoogleKey == other.rcGoogleKey &&
rcIosKey == other.rcIosKey &&
rcOfferingName == other.rcOfferingName &&
stripeManagementUrl == other.stripeManagementUrl &&
botName == other.botName;
}
}

@ -10,4 +10,5 @@ class PLocalKey {
static const String justInputtedCode = 'justInputtedCode';
static const String availableSubscriptionInfo = 'availableSubscriptionInfo';
static const String showedUpdateDialog = 'showedUpdateDialog';
static const String appConfigOverride = 'appConfigOverride';
}

@ -107,17 +107,35 @@ class PangeaController {
_logOutfromPangea() {
debugPrint("Pangea logout");
GoogleAnalytics.logout();
_clearCachedData();
clearCache();
}
void _clearCachedData() {
GetStorage('mode_list_storage').erase();
GetStorage('activity_plan_storage').erase();
GetStorage('bookmarked_activities').erase();
GetStorage('objective_list_storage').erase();
GetStorage('topic_list_storage').erase();
GetStorage('lemma_storage').erase();
GetStorage().erase();
static final List<String> _storageKeys = [
'mode_list_storage',
'activity_plan_storage',
'bookmarked_activities',
'objective_list_storage',
'topic_list_storage',
'activity_plan_search_storage',
"analytics_storage",
"version_storage",
'lemma_storage',
'svg_cache',
'morphs_storage',
'morph_meaning_storage',
'practice_record_cache',
'practice_selection_cache',
'class_storage',
'subscription_storage',
'vocab_storage',
];
Future<void> clearCache() async {
final List<Future<void>> futures = [];
for (final key in _storageKeys) {
futures.add(GetStorage(key).erase());
}
await Future.wait(futures);
}
Future<void> checkHomeServerAction() async {
@ -339,7 +357,7 @@ class PangeaController {
_languageStream ??= userController.stateStream.listen((update) {
if (update is Map<String, dynamic> &&
update['prev_target_lang'] != null) {
_clearCachedData();
clearCache();
}
});
}

@ -13,11 +13,11 @@ class PApiUrls {
static String subscriptionPrefix = "/subscription";
static String accountPrefix = "/account";
static String choreoEndpoint =
static String get choreoEndpoint =>
"${Environment.choreoApi}${PApiUrls.choreoPrefix}";
static String subscriptionEndpoint =
static String get subscriptionEndpoint =>
"${Environment.choreoApi}${PApiUrls.subscriptionPrefix}";
static String accountEndpoint =
static String get accountEndpoint =>
"${Environment.choreoApi}${PApiUrls.accountPrefix}";
/// ---------------------- Util --------------------------------------

@ -29,7 +29,7 @@ class ErrorHandler {
options.debug = kDebugMode;
options.environment = kDebugMode
? "debug"
: Environment.isStaging
: Environment.isStagingEnvironment
? "staging"
: "productionC";
},

@ -3,15 +3,57 @@ import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:go_router/go_router.dart';
import 'package:fluffychat/pangea/common/config/environment.dart';
import 'package:fluffychat/pangea/login/pages/pangea_login_scaffold.dart';
import 'package:fluffychat/pangea/login/widgets/app_config_dialog.dart';
import 'package:fluffychat/pangea/login/widgets/full_width_button.dart';
class LoginOrSignupView extends StatelessWidget {
class LoginOrSignupView extends StatefulWidget {
const LoginOrSignupView({super.key});
@override
State<LoginOrSignupView> createState() => LoginOrSignupViewState();
}
class LoginOrSignupViewState extends State<LoginOrSignupView> {
List<AppConfigOverride> _overrides = [];
@override
void initState() {
super.initState();
_loadOverrides();
}
Future<void> _loadOverrides() async {
final overrides = await Environment.getAppConfigOverrides();
if (mounted) {
setState(() => _overrides = overrides);
}
}
Future<void> _setEnvironment() async {
if (_overrides.isEmpty) return;
final resp = await showDialog<AppConfigOverride?>(
context: context,
builder: (context) => AppConfigDialog(overrides: _overrides),
);
await Environment.setAppConfigOverride(resp);
setState(() {});
}
@override
Widget build(BuildContext context) {
return PangeaLoginScaffold(
actions: Environment.isStagingEnvironment && _overrides.isNotEmpty
? [
IconButton(
icon: const Icon(Icons.settings_outlined),
onPressed: _setEnvironment,
),
]
: null,
children: [
FullWidthButton(
title: L10n.of(context).createAnAccount,

@ -13,6 +13,7 @@ class PangeaLoginScaffold extends StatelessWidget {
final List<Widget> children;
final bool showAppName;
final AppBar? customAppBar;
final List<Widget>? actions;
const PangeaLoginScaffold({
required this.children,
@ -21,6 +22,7 @@ class PangeaLoginScaffold extends StatelessWidget {
this.mainAssetUrl,
this.showAppName = true,
this.customAppBar,
this.actions,
super.key,
});
@ -32,6 +34,7 @@ class PangeaLoginScaffold extends StatelessWidget {
appBar: customAppBar ??
AppBar(
toolbarHeight: isColumnMode ? null : 40.0,
actions: actions,
),
body: LayoutBuilder(
builder: (context, constraints) {

@ -0,0 +1,95 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:fluffychat/pangea/common/config/environment.dart';
import 'package:fluffychat/widgets/adaptive_dialogs/adaptive_dialog_action.dart';
class AppConfigDialog extends StatefulWidget {
final List<AppConfigOverride> overrides;
const AppConfigDialog({
super.key,
required this.overrides,
});
@override
State<AppConfigDialog> createState() => AppConfigDialogState();
}
class AppConfigDialogState extends State<AppConfigDialog> {
AppConfigOverride? selectedOverride;
@override
void initState() {
super.initState();
selectedOverride = Environment.appConfigOverride;
}
@override
Widget build(BuildContext context) {
return AlertDialog.adaptive(
title: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 256),
child: Text(
L10n.of(context).addEnvironmentOverride,
textAlign: TextAlign.center,
),
),
content: Material(
type: MaterialType.transparency,
child: Container(
padding: const EdgeInsets.all(16.0),
constraints: const BoxConstraints(
maxWidth: 256,
),
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
...widget.overrides.map((override) {
return RadioListTile<AppConfigOverride?>.adaptive(
title: Text(
override.environment ?? L10n.of(context).unkDisplayName,
),
value: override,
groupValue: selectedOverride,
onChanged: (override) {
setState(() {
selectedOverride = override;
});
},
);
}).toList()
..insert(
0,
RadioListTile<AppConfigOverride?>.adaptive(
title: Text(L10n.of(context).defaultOption),
value: null,
groupValue: selectedOverride,
onChanged: (override) {
setState(() {
selectedOverride = null;
});
},
),
),
],
),
),
),
),
actions: [
AdaptiveDialogAction(
bigButtons: true,
onPressed: () => Navigator.of(context).pop(selectedOverride),
child: Text(L10n.of(context).submit),
),
AdaptiveDialogAction(
bigButtons: true,
onPressed: Navigator.of(context).pop,
child: Text(L10n.of(context).close),
),
],
);
}
}

@ -37,6 +37,7 @@ enum SubscriptionStatus {
}
class SubscriptionController extends BaseController {
static final GetStorage subscriptionBox = GetStorage("subscription_storage");
late PangeaController _pangeaController;
CurrentSubscriptionInfo? currentSubscriptionInfo;
@ -81,7 +82,6 @@ class SubscriptionController extends BaseController {
await initialize();
}
final GetStorage subscriptionBox = GetStorage("subscription_storage");
Future<void> _initialize() async {
try {
if (_userID == null) {
@ -374,6 +374,37 @@ class SubscriptionController extends BaseController {
String? get defaultManagementURL =>
currentSubscriptionInfo?.currentSubscription
?.defaultManagementURL(availableSubscriptionInfo?.appIds);
Future<void> setCachedSubscriptionInfo(
AvailableSubscriptionsInfo info,
) =>
subscriptionBox.write(
PLocalKey.availableSubscriptionInfo,
info.toJson(),
);
Future<AvailableSubscriptionsInfo?> getCachedSubscriptionInfo() async {
final entry = subscriptionBox.read(
PLocalKey.availableSubscriptionInfo,
);
if (entry is! Map<String, dynamic>) {
return null;
}
try {
final resp = AvailableSubscriptionsInfo.fromJson(entry);
return resp.lastUpdated == null ? null : resp;
} catch (e, s) {
ErrorHandler.logError(
e: e,
s: s,
data: {
"entry": entry,
},
);
return null;
}
}
}
enum SubscriptionDuration {

@ -1,6 +1,5 @@
import 'package:collection/collection.dart';
import 'package:fluffychat/pangea/common/constants/local.key.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import 'package:fluffychat/pangea/subscription/controllers/subscription_controller.dart';
import 'package:fluffychat/pangea/subscription/repo/subscription_repo.dart';
@ -74,9 +73,6 @@ class AvailableSubscriptionsInfo {
List<SubscriptionDetails>? allProducts;
DateTime? lastUpdated;
final subscriptionBox =
MatrixState.pangeaController.subscriptionController.subscriptionBox;
AvailableSubscriptionsInfo({
this.appIds,
this.allProducts,
@ -84,7 +80,8 @@ class AvailableSubscriptionsInfo {
});
Future<void> setAvailableSubscriptions() async {
final cachedInfo = _getCachedSubscriptionInfo();
final cachedInfo = await MatrixState.pangeaController.subscriptionController
.getCachedSubscriptionInfo();
appIds ??= cachedInfo?.appIds ?? await SubscriptionRepo.getAppIds();
allProducts ??=
cachedInfo?.allProducts ?? await SubscriptionRepo.getAllProducts();
@ -102,11 +99,8 @@ class AvailableSubscriptionsInfo {
Future<void> _cacheSubscriptionInfo() async {
try {
final json = toJson();
await subscriptionBox.write(
PLocalKey.availableSubscriptionInfo,
json,
);
MatrixState.pangeaController.subscriptionController
.setCachedSubscriptionInfo(this);
} catch (e, s) {
ErrorHandler.logError(
e: e,
@ -119,29 +113,6 @@ class AvailableSubscriptionsInfo {
}
}
AvailableSubscriptionsInfo? _getCachedSubscriptionInfo() {
final json = subscriptionBox.read(
PLocalKey.availableSubscriptionInfo,
);
if (json is! Map<String, dynamic>) {
return null;
}
try {
final resp = AvailableSubscriptionsInfo.fromJson(json);
return resp.lastUpdated == null ? null : resp;
} catch (e, s) {
ErrorHandler.logError(
e: e,
s: s,
data: {
"json": json,
},
);
return null;
}
}
factory AvailableSubscriptionsInfo.fromJson(Map<String, dynamic> json) {
if (!json.containsKey('app_ids') || !json.containsKey('all_products')) {
throw "Cached subscription info is missing required fields";

Loading…
Cancel
Save