11import 'package:core/core.dart' ;
22import 'package:flutter/material.dart' ;
3+ import 'package:flutter_news_app_web_dashboard_full_source_code/l10n/app_localizations.dart' ;
34import 'package:flutter_news_app_web_dashboard_full_source_code/l10n/l10n.dart' ;
45import 'package:flutter_news_app_web_dashboard_full_source_code/shared/extensions/banner_ad_shape_l10n.dart' ;
56import 'package:flutter_news_app_web_dashboard_full_source_code/shared/extensions/in_article_ad_slot_type_l10n.dart' ;
7+ import 'package:flutter_news_app_web_dashboard_full_source_code/shared/extensions/app_user_role_l10n.dart' ;
68import 'package:ui_kit/ui_kit.dart' ;
79
810/// {@template article_ad_settings_form}
@@ -28,14 +30,28 @@ class ArticleAdSettingsForm extends StatefulWidget {
2830
2931class _ArticleAdSettingsFormState extends State <ArticleAdSettingsForm >
3032 with SingleTickerProviderStateMixin {
33+ late TabController _tabController;
34+
3135 @override
3236 void initState () {
3337 super .initState ();
38+ _tabController = TabController (
39+ length: AppUserRole .values.length,
40+ vsync: this ,
41+ );
3442 }
3543
3644 @override
3745 void didUpdateWidget (covariant ArticleAdSettingsForm oldWidget) {
3846 super .didUpdateWidget (oldWidget);
47+ // No specific controller updates needed here as the UI rebuilds based on
48+ // the remoteConfig directly.
49+ }
50+
51+ @override
52+ void dispose () {
53+ _tabController.dispose ();
54+ super .dispose ();
3955 }
4056
4157 @override
@@ -134,34 +150,92 @@ class _ArticleAdSettingsFormState extends State<ArticleAdSettingsForm>
134150 textAlign: TextAlign .start,
135151 ),
136152 const SizedBox (height: AppSpacing .lg),
137- ...articleAdConfig.inArticleAdSlotConfigurations.map (
138- (slotConfig) => SwitchListTile (
139- title: Text (slotConfig.slotType.l10n (context)),
140- value: slotConfig.enabled,
141- onChanged: (value) {
142- final updatedSlots = articleAdConfig
143- .inArticleAdSlotConfigurations
144- .map (
145- (e) => e.slotType == slotConfig.slotType
146- ? e.copyWith (enabled: value)
147- : e,
148- )
149- .toList ();
150- widget.onConfigChanged (
151- widget.remoteConfig.copyWith (
152- adConfig: adConfig.copyWith (
153- articleAdConfiguration: articleAdConfig.copyWith (
154- inArticleAdSlotConfigurations: updatedSlots,
155- ),
153+ Align (
154+ alignment: AlignmentDirectional .centerStart,
155+ child: SizedBox (
156+ height: kTextTabBarHeight,
157+ child: TabBar (
158+ controller: _tabController,
159+ tabAlignment: TabAlignment .start,
160+ isScrollable: true ,
161+ tabs: AppUserRole .values
162+ .map ((role) => Tab (text: role.l10n (context)))
163+ .toList (),
164+ ),
165+ ),
166+ ),
167+ const SizedBox (height: AppSpacing .lg),
168+ SizedBox (
169+ height: 250 ,
170+ child: TabBarView (
171+ controller: _tabController,
172+ children: AppUserRole .values
173+ .map (
174+ (role) => _buildRoleSpecificFields (
175+ context,
176+ l10n,
177+ role,
178+ articleAdConfig,
156179 ),
157- ),
158- );
159- },
180+ )
181+ .toList (),
160182 ),
161183 ),
162184 ],
163185 ),
164186 ],
165187 );
166188 }
189+
190+ /// Builds role-specific configuration fields for in-article ad slots.
191+ ///
192+ /// This widget displays checkboxes for each [InArticleAdSlotType] for a
193+ /// given [AppUserRole] , allowing to enable/disable specific ad slots.
194+ Widget _buildRoleSpecificFields (
195+ BuildContext context,
196+ AppLocalizations l10n,
197+ AppUserRole role,
198+ ArticleAdConfiguration config,
199+ ) {
200+ final roleSlots = config.visibleTo[role];
201+ final isEnabled = role != AppUserRole .premiumUser;
202+
203+ return Column (
204+ children: [
205+ // Checkbox for each InArticleAdSlotType
206+ for (final slotType in InArticleAdSlotType .values)
207+ CheckboxListTile (
208+ title: Text (slotType.l10n (context)),
209+ value: (roleSlots != null && roleSlots[slotType] == true ) &&
210+ isEnabled,
211+ onChanged: isEnabled
212+ ? (value) {
213+ final newRoleSlots =
214+ Map <InArticleAdSlotType , bool >.from (roleSlots ?? {});
215+ if (value ?? false ) {
216+ newRoleSlots[slotType] = true ;
217+ } else {
218+ newRoleSlots.remove (slotType);
219+ }
220+
221+ final newVisibleTo =
222+ Map <AppUserRole , Map <InArticleAdSlotType , bool >>.from (
223+ config.visibleTo,
224+ )..[role] = newRoleSlots;
225+
226+ widget.onConfigChanged (
227+ widget.remoteConfig.copyWith (
228+ adConfig: widget.remoteConfig.adConfig.copyWith (
229+ articleAdConfiguration: config.copyWith (
230+ visibleTo: newVisibleTo,
231+ ),
232+ ),
233+ ),
234+ );
235+ }
236+ : null ,
237+ ),
238+ ],
239+ );
240+ }
167241}
0 commit comments