Skip to content

Commit 844ea7d

Browse files
committed
refactor(app_configuration): implement single ExpansionTile open functionality
- Convert AdvertisementsConfigurationTab to StatefulWidget - Add ValueNotifier to track expanded tile index - Modify ExpansionTiles to collapse when others are opened - Ensure only one top-level ExpansionTile can be open at a time
1 parent 2c84455 commit 844ea7d

File tree

1 file changed

+95
-43
lines changed

1 file changed

+95
-43
lines changed

lib/app_configuration/view/tabs/advertisements_configuration_tab.dart

Lines changed: 95 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@ import 'package:flutter_news_app_web_dashboard_full_source_code/app_configuratio
44
import 'package:flutter_news_app_web_dashboard_full_source_code/app_configuration/widgets/article_ad_settings_form.dart';
55
import 'package:flutter_news_app_web_dashboard_full_source_code/app_configuration/widgets/feed_ad_settings_form.dart';
66
import 'package:flutter_news_app_web_dashboard_full_source_code/l10n/l10n.dart';
7+
import 'package:flutter/foundation.dart';
78
import 'package:ui_kit/ui_kit.dart';
89

910
/// {@template advertisements_configuration_tab}
1011
/// A widget representing the "Advertisements" tab in the App Configuration page.
1112
///
1213
/// This tab allows configuration of various ad settings.
1314
/// {@endtemplate}
14-
class AdvertisementsConfigurationTab extends StatelessWidget {
15+
class AdvertisementsConfigurationTab extends StatefulWidget {
1516
/// {@macro advertisements_configuration_tab}
1617
const AdvertisementsConfigurationTab({
1718
required this.remoteConfig,
@@ -25,6 +26,24 @@ class AdvertisementsConfigurationTab extends StatelessWidget {
2526
/// Callback to notify parent of changes to the [RemoteConfig].
2627
final ValueChanged<RemoteConfig> onConfigChanged;
2728

29+
@override
30+
State<AdvertisementsConfigurationTab> createState() =>
31+
_AdvertisementsConfigurationTabState();
32+
}
33+
34+
class _AdvertisementsConfigurationTabState
35+
extends State<AdvertisementsConfigurationTab> {
36+
/// Notifier for the index of the currently expanded top-level ExpansionTile.
37+
///
38+
/// A value of `null` means no tile is expanded.
39+
final ValueNotifier<int?> _expandedTileIndex = ValueNotifier<int?>(null);
40+
41+
@override
42+
void dispose() {
43+
_expandedTileIndex.dispose();
44+
super.dispose();
45+
}
46+
2847
@override
2948
Widget build(BuildContext context) {
3049
final l10n = AppLocalizationsX(context).l10n;
@@ -33,54 +52,87 @@ class AdvertisementsConfigurationTab extends StatelessWidget {
3352
padding: const EdgeInsets.all(AppSpacing.lg),
3453
children: [
3554
// Top-level ExpansionTile for Ad Platform Configuration
36-
ExpansionTile(
37-
title: Text(l10n.adPlatformConfigurationTitle),
38-
childrenPadding: const EdgeInsetsDirectional.only(
39-
start: AppSpacing.lg, // Adjusted padding for hierarchy
40-
top: AppSpacing.md,
41-
bottom: AppSpacing.md,
42-
),
43-
expandedCrossAxisAlignment: CrossAxisAlignment.start, // Align content to start
44-
children: [
45-
AdPlatformConfigForm(
46-
remoteConfig: remoteConfig,
47-
onConfigChanged: onConfigChanged,
48-
),
49-
],
55+
ValueListenableBuilder<int?>(
56+
valueListenable: _expandedTileIndex,
57+
builder: (context, expandedIndex, child) {
58+
const tileIndex = 0;
59+
return ExpansionTile(
60+
key: ValueKey('adPlatformConfigTile_$expandedIndex'),
61+
title: Text(l10n.adPlatformConfigurationTitle),
62+
childrenPadding: const EdgeInsetsDirectional.only(
63+
start: AppSpacing.lg,
64+
top: AppSpacing.md,
65+
bottom: AppSpacing.md,
66+
),
67+
expandedCrossAxisAlignment: CrossAxisAlignment.start,
68+
onExpansionChanged: (isExpanded) {
69+
_expandedTileIndex.value = isExpanded ? tileIndex : null;
70+
},
71+
initiallyExpanded: expandedIndex == tileIndex,
72+
children: [
73+
AdPlatformConfigForm(
74+
remoteConfig: widget.remoteConfig,
75+
onConfigChanged: widget.onConfigChanged,
76+
),
77+
],
78+
);
79+
},
5080
),
5181
const SizedBox(height: AppSpacing.lg),
5282
// Top-level ExpansionTile for Feed Ad Settings
53-
ExpansionTile(
54-
title: Text(l10n.feedAdSettingsTitle),
55-
childrenPadding: const EdgeInsetsDirectional.only(
56-
start: AppSpacing.lg, // Adjusted padding for hierarchy
57-
top: AppSpacing.md,
58-
bottom: AppSpacing.md,
59-
),
60-
expandedCrossAxisAlignment: CrossAxisAlignment.start, // Align content to start
61-
children: [
62-
FeedAdSettingsForm(
63-
remoteConfig: remoteConfig,
64-
onConfigChanged: onConfigChanged,
65-
),
66-
],
83+
ValueListenableBuilder<int?>(
84+
valueListenable: _expandedTileIndex,
85+
builder: (context, expandedIndex, child) {
86+
const tileIndex = 1;
87+
return ExpansionTile(
88+
key: ValueKey('feedAdSettingsTile_$expandedIndex'),
89+
title: Text(l10n.feedAdSettingsTitle),
90+
childrenPadding: const EdgeInsetsDirectional.only(
91+
start: AppSpacing.lg,
92+
top: AppSpacing.md,
93+
bottom: AppSpacing.md,
94+
),
95+
expandedCrossAxisAlignment: CrossAxisAlignment.start,
96+
onExpansionChanged: (isExpanded) {
97+
_expandedTileIndex.value = isExpanded ? tileIndex : null;
98+
},
99+
initiallyExpanded: expandedIndex == tileIndex,
100+
children: [
101+
FeedAdSettingsForm(
102+
remoteConfig: widget.remoteConfig,
103+
onConfigChanged: widget.onConfigChanged,
104+
),
105+
],
106+
);
107+
},
67108
),
68109
const SizedBox(height: AppSpacing.lg),
69110
// Top-level ExpansionTile for Article Ad Settings
70-
ExpansionTile(
71-
title: Text(l10n.articleAdSettingsTitle),
72-
childrenPadding: const EdgeInsetsDirectional.only(
73-
start: AppSpacing.lg, // Adjusted padding for hierarchy
74-
top: AppSpacing.md,
75-
bottom: AppSpacing.md,
76-
),
77-
expandedCrossAxisAlignment: CrossAxisAlignment.start, // Align content to start
78-
children: [
79-
ArticleAdSettingsForm(
80-
remoteConfig: remoteConfig,
81-
onConfigChanged: onConfigChanged,
82-
),
83-
],
111+
ValueListenableBuilder<int?>(
112+
valueListenable: _expandedTileIndex,
113+
builder: (context, expandedIndex, child) {
114+
const tileIndex = 2;
115+
return ExpansionTile(
116+
key: ValueKey('articleAdSettingsTile_$expandedIndex'),
117+
title: Text(l10n.articleAdSettingsTitle),
118+
childrenPadding: const EdgeInsetsDirectional.only(
119+
start: AppSpacing.lg,
120+
top: AppSpacing.md,
121+
bottom: AppSpacing.md,
122+
),
123+
expandedCrossAxisAlignment: CrossAxisAlignment.start,
124+
onExpansionChanged: (isExpanded) {
125+
_expandedTileIndex.value = isExpanded ? tileIndex : null;
126+
},
127+
initiallyExpanded: expandedIndex == tileIndex,
128+
children: [
129+
ArticleAdSettingsForm(
130+
remoteConfig: widget.remoteConfig,
131+
onConfigChanged: widget.onConfigChanged,
132+
),
133+
],
134+
);
135+
},
84136
),
85137
],
86138
);

0 commit comments

Comments
 (0)