Skip to content

Commit f0893b0

Browse files
committed
refactor(ad): improve interstitial ad config management
- Replace single config object with map for better role-based frequency control - Add checkbox to toggle ad visibility for each user role - Update controllers initialization and updates logic - Simplify transitions retrieval and update methods - Enhance comments and code structure for better readability
1 parent f9f9cd9 commit f0893b0

File tree

1 file changed

+129
-119
lines changed

1 file changed

+129
-119
lines changed

lib/app_configuration/widgets/interstitial_ad_settings_form.dart

Lines changed: 129 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,11 @@ class InterstitialAdSettingsForm extends StatefulWidget {
3131
class _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

Comments
 (0)