From ccb7ef204e63b76808203d029db9649c9c3d7e32 Mon Sep 17 00:00:00 2001 From: Jigar-f Date: Fri, 27 Dec 2024 12:37:16 +0530 Subject: [PATCH 01/19] added plugin for sparrow. --- pubspec.lock | 16 ++++++++++++++++ pubspec.yaml | 2 ++ 2 files changed, 18 insertions(+) diff --git a/pubspec.lock b/pubspec.lock index 54129718b..88b6c7e52 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -892,6 +892,14 @@ packages: description: flutter source: sdk version: "0.0.0" + get: + dependency: transitive + description: + name: get + sha256: e4e7335ede17452b391ed3b2ede016545706c01a02292a6c97619705e7d2a85e + url: "https://pub.dev" + source: hosted + version: "4.6.6" get_it: dependency: "direct main" description: @@ -1822,6 +1830,14 @@ packages: url: "https://pub.dev" source: hosted version: "8.1.0" + surveysparrow_flutter_sdk: + dependency: "direct main" + description: + name: surveysparrow_flutter_sdk + sha256: "3eea5fe3823cc8cb5e96c35eb9dc74e04c321c85031e3cbd09ef59dc525fc4f1" + url: "https://pub.dev" + source: hosted + version: "1.2.0" sync_http: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 1fbb5adf1..937a2e17e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -136,6 +136,8 @@ dependencies: #Loading animated_loading_border: ^0.0.2 shimmer: ^3.0.0 + # Survey sdk + surveysparrow_flutter_sdk: ^1.2.0 dev_dependencies: integration_test: From 8765fa3ffe3019d40a64dc5566e0970d84dcc053 Mon Sep 17 00:00:00 2001 From: Jigar-f Date: Mon, 6 Jan 2025 15:09:09 +0530 Subject: [PATCH 02/19] Created survey service. --- lib/core/service/injection_container.dart | 2 ++ lib/core/service/survey_service.dart | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 lib/core/service/survey_service.dart diff --git a/lib/core/service/injection_container.dart b/lib/core/service/injection_container.dart index e2c92d341..9a6a73433 100644 --- a/lib/core/service/injection_container.dart +++ b/lib/core/service/injection_container.dart @@ -1,9 +1,11 @@ import 'package:get_it/get_it.dart'; import 'package:lantern/core/service/app_purchase.dart'; +import 'package:lantern/core/service/survey_service.dart'; final GetIt sl = GetIt.instance; void init() { //Inject sl.registerLazySingleton(() => AppPurchase()); + sl.registerLazySingleton(() => SurveyService()); } diff --git a/lib/core/service/survey_service.dart b/lib/core/service/survey_service.dart new file mode 100644 index 000000000..55a813a08 --- /dev/null +++ b/lib/core/service/survey_service.dart @@ -0,0 +1,16 @@ +import 'package:surveysparrow_flutter_sdk/surveysparrow.dart'; + +enum SurveyScreens { homeScreen } + +//This class use spot check service for survey +class SurveyService { + final SpotCheck spotCheck = SpotCheck( + domainName: "", + targetToken: "", + userDetails: {}, + ); + + void trackScreen(SurveyScreens screen) { + spotCheck.trackScreen(screen.name); + } +} From 24d284318fba93401e5a37c40b7af64a35d10c57 Mon Sep 17 00:00:00 2001 From: Jigar-f Date: Tue, 7 Jan 2025 17:59:33 +0530 Subject: [PATCH 03/19] Added spot check survey for testing. --- lib/core/service/survey_service.dart | 22 ++- lib/features/checkout/plans.dart | 209 +++++++++++++++------------ 2 files changed, 131 insertions(+), 100 deletions(-) diff --git a/lib/core/service/survey_service.dart b/lib/core/service/survey_service.dart index 55a813a08..37a3a2b7c 100644 --- a/lib/core/service/survey_service.dart +++ b/lib/core/service/survey_service.dart @@ -1,16 +1,24 @@ import 'package:surveysparrow_flutter_sdk/surveysparrow.dart'; -enum SurveyScreens { homeScreen } +import '../utils/common.dart'; + +enum SurveyScreens { + homeScreen, + plansScreen +} //This class use spot check service for survey class SurveyService { - final SpotCheck spotCheck = SpotCheck( - domainName: "", - targetToken: "", - userDetails: {}, - ); + final SpotCheck _spotCheck = SpotCheck( + domainName: "lantern.surveysparrow.com", + targetToken: "tar-87GWRfobkr3uxkKVog9C6V", + userDetails: {}); void trackScreen(SurveyScreens screen) { - spotCheck.trackScreen(screen.name); + _spotCheck.trackScreen(screen.name); + } + + Widget surveyWidget() { + return _spotCheck; } } diff --git a/lib/features/checkout/plans.dart b/lib/features/checkout/plans.dart index d8f84fcaa..ce9cb7b8b 100644 --- a/lib/features/checkout/plans.dart +++ b/lib/features/checkout/plans.dart @@ -1,114 +1,138 @@ -import 'package:lantern/core/utils/common.dart'; import 'package:lantern/core/app/app_loading_dialog.dart'; +import 'package:lantern/core/service/survey_service.dart'; +import 'package:lantern/core/utils/common.dart'; +import 'package:lantern/core/utils/utils.dart'; import 'package:lantern/features/checkout/feature_list.dart'; import 'package:lantern/features/checkout/plan_details.dart'; -import 'package:lantern/core/utils/utils.dart'; @RoutePage(name: "PlansPage") -class PlansPage extends StatelessWidget { +class PlansPage extends StatefulWidget { const PlansPage({super.key}); + + @override + State createState() => _PlansPageState(); +} + +class _PlansPageState extends State { + final surveyService = sl.get(); + + @override + void initState() { + surveyService.trackScreen(SurveyScreens.plansScreen); + super.initState(); + } + @override Widget build(BuildContext context) { - return FullScreenDialog( - bgColor: white, - widget: sessionModel - .proUser((BuildContext context, bool proUser, Widget? child) { - return sessionModel.plans( - builder: ( - context, - Iterable> plans, - Widget? child, - ) { - if (plans.isEmpty) { - // show user option to retry - return RetryWidget(onRetryTap: () => onRetryTap(context)); - } - return Column( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Expanded( - child: ListView( - shrinkWrap: true, + return Scaffold( + body: Stack( + children: [ + FullScreenDialog( + bgColor: white, + widget: sessionModel + .proUser((BuildContext context, bool proUser, Widget? child) { + return sessionModel.plans( + builder: ( + context, + Iterable> plans, + Widget? child, + ) { + if (plans.isEmpty) { + // show user option to retry + return RetryWidget(onRetryTap: () => onRetryTap(context)); + } + return Column( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.end, children: [ - _buildHeader(context), - Container( - color: white, - padding: const EdgeInsetsDirectional.only( - start: 24, - end: 24, - ), - child: Column( + Expanded( + child: ListView( + shrinkWrap: true, children: [ - // * Renewal text or upsell - if (plans.last.value.renewalText != '') - Padding( - padding: const EdgeInsetsDirectional.only( - bottom: 12.0, - ), - child: CText( - plans.last.value.renewalText, - style: tsBody1, - ), - ), - const Padding( - padding: EdgeInsetsDirectional.only( - bottom: 8.0, - ), - child: CDivider(), - ), - FeatureList(), - const CDivider(height: 24), - ], - ), - ), - // * Card - ...plans.toList().reversed.map( - (plan) => Container( + _buildHeader(context), + Container( color: white, padding: const EdgeInsetsDirectional.only( - start: 32.0, - end: 32.0, + start: 24, + end: 24, ), - child: PlanCard( - plan: plan.value, - isPro: proUser, + child: Column( + children: [ + // * Renewal text or upsell + if (plans.last.value.renewalText != '') + Padding( + padding: const EdgeInsetsDirectional.only( + bottom: 12.0, + ), + child: CText( + plans.last.value.renewalText, + style: tsBody1, + ), + ), + const Padding( + padding: EdgeInsetsDirectional.only( + bottom: 8.0, + ), + child: CDivider(), + ), + FeatureList(), + const CDivider(height: 24), + ], ), ), - ), - FutureBuilder( - future: AppMethods.showRestorePurchaseButton(proUser), - builder: (context, snapshot) { - if (snapshot.hasData && snapshot.data as bool) { - return Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - TextButton( - onPressed: () => restorePurchases(context), - style: TextButton.styleFrom( - foregroundColor: pink5, + // * Card + ...plans.toList().reversed.map( + (plan) => Container( + color: white, + padding: const EdgeInsetsDirectional.only( + start: 32.0, + end: 32.0, + ), + child: PlanCard( + plan: plan.value, + isPro: proUser, + ), ), - child: CText( - "restore_purchase".i18n.toUpperCase(), - style: tsButton.copiedWith( - color: pink5, - )), ), - ], - ); - } - return const SizedBox(); - }, + FutureBuilder( + future: + AppMethods.showRestorePurchaseButton(proUser), + builder: (context, snapshot) { + if (snapshot.hasData && snapshot.data as bool) { + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + TextButton( + onPressed: () => + restorePurchases(context), + style: TextButton.styleFrom( + foregroundColor: pink5, + ), + child: CText( + "restore_purchase".i18n.toUpperCase(), + style: tsButton.copiedWith( + color: pink5, + )), + ), + ], + ); + } + return const SizedBox(); + }, + ), + ], + ), ), + _buildFooter(context, proUser), ], - ), - ), - _buildFooter(context, proUser), - ], - ); - }, - ); - }), + ); + }, + ); + }), + ), + sl.get().surveyWidget() + ], + ), ); } @@ -181,7 +205,6 @@ class PlansPage extends StatelessWidget { } // class methods - Future onRetryTap(BuildContext context) async { try { AppLoadingDialog.showLoadingDialog(context); From f3161c7b9f3cb4d075c550208043b0199dbdc7a8 Mon Sep 17 00:00:00 2001 From: Jigar-f Date: Mon, 13 Jan 2025 18:16:14 +0530 Subject: [PATCH 04/19] Add spot check support in homscreen. --- desktop/app/config.go | 2 ++ lib/core/service/survey_service.dart | 12 +++----- lib/core/utils/config.dart | 42 ++++++++++++++------------ lib/features/account/report_issue.dart | 2 +- lib/features/checkout/plans.dart | 1 - lib/features/home/home.dart | 26 +++++++++++----- lib/features/vpn/vpn_tab.dart | 2 +- 7 files changed, 50 insertions(+), 37 deletions(-) diff --git a/desktop/app/config.go b/desktop/app/config.go index dbeb6c1b8..6c7fb2cae 100644 --- a/desktop/app/config.go +++ b/desktop/app/config.go @@ -54,6 +54,7 @@ type ConfigOptions struct { ExpirationDate string `json:"expirationDate"` Chat ChatOptions `json:"chat"` ProxyAll bool `json:"proxyAll"` + Country string `json:"country"` } func (s *configService) StartService(channel ws.UIChannel) (err error) { @@ -109,6 +110,7 @@ func (app *App) sendConfigOptions() { ExpirationDate: app.settings.GetExpirationDate(), Devices: app.devices(), ProxyAll: app.settings.GetProxyAll(), + Country: app.settings.GetCountry(), Chat: ChatOptions{ AcceptedTermsVersion: 0, OnBoardingStatus: false, diff --git a/lib/core/service/survey_service.dart b/lib/core/service/survey_service.dart index 37a3a2b7c..dd38200a3 100644 --- a/lib/core/service/survey_service.dart +++ b/lib/core/service/survey_service.dart @@ -2,17 +2,15 @@ import 'package:surveysparrow_flutter_sdk/surveysparrow.dart'; import '../utils/common.dart'; -enum SurveyScreens { - homeScreen, - plansScreen -} +enum SurveyScreens { homeScreen, plansScreen, vpnTap } //This class use spot check service for survey class SurveyService { final SpotCheck _spotCheck = SpotCheck( - domainName: "lantern.surveysparrow.com", - targetToken: "tar-87GWRfobkr3uxkKVog9C6V", - userDetails: {}); + domainName: "lantern.surveysparrow.com", + targetToken: "tar-avDLqWvShqjDf3fydPDpbQ", + userDetails: {}, + ); void trackScreen(SurveyScreens screen) { _spotCheck.trackScreen(screen.name); diff --git a/lib/core/utils/config.dart b/lib/core/utils/config.dart index 3151a97a6..982f2743d 100644 --- a/lib/core/utils/config.dart +++ b/lib/core/utils/config.dart @@ -47,6 +47,7 @@ class ConfigOptions { final Map? paymentMethods; final _ChatOptions chat; + final String country; ConfigOptions({ this.developmentMode = false, @@ -62,10 +63,11 @@ class ConfigOptions { this.httpProxyAddr = '', this.socksProxyAddr = '', this.deviceId = '', - this.plans = null, - this.paymentMethods = null, + this.plans, + this.paymentMethods, required this.devices, this.chat = const _ChatOptions(), + required this.country, }); bool get startupReady => @@ -83,24 +85,24 @@ class ConfigOptions { final paymentMethods = paymentMethodsFromJson(parsedJson['paymentMethods']); return ConfigOptions( - developmentMode: parsedJson['developmentMode'], - authEnabled: parsedJson['authEnabled'], - chatEnabled: parsedJson['chatEnabled'], - httpProxyAddr: parsedJson['httpProxyAddr'], - socksProxyAddr: parsedJson['socksProxyAddr'], - splitTunneling: parsedJson['splitTunneling'], - hasSucceedingProxy: parsedJson['hasSucceedingProxy'], - fetchedGlobalConfig: parsedJson['fetchedGlobalConfig'], - fetchedProxiesConfig: parsedJson['fetchedProxiesConfig'], - plans: plans, - chat: _ChatOptions.fromJson(parsedJson['chat']), - paymentMethods: paymentMethods, - devices: _parseDevices(parsedJson), - replicaAddr: parsedJson['replicaAddr'].toString(), - deviceId: parsedJson['deviceId'].toString(), - expirationDate: parsedJson['expirationDate'].toString(), - sdkVersion: parsedJson['sdkVersion'].toString(), - ); + developmentMode: parsedJson['developmentMode'], + authEnabled: parsedJson['authEnabled'], + chatEnabled: parsedJson['chatEnabled'], + httpProxyAddr: parsedJson['httpProxyAddr'], + socksProxyAddr: parsedJson['socksProxyAddr'], + splitTunneling: parsedJson['splitTunneling'], + hasSucceedingProxy: parsedJson['hasSucceedingProxy'], + fetchedGlobalConfig: parsedJson['fetchedGlobalConfig'], + fetchedProxiesConfig: parsedJson['fetchedProxiesConfig'], + plans: plans, + chat: _ChatOptions.fromJson(parsedJson['chat']), + paymentMethods: paymentMethods, + devices: _parseDevices(parsedJson), + replicaAddr: parsedJson['replicaAddr'].toString(), + deviceId: parsedJson['deviceId'].toString(), + expirationDate: parsedJson['expirationDate'].toString(), + sdkVersion: parsedJson['sdkVersion'].toString(), + country: parsedJson['country'] ?? ""); } static Devices _parseDevices(Map json) { diff --git a/lib/features/account/report_issue.dart b/lib/features/account/report_issue.dart index a44d80380..504dbc46a 100644 --- a/lib/features/account/report_issue.dart +++ b/lib/features/account/report_issue.dart @@ -7,7 +7,7 @@ import 'package:lantern/core/utils/common.dart'; class ReportIssue extends StatefulWidget { final String? description; - const ReportIssue({Key? key, this.description}) : super(key: key); + const ReportIssue({super.key, this.description}); @override State createState() => _ReportIssueState(); diff --git a/lib/features/checkout/plans.dart b/lib/features/checkout/plans.dart index ce9cb7b8b..95e747688 100644 --- a/lib/features/checkout/plans.dart +++ b/lib/features/checkout/plans.dart @@ -18,7 +18,6 @@ class _PlansPageState extends State { @override void initState() { - surveyService.trackScreen(SurveyScreens.plansScreen); super.initState(); } diff --git a/lib/features/home/home.dart b/lib/features/home/home.dart index ec7b187ca..84728f0da 100644 --- a/lib/features/home/home.dart +++ b/lib/features/home/home.dart @@ -12,6 +12,7 @@ import 'package:lantern/features/vpn/vpn.dart'; import 'package:lantern/features/vpn/vpn_tab.dart'; import 'package:logger/logger.dart'; +import '../../core/service/survey_service.dart'; import '../messaging/messaging_model.dart'; @RoutePage(name: 'Home') @@ -19,18 +20,20 @@ class HomePage extends StatefulWidget { const HomePage({super.key}); @override - _HomePageState createState() => _HomePageState(); + State createState() => _HomePageState(); } class _HomePageState extends State { Function()? _cancelEventSubscription; Function userNew = once(); + final surveyService = sl.get(); @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((timeStamp) { _startupSequence(); + surveyService.trackScreen(SurveyScreens.homeScreen); }); } @@ -164,14 +167,23 @@ class _HomePageState extends State { _checkForFirstTimeVisit(); }); } - return messagingModel.getOnBoardingStatus((_, isOnboarded, child) { final tab = tabModel.currentIndex; return Scaffold( - body: buildBody(tab, isOnboarded), - bottomNavigationBar: CustomBottomBar( - selectedTab: tab, - isDevelop: developmentMode, + backgroundColor: Colors.transparent, + body: Stack( + children: [ + Scaffold( + body: buildBody(tab, isOnboarded), + bottomNavigationBar: CustomBottomBar( + selectedTab: tab, + isDevelop: developmentMode, + ), + ), + // Wrap the survey widget in a scaffold to ensure it's + // always on top of the bottom bar. + surveyService.surveyWidget(), + ], ), ); }); @@ -196,7 +208,7 @@ class _HomePageState extends State { ? Chats() : Welcome(); case TAB_VPN: - return const VPNTab(); + return VPNTab(); case TAB_REPLICA: return ReplicaTab(); case TAB_ACCOUNT: diff --git a/lib/features/vpn/vpn_tab.dart b/lib/features/vpn/vpn_tab.dart index e6c57e358..7b3d28603 100644 --- a/lib/features/vpn/vpn_tab.dart +++ b/lib/features/vpn/vpn_tab.dart @@ -12,7 +12,7 @@ import 'vpn_status.dart'; import 'vpn_switch.dart'; class VPNTab extends StatelessWidget { - const VPNTab({Key? key}) : super(key: key); + const VPNTab({super.key}); @override Widget build(BuildContext context) { From 79f5fa46ef6efa86e2e958b4b23dd7bca6eb1563 Mon Sep 17 00:00:00 2001 From: Jigar-f Date: Tue, 14 Jan 2025 12:17:37 +0530 Subject: [PATCH 05/19] Write survey config on file. --- lib/core/app/app_enums.dart | 7 +++ lib/core/service/survey_service.dart | 69 +++++++++++++++++++++++++++- lib/features/home/home.dart | 8 +++- lib/features/vpn/vpn_switch.dart | 6 +++ 4 files changed, 88 insertions(+), 2 deletions(-) diff --git a/lib/core/app/app_enums.dart b/lib/core/app/app_enums.dart index b78ca8be6..b6b86b600 100644 --- a/lib/core/app/app_enums.dart +++ b/lib/core/app/app_enums.dart @@ -23,3 +23,10 @@ extension AuthFlowExtension on AuthFlow { bool get isUpdateAccount => this == AuthFlow.updateAccount; bool get isRestoreAccount => this == AuthFlow.restoreAccount; } + +enum VpnStatus{ + connected, + disconnected, + connecting, + disconnecting +} diff --git a/lib/core/service/survey_service.dart b/lib/core/service/survey_service.dart index dd38200a3..5ffcda77e 100644 --- a/lib/core/service/survey_service.dart +++ b/lib/core/service/survey_service.dart @@ -1,8 +1,9 @@ +import 'package:path_provider/path_provider.dart'; import 'package:surveysparrow_flutter_sdk/surveysparrow.dart'; import '../utils/common.dart'; -enum SurveyScreens { homeScreen, plansScreen, vpnTap } +enum SurveyScreens { homeScreen } //This class use spot check service for survey class SurveyService { @@ -12,6 +13,10 @@ class SurveyService { userDetails: {}, ); + SurveyService() { + _createConfigIfNeeded(); + } + void trackScreen(SurveyScreens screen) { _spotCheck.trackScreen(screen.name); } @@ -19,4 +24,66 @@ class SurveyService { Widget surveyWidget() { return _spotCheck; } + + Future get _surveyConfigPath async { + final cacheDir = await getApplicationCacheDirectory(); + final filePath = '${cacheDir.path}/survey_config.json'; + return filePath; + } + + Future _createConfigIfNeeded() async { + final filePath = await _surveyConfigPath; + final file = File(filePath); + if (!await file.exists()) { + await file.create(recursive: true); + + const surveyConfig = { + "isShowSurvey": false, + "lastSurveyDate": "", + "vpnConnectCount": 0 + }; + final jsonString = jsonEncode(surveyConfig); + await file.writeAsString(jsonString); + } + } + + Future incrementVpnConnectCount() async { + try { + final filePath = await _surveyConfigPath; + final file = File(filePath); + if (await file.exists()) { + final content = await file.readAsString(); + final surveyConfig = jsonDecode(content) as Map; + // Increment the vpnConnectCount field + surveyConfig['vpnConnectCount'] = + (surveyConfig['vpnConnectCount'] ?? 0) + 1; + final updatedJsonString = jsonEncode(surveyConfig); + await file.writeAsString(updatedJsonString); + appLogger.d('vpnConnectCount updated successfully.'); + } else { + appLogger.d('File does not exist. No changes were made.'); + } + } catch (e) { + appLogger.d('Failed to update vpnConnectCount: $e'); + } + } + + Future surveyAvailable() async { + try { + final filePath = await _surveyConfigPath; + final file = File(filePath); + if (await file.exists()) { + final content = await file.readAsString(); + final Map surveyConfig = jsonDecode(content); + final vpnConnectCount = surveyConfig['vpnConnectCount'] ?? 0; + return vpnConnectCount >= 10; + } else { + appLogger.d('Survey config file does not exist.'); + return false; + } + } catch (e) { + appLogger.e('Failed to check survey availability: $e'); + return false; + } + } } diff --git a/lib/features/home/home.dart b/lib/features/home/home.dart index 84728f0da..878e59b3e 100644 --- a/lib/features/home/home.dart +++ b/lib/features/home/home.dart @@ -33,7 +33,6 @@ class _HomePageState extends State { super.initState(); WidgetsBinding.instance.addPostFrameCallback((timeStamp) { _startupSequence(); - surveyService.trackScreen(SurveyScreens.homeScreen); }); } @@ -42,6 +41,13 @@ class _HomePageState extends State { channelListener(); return; } + checkIfSurveyIsAvailable(); + } + + Future checkIfSurveyIsAvailable() async { + if (await surveyService.surveyAvailable()) { + surveyService.trackScreen(SurveyScreens.homeScreen); + } } void channelListener() { diff --git a/lib/features/vpn/vpn_switch.dart b/lib/features/vpn/vpn_switch.dart index a9ad3b141..fd9fa6f86 100644 --- a/lib/features/vpn/vpn_switch.dart +++ b/lib/features/vpn/vpn_switch.dart @@ -3,6 +3,7 @@ import 'dart:ui' as ui; import 'package:animated_toggle_switch/animated_toggle_switch.dart'; import 'package:lantern/common/ui/custom/internet_checker.dart'; import 'package:lantern/core/helpers/ad_helper.dart'; +import 'package:lantern/core/service/survey_service.dart'; import 'package:lantern/core/utils/common.dart'; import 'package:lantern/core/utils/common_desktop.dart'; import 'package:lantern/features/vpn/vpn.dart'; @@ -137,6 +138,11 @@ class _VPNSwitchState extends State { }, ); } + + if (vpnStatus == VpnStatus.disconnected.name) { + // Update survey count + sl.get().incrementVpnConnectCount(); + } } Future vpnProcessForDesktop(String vpnStatus) async { From 5f32ac75d97fd0fff5e26ad0be45a9bb3b818a6a Mon Sep 17 00:00:00 2001 From: Jigar-f Date: Tue, 14 Jan 2025 12:28:16 +0530 Subject: [PATCH 06/19] Use vpn status as enum to avoid mistakes. --- lib/core/service/survey_service.dart | 25 +++++++++++++++---------- lib/features/vpn/vpn_switch.dart | 28 ++++++++++++++++------------ 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/lib/core/service/survey_service.dart b/lib/core/service/survey_service.dart index 5ffcda77e..f85a381b6 100644 --- a/lib/core/service/survey_service.dart +++ b/lib/core/service/survey_service.dart @@ -34,16 +34,21 @@ class SurveyService { Future _createConfigIfNeeded() async { final filePath = await _surveyConfigPath; final file = File(filePath); - if (!await file.exists()) { - await file.create(recursive: true); + try { + if (!await file.exists()) { + await file.create(recursive: true); - const surveyConfig = { - "isShowSurvey": false, - "lastSurveyDate": "", - "vpnConnectCount": 0 - }; - final jsonString = jsonEncode(surveyConfig); - await file.writeAsString(jsonString); + const surveyConfig = { + "isShowSurvey": false, + "lastSurveyDate": "", + "vpnConnectCount": 0 + }; + final jsonString = jsonEncode(surveyConfig); + await file.writeAsString(jsonString); + appLogger.d("Write init config done $filePath"); + } + } catch (e) { + appLogger.e("Error while creating config"); } } @@ -76,7 +81,7 @@ class SurveyService { final content = await file.readAsString(); final Map surveyConfig = jsonDecode(content); final vpnConnectCount = surveyConfig['vpnConnectCount'] ?? 0; - return vpnConnectCount >= 10; + return vpnConnectCount >= 5; } else { appLogger.d('Survey config file does not exist.'); return false; diff --git a/lib/features/vpn/vpn_switch.dart b/lib/features/vpn/vpn_switch.dart index fd9fa6f86..da4ba2b6e 100644 --- a/lib/features/vpn/vpn_switch.dart +++ b/lib/features/vpn/vpn_switch.dart @@ -15,7 +15,6 @@ class VPNSwitch extends StatefulWidget { @override State createState() => _VPNSwitchState(); } - //implement this switch with loading implementation //https://pub.dev/packages/animated_toggle_switch class _VPNSwitchState extends State { @@ -38,9 +37,9 @@ class _VPNSwitchState extends State { disabledOpacity: 1, enabled: (internetStatusProvider.isConnected && !vpnNotifier.isFlashlightInitializedFailed), - initialValue: vpnStatus == 'connected' || - vpnStatus == 'disconnecting' || - vpnStatus == 'connecting', + initialValue: vpnStatus == VpnStatus.connected.name || + vpnStatus == VpnStatus.disconnecting.name || + vpnStatus == VpnStatus.connecting.name, activeColor: onSwitchColor, inactiveColor: (internetStatusProvider.isConnected && !vpnNotifier.isFlashlightInitializedFailed) @@ -54,7 +53,7 @@ class _VPNSwitchState extends State { } else { return CustomAnimatedToggleSwitch( current: vpnNotifier.vpnStatus.value, - values: const ['disconnected', 'connected'], + values: [VpnStatus.disconnected.name, VpnStatus.connected.name], iconBuilder: (context, local, global) => const SizedBox(), height: 72, spacing: 28.0, @@ -90,10 +89,10 @@ class _VPNSwitchState extends State { }, onChanged: (newValue) {}, onTap: (props) { - if (vpnNotifier.vpnStatus.value == 'connected') { - vpnProcessForDesktop('disconnected'); + if (vpnNotifier.vpnStatus.value == VpnStatus.connected.name) { + vpnProcessForDesktop(VpnStatus.disconnected.name); } else { - vpnProcessForDesktop('connected'); + vpnProcessForDesktop(VpnStatus.connected.name); } }, ); @@ -112,7 +111,8 @@ class _VPNSwitchState extends State { } bool isIdle(String vpnStatus) => - vpnStatus != 'connecting' && vpnStatus != 'disconnecting'; + vpnStatus != VpnStatus.connecting.name && + vpnStatus != VpnStatus.disconnecting.name; Future vpnProcessForMobile( bool newValue, String vpnStatus, bool userHasPermission) async { @@ -120,7 +120,7 @@ class _VPNSwitchState extends State { //if ads is not ready then wait for at least 5 seconds and then show ads //if ads is ready then show ads immediately - if (vpnStatus != 'connected' && userHasPermission) { + if (vpnStatus != VpnStatus.connected.name && userHasPermission) { if (!await adHelper.isAdsReadyToShow()) { await vpnModel.connectingDelay(newValue); await Future.delayed(const Duration(seconds: 5)); @@ -130,7 +130,7 @@ class _VPNSwitchState extends State { await vpnModel.switchVPN(newValue); //add delayed to avoid flickering - if (vpnStatus != 'connected') { + if (vpnStatus != VpnStatus.connected.name) { Future.delayed( const Duration(seconds: 1), () async { @@ -150,8 +150,12 @@ class _VPNSwitchState extends State { try { await LanternFFI.sendVpnStatus(vpnStatus); vpnNotifier.updateVpnStatus(vpnStatus); + if (vpnStatus == VpnStatus.disconnected.name) { + // Update survey count + sl.get().incrementVpnConnectCount(); + } } catch (e) { - await vpnNotifier.updateVpnStatus('disconnected'); + await vpnNotifier.updateVpnStatus(VpnStatus.disconnected.name); showSnackbar(context: context, content: e.localizedDescription); mainLogger.e("Error while sending vpn status: $e"); } From ef5fb0da7b5a3929a1443ad12d2923ca57b6d948 Mon Sep 17 00:00:00 2001 From: Jigar-f Date: Tue, 14 Jan 2025 13:12:36 +0530 Subject: [PATCH 07/19] Update home.dart --- lib/features/home/home.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/features/home/home.dart b/lib/features/home/home.dart index 878e59b3e..c65fdcc4b 100644 --- a/lib/features/home/home.dart +++ b/lib/features/home/home.dart @@ -37,11 +37,11 @@ class _HomePageState extends State { } void _startupSequence() { + checkIfSurveyIsAvailable(); if (isMobile()) { channelListener(); return; } - checkIfSurveyIsAvailable(); } Future checkIfSurveyIsAvailable() async { From 401a46ed0f3d9d31a9a59e006424cb8fbdf1919a Mon Sep 17 00:00:00 2001 From: Jigar-f Date: Tue, 14 Jan 2025 15:34:48 +0530 Subject: [PATCH 08/19] Add country segmentation for survey. --- lib/core/service/survey_service.dart | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/lib/core/service/survey_service.dart b/lib/core/service/survey_service.dart index f85a381b6..f131d88e7 100644 --- a/lib/core/service/survey_service.dart +++ b/lib/core/service/survey_service.dart @@ -7,6 +7,8 @@ enum SurveyScreens { homeScreen } //This class use spot check service for survey class SurveyService { + // Need to have spot check for each region + // Russia, Belarus, Ukraine, China, Iran, UAE, Myanmar final SpotCheck _spotCheck = SpotCheck( domainName: "lantern.surveysparrow.com", targetToken: "tar-avDLqWvShqjDf3fydPDpbQ", @@ -22,7 +24,31 @@ class SurveyService { } Widget surveyWidget() { - return _spotCheck; + switch (sessionModel.country.value?.toLowerCase()) { + case 'ru': + //Russia + return _spotCheck; + case 'ir': + //Iran + return _spotCheck; + case 'by': + //Belarus + return _spotCheck; + case 'ua': + //Ukraine + return _spotCheck; + case 'cn': + //China + return _spotCheck; + case 'mm': + //Myanmar + return _spotCheck; + case 'uae': + //UAE + return _spotCheck; + default: + return const SizedBox.shrink(); + } } Future get _surveyConfigPath async { From a99f58664d0e5024576488a73e1dc20f8020285c Mon Sep 17 00:00:00 2001 From: Jigar-f Date: Wed, 15 Jan 2025 15:59:27 +0530 Subject: [PATCH 09/19] Added localisation support in survey. --- lib/core/service/survey_service.dart | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/core/service/survey_service.dart b/lib/core/service/survey_service.dart index f131d88e7..53abbe8da 100644 --- a/lib/core/service/survey_service.dart +++ b/lib/core/service/survey_service.dart @@ -11,8 +11,9 @@ class SurveyService { // Russia, Belarus, Ukraine, China, Iran, UAE, Myanmar final SpotCheck _spotCheck = SpotCheck( domainName: "lantern.surveysparrow.com", - targetToken: "tar-avDLqWvShqjDf3fydPDpbQ", + targetToken: "tar-9ewB7CH6jtNvtk3MyUQM3i", userDetails: {}, + sparrowLang: Localization.locale.split('_').first, ); SurveyService() { @@ -46,6 +47,10 @@ class SurveyService { case 'uae': //UAE return _spotCheck; + // This is just for testing + case 'in': + //UAE + return _spotCheck; default: return const SizedBox.shrink(); } @@ -64,11 +69,7 @@ class SurveyService { if (!await file.exists()) { await file.create(recursive: true); - const surveyConfig = { - "isShowSurvey": false, - "lastSurveyDate": "", - "vpnConnectCount": 0 - }; + const surveyConfig = {"lastSurveyDate": "", "vpnConnectCount": 0}; final jsonString = jsonEncode(surveyConfig); await file.writeAsString(jsonString); appLogger.d("Write init config done $filePath"); @@ -107,7 +108,9 @@ class SurveyService { final content = await file.readAsString(); final Map surveyConfig = jsonDecode(content); final vpnConnectCount = surveyConfig['vpnConnectCount'] ?? 0; - return vpnConnectCount >= 5; + appLogger.d('Survey config. ${surveyConfig.toString()}'); + if (vpnConnectCount >= 2) {} + return vpnConnectCount >= 2; } else { appLogger.d('Survey config file does not exist.'); return false; From 17ba2059ba479323fe10d5beadb00efbb4f58a5c Mon Sep 17 00:00:00 2001 From: Jigar-f Date: Wed, 15 Jan 2025 16:27:43 +0530 Subject: [PATCH 10/19] Fix Di issue. --- lib/core/service/injection_container.dart | 7 ++++++- lib/main.dart | 5 +---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/core/service/injection_container.dart b/lib/core/service/injection_container.dart index 9a6a73433..0481782ef 100644 --- a/lib/core/service/injection_container.dart +++ b/lib/core/service/injection_container.dart @@ -1,11 +1,16 @@ import 'package:get_it/get_it.dart'; import 'package:lantern/core/service/app_purchase.dart'; import 'package:lantern/core/service/survey_service.dart'; +import 'package:lantern/core/utils/common.dart'; final GetIt sl = GetIt.instance; void init() { //Inject - sl.registerLazySingleton(() => AppPurchase()); + if (isMobile()) { + sl.registerLazySingleton(() => AppPurchase()); + sl().init(); + } + sl.registerLazySingleton(() => SurveyService()); } diff --git a/lib/main.dart b/lib/main.dart index b9ed0cde6..0a37c66d7 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -4,7 +4,6 @@ import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_driver/driver_extension.dart'; import 'package:google_mobile_ads/google_mobile_ads.dart'; import 'package:lantern/app.dart'; -import 'package:lantern/core/service/app_purchase.dart'; import 'package:lantern/core/utils/common.dart'; import 'package:lantern/core/utils/common_desktop.dart'; import 'package:lantern/features/replica/ui/utils.dart'; @@ -29,7 +28,7 @@ Future main() async { } catch (error) { appLogger.e("Error loading .env file: $error"); } - + init(); if (isDesktop()) { if (Platform.isWindows) await initializeWebViewEnvironment(); await windowManager.ensureInitialized(); @@ -39,8 +38,6 @@ Future main() async { } else { await _initGoogleMobileAds(); // Inject all the services - init(); - sl().init(); // Due to replica we are using lot of cache // clear if goes to above limit CustomCacheManager().clearCacheIfExceeded(); From 39ad3926ac0ac415037a7f0ff2003a5a12d3322b Mon Sep 17 00:00:00 2001 From: Jigar-f Date: Thu, 16 Jan 2025 13:37:18 +0530 Subject: [PATCH 11/19] Complete country segment. --- lib/core/app/app_secret.dart | 13 +++- lib/core/service/survey_service.dart | 109 +++++++++++++++++++++++---- lib/core/utils/common.dart | 4 +- lib/features/home/home.dart | 2 +- 4 files changed, 108 insertions(+), 20 deletions(-) diff --git a/lib/core/app/app_secret.dart b/lib/core/app/app_secret.dart index 86d462a62..06efa8547 100644 --- a/lib/core/app/app_secret.dart +++ b/lib/core/app/app_secret.dart @@ -5,12 +5,21 @@ import 'package:flutter_dotenv/flutter_dotenv.dart'; class AppSecret { static String androidAdsAppId = dotenv.get('Android_interstitialAd'); static String iOSAdsAppId = dotenv.get('IOS_interstitialAd'); + static String testingSpotCheckTargetToken = dotenv.get('TESTING_SPOTCHECK_TARGET_TOKEN'); + static String iranSpotCheckTargetToken = dotenv.get('IRAN_SPOTCHECK_TARGET_TOKEN'); + static String russiaSpotCheckTargetToken = dotenv.get('RUSSIA_SPOTCHECK_TARGET_TOKEN'); + static String ukraineSpotCheckTargetToken = dotenv.get('UKRAINE_SPOTCHECK_TARGET_TOKEN'); + static String belarusSpotCheckTargetToken = dotenv.get('BELARUS_SPOTCHECK_TARGET_TOKEN'); + static String chinaSpotCheckTargetToken = dotenv.get('CHINA_SPOTCHECK_TARGET_TOKEN'); + static String UAEspotCheckTargetToken = dotenv.get('UAE_SPOTCHECK_TARGET_TOKEN'); + static String myanmarSpotCheckTargetToken = dotenv.get('MYANMAR_SPOTCHECK_TARGET_TOKEN'); + + + static String tos = 'https://s3.amazonaws.com/lantern/Lantern-TOS.pdf'; static String privacyPolicy = 'https://s3.amazonaws.com/lantern/LanternPrivacyPolicy.pdf'; static String privacyPolicyV2 = 'https://lantern.io/privacy'; static String tosV2 = 'https://lantern.io/terms'; - static String videoInterstitialZoneId = dotenv.get('VideoInterstitialZoneId'); - static String interstitialZoneId =dotenv.get('InterstitialZoneId'); static String dnsConfig() { diff --git a/lib/core/service/survey_service.dart b/lib/core/service/survey_service.dart index 53abbe8da..bacecb399 100644 --- a/lib/core/service/survey_service.dart +++ b/lib/core/service/survey_service.dart @@ -9,48 +9,125 @@ enum SurveyScreens { homeScreen } class SurveyService { // Need to have spot check for each region // Russia, Belarus, Ukraine, China, Iran, UAE, Myanmar - final SpotCheck _spotCheck = SpotCheck( + + final int _VPNCONNECTED_COUNT = 10; + + final SpotCheck _testingSpotCheck = SpotCheck( domainName: "lantern.surveysparrow.com", - targetToken: "tar-9ewB7CH6jtNvtk3MyUQM3i", + targetToken: AppSecret.testingSpotCheckTargetToken, userDetails: {}, sparrowLang: Localization.locale.split('_').first, ); + final SpotCheck _russiaSpotCheck = SpotCheck( + domainName: "lantern.surveysparrow.com", + targetToken: AppSecret.russiaSpotCheckTargetToken, + // Should Not Pass userDetails as const + userDetails: {}); + + final SpotCheck _iranSpotCheck = SpotCheck( + domainName: "lantern.surveysparrow.com", + targetToken: AppSecret.iranSpotCheckTargetToken, + // Should Not Pass userDetails as const + userDetails: {}); + + final SpotCheck _ukraineSpotCheck = SpotCheck( + domainName: "lantern.surveysparrow.com", + targetToken: AppSecret.ukraineSpotCheckTargetToken, + // Should Not Pass userDetails as const + userDetails: {}); + final SpotCheck _belarusSpotCheck = SpotCheck( + domainName: "lantern.surveysparrow.com", + targetToken: AppSecret.belarusSpotCheckTargetToken, + // Should Not Pass userDetails as const + userDetails: {}); + + final SpotCheck _chinaSpotCheck = SpotCheck( + domainName: "lantern.surveysparrow.com", + targetToken: AppSecret.chinaSpotCheckTargetToken, + // Should Not Pass userDetails as const + userDetails: {}); + + final SpotCheck _UAEspotCheck = SpotCheck( + domainName: "lantern.surveysparrow.com", + targetToken: AppSecret.UAEspotCheckTargetToken, + // Should Not Pass userDetails as const + userDetails: {}); + + final SpotCheck _myanmarSpotCheck = SpotCheck( + domainName: "lantern.surveysparrow.com", + targetToken: AppSecret.myanmarSpotCheckTargetToken, + // Should Not Pass userDetails as const + userDetails: {}); + SurveyService() { _createConfigIfNeeded(); } void trackScreen(SurveyScreens screen) { - _spotCheck.trackScreen(screen.name); + switch (sessionModel.country.value?.toLowerCase()) { + case 'ru': + //Russia + _russiaSpotCheck.trackScreen(screen.name); + break; + case 'ir': + //Iran + return _iranSpotCheck.trackScreen(screen.name); + break; + case 'by': + //Belarus + _belarusSpotCheck.trackScreen(screen.name); + break; + case 'ua': + //Ukraine + _ukraineSpotCheck.trackScreen(screen.name); + break; + case 'cn': + //China + _chinaSpotCheck.trackScreen(screen.name); + break; + case 'mm': + //Myanmar + _myanmarSpotCheck.trackScreen(screen.name); + break; + case 'uae': + //UAE + _UAEspotCheck.trackScreen(screen.name); + break; + // This is just for testing + case 'in': + _testingSpotCheck.trackScreen(screen.name); + break; + } } Widget surveyWidget() { switch (sessionModel.country.value?.toLowerCase()) { case 'ru': //Russia - return _spotCheck; + return _russiaSpotCheck; case 'ir': //Iran - return _spotCheck; + return _iranSpotCheck; case 'by': //Belarus - return _spotCheck; + return _belarusSpotCheck; case 'ua': //Ukraine - return _spotCheck; + return _ukraineSpotCheck; case 'cn': //China - return _spotCheck; + return _chinaSpotCheck; case 'mm': //Myanmar - return _spotCheck; + return _myanmarSpotCheck; case 'uae': //UAE - return _spotCheck; + return _UAEspotCheck; // This is just for testing case 'in': //UAE - return _spotCheck; + return _testingSpotCheck; default: return const SizedBox.shrink(); } @@ -69,7 +146,7 @@ class SurveyService { if (!await file.exists()) { await file.create(recursive: true); - const surveyConfig = {"lastSurveyDate": "", "vpnConnectCount": 0}; + const surveyConfig = {"vpnConnectCount": 0}; final jsonString = jsonEncode(surveyConfig); await file.writeAsString(jsonString); appLogger.d("Write init config done $filePath"); @@ -109,8 +186,12 @@ class SurveyService { final Map surveyConfig = jsonDecode(content); final vpnConnectCount = surveyConfig['vpnConnectCount'] ?? 0; appLogger.d('Survey config. ${surveyConfig.toString()}'); - if (vpnConnectCount >= 2) {} - return vpnConnectCount >= 2; + if (vpnConnectCount >= _VPNCONNECTED_COUNT) { + appLogger.d('Survey is available.'); + return true; + } + appLogger.d('Survey is not available.'); + return false; } else { appLogger.d('Survey config file does not exist.'); return false; diff --git a/lib/core/utils/common.dart b/lib/core/utils/common.dart index 46f1c6023..f3e1b663b 100644 --- a/lib/core/utils/common.dart +++ b/lib/core/utils/common.dart @@ -128,10 +128,8 @@ final appLogger = Logger( errorMethodCount: 5, colors: true, printEmojis: true, - printTime: true, ), - filter: ProductionFilter(), - output: ConsoleOutput(), + level: Level.debug, ); bool isMobile() { diff --git a/lib/features/home/home.dart b/lib/features/home/home.dart index c65fdcc4b..70e2599a0 100644 --- a/lib/features/home/home.dart +++ b/lib/features/home/home.dart @@ -37,8 +37,8 @@ class _HomePageState extends State { } void _startupSequence() { - checkIfSurveyIsAvailable(); if (isMobile()) { + checkIfSurveyIsAvailable(); channelListener(); return; } From de54938f55096dbd31517b06e7dc2830403f22c8 Mon Sep 17 00:00:00 2001 From: Jigar-f Date: Thu, 16 Jan 2025 13:51:49 +0530 Subject: [PATCH 12/19] Update app.env step in CI. --- .github/workflows/build.yml | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b669771f2..472cd4249 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -224,18 +224,12 @@ jobs: fileDir: './android/app' encodedString: ${{ secrets.KEYSTORE }} - - name: Generate app.env - env: - ANDROID_INTERSTITIAL_AD_ID: ${{ secrets.INTERSTITIAL_AD_UNIT_ID }} - IOS_INTERSTITIAL_AD_ID: ${{ secrets.INTERSTITIAL_AD_UNIT_ID_IOS }} - TAPSELL_VIDEO_INTERSTITIAL_ZONE_ID: ${{ secrets.TAPSELL_VIDEO_INTERSTITIAL_ZONE_ID }} - TAPSELL_INTERSTITIAL_ZONE_ID: ${{ secrets.TAPSELL_INTERSTITIAL_ZONE_ID }} + + - name: Decode APP_ENV and write to app.env run: | - touch app.env - echo "Android_interstitialAd=$ANDROID_INTERSTITIAL_AD_ID" > app.env - echo "IOS_interstitialAd=$IOS_INTERSTITIAL_AD_ID" >> app.env - echo "VideoInterstitialZoneId=$TAPSELL_VIDEO_INTERSTITIAL_ZONE_ID" >> app.env - echo "InterstitialZoneId=$TAPSELL_INTERSTITIAL_ZONE_ID" >> app.env + echo "${{ secrets.APP_ENV }}" | base64 --decode > app.env + echo "File 'app.env' created." + ls -lh app.env - name: Extract app version from pubspec.yaml id: extract_version From 08ce4bf6347c218bd855fb5efc81d7487a5c8df7 Mon Sep 17 00:00:00 2001 From: Jigar-f Date: Thu, 16 Jan 2025 16:37:25 +0530 Subject: [PATCH 13/19] Fix merge conflicts. --- lib/main.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/main.dart b/lib/main.dart index 0a37c66d7..949212629 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -28,7 +28,7 @@ Future main() async { } catch (error) { appLogger.e("Error loading .env file: $error"); } - init(); + initServices(); if (isDesktop()) { if (Platform.isWindows) await initializeWebViewEnvironment(); await windowManager.ensureInitialized(); From 4e2e94cac3066e8bda5138ed92b7075df8795b6a Mon Sep 17 00:00:00 2001 From: Jigar-f Date: Mon, 20 Jan 2025 17:30:50 +0530 Subject: [PATCH 14/19] Added support for macos survey. --- lib/core/service/survey_service.dart | 2 +- lib/core/service/websocket_subscriber.dart | 1 + lib/features/home/home.dart | 2 +- pubspec.lock | 73 +++++++++++----------- pubspec.yaml | 8 ++- 5 files changed, 46 insertions(+), 40 deletions(-) diff --git a/lib/core/service/survey_service.dart b/lib/core/service/survey_service.dart index bacecb399..aa9ea7840 100644 --- a/lib/core/service/survey_service.dart +++ b/lib/core/service/survey_service.dart @@ -72,7 +72,7 @@ class SurveyService { break; case 'ir': //Iran - return _iranSpotCheck.trackScreen(screen.name); + _iranSpotCheck.trackScreen(screen.name); break; case 'by': //Belarus diff --git a/lib/core/service/websocket_subscriber.dart b/lib/core/service/websocket_subscriber.dart index 142f77d8b..f28ff7d42 100644 --- a/lib/core/service/websocket_subscriber.dart +++ b/lib/core/service/websocket_subscriber.dart @@ -113,6 +113,7 @@ class WebsocketSubscriber { sessionModel.isAuthEnabled.value = config.authEnabled; sessionModel.configNotifier.value = config; + sessionModel.country.value = config.country; _updatePlans(config.plans); _updatePaymentMethods(config.paymentMethods); break; diff --git a/lib/features/home/home.dart b/lib/features/home/home.dart index 70e2599a0..878e59b3e 100644 --- a/lib/features/home/home.dart +++ b/lib/features/home/home.dart @@ -38,10 +38,10 @@ class _HomePageState extends State { void _startupSequence() { if (isMobile()) { - checkIfSurveyIsAvailable(); channelListener(); return; } + checkIfSurveyIsAvailable(); } Future checkIfSurveyIsAvailable() async { diff --git a/pubspec.lock b/pubspec.lock index 1ab1bc3eb..f938f7ea4 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,23 +5,23 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab" + sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834 url: "https://pub.dev" source: hosted - version: "76.0.0" + version: "72.0.0" _macros: dependency: transitive description: dart source: sdk - version: "0.3.3" + version: "0.3.2" analyzer: dependency: transitive description: name: analyzer - sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e" + sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139 url: "https://pub.dev" source: hosted - version: "6.11.0" + version: "6.7.0" animated_loading_border: dependency: "direct main" description: @@ -338,10 +338,10 @@ packages: dependency: transitive description: name: collection - sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dev" source: hosted - version: "1.19.0" + version: "1.18.0" connectivity_plus: dependency: transitive description: @@ -927,10 +927,11 @@ packages: google_mobile_ads: dependency: "direct main" description: - name: google_mobile_ads - sha256: "4775006383a27a5d86d46f8fb452bfcb17794fc0a46c732979e49a8eb1c8963f" - url: "https://pub.dev" - source: hosted + path: "packages/google_mobile_ads" + ref: "6aa897e3dcc2b2d97f4df61192b015388ce876d6" + resolved-ref: "6aa897e3dcc2b2d97f4df61192b015388ce876d6" + url: "https://github.com/googleads/googleads-mobile-flutter" + source: git version: "5.2.0" graphs: dependency: transitive @@ -1109,18 +1110,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" url: "https://pub.dev" source: hosted - version: "10.0.7" + version: "10.0.5" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" url: "https://pub.dev" source: hosted - version: "3.0.8" + version: "3.0.5" leak_tracker_testing: dependency: transitive description: @@ -1165,10 +1166,10 @@ packages: dependency: transitive description: name: macros - sha256: "1d9e801cd66f7ea3663c45fc708450db1fa57f988142c64289142c9b7ee80656" + sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536" url: "https://pub.dev" source: hosted - version: "0.1.3-main.0" + version: "0.1.2-main.4" markdown: dependency: transitive description: @@ -1709,7 +1710,7 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.0" + version: "0.0.99" sliver_tools: dependency: "direct main" description: @@ -1786,10 +1787,10 @@ packages: dependency: transitive description: name: stack_trace - sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" url: "https://pub.dev" source: hosted - version: "1.12.0" + version: "1.11.1" stop_watch_timer: dependency: "direct main" description: @@ -1818,10 +1819,10 @@ packages: dependency: transitive description: name: string_scanner - sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.2.0" styled_text: dependency: "direct main" description: @@ -1834,10 +1835,10 @@ packages: dependency: "direct main" description: name: surveysparrow_flutter_sdk - sha256: "3eea5fe3823cc8cb5e96c35eb9dc74e04c321c85031e3cbd09ef59dc525fc4f1" + sha256: "04b2605aab35aa7aa86c4224ce92cabb6e20b6acb38e155270ce24cd2cc32164" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.2.1" sync_http: dependency: transitive description: @@ -1866,10 +1867,10 @@ packages: dependency: transitive description: name: test_api - sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" url: "https://pub.dev" source: hosted - version: "0.7.3" + version: "0.7.2" timezone: dependency: transitive description: @@ -2058,10 +2059,10 @@ packages: dependency: transitive description: name: vm_service - sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" url: "https://pub.dev" source: hosted - version: "14.3.0" + version: "14.2.5" watcher: dependency: transitive description: @@ -2098,26 +2099,26 @@ packages: dependency: transitive description: name: webdriver - sha256: "3d773670966f02a646319410766d3b5e1037efb7f07cc68f844d5e06cd4d61c8" + sha256: "003d7da9519e1e5f329422b36c4dcdf18d7d2978d1ba099ea4e45ba490ed845e" url: "https://pub.dev" source: hosted - version: "3.0.4" + version: "3.0.3" webview_flutter: dependency: transitive description: name: webview_flutter - sha256: ec81f57aa1611f8ebecf1d2259da4ef052281cb5ad624131c93546c79ccc7736 + sha256: "889a0a678e7c793c308c68739996227c9661590605e70b1f6cf6b9a6634f7aec" url: "https://pub.dev" source: hosted - version: "4.9.0" + version: "4.10.0" webview_flutter_android: dependency: transitive description: name: webview_flutter_android - sha256: "47a8da40d02befda5b151a26dba71f47df471cddd91dfdb7802d0a87c5442558" + sha256: "5568f17a9c25c0fdd0737900fa1c2d1fee2d780bc212d9aec10c2d1f48ef0f59" url: "https://pub.dev" source: hosted - version: "3.16.9" + version: "4.3.1" webview_flutter_platform_interface: dependency: transitive description: @@ -2130,10 +2131,10 @@ packages: dependency: transitive description: name: webview_flutter_wkwebview - sha256: "3be297aa4ca78205abdd284cf55f168c35246c75b3079990ad8ba9d257681a30" + sha256: "4adc14ea9a770cc9e2c8f1ac734536bd40e82615bd0fa6b94be10982de656cc7" url: "https://pub.dev" source: hosted - version: "3.16.2" + version: "3.17.0" win32: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 937a2e17e..4f164cdfb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -124,7 +124,11 @@ dependencies: in_app_purchase: ^3.2.0 # Ads - google_mobile_ads: ^5.2.0 + google_mobile_ads: + git: + url: https://github.com/googleads/googleads-mobile-flutter + ref: 6aa897e3dcc2b2d97f4df61192b015388ce876d6 + path: packages/google_mobile_ads retry: ^3.1.2 # Generate bindings to native libraries @@ -137,7 +141,7 @@ dependencies: animated_loading_border: ^0.0.2 shimmer: ^3.0.0 # Survey sdk - surveysparrow_flutter_sdk: ^1.2.0 + surveysparrow_flutter_sdk: ^1.2.1 dev_dependencies: integration_test: From 1b2c57de7ccc7856c6323f66063565d56e09dcd3 Mon Sep 17 00:00:00 2001 From: Jigar-f Date: Tue, 21 Jan 2025 11:56:24 +0530 Subject: [PATCH 15/19] Add default testing survey. --- lib/core/service/survey_service.dart | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/lib/core/service/survey_service.dart b/lib/core/service/survey_service.dart index aa9ea7840..d193ed324 100644 --- a/lib/core/service/survey_service.dart +++ b/lib/core/service/survey_service.dart @@ -72,7 +72,7 @@ class SurveyService { break; case 'ir': //Iran - _iranSpotCheck.trackScreen(screen.name); + _iranSpotCheck.trackScreen(screen.name); break; case 'by': //Belarus @@ -95,7 +95,7 @@ class SurveyService { _UAEspotCheck.trackScreen(screen.name); break; // This is just for testing - case 'in': + default: _testingSpotCheck.trackScreen(screen.name); break; } @@ -125,11 +125,8 @@ class SurveyService { //UAE return _UAEspotCheck; // This is just for testing - case 'in': - //UAE - return _testingSpotCheck; default: - return const SizedBox.shrink(); + return _testingSpotCheck; } } From 7c7a2224e59d4c5b308e81969d332d11f752bdb9 Mon Sep 17 00:00:00 2001 From: Jigar-f Date: Mon, 27 Jan 2025 14:47:16 +0530 Subject: [PATCH 16/19] Dynamic survey handling. --- lib/core/service/survey_service.dart | 187 ++++++++++++--------------- lib/core/utils/common.dart | 1 + lib/features/home/home.dart | 2 +- lib/features/home/session_model.dart | 2 +- 4 files changed, 85 insertions(+), 107 deletions(-) diff --git a/lib/core/service/survey_service.dart b/lib/core/service/survey_service.dart index d193ed324..9bc0c34b2 100644 --- a/lib/core/service/survey_service.dart +++ b/lib/core/service/survey_service.dart @@ -5,129 +5,106 @@ import '../utils/common.dart'; enum SurveyScreens { homeScreen } +enum SurveyCountry { + russia('ru'), + belarus('by'), + ukraine('ua'), + china('cn'), + iran('ir'), + uae('uae'), + myanmar('mm'), + testing('testing'); + + const SurveyCountry(this.countryCode); + + final String countryCode; +} + //This class use spot check service for survey class SurveyService { // Need to have spot check for each region // Russia, Belarus, Ukraine, China, Iran, UAE, Myanmar + SpotCheck? spotCheck; final int _VPNCONNECTED_COUNT = 10; - final SpotCheck _testingSpotCheck = SpotCheck( - domainName: "lantern.surveysparrow.com", - targetToken: AppSecret.testingSpotCheckTargetToken, - userDetails: {}, - sparrowLang: Localization.locale.split('_').first, - ); - - final SpotCheck _russiaSpotCheck = SpotCheck( - domainName: "lantern.surveysparrow.com", - targetToken: AppSecret.russiaSpotCheckTargetToken, - // Should Not Pass userDetails as const - userDetails: {}); - - final SpotCheck _iranSpotCheck = SpotCheck( - domainName: "lantern.surveysparrow.com", - targetToken: AppSecret.iranSpotCheckTargetToken, - // Should Not Pass userDetails as const - userDetails: {}); - - final SpotCheck _ukraineSpotCheck = SpotCheck( - domainName: "lantern.surveysparrow.com", - targetToken: AppSecret.ukraineSpotCheckTargetToken, - // Should Not Pass userDetails as const - userDetails: {}); - final SpotCheck _belarusSpotCheck = SpotCheck( - domainName: "lantern.surveysparrow.com", - targetToken: AppSecret.belarusSpotCheckTargetToken, - // Should Not Pass userDetails as const - userDetails: {}); - - final SpotCheck _chinaSpotCheck = SpotCheck( - domainName: "lantern.surveysparrow.com", - targetToken: AppSecret.chinaSpotCheckTargetToken, - // Should Not Pass userDetails as const - userDetails: {}); - - final SpotCheck _UAEspotCheck = SpotCheck( - domainName: "lantern.surveysparrow.com", - targetToken: AppSecret.UAEspotCheckTargetToken, - // Should Not Pass userDetails as const - userDetails: {}); - - final SpotCheck _myanmarSpotCheck = SpotCheck( - domainName: "lantern.surveysparrow.com", - targetToken: AppSecret.myanmarSpotCheckTargetToken, - // Should Not Pass userDetails as const - userDetails: {}); - SurveyService() { _createConfigIfNeeded(); + countryListener(); } - void trackScreen(SurveyScreens screen) { - switch (sessionModel.country.value?.toLowerCase()) { - case 'ru': - //Russia - _russiaSpotCheck.trackScreen(screen.name); + void countryListener() { + if (sessionModel.country.value!.isNotEmpty) { + createSpotCheckByCountry(sessionModel.country.value!.toLowerCase()); + return; + } + sessionModel.country.addListener(() { + final country = sessionModel.country.value; + appLogger.d('Country listener $country'); + if (country != null && country.isNotEmpty) { + appLogger.d('Country found $country'); + createSpotCheckByCountry(country.toLowerCase()); + sessionModel.country + .removeListener(() {}); // Remove listener after getting value + } + }); + } + + //Create method to create spot check by country + //argument by string and use enum for country + //make sure when create country should not be null or empty + SpotCheck createSpotCheckByCountry(String country) { + appLogger.d('Create spot check for country $country'); + if (spotCheck != null) { + return spotCheck!; + } + final surveyCountry = SurveyCountry.values.firstWhere( + (e) => e.countryCode == country, + orElse: () => SurveyCountry.testing, + ); + String targetToken; + switch (surveyCountry) { + case SurveyCountry.russia: + targetToken = AppSecret.russiaSpotCheckTargetToken; break; - case 'ir': - //Iran - _iranSpotCheck.trackScreen(screen.name); + case SurveyCountry.belarus: + targetToken = AppSecret.belarusSpotCheckTargetToken; break; - case 'by': - //Belarus - _belarusSpotCheck.trackScreen(screen.name); + case SurveyCountry.ukraine: + targetToken = AppSecret.ukraineSpotCheckTargetToken; break; - case 'ua': - //Ukraine - _ukraineSpotCheck.trackScreen(screen.name); + case SurveyCountry.china: + targetToken = AppSecret.chinaSpotCheckTargetToken; break; - case 'cn': - //China - _chinaSpotCheck.trackScreen(screen.name); + case SurveyCountry.iran: + targetToken = AppSecret.iranSpotCheckTargetToken; break; - case 'mm': - //Myanmar - _myanmarSpotCheck.trackScreen(screen.name); + case SurveyCountry.uae: + targetToken = AppSecret.UAEspotCheckTargetToken; break; - case 'uae': - //UAE - _UAEspotCheck.trackScreen(screen.name); + case SurveyCountry.myanmar: + targetToken = AppSecret.myanmarSpotCheckTargetToken; break; - // This is just for testing + case SurveyCountry.testing: default: - _testingSpotCheck.trackScreen(screen.name); + targetToken = AppSecret.testingSpotCheckTargetToken; + appLogger.d('${country.toUpperCase()} not found, using testing token'); break; } + spotCheck = SpotCheck( + domainName: "lantern.surveysparrow.com", + targetToken: targetToken, + userDetails: {}); + return spotCheck!; + } + + void trackScreen(SurveyScreens screen) { + appLogger.d('Track screen $screen'); + spotCheck?.trackScreen(screen.name); } Widget surveyWidget() { - switch (sessionModel.country.value?.toLowerCase()) { - case 'ru': - //Russia - return _russiaSpotCheck; - case 'ir': - //Iran - return _iranSpotCheck; - case 'by': - //Belarus - return _belarusSpotCheck; - case 'ua': - //Ukraine - return _ukraineSpotCheck; - case 'cn': - //China - return _chinaSpotCheck; - case 'mm': - //Myanmar - return _myanmarSpotCheck; - case 'uae': - //UAE - return _UAEspotCheck; - // This is just for testing - default: - return _testingSpotCheck; - } + return spotCheck!; } Future get _surveyConfigPath async { @@ -165,12 +142,12 @@ class SurveyService { (surveyConfig['vpnConnectCount'] ?? 0) + 1; final updatedJsonString = jsonEncode(surveyConfig); await file.writeAsString(updatedJsonString); - appLogger.d('vpnConnectCount updated successfully.'); + appLogger.i('vpnConnectCount updated successfully.'); } else { - appLogger.d('File does not exist. No changes were made.'); + appLogger.i('File does not exist. No changes were made.'); } } catch (e) { - appLogger.d('Failed to update vpnConnectCount: $e'); + appLogger.i('Failed to update vpnConnectCount: $e'); } } @@ -182,15 +159,15 @@ class SurveyService { final content = await file.readAsString(); final Map surveyConfig = jsonDecode(content); final vpnConnectCount = surveyConfig['vpnConnectCount'] ?? 0; - appLogger.d('Survey config. ${surveyConfig.toString()}'); + appLogger.i('Survey config. ${surveyConfig.toString()}'); if (vpnConnectCount >= _VPNCONNECTED_COUNT) { appLogger.d('Survey is available.'); return true; } - appLogger.d('Survey is not available.'); + appLogger.i('Survey is not available.'); return false; } else { - appLogger.d('Survey config file does not exist.'); + appLogger.i('Survey config file does not exist.'); return false; } } catch (e) { diff --git a/lib/core/utils/common.dart b/lib/core/utils/common.dart index f3e1b663b..9cca429e4 100644 --- a/lib/core/utils/common.dart +++ b/lib/core/utils/common.dart @@ -128,6 +128,7 @@ final appLogger = Logger( errorMethodCount: 5, colors: true, printEmojis: true, + ), level: Level.debug, ); diff --git a/lib/features/home/home.dart b/lib/features/home/home.dart index 878e59b3e..c65fdcc4b 100644 --- a/lib/features/home/home.dart +++ b/lib/features/home/home.dart @@ -37,11 +37,11 @@ class _HomePageState extends State { } void _startupSequence() { + checkIfSurveyIsAvailable(); if (isMobile()) { channelListener(); return; } - checkIfSurveyIsAvailable(); } Future checkIfSurveyIsAvailable() async { diff --git a/lib/features/home/session_model.dart b/lib/features/home/session_model.dart index 4a06d2436..a4d3b3306 100644 --- a/lib/features/home/session_model.dart +++ b/lib/features/home/session_model.dart @@ -55,7 +55,7 @@ class SessionModel extends Model { * So show banner only if proxyAvailable is false */ proxyAvailable = singleValueNotifier('hasSucceedingProxy', true); - country = singleValueNotifier('geo_country_code', 'US'); + country = singleValueNotifier('geo_country_code', ''); /// This warning is not needed for the Non pro user /// This flow is not needed anymore From 21a0b5815789148b2bbf3124886a12b5aecd371d Mon Sep 17 00:00:00 2001 From: Jigar-f Date: Mon, 27 Jan 2025 14:57:18 +0530 Subject: [PATCH 17/19] Read config changes. --- lib/core/service/survey_service.dart | 56 +++++++++++++--------------- 1 file changed, 25 insertions(+), 31 deletions(-) diff --git a/lib/core/service/survey_service.dart b/lib/core/service/survey_service.dart index 9bc0c34b2..34946b704 100644 --- a/lib/core/service/survey_service.dart +++ b/lib/core/service/survey_service.dart @@ -119,7 +119,6 @@ class SurveyService { try { if (!await file.exists()) { await file.create(recursive: true); - const surveyConfig = {"vpnConnectCount": 0}; final jsonString = jsonEncode(surveyConfig); await file.writeAsString(jsonString); @@ -132,20 +131,14 @@ class SurveyService { Future incrementVpnConnectCount() async { try { - final filePath = await _surveyConfigPath; - final file = File(filePath); - if (await file.exists()) { - final content = await file.readAsString(); - final surveyConfig = jsonDecode(content) as Map; - // Increment the vpnConnectCount field - surveyConfig['vpnConnectCount'] = - (surveyConfig['vpnConnectCount'] ?? 0) + 1; - final updatedJsonString = jsonEncode(surveyConfig); - await file.writeAsString(updatedJsonString); - appLogger.i('vpnConnectCount updated successfully.'); - } else { - appLogger.i('File does not exist. No changes were made.'); - } + final content = await readSurveyConfig(); + final surveyConfig = jsonDecode(content.$2) as Map; + // Increment the vpnConnectCount field + surveyConfig['vpnConnectCount'] = + (surveyConfig['vpnConnectCount'] ?? 0) + 1; + final updatedJsonString = jsonEncode(surveyConfig); + await content.$1.writeAsString(updatedJsonString); + appLogger.i('vpnConnectCount updated successfully.'); } catch (e) { appLogger.i('Failed to update vpnConnectCount: $e'); } @@ -153,26 +146,27 @@ class SurveyService { Future surveyAvailable() async { try { - final filePath = await _surveyConfigPath; - final file = File(filePath); - if (await file.exists()) { - final content = await file.readAsString(); - final Map surveyConfig = jsonDecode(content); - final vpnConnectCount = surveyConfig['vpnConnectCount'] ?? 0; - appLogger.i('Survey config. ${surveyConfig.toString()}'); - if (vpnConnectCount >= _VPNCONNECTED_COUNT) { - appLogger.d('Survey is available.'); - return true; - } - appLogger.i('Survey is not available.'); - return false; - } else { - appLogger.i('Survey config file does not exist.'); - return false; + final content = await readSurveyConfig(); + final Map surveyConfig = jsonDecode(content.$2); + final vpnConnectCount = surveyConfig['vpnConnectCount'] ?? 0; + appLogger.i('Survey config. ${surveyConfig.toString()}'); + if (vpnConnectCount >= _VPNCONNECTED_COUNT) { + appLogger.d('Survey is available.'); + return true; } + appLogger.i('Survey is not available.'); + return false; } catch (e) { appLogger.e('Failed to check survey availability: $e'); return false; } } + + //this read survey config method will return file and string + Future<(File, String)> readSurveyConfig() async { + final filePath = await _surveyConfigPath; + final file = File(filePath); + final content = await file.readAsString(); + return (file, content); + } } From ee92ab60062e179e76fcaf7bd67413965507ab63 Mon Sep 17 00:00:00 2001 From: Jigar-f Date: Mon, 27 Jan 2025 17:09:02 +0530 Subject: [PATCH 18/19] Hide survey in windows and Linux. --- lib/core/service/injection_container.dart | 1 + lib/core/service/survey_service.dart | 6 + lib/features/checkout/plans.dart | 207 ++++++++++------------ lib/features/home/home.dart | 4 + 4 files changed, 105 insertions(+), 113 deletions(-) diff --git a/lib/core/service/injection_container.dart b/lib/core/service/injection_container.dart index 559cdeb7b..650b642ec 100644 --- a/lib/core/service/injection_container.dart +++ b/lib/core/service/injection_container.dart @@ -12,5 +12,6 @@ void initServices() { sl().init(); } + sl.registerLazySingleton(() => SurveyService()); } diff --git a/lib/core/service/survey_service.dart b/lib/core/service/survey_service.dart index 34946b704..648585165 100644 --- a/lib/core/service/survey_service.dart +++ b/lib/core/service/survey_service.dart @@ -29,6 +29,9 @@ class SurveyService { final int _VPNCONNECTED_COUNT = 10; SurveyService() { + if (Platform.isWindows || Platform.isLinux) { + return; + } _createConfigIfNeeded(); countryListener(); } @@ -104,6 +107,9 @@ class SurveyService { } Widget surveyWidget() { + if (Platform.isWindows || Platform.isLinux) { + return const SizedBox(); + } return spotCheck!; } diff --git a/lib/features/checkout/plans.dart b/lib/features/checkout/plans.dart index 95e747688..e38ae86d7 100644 --- a/lib/features/checkout/plans.dart +++ b/lib/features/checkout/plans.dart @@ -6,131 +6,112 @@ import 'package:lantern/features/checkout/feature_list.dart'; import 'package:lantern/features/checkout/plan_details.dart'; @RoutePage(name: "PlansPage") -class PlansPage extends StatefulWidget { +class PlansPage extends StatelessWidget { const PlansPage({super.key}); - @override - State createState() => _PlansPageState(); -} - -class _PlansPageState extends State { - final surveyService = sl.get(); - - @override - void initState() { - super.initState(); - } - @override Widget build(BuildContext context) { return Scaffold( - body: Stack( - children: [ - FullScreenDialog( - bgColor: white, - widget: sessionModel - .proUser((BuildContext context, bool proUser, Widget? child) { - return sessionModel.plans( - builder: ( - context, - Iterable> plans, - Widget? child, - ) { - if (plans.isEmpty) { - // show user option to retry - return RetryWidget(onRetryTap: () => onRetryTap(context)); - } - return Column( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Expanded( - child: ListView( - shrinkWrap: true, - children: [ - _buildHeader(context), - Container( - color: white, - padding: const EdgeInsetsDirectional.only( - start: 24, - end: 24, - ), - child: Column( - children: [ - // * Renewal text or upsell - if (plans.last.value.renewalText != '') - Padding( - padding: const EdgeInsetsDirectional.only( - bottom: 12.0, - ), - child: CText( - plans.last.value.renewalText, - style: tsBody1, - ), - ), - const Padding( - padding: EdgeInsetsDirectional.only( - bottom: 8.0, - ), - child: CDivider(), + body: FullScreenDialog( + bgColor: white, + widget: sessionModel + .proUser((BuildContext context, bool proUser, Widget? child) { + return sessionModel.plans( + builder: ( + context, + Iterable> plans, + Widget? child, + ) { + if (plans.isEmpty) { + // show user option to retry + return RetryWidget(onRetryTap: () => onRetryTap(context)); + } + return Column( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Expanded( + child: ListView( + shrinkWrap: true, + children: [ + _buildHeader(context), + Container( + color: white, + padding: const EdgeInsetsDirectional.only( + start: 24, + end: 24, + ), + child: Column( + children: [ + // * Renewal text or upsell + if (plans.last.value.renewalText != '') + Padding( + padding: const EdgeInsetsDirectional.only( + bottom: 12.0, ), - FeatureList(), - const CDivider(height: 24), - ], + child: CText( + plans.last.value.renewalText, + style: tsBody1, + ), + ), + const Padding( + padding: EdgeInsetsDirectional.only( + bottom: 8.0, + ), + child: CDivider(), + ), + FeatureList(), + const CDivider(height: 24), + ], + ), + ), + // * Card + ...plans.toList().reversed.map( + (plan) => Container( + color: white, + padding: const EdgeInsetsDirectional.only( + start: 32.0, + end: 32.0, + ), + child: PlanCard( + plan: plan.value, + isPro: proUser, + ), ), ), - // * Card - ...plans.toList().reversed.map( - (plan) => Container( - color: white, - padding: const EdgeInsetsDirectional.only( - start: 32.0, - end: 32.0, - ), - child: PlanCard( - plan: plan.value, - isPro: proUser, + FutureBuilder( + future: AppMethods.showRestorePurchaseButton(proUser), + builder: (context, snapshot) { + if (snapshot.hasData && snapshot.data as bool) { + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + TextButton( + onPressed: () => restorePurchases(context), + style: TextButton.styleFrom( + foregroundColor: pink5, ), + child: CText( + "restore_purchase".i18n.toUpperCase(), + style: tsButton.copiedWith( + color: pink5, + )), ), - ), - FutureBuilder( - future: - AppMethods.showRestorePurchaseButton(proUser), - builder: (context, snapshot) { - if (snapshot.hasData && snapshot.data as bool) { - return Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - TextButton( - onPressed: () => - restorePurchases(context), - style: TextButton.styleFrom( - foregroundColor: pink5, - ), - child: CText( - "restore_purchase".i18n.toUpperCase(), - style: tsButton.copiedWith( - color: pink5, - )), - ), - ], - ); - } - return const SizedBox(); - }, - ), - ], + ], + ); + } + return const SizedBox(); + }, ), - ), - _buildFooter(context, proUser), - ], - ); - }, + ], + ), + ), + _buildFooter(context, proUser), + ], ); - }), - ), - sl.get().surveyWidget() - ], + }, + ); + }), ), ); } diff --git a/lib/features/home/home.dart b/lib/features/home/home.dart index c65fdcc4b..0866a468d 100644 --- a/lib/features/home/home.dart +++ b/lib/features/home/home.dart @@ -45,6 +45,10 @@ class _HomePageState extends State { } Future checkIfSurveyIsAvailable() async { + if (Platform.isWindows || Platform.isLinux) { + //Survey sparrow does not support windows and linux + return; + } if (await surveyService.surveyAvailable()) { surveyService.trackScreen(SurveyScreens.homeScreen); } From 7189f84b12cd9246dd51850cd143d9f9aec6ce25 Mon Sep 17 00:00:00 2001 From: Jigar-f Date: Tue, 28 Jan 2025 16:00:53 +0530 Subject: [PATCH 19/19] add default contry. --- lib/core/service/survey_service.dart | 5 ++--- lib/features/home/session_model.dart | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/core/service/survey_service.dart b/lib/core/service/survey_service.dart index 648585165..3fa1d225e 100644 --- a/lib/core/service/survey_service.dart +++ b/lib/core/service/survey_service.dart @@ -33,17 +33,16 @@ class SurveyService { return; } _createConfigIfNeeded(); - countryListener(); + _countryListener(); } - void countryListener() { + void _countryListener() { if (sessionModel.country.value!.isNotEmpty) { createSpotCheckByCountry(sessionModel.country.value!.toLowerCase()); return; } sessionModel.country.addListener(() { final country = sessionModel.country.value; - appLogger.d('Country listener $country'); if (country != null && country.isNotEmpty) { appLogger.d('Country found $country'); createSpotCheckByCountry(country.toLowerCase()); diff --git a/lib/features/home/session_model.dart b/lib/features/home/session_model.dart index a4d3b3306..4a06d2436 100644 --- a/lib/features/home/session_model.dart +++ b/lib/features/home/session_model.dart @@ -55,7 +55,7 @@ class SessionModel extends Model { * So show banner only if proxyAvailable is false */ proxyAvailable = singleValueNotifier('hasSucceedingProxy', true); - country = singleValueNotifier('geo_country_code', ''); + country = singleValueNotifier('geo_country_code', 'US'); /// This warning is not needed for the Non pro user /// This flow is not needed anymore