From fb5c847c6de7a4e82d995196d22616f9967daac9 Mon Sep 17 00:00:00 2001 From: zohreh-deriv Date: Tue, 13 Aug 2024 11:41:49 +0800 Subject: [PATCH 1/6] feat: add ability to support feature flag toggles by passing their widgets --- .../layouts/deriv_setting_layout.dart | 94 ++++++++++++++++++- 1 file changed, 89 insertions(+), 5 deletions(-) diff --git a/packages/deriv_auth/lib/features/setting_page/presentation/layouts/deriv_setting_layout.dart b/packages/deriv_auth/lib/features/setting_page/presentation/layouts/deriv_setting_layout.dart index e61f0d754..edace2823 100644 --- a/packages/deriv_auth/lib/features/setting_page/presentation/layouts/deriv_setting_layout.dart +++ b/packages/deriv_auth/lib/features/setting_page/presentation/layouts/deriv_setting_layout.dart @@ -22,6 +22,8 @@ class DerivSettingLayout extends StatefulWidget { this.stagingApp = 'com.deriv.app.staging', this.getAppEnv, this.setAppEnv, + this.underDevelopmentFeatures, + this.productionFeatures, Key? key, }) : super(key: key); @@ -53,6 +55,12 @@ class DerivSettingLayout extends StatefulWidget { /// Sets environment variable final Future Function({required bool value})? setAppEnv; + /// Under development features. + final Widget? underDevelopmentFeatures; + + /// Production features. + final Widget? productionFeatures; + @override _SettingsPageState createState() => _SettingsPageState(); } @@ -74,7 +82,54 @@ class _SettingsPageState extends State { } @override - Widget build(BuildContext context) => WillPopScope( + Widget build(BuildContext context) => + widget.underDevelopmentFeatures != null || + widget.productionFeatures != null + ? DefaultTabController( + length: 2, + child: WillPopScope( + onWillPop: () async { + final String endpoint = _endpointController.text.isNotEmpty + ? _endpointController.text + : defaultEndpoint; + final String appId = _appIdController.text.isNotEmpty + ? _appIdController.text + : defaultAppId; + await Future.wait(>[ + await widget.saveValues(endpoint: endpoint, appId: appId), + await widget.updateFlavorConfigs( + endpoint: endpoint, appId: appId), + ]); + return true; + }, + child: Scaffold( + key: const ValueKey('app_settings_page'), + appBar: AppBar( + elevation: ThemeProvider.zeroMargin, + title: Text(widget.appLabel), + leading: const BackButton( + key: ValueKey('app_settings_page_back_button'), + ), + bottom: const TabBar( + tabs: [ + Text('Under Development'), + Text('Production'), + ], + labelPadding: EdgeInsets.all(ThemeProvider.margin16), + ), + ), + body: TabBarView( + children: [ + _buildUnderDevelopmentTab(), + _buildProductionTab(), + ], + ), + ), + ), + ) + : _buildBasicAppSettings(); + + Widget _buildBasicAppSettings() => WillPopScope( onWillPop: () async { final String endpoint = _endpointController.text.isNotEmpty ? _endpointController.text @@ -102,9 +157,9 @@ class _SettingsPageState extends State { children: [ _title, const SizedBox(height: ThemeProvider.margin16), - _endpoint, + _endpointTextInput, const SizedBox(height: ThemeProvider.margin16), - _appId, + _appIdTextInput, const SizedBox(width: ThemeProvider.margin08), _buildEnvironmentSwitcher, ], @@ -113,6 +168,35 @@ class _SettingsPageState extends State { ), ); + Widget _buildUnderDevelopmentTab() => Column( + children: [ + _endpointTextInput, + const SizedBox(height: ThemeProvider.margin16), + _appIdTextInput, + const SizedBox(height: ThemeProvider.margin16), + widget.underDevelopmentFeatures != null + ? widget.underDevelopmentFeatures! + : _buildEmptyPage(), + ], + ); + + Widget _buildProductionTab() => Column( + children: [ + widget.productionFeatures != null + ? widget.productionFeatures! + : _buildEmptyPage() + ], + ); + + Center _buildEmptyPage() => Center( + child: Text( + 'No Under Development Feature Exist.', + style: TextStyles.body1.copyWith( + color: context.theme.colors.prominent, + ), + ), + ); + Widget get _buildEnvironmentSwitcher => FutureBuilder( future: packageInfo, builder: (BuildContext context, AsyncSnapshot snapshot) { @@ -163,7 +247,7 @@ class _SettingsPageState extends State { ), ); - Widget get _endpoint => _buildTextInputField( + Widget get _endpointTextInput => _buildTextInputField( label: context.derivAuthLocalization.labelEndpoint, semantic: context.derivAuthLocalization.semanticEndpoint, controller: _endpointController, @@ -172,7 +256,7 @@ class _SettingsPageState extends State { : context.derivAuthLocalization.warnInvalidEndpoint, ); - Widget get _appId => _buildTextInputField( + Widget get _appIdTextInput => _buildTextInputField( label: context.derivAuthLocalization.labelApplicationID, semantic: context.derivAuthLocalization.semanticApplicationID, controller: _appIdController, From 79e7544610c1254073c2bf9a813a8b44d80e00cd Mon Sep 17 00:00:00 2001 From: zohreh-deriv Date: Tue, 13 Aug 2024 12:03:41 +0800 Subject: [PATCH 2/6] chore: add key --- .../setting_page/presentation/layouts/deriv_setting_layout.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/deriv_auth/lib/features/setting_page/presentation/layouts/deriv_setting_layout.dart b/packages/deriv_auth/lib/features/setting_page/presentation/layouts/deriv_setting_layout.dart index edace2823..53bc4df7a 100644 --- a/packages/deriv_auth/lib/features/setting_page/presentation/layouts/deriv_setting_layout.dart +++ b/packages/deriv_auth/lib/features/setting_page/presentation/layouts/deriv_setting_layout.dart @@ -147,6 +147,7 @@ class _SettingsPageState extends State { return true; }, child: Scaffold( + key: const ValueKey('app_settings_page'), appBar: AppBar( elevation: ThemeProvider.zeroMargin, title: Text(widget.appLabel), From bf0139463f8c5a550f08bfd63ab998c19c5ce56f Mon Sep 17 00:00:00 2001 From: zohreh-deriv Date: Wed, 14 Aug 2024 12:01:03 +0800 Subject: [PATCH 3/6] fix: env toggle condition and add some vertical space to the widgets --- .../layouts/deriv_setting_layout.dart | 75 ++++++++++--------- 1 file changed, 40 insertions(+), 35 deletions(-) diff --git a/packages/deriv_auth/lib/features/setting_page/presentation/layouts/deriv_setting_layout.dart b/packages/deriv_auth/lib/features/setting_page/presentation/layouts/deriv_setting_layout.dart index 53bc4df7a..bde1ea2b5 100644 --- a/packages/deriv_auth/lib/features/setting_page/presentation/layouts/deriv_setting_layout.dart +++ b/packages/deriv_auth/lib/features/setting_page/presentation/layouts/deriv_setting_layout.dart @@ -171,6 +171,7 @@ class _SettingsPageState extends State { Widget _buildUnderDevelopmentTab() => Column( children: [ + const SizedBox(height: ThemeProvider.margin16), _endpointTextInput, const SizedBox(height: ThemeProvider.margin16), _appIdTextInput, @@ -183,6 +184,7 @@ class _SettingsPageState extends State { Widget _buildProductionTab() => Column( children: [ + const SizedBox(height: ThemeProvider.margin16), widget.productionFeatures != null ? widget.productionFeatures! : _buildEmptyPage() @@ -198,41 +200,44 @@ class _SettingsPageState extends State { ), ); - Widget get _buildEnvironmentSwitcher => FutureBuilder( - future: packageInfo, - builder: (BuildContext context, AsyncSnapshot snapshot) { - if (snapshot.hasData && - (snapshot.data?.packageName == widget.devApp || - snapshot.data?.packageName == widget.stagingApp)) { - return Padding( - padding: - const EdgeInsets.symmetric(horizontal: ThemeProvider.margin16), - child: Row( - children: [ - const Text('Production environment'), - const SizedBox(width: ThemeProvider.margin08), - FutureBuilder( - future: widget.getAppEnv, - builder: - (BuildContext context, AsyncSnapshot snapshot) { - if (snapshot.hasData && widget.setAppEnv != null) { - return Switch( - value: snapshot.data ?? false, - onChanged: (bool val) { - setState(() { - widget.setAppEnv!(value: val); - }); - }, - ); - } - return const SizedBox.shrink(); - }) - ], - ), - ); - } - return const SizedBox.shrink(); - }); + Widget get _buildEnvironmentSwitcher => widget.setAppEnv != null && + widget.getAppEnv != null + ? FutureBuilder( + future: packageInfo, + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.hasData && + (snapshot.data?.packageName == widget.devApp || + snapshot.data?.packageName == widget.stagingApp)) { + return Padding( + padding: const EdgeInsets.symmetric( + horizontal: ThemeProvider.margin16), + child: Row( + children: [ + const Text('Production environment'), + const SizedBox(width: ThemeProvider.margin08), + FutureBuilder( + future: widget.getAppEnv, + builder: (BuildContext context, + AsyncSnapshot snapshot) { + if (snapshot.hasData) { + return Switch( + value: snapshot.data ?? false, + onChanged: (bool val) { + setState(() { + widget.setAppEnv!(value: val); + }); + }, + ); + } + return const SizedBox.shrink(); + }) + ], + ), + ); + } + return const SizedBox.shrink(); + }) + : const SizedBox.shrink(); Widget get _title => Padding( padding: const EdgeInsets.only( From dad379bdc168f8b3600d7e551d7d365da64179d8 Mon Sep 17 00:00:00 2001 From: zohreh-deriv Date: Wed, 14 Aug 2024 13:08:18 +0800 Subject: [PATCH 4/6] style: ui improvement --- .../presentation/layouts/deriv_setting_layout.dart | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/deriv_auth/lib/features/setting_page/presentation/layouts/deriv_setting_layout.dart b/packages/deriv_auth/lib/features/setting_page/presentation/layouts/deriv_setting_layout.dart index bde1ea2b5..4e3aa147a 100644 --- a/packages/deriv_auth/lib/features/setting_page/presentation/layouts/deriv_setting_layout.dart +++ b/packages/deriv_auth/lib/features/setting_page/presentation/layouts/deriv_setting_layout.dart @@ -191,14 +191,16 @@ class _SettingsPageState extends State { ], ); - Center _buildEmptyPage() => Center( - child: Text( - 'No Under Development Feature Exist.', - style: TextStyles.body1.copyWith( - color: context.theme.colors.prominent, + Widget _buildEmptyPage() => Expanded( + child: Center( + child: Text( + 'No Under Development Feature Exist.', + style: TextStyles.body1.copyWith( + color: context.theme.colors.prominent, + ), ), ), - ); + ); Widget get _buildEnvironmentSwitcher => widget.setAppEnv != null && widget.getAppEnv != null From 164a7d84116bc87bf9e6321ac8514051f5178485 Mon Sep 17 00:00:00 2001 From: zohreh-deriv Date: Wed, 14 Aug 2024 13:24:34 +0800 Subject: [PATCH 5/6] feat: add feature flag configs to setting page model --- .../core/models/setting_page_model.dart | 16 ++++++++++++++++ .../features/settings/pages/settings_page.dart | 5 +++++ 2 files changed, 21 insertions(+) diff --git a/packages/deriv_auth/lib/features/single_entry/core/models/setting_page_model.dart b/packages/deriv_auth/lib/features/single_entry/core/models/setting_page_model.dart index 3093a9857..d03f97244 100644 --- a/packages/deriv_auth/lib/features/single_entry/core/models/setting_page_model.dart +++ b/packages/deriv_auth/lib/features/single_entry/core/models/setting_page_model.dart @@ -10,6 +10,10 @@ class SettingPageModel { required this.saveValues, required this.updateFlavorConfigs, this.settingsPageNavigation, + this.getAppEnv, + this.setAppEnv, + this.underDevelopmentFeatures, + this.productionFeatures, }); /// Setting page App label @@ -30,4 +34,16 @@ class SettingPageModel { /// Settings page navigation final Function(BuildContext context)? settingsPageNavigation; + + /// Gets environment variable + final Future? getAppEnv; + + /// Sets environment variable + final Future Function({required bool value})? setAppEnv; + + /// Under development features. + final Widget? underDevelopmentFeatures; + + /// Production features. + final Widget? productionFeatures; } diff --git a/packages/deriv_auth/lib/features/single_entry/features/settings/pages/settings_page.dart b/packages/deriv_auth/lib/features/single_entry/features/settings/pages/settings_page.dart index 149c3a540..fc4c5a830 100644 --- a/packages/deriv_auth/lib/features/single_entry/features/settings/pages/settings_page.dart +++ b/packages/deriv_auth/lib/features/single_entry/features/settings/pages/settings_page.dart @@ -20,5 +20,10 @@ class _SettingsPageState extends State { saveValues: AuthData().data.settingPageModel.saveValues, appId: AuthData().data.settingPageModel.appId.call(), endpoint: AuthData().data.settingPageModel.endpoint.call(), + underDevelopmentFeatures: + AuthData().data.settingPageModel.underDevelopmentFeatures, + productionFeatures: AuthData().data.settingPageModel.productionFeatures, + setAppEnv: AuthData().data.settingPageModel.setAppEnv, + getAppEnv: AuthData().data.settingPageModel.getAppEnv, ); } From d5d9ff0e345f9c8929560b720b720291ebda4cbe Mon Sep 17 00:00:00 2001 From: zohreh-deriv Date: Thu, 3 Oct 2024 13:32:39 +0800 Subject: [PATCH 6/6] refactor: pass a widget to show feature flag inside settings page --- .../layouts/deriv_setting_layout.dart | 116 +++++------------- .../core/models/setting_page_model.dart | 10 +- .../settings/pages/settings_page.dart | 4 +- 3 files changed, 35 insertions(+), 95 deletions(-) diff --git a/packages/deriv_auth/lib/features/setting_page/presentation/layouts/deriv_setting_layout.dart b/packages/deriv_auth/lib/features/setting_page/presentation/layouts/deriv_setting_layout.dart index 4e3aa147a..827a9d1ea 100644 --- a/packages/deriv_auth/lib/features/setting_page/presentation/layouts/deriv_setting_layout.dart +++ b/packages/deriv_auth/lib/features/setting_page/presentation/layouts/deriv_setting_layout.dart @@ -22,8 +22,7 @@ class DerivSettingLayout extends StatefulWidget { this.stagingApp = 'com.deriv.app.staging', this.getAppEnv, this.setAppEnv, - this.underDevelopmentFeatures, - this.productionFeatures, + this.features, Key? key, }) : super(key: key); @@ -55,11 +54,8 @@ class DerivSettingLayout extends StatefulWidget { /// Sets environment variable final Future Function({required bool value})? setAppEnv; - /// Under development features. - final Widget? underDevelopmentFeatures; - - /// Production features. - final Widget? productionFeatures; + /// Feature flag widget that should be listed in the setting page. + final Widget? features; @override _SettingsPageState createState() => _SettingsPageState(); @@ -82,52 +78,35 @@ class _SettingsPageState extends State { } @override - Widget build(BuildContext context) => - widget.underDevelopmentFeatures != null || - widget.productionFeatures != null - ? DefaultTabController( - length: 2, - child: WillPopScope( - onWillPop: () async { - final String endpoint = _endpointController.text.isNotEmpty - ? _endpointController.text - : defaultEndpoint; - final String appId = _appIdController.text.isNotEmpty - ? _appIdController.text - : defaultAppId; - await Future.wait(>[ - await widget.saveValues(endpoint: endpoint, appId: appId), - await widget.updateFlavorConfigs( - endpoint: endpoint, appId: appId), - ]); - return true; - }, - child: Scaffold( - key: const ValueKey('app_settings_page'), - appBar: AppBar( - elevation: ThemeProvider.zeroMargin, - title: Text(widget.appLabel), - leading: const BackButton( - key: ValueKey('app_settings_page_back_button'), - ), - bottom: const TabBar( - tabs: [ - Text('Under Development'), - Text('Production'), - ], - labelPadding: EdgeInsets.all(ThemeProvider.margin16), - ), - ), - body: TabBarView( - children: [ - _buildUnderDevelopmentTab(), - _buildProductionTab(), - ], - ), - ), + Widget build(BuildContext context) => widget.features != null + ? WillPopScope( + onWillPop: () async { + final String endpoint = _endpointController.text.isNotEmpty + ? _endpointController.text + : defaultEndpoint; + final String appId = _appIdController.text.isNotEmpty + ? _appIdController.text + : defaultAppId; + await Future.wait(>[ + await widget.saveValues(endpoint: endpoint, appId: appId), + await widget.updateFlavorConfigs( + endpoint: endpoint, appId: appId), + ]); + return true; + }, + child: Scaffold( + key: const ValueKey('app_settings_page'), + appBar: AppBar( + elevation: ThemeProvider.zeroMargin, + title: Text(widget.appLabel), + leading: const BackButton( + key: ValueKey('app_settings_page_back_button'), ), - ) - : _buildBasicAppSettings(); + ), + body: widget.features, + ), + ) + : _buildBasicAppSettings(); Widget _buildBasicAppSettings() => WillPopScope( onWillPop: () async { @@ -169,39 +148,6 @@ class _SettingsPageState extends State { ), ); - Widget _buildUnderDevelopmentTab() => Column( - children: [ - const SizedBox(height: ThemeProvider.margin16), - _endpointTextInput, - const SizedBox(height: ThemeProvider.margin16), - _appIdTextInput, - const SizedBox(height: ThemeProvider.margin16), - widget.underDevelopmentFeatures != null - ? widget.underDevelopmentFeatures! - : _buildEmptyPage(), - ], - ); - - Widget _buildProductionTab() => Column( - children: [ - const SizedBox(height: ThemeProvider.margin16), - widget.productionFeatures != null - ? widget.productionFeatures! - : _buildEmptyPage() - ], - ); - - Widget _buildEmptyPage() => Expanded( - child: Center( - child: Text( - 'No Under Development Feature Exist.', - style: TextStyles.body1.copyWith( - color: context.theme.colors.prominent, - ), - ), - ), - ); - Widget get _buildEnvironmentSwitcher => widget.setAppEnv != null && widget.getAppEnv != null ? FutureBuilder( diff --git a/packages/deriv_auth/lib/features/single_entry/core/models/setting_page_model.dart b/packages/deriv_auth/lib/features/single_entry/core/models/setting_page_model.dart index d03f97244..7211e4912 100644 --- a/packages/deriv_auth/lib/features/single_entry/core/models/setting_page_model.dart +++ b/packages/deriv_auth/lib/features/single_entry/core/models/setting_page_model.dart @@ -12,8 +12,7 @@ class SettingPageModel { this.settingsPageNavigation, this.getAppEnv, this.setAppEnv, - this.underDevelopmentFeatures, - this.productionFeatures, + this.features, }); /// Setting page App label @@ -41,9 +40,6 @@ class SettingPageModel { /// Sets environment variable final Future Function({required bool value})? setAppEnv; - /// Under development features. - final Widget? underDevelopmentFeatures; - - /// Production features. - final Widget? productionFeatures; + /// Feature flag widget that should be listed in the setting page. + final Widget? features; } diff --git a/packages/deriv_auth/lib/features/single_entry/features/settings/pages/settings_page.dart b/packages/deriv_auth/lib/features/single_entry/features/settings/pages/settings_page.dart index fc4c5a830..bfe7d55a8 100644 --- a/packages/deriv_auth/lib/features/single_entry/features/settings/pages/settings_page.dart +++ b/packages/deriv_auth/lib/features/single_entry/features/settings/pages/settings_page.dart @@ -20,9 +20,7 @@ class _SettingsPageState extends State { saveValues: AuthData().data.settingPageModel.saveValues, appId: AuthData().data.settingPageModel.appId.call(), endpoint: AuthData().data.settingPageModel.endpoint.call(), - underDevelopmentFeatures: - AuthData().data.settingPageModel.underDevelopmentFeatures, - productionFeatures: AuthData().data.settingPageModel.productionFeatures, + features: AuthData().data.settingPageModel.features, setAppEnv: AuthData().data.settingPageModel.setAppEnv, getAppEnv: AuthData().data.settingPageModel.getAppEnv, );