@@ -27,14 +27,16 @@ class ArticleAdSettingsForm extends StatefulWidget {
2727 State <ArticleAdSettingsForm > createState () => _ArticleAdSettingsFormState ();
2828}
2929
30- class _ArticleAdSettingsFormState extends State <ArticleAdSettingsForm > {
31- AppUserRole _selectedUserRole = AppUserRole .guestUser;
30+ class _ArticleAdSettingsFormState extends State <ArticleAdSettingsForm >
31+ with SingleTickerProviderStateMixin {
32+ late TabController _tabController;
3233 late final Map <AppUserRole , TextEditingController >
33- _articlesToReadBeforeShowingInterstitialAdsControllers;
34+ _articlesToReadBeforeShowingInterstitialAdsControllers;
3435
3536 @override
3637 void initState () {
3738 super .initState ();
39+ _tabController = TabController (length: AppUserRole .values.length, vsync: this );
3840 _initializeControllers ();
3941 }
4042
@@ -52,19 +54,17 @@ class _ArticleAdSettingsFormState extends State<ArticleAdSettingsForm> {
5254 final interstitialConfig = articleAdConfig.interstitialAdConfiguration;
5355 _articlesToReadBeforeShowingInterstitialAdsControllers = {
5456 for (final role in AppUserRole .values)
55- role:
56- TextEditingController (
57- text: _getArticlesBeforeInterstitial (
58- interstitialConfig,
59- role,
60- ).toString (),
61- )
62- ..selection = TextSelection .collapsed (
63- offset: _getArticlesBeforeInterstitial (
64- interstitialConfig,
65- role,
66- ).toString ().length,
67- ),
57+ role: TextEditingController (
58+ text: _getArticlesBeforeInterstitial (
59+ interstitialConfig,
60+ role,
61+ ).toString (),
62+ )..selection = TextSelection .collapsed (
63+ offset: _getArticlesBeforeInterstitial (
64+ interstitialConfig,
65+ role,
66+ ).toString ().length,
67+ ),
6868 };
6969 }
7070
@@ -79,15 +79,15 @@ class _ArticleAdSettingsFormState extends State<ArticleAdSettingsForm> {
7979 _articlesToReadBeforeShowingInterstitialAdsControllers[role]? .text =
8080 newInterstitialValue;
8181 _articlesToReadBeforeShowingInterstitialAdsControllers[role]
82- ? .selection = TextSelection .collapsed (
83- offset: newInterstitialValue.length,
84- );
82+ ? .selection =
83+ TextSelection .collapsed (offset: newInterstitialValue.length);
8584 }
8685 }
8786 }
8887
8988 @override
9089 void dispose () {
90+ _tabController.dispose ();
9191 for (final controller
9292 in _articlesToReadBeforeShowingInterstitialAdsControllers.values) {
9393 controller.dispose ();
@@ -122,20 +122,29 @@ class _ArticleAdSettingsFormState extends State<ArticleAdSettingsForm> {
122122 const SizedBox (height: AppSpacing .lg),
123123 ExpansionTile (
124124 title: Text (l10n.defaultInArticleAdTypeSelectionTitle),
125- childrenPadding: const EdgeInsets .symmetric (
126- horizontal: AppSpacing .xxl,
127- vertical: AppSpacing .md,
125+ childrenPadding: const EdgeInsetsDirectional .only (
126+ start: AppSpacing .lg, // Adjusted padding for hierarchy
127+ top: AppSpacing .md,
128+ bottom: AppSpacing .md,
128129 ),
130+ expandedCrossAxisAlignment: CrossAxisAlignment .start, // Align content to start
129131 children: [
130132 Text (
131133 l10n.defaultInArticleAdTypeSelectionDescription,
132134 style: Theme .of (context).textTheme.bodySmall? .copyWith (
133135 color: Theme .of (context).colorScheme.onSurface.withOpacity (0.7 ),
134136 ),
137+ textAlign: TextAlign .start, // Ensure text aligns to start
135138 ),
136139 const SizedBox (height: AppSpacing .lg),
137- Center (
140+ Align (
141+ alignment: AlignmentDirectional .centerStart,
138142 child: SegmentedButton <AdType >(
143+ style: SegmentedButton .styleFrom (
144+ shape: const RoundedRectangleBorder (
145+ borderRadius: BorderRadius .zero,
146+ ),
147+ ),
139148 segments: AdType .values
140149 .where (
141150 (type) => type == AdType .native || type == AdType .banner,
@@ -166,10 +175,12 @@ class _ArticleAdSettingsFormState extends State<ArticleAdSettingsForm> {
166175 const SizedBox (height: AppSpacing .lg),
167176 ExpansionTile (
168177 title: Text (l10n.interstitialAdSettingsTitle),
169- childrenPadding: const EdgeInsets .symmetric (
170- horizontal: AppSpacing .xxl,
171- vertical: AppSpacing .md,
178+ childrenPadding: const EdgeInsetsDirectional .only (
179+ start: AppSpacing .lg, // Adjusted padding for hierarchy
180+ top: AppSpacing .md,
181+ bottom: AppSpacing .md,
172182 ),
183+ expandedCrossAxisAlignment: CrossAxisAlignment .start, // Align content to start
173184 children: [
174185 SwitchListTile (
175186 title: Text (l10n.enableInterstitialAdsLabel),
@@ -190,10 +201,12 @@ class _ArticleAdSettingsFormState extends State<ArticleAdSettingsForm> {
190201 ),
191202 ExpansionTile (
192203 title: Text (l10n.userRoleInterstitialFrequencyTitle),
193- childrenPadding: const EdgeInsets .symmetric (
194- horizontal: AppSpacing .xxl,
195- vertical: AppSpacing .md,
204+ childrenPadding: const EdgeInsetsDirectional .only (
205+ start: AppSpacing .xl, // Further adjusted padding for nested hierarchy
206+ top: AppSpacing .md,
207+ bottom: AppSpacing .md,
196208 ),
209+ expandedCrossAxisAlignment: CrossAxisAlignment .start, // Align content to start
197210 children: [
198211 Text (
199212 l10n.userRoleInterstitialFrequencyDescription,
@@ -202,56 +215,62 @@ class _ArticleAdSettingsFormState extends State<ArticleAdSettingsForm> {
202215 context,
203216 ).colorScheme.onSurface.withOpacity (0.7 ),
204217 ),
218+ textAlign: TextAlign .start, // Ensure text aligns to start
205219 ),
206220 const SizedBox (height: AppSpacing .lg),
221+ // Replaced SegmentedButton with TabBar for role selection
207222 Align (
208223 alignment: AlignmentDirectional .centerStart,
209- child: SegmentedButton <AppUserRole >(
210- style: SegmentedButton .styleFrom (
211- shape: const RoundedRectangleBorder (
212- borderRadius: BorderRadius .zero,
213- ),
224+ child: SizedBox (
225+ height: kTextTabBarHeight,
226+ child: TabBar (
227+ controller: _tabController,
228+ tabAlignment: TabAlignment .start,
229+ isScrollable: true ,
230+ tabs: AppUserRole .values
231+ .map ((role) => Tab (text: role.l10n (context)))
232+ .toList (),
214233 ),
215- segments: AppUserRole .values
234+ ),
235+ ),
236+ const SizedBox (height: AppSpacing .lg),
237+ // TabBarView to display role-specific fields
238+ SizedBox (
239+ height: 250 , // Fixed height for TabBarView within a ListView
240+ child: TabBarView (
241+ controller: _tabController,
242+ children: AppUserRole .values
216243 .map (
217- (role) => ButtonSegment <AppUserRole >(
218- value: role,
219- label: Text (role.l10n (context)),
244+ (role) => _buildInterstitialRoleSpecificFields (
245+ context,
246+ l10n,
247+ role,
248+ articleAdConfig.interstitialAdConfiguration,
220249 ),
221250 )
222251 .toList (),
223- selected: {_selectedUserRole},
224- onSelectionChanged: (newSelection) {
225- setState (() {
226- _selectedUserRole = newSelection.first;
227- });
228- },
229252 ),
230253 ),
231- const SizedBox (height: AppSpacing .lg),
232- _buildInterstitialRoleSpecificFields (
233- context,
234- l10n,
235- _selectedUserRole,
236- articleAdConfig.interstitialAdConfiguration,
237- ),
238254 ],
239255 ),
240256 ],
241257 ),
242258 const SizedBox (height: AppSpacing .lg),
243259 ExpansionTile (
244260 title: Text (l10n.inArticleAdSlotPlacementsTitle),
245- childrenPadding: const EdgeInsets .symmetric (
246- horizontal: AppSpacing .xxl,
247- vertical: AppSpacing .md,
261+ childrenPadding: const EdgeInsetsDirectional .only (
262+ start: AppSpacing .lg, // Adjusted padding for hierarchy
263+ top: AppSpacing .md,
264+ bottom: AppSpacing .md,
248265 ),
266+ expandedCrossAxisAlignment: CrossAxisAlignment .start, // Align content to start
249267 children: [
250268 Text (
251269 l10n.inArticleAdSlotPlacementsDescription,
252270 style: Theme .of (context).textTheme.bodySmall? .copyWith (
253271 color: Theme .of (context).colorScheme.onSurface.withOpacity (0.7 ),
254272 ),
273+ textAlign: TextAlign .start, // Ensure text aligns to start
255274 ),
256275 const SizedBox (height: AppSpacing .lg),
257276 ...articleAdConfig.inArticleAdSlotConfigurations.map (
0 commit comments