Skip to content
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
c2eb002
feat(l10n): add Arabic and English translations for about icon and cl…
fulleni Sep 25, 2025
3a32342
feat(app_shell): enhance navigation rail and simplify app bar
fulleni Sep 25, 2025
c7ada33
refactor(app_configuration): improve app configuration page layout
fulleni Sep 25, 2025
97ebae9
refactor(content_management): improve code formatting and structure
fulleni Sep 25, 2025
61187cf
style: format
fulleni Sep 25, 2025
d966b03
style: format
fulleni Sep 25, 2025
619dc4b
feat(settings): add about icon to settings page
fulleni Sep 25, 2025
9a4b38a
feat(ui): add about icon widget
fulleni Sep 25, 2025
2c5b818
feat(ui): add user navigation rail footer widget
fulleni Sep 25, 2025
241696a
feat(shared): add exports for new widgets
fulleni Sep 25, 2025
066fed5
refactor(app_shell): restructure navigation rail and app bar
fulleni Sep 25, 2025
6f532dd
feat(app_configuration): move about icon to app bar title
fulleni Sep 25, 2025
86b857e
feat(ui): add about icon to app bar titles and update user navigation…
fulleni Sep 25, 2025
a64cdab
style(app_configuration): adjust title spacing and remove font style
fulleni Sep 25, 2025
f972771
style(content_management): increase spacing between title and icon
fulleni Sep 25, 2025
d314ad0
style(settings): increase spacing between title and icon
fulleni Sep 25, 2025
6f87789
feat(AboutIcon): customize icon color and size
fulleni Sep 25, 2025
657623e
feat(app_shell): refactor navigation rail and add settings/logout tiles
fulleni Sep 25, 2025
11a5173
refactor: remove unused UserNavigationRailFooter widget
fulleni Sep 25, 2025
850f704
feat(navigator): extend navigator in more screen sizes
fulleni Sep 25, 2025
e8150dc
refactor(widgets): remove unused export
fulleni Sep 25, 2025
3c38f6d
style: misc
fulleni Sep 25, 2025
02502fb
style(content_management): decrease column spacing in headlines page
fulleni Sep 25, 2025
e51691f
style(content_management): improve layout and spacing of action buttons
fulleni Sep 25, 2025
ff69e0d
style(content_management): adjust padding for filter pages
fulleni Sep 25, 2025
016306c
style(spacing): adjust spacing between title and About icon
fulleni Sep 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 103 additions & 35 deletions lib/app/view/app_shell.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,42 +25,12 @@ class AppShell extends StatelessWidget {
@override
Widget build(BuildContext context) {
final l10n = AppLocalizationsX(context).l10n;
final theme = Theme.of(context);

// Use the same text style as the NavigationRail labels for consistency.
final navRailLabelStyle = theme.textTheme.labelMedium;

return Scaffold(
appBar: AppBar(
title: Text(l10n.dashboardTitle),
actions: [
PopupMenuButton<String>(
onSelected: (value) {
if (value == 'settings') {
context.goNamed(Routes.settingsName);
} else if (value == 'signOut') {
context.read<AppBloc>().add(const AppLogoutRequested());
}
},
itemBuilder: (BuildContext context) => <PopupMenuEntry<String>>[
PopupMenuItem<String>(
value: 'settings',
child: Text(l10n.settings),
),
PopupMenuItem<String>(
value: 'signOut',
child: Text(l10n.signOut),
),
],
child: Padding(
padding: const EdgeInsets.all(AppSpacing.sm),
child: CircleAvatar(
backgroundColor: Theme.of(context).colorScheme.primaryContainer,
child: Icon(
Icons.person,
color: Theme.of(context).colorScheme.onPrimaryContainer,
),
),
),
),
const SizedBox(width: AppSpacing.sm),
],
),
body: AdaptiveScaffold(
selectedIndex: navigationShell.currentIndex,
onSelectedIndexChange: (index) {
Expand All @@ -86,6 +56,104 @@ class AppShell extends StatelessWidget {
label: l10n.appConfiguration,
),
],
leadingUnextendedNavRail: const Padding(
padding: EdgeInsets.symmetric(vertical: AppSpacing.lg),
child: Icon(Icons.newspaper_outlined),
),
leadingExtendedNavRail: Padding(
padding: const EdgeInsets.all(AppSpacing.lg),
child: Row(
children: [
const Icon(Icons.newspaper_outlined),
const SizedBox(width: AppSpacing.md),
Text(
l10n.dashboardTitle,
style: theme.textTheme.titleLarge?.copyWith(
color: theme.colorScheme.primary,
),
),
],
),
),
trailingNavRail: Builder(
builder: (context) {
final isExtended =
Breakpoints.mediumLarge.isActive(context) ||
Breakpoints.small.isActive(context);
return Expanded(
child: Padding(
padding: const EdgeInsets.only(bottom: AppSpacing.lg),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
// Settings Tile
InkWell(
onTap: () => context.goNamed(Routes.settingsName),
child: Padding(
padding: EdgeInsets.symmetric(
vertical: AppSpacing.md,
horizontal: isExtended ? 24 : 16,
),
child: Row(
mainAxisAlignment: isExtended
? MainAxisAlignment.start
: MainAxisAlignment.center,
children: [
Icon(
Icons.settings_outlined,
color: theme.colorScheme.onSurfaceVariant,
size: 24,
),
if (isExtended) ...[
const SizedBox(width: AppSpacing.lg),
Text(
l10n.settings,
style: navRailLabelStyle,
),
],
],
),
),
),
// Sign Out Tile
InkWell(
onTap: () => context.read<AppBloc>().add(
const AppLogoutRequested(),
),
child: Padding(
padding: EdgeInsets.symmetric(
vertical: AppSpacing.md,
horizontal: isExtended ? 24 : 16,
),
child: Row(
mainAxisAlignment: isExtended
? MainAxisAlignment.start
: MainAxisAlignment.center,
children: [
Icon(
Icons.logout,
color: theme.colorScheme.error,
size: 24,
),
if (isExtended) ...[
const SizedBox(width: AppSpacing.lg),
Text(
l10n.signOut,
style: navRailLabelStyle?.copyWith(
color: theme.colorScheme.error,
),
),
],
],
),
),
),
],
),
),
);
},
),
body: (_) => Padding(
padding: const EdgeInsets.fromLTRB(
0,
Expand Down
59 changes: 24 additions & 35 deletions lib/app_configuration/view/app_configuration_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'package:flutter_news_app_web_dashboard_full_source_code/app_configuratio
import 'package:flutter_news_app_web_dashboard_full_source_code/app_configuration/view/tabs/feed_configuration_tab.dart';
import 'package:flutter_news_app_web_dashboard_full_source_code/app_configuration/view/tabs/general_configuration_tab.dart';
import 'package:flutter_news_app_web_dashboard_full_source_code/l10n/l10n.dart';
import 'package:flutter_news_app_web_dashboard_full_source_code/shared/widgets/about_icon.dart';
import 'package:ui_kit/ui_kit.dart';

/// {@template app_configuration_page}
Expand Down Expand Up @@ -44,42 +45,30 @@ class _AppConfigurationPageState extends State<AppConfigurationPage>
final l10n = AppLocalizationsX(context).l10n;
return Scaffold(
appBar: AppBar(
title: Text(
l10n.appConfigurationPageTitle,
style: Theme.of(context).textTheme.headlineSmall,
title: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
l10n.appConfigurationPageTitle,
),
const SizedBox(
width: AppSpacing.sm,
),
AboutIcon(
dialogTitle: l10n.appConfigurationPageTitle,
dialogDescription: l10n.appConfigurationPageDescription,
),
],
),
bottom: PreferredSize(
preferredSize: const Size.fromHeight(
kTextTabBarHeight + AppSpacing.lg,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(
left: AppSpacing.lg,
right: AppSpacing.lg,
bottom: AppSpacing.lg,
),
child: Text(
l10n.appConfigurationPageDescription,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
),
TabBar(
controller: _tabController,
tabAlignment: TabAlignment.start,
isScrollable: true,
tabs: [
Tab(text: l10n.generalTab),
Tab(text: l10n.feedTab),
Tab(text: l10n.advertisementsTab),
],
),
],
),
bottom: TabBar(
controller: _tabController,
tabAlignment: TabAlignment.start,
isScrollable: true,
tabs: [
Tab(text: l10n.generalTab),
Tab(text: l10n.feedTab),
Tab(text: l10n.advertisementsTab),
],
),
),
body: BlocConsumer<AppConfigurationBloc, AppConfigurationState>(
Expand Down
3 changes: 0 additions & 3 deletions lib/app_configuration/widgets/feed_ad_settings_form.dart
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,6 @@ class _FeedAdSettingsFormState extends State<FeedAdSettingsForm>
vsync: this,
);
_initializeControllers();
// Removed _tabController.addListener(_onTabChanged); as automatic disabling
// for premium users is no longer required.
}

/// Initializes text editing controllers for each user role based on current
Expand Down Expand Up @@ -272,7 +270,6 @@ class _FeedAdSettingsFormState extends State<FeedAdSettingsForm>
FeedAdConfiguration config,
) {
final roleConfig = config.visibleTo[role];
// Removed isEnabled check as premium users can now be manually configured.

return Column(
children: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,6 @@ class _InterstitialAdSettingsFormState extends State<InterstitialAdSettingsForm>
vsync: this,
);
_initializeControllers();
// Removed _tabController.addListener(_onTabChanged); as automatic disabling
// for premium users is no longer required.
}

/// Initializes text editing controllers for each user role based on current
Expand Down Expand Up @@ -204,7 +202,6 @@ class _InterstitialAdSettingsFormState extends State<InterstitialAdSettingsForm>
InterstitialAdConfiguration config,
) {
final roleConfig = config.visibleTo[role];
// Removed isEnabled check as premium users can now be manually configured.

return Column(
children: [
Expand Down Expand Up @@ -265,7 +262,6 @@ class _InterstitialAdSettingsFormState extends State<InterstitialAdSettingsForm>
},
controller:
_transitionsBeforeShowingInterstitialAdsControllers[role],
// Removed enabled: isEnabled
),
),
],
Expand Down
16 changes: 9 additions & 7 deletions lib/content_management/bloc/content_management_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,10 @@ class ContentManagementBloc
);
});

_deletionEventsSubscription = _pendingDeletionsService.deletionEvents.listen(
(event) => add(DeletionEventReceived(event)),
);
_deletionEventsSubscription = _pendingDeletionsService.deletionEvents
.listen(
(event) => add(DeletionEventReceived(event)),
);
}

final DataRepository<Headline> _headlinesRepository;
Expand All @@ -120,7 +121,8 @@ class ContentManagementBloc
late final StreamSubscription<Type> _headlineUpdateSubscription;
late final StreamSubscription<Type> _topicUpdateSubscription;
late final StreamSubscription<Type> _sourceUpdateSubscription;
late final StreamSubscription<DeletionEvent<dynamic>> _deletionEventsSubscription;
late final StreamSubscription<DeletionEvent<dynamic>>
_deletionEventsSubscription;

@override
Future<void> close() {
Expand Down Expand Up @@ -221,7 +223,8 @@ class ContentManagementBloc
final previousHeadlines = isPaginating ? state.headlines : <Headline>[];

final paginatedHeadlines = await _headlinesRepository.readAll(
filter: event.filter ?? buildHeadlinesFilterMap(_headlinesFilterBloc.state),
filter:
event.filter ?? buildHeadlinesFilterMap(_headlinesFilterBloc.state),
sort: [const SortOption('updatedAt', SortOrder.desc)],
pagination: PaginationOptions(
cursor: event.startAfterId,
Expand Down Expand Up @@ -609,8 +612,7 @@ class ContentManagementBloc
final previousSources = isPaginating ? state.sources : <Source>[];

final paginatedSources = await _sourcesRepository.readAll(
filter:
event.filter ?? buildSourcesFilterMap(_sourcesFilterBloc.state),
filter: event.filter ?? buildSourcesFilterMap(_sourcesFilterBloc.state),
sort: [const SortOption('updatedAt', SortOrder.desc)],
pagination: PaginationOptions(
cursor: event.startAfterId,
Expand Down
8 changes: 3 additions & 5 deletions lib/content_management/bloc/content_management_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,9 @@ class ContentManagementState extends Equatable {
sources: sources ?? this.sources,
sourcesCursor: sourcesCursor ?? this.sourcesCursor,
sourcesHasMore: sourcesHasMore ?? this.sourcesHasMore,
exception: exception, // Explicitly set to null if not provided
lastPendingDeletionId:
lastPendingDeletionId, // Explicitly set to null if not provided
snackbarMessage:
snackbarMessage, // Explicitly set to null if not provided
exception: exception,
lastPendingDeletionId: lastPendingDeletionId,
snackbarMessage: snackbarMessage,
);
}

Expand Down
Loading
Loading