@@ -31,8 +31,11 @@ class InterstitialAdSettingsForm extends StatefulWidget {
3131class _InterstitialAdSettingsFormState extends State <InterstitialAdSettingsForm >
3232 with SingleTickerProviderStateMixin {
3333 late TabController _tabController;
34+
35+ /// Controllers for transitions before showing interstitial ads, mapped by user role.
36+ /// These are used to manage text input for each role's interstitial ad frequency.
3437 late final Map <AppUserRole , TextEditingController >
35- _transitionsBeforeShowingInterstitialAdsControllers;
38+ _transitionsBeforeShowingInterstitialAdsControllers;
3639
3740 @override
3841 void initState () {
@@ -45,6 +48,51 @@ class _InterstitialAdSettingsFormState extends State<InterstitialAdSettingsForm>
4548 _tabController.addListener (_onTabChanged);
4649 }
4750
51+ /// Initializes text editing controllers for each user role based on current
52+ /// remote config values.
53+ void _initializeControllers () {
54+ final interstitialConfig =
55+ widget.remoteConfig.adConfig.interstitialAdConfiguration;
56+ _transitionsBeforeShowingInterstitialAdsControllers = {
57+ for (final role in AppUserRole .values)
58+ role: TextEditingController (
59+ text: _getTransitionsBeforeInterstitial (
60+ interstitialConfig,
61+ role,
62+ ).toString (),
63+ )..selection = TextSelection .collapsed (
64+ offset: _getTransitionsBeforeInterstitial (
65+ interstitialConfig,
66+ role,
67+ ).toString ().length,
68+ ),
69+ };
70+ }
71+
72+ /// Updates text editing controllers when the widget's remote config changes.
73+ /// This ensures the form fields reflect the latest configuration.
74+ void _updateControllers () {
75+ final interstitialConfig =
76+ widget.remoteConfig.adConfig.interstitialAdConfiguration;
77+ for (final role in AppUserRole .values) {
78+ final newInterstitialValue = _getTransitionsBeforeInterstitial (
79+ interstitialConfig,
80+ role,
81+ ).toString ();
82+ if (_transitionsBeforeShowingInterstitialAdsControllers[role]? .text !=
83+ newInterstitialValue) {
84+ _transitionsBeforeShowingInterstitialAdsControllers[role]? .text =
85+ newInterstitialValue;
86+ _transitionsBeforeShowingInterstitialAdsControllers[role]? .selection =
87+ TextSelection .collapsed (
88+ offset: newInterstitialValue.length,
89+ );
90+ }
91+ }
92+ }
93+
94+ /// Listener for tab changes to enforce business rules, specifically for
95+ /// premium users who should not see ads.
4896 void _onTabChanged () {
4997 if (_tabController.indexIsChanging) return ;
5098
@@ -55,18 +103,19 @@ class _InterstitialAdSettingsFormState extends State<InterstitialAdSettingsForm>
55103
56104 // If the value for premium is not 0, update the config.
57105 // This enforces the business rule that premium users do not see ads.
58- if (interstitialAdConfig
59- .feedInterstitialAdFrequencyConfig
60- .premiumUserTransitionsBeforeShowingInterstitialAds !=
61- 0 ) {
62- final updatedFrequencyConfig = interstitialAdConfig
63- .feedInterstitialAdFrequencyConfig
64- .copyWith (
65- premiumUserTransitionsBeforeShowingInterstitialAds: 0 ,
66- );
67- final updatedInterstitialAdConfig = interstitialAdConfig.copyWith (
68- feedInterstitialAdFrequencyConfig: updatedFrequencyConfig,
69- );
106+ final premiumRoleConfig =
107+ interstitialAdConfig.visibleTo[AppUserRole .premiumUser];
108+ if (premiumRoleConfig != null &&
109+ premiumRoleConfig.transitionsBeforeShowingInterstitialAds != 0 ) {
110+ final updatedVisibleTo = Map <AppUserRole , InterstitialAdFrequencyConfig >.from (
111+ interstitialAdConfig.visibleTo,
112+ )..[AppUserRole .premiumUser] = const InterstitialAdFrequencyConfig (
113+ transitionsBeforeShowingInterstitialAds: 0 ,
114+ );
115+
116+ final updatedInterstitialAdConfig =
117+ interstitialAdConfig.copyWith (visibleTo: updatedVisibleTo);
118+
70119 widget.onConfigChanged (
71120 widget.remoteConfig.copyWith (
72121 adConfig: adConfig.copyWith (
@@ -87,47 +136,6 @@ class _InterstitialAdSettingsFormState extends State<InterstitialAdSettingsForm>
87136 }
88137 }
89138
90- void _initializeControllers () {
91- final interstitialConfig =
92- widget.remoteConfig.adConfig.interstitialAdConfiguration;
93- _transitionsBeforeShowingInterstitialAdsControllers = {
94- for (final role in AppUserRole .values)
95- role:
96- TextEditingController (
97- text: _getTransitionsBeforeInterstitial (
98- interstitialConfig,
99- role,
100- ).toString (),
101- )
102- ..selection = TextSelection .collapsed (
103- offset: _getTransitionsBeforeInterstitial (
104- interstitialConfig,
105- role,
106- ).toString ().length,
107- ),
108- };
109- }
110-
111- void _updateControllers () {
112- final interstitialConfig =
113- widget.remoteConfig.adConfig.interstitialAdConfiguration;
114- for (final role in AppUserRole .values) {
115- final newInterstitialValue = _getTransitionsBeforeInterstitial (
116- interstitialConfig,
117- role,
118- ).toString ();
119- if (_transitionsBeforeShowingInterstitialAdsControllers[role]? .text !=
120- newInterstitialValue) {
121- _transitionsBeforeShowingInterstitialAdsControllers[role]? .text =
122- newInterstitialValue;
123- _transitionsBeforeShowingInterstitialAdsControllers[role]? .selection =
124- TextSelection .collapsed (
125- offset: newInterstitialValue.length,
126- );
127- }
128- }
129- }
130-
131139 @override
132140 void dispose () {
133141 _tabController
@@ -220,90 +228,92 @@ class _InterstitialAdSettingsFormState extends State<InterstitialAdSettingsForm>
220228 );
221229 }
222230
231+ /// Builds role-specific configuration fields for interstitial ad frequency.
232+ ///
233+ /// This widget displays an input field for `transitionsBeforeShowingInterstitialAds`
234+ /// for a given [AppUserRole] . Premium users have this field disabled
235+ /// as they should not see ads.
223236 Widget _buildInterstitialRoleSpecificFields (
224237 BuildContext context,
225238 AppLocalizations l10n,
226239 AppUserRole role,
227240 InterstitialAdConfiguration config,
228241 ) {
229- // Premium users do not see ads, so their settings are disabled.
242+ final roleConfig = config.visibleTo[role];
230243 final isEnabled = role != AppUserRole .premiumUser;
231244
232245 return Column (
233246 children: [
234- AppConfigIntField (
235- label: l10n.transitionsBeforeInterstitialAdsLabel,
236- description: l10n.transitionsBeforeInterstitialAdsDescription,
237- value: _getTransitionsBeforeInterstitial (config, role),
238- onChanged: (value) {
239- widget.onConfigChanged (
240- widget.remoteConfig.copyWith (
241- adConfig: widget.remoteConfig.adConfig.copyWith (
242- interstitialAdConfiguration:
243- _updateTransitionsBeforeInterstitial (
244- config,
245- value,
246- role,
247+ CheckboxListTile (
248+ title: Text (l10n.visibleToRoleLabel (role.l10n (context))),
249+ value: roleConfig != null && isEnabled,
250+ onChanged: isEnabled
251+ ? (value) {
252+ final newVisibleTo =
253+ Map <AppUserRole , InterstitialAdFrequencyConfig >.from (
254+ config.visibleTo,
255+ );
256+ if (value ?? false ) {
257+ // Default value when enabling for a role
258+ newVisibleTo[role] = const InterstitialAdFrequencyConfig (
259+ transitionsBeforeShowingInterstitialAds: 5 ,
260+ );
261+ } else {
262+ newVisibleTo.remove (role);
263+ }
264+ widget.onConfigChanged (
265+ widget.remoteConfig.copyWith (
266+ adConfig: widget.remoteConfig.adConfig.copyWith (
267+ interstitialAdConfiguration: config.copyWith (
268+ visibleTo: newVisibleTo,
269+ ),
247270 ),
248- ),
249- ),
250- );
251- },
252- controller: _transitionsBeforeShowingInterstitialAdsControllers[role],
253- enabled: isEnabled,
271+ ),
272+ );
273+ }
274+ : null ,
254275 ),
276+ if (roleConfig != null )
277+ Padding (
278+ padding: const EdgeInsets .symmetric (
279+ horizontal: AppSpacing .lg,
280+ vertical: AppSpacing .sm,
281+ ),
282+ child: AppConfigIntField (
283+ label: l10n.transitionsBeforeInterstitialAdsLabel,
284+ description: l10n.transitionsBeforeInterstitialAdsDescription,
285+ value: roleConfig.transitionsBeforeShowingInterstitialAds,
286+ onChanged: (value) {
287+ final newRoleConfig =
288+ roleConfig.copyWith (transitionsBeforeShowingInterstitialAds: value);
289+ final newVisibleTo =
290+ Map <AppUserRole , InterstitialAdFrequencyConfig >.from (
291+ config.visibleTo,
292+ )..[role] = newRoleConfig;
293+ widget.onConfigChanged (
294+ widget.remoteConfig.copyWith (
295+ adConfig: widget.remoteConfig.adConfig.copyWith (
296+ interstitialAdConfiguration: config.copyWith (
297+ visibleTo: newVisibleTo,
298+ ),
299+ ),
300+ ),
301+ );
302+ },
303+ controller: _transitionsBeforeShowingInterstitialAdsControllers[role],
304+ enabled: isEnabled,
305+ ),
306+ ),
255307 ],
256308 );
257309 }
258310
311+ /// Retrieves the number of transitions before showing an interstitial ad
312+ /// for a specific role from the configuration.
259313 int _getTransitionsBeforeInterstitial (
260314 InterstitialAdConfiguration config,
261315 AppUserRole role,
262316 ) {
263- switch (role) {
264- case AppUserRole .guestUser:
265- return config
266- .feedInterstitialAdFrequencyConfig
267- .guestTransitionsBeforeShowingInterstitialAds;
268- case AppUserRole .standardUser:
269- return config
270- .feedInterstitialAdFrequencyConfig
271- .standardUserTransitionsBeforeShowingInterstitialAds;
272- case AppUserRole .premiumUser:
273- return config
274- .feedInterstitialAdFrequencyConfig
275- .premiumUserTransitionsBeforeShowingInterstitialAds;
276- }
277- }
278-
279- InterstitialAdConfiguration _updateTransitionsBeforeInterstitial (
280- InterstitialAdConfiguration config,
281- int value,
282- AppUserRole role,
283- ) {
284- final currentFrequencyConfig = config.feedInterstitialAdFrequencyConfig;
285-
286- InterstitialAdFrequencyConfig newFrequencyConfig;
287-
288- switch (role) {
289- case AppUserRole .guestUser:
290- newFrequencyConfig = currentFrequencyConfig.copyWith (
291- guestTransitionsBeforeShowingInterstitialAds: value,
292- );
293- case AppUserRole .standardUser:
294- newFrequencyConfig = currentFrequencyConfig.copyWith (
295- standardUserTransitionsBeforeShowingInterstitialAds: value,
296- );
297- case AppUserRole .premiumUser:
298- // Premium users should not see ads, so their frequency is always 0.
299- // The UI field is disabled, but this is a safeguard.
300- newFrequencyConfig = currentFrequencyConfig.copyWith (
301- premiumUserTransitionsBeforeShowingInterstitialAds: 0 ,
302- );
303- }
304-
305- return config.copyWith (
306- feedInterstitialAdFrequencyConfig: newFrequencyConfig,
307- );
317+ return config.visibleTo[role]? .transitionsBeforeShowingInterstitialAds ?? 0 ;
308318 }
309319}
0 commit comments