Skip to content
Merged
Show file tree
Hide file tree
Changes from 91 commits
Commits
Show all changes
94 commits
Select commit Hold shift + click to select a range
91556e2
refactor(bootstrap): restructure app initialization process
fulleni Sep 15, 2025
0f71f7a
feat(app): enhance App widget documentation and functionality
fulleni Sep 15, 2025
1f8fe32
refactor(AppBloc): enhance initial bootstrap with remote config
fulleni Sep 15, 2025
bec635f
refactor(data): inline countriesClient initialization
fulleni Sep 15, 2025
95fc7bc
fix(bootstrap): handle remote config fetch errors
fulleni Sep 15, 2025
e0220e2
refactor(status): replace StatusPage with CriticalErrorPage
fulleni Sep 15, 2025
ede7c04
feat(app): implement critical error handling
fulleni Sep 15, 2025
7ac9ae4
refactor(app): simplify app lifecycle and error handling
fulleni Sep 15, 2025
422fdbf
refactor(app): improve initial app config fetching and error handling
fulleni Sep 15, 2025
4c9c770
feat(app): add user preferences management in AppState
fulleni Sep 15, 2025
8a01f5f
feat(app): add AppStarted event for initial app bootstrap
fulleni Sep 15, 2025
e966179
refactor(AppBloc): improve app startup and data loading process
fulleni Sep 15, 2025
2bffd3e
feat(app): implement user preferences loading and error handling
fulleni Sep 15, 2025
0a78bbd
refactor(settings): rethrow exceptions for centralized error handling
fulleni Sep 15, 2025
3a89338
refactor(app): improve AppBloc initialization and user data loading
fulleni Sep 15, 2025
22ca2f2
feat(app): add AppUserDataLoaded event
fulleni Sep 15, 2025
ccfa889
refactor(app): make `settings` nullable in `AppState`
fulleni Sep 15, 2025
b977696
refactor(app): improve app initialization and loading state handling
fulleni Sep 15, 2025
49e275b
refactor(app): derive theme and display settings from UserAppSettings
fulleni Sep 16, 2025
9720106
refactor(app): update AppEvent hierarchy and add new events
fulleni Sep 16, 2025
d59645b
refactor(bloc): streamline AppBloc and enhanceAppState
fulleni Sep 16, 2025
81b7a08
refactor(app): improve code structure and naming
fulleni Sep 16, 2025
ed1815c
fix(app): use AppPeriodicConfigFetchRequested for background checks
fulleni Sep 16, 2025
a1248fc
refactor(app): remove unused AppUserDataLoaded event
fulleni Sep 16, 2025
c60f14f
refactor(AppBloc): centralize user data fetching logic
fulleni Sep 16, 2025
27ffefc
refactor(app): split AppSettingsRefreshed into more specific events
fulleni Sep 16, 2025
38ba5dd
refactor(app): split user settings fetch into separate functions
fulleni Sep 16, 2025
49e2be1
fix(settings): update font settings page to use correct event
fulleni Sep 16, 2025
c0f829d
refactor(router): remove unused AccountBloc parameter
fulleni Sep 16, 2025
76a6b3a
feat(app): add event for user content preferences changes
fulleni Sep 16, 2025
ef192c4
feat(app): implement user content preferences update in AppBloc
fulleni Sep 16, 2025
f5fc7dc
refactor(account): remove preferences from AccountState
fulleni Sep 16, 2025
6ee2e69
refactor(account): remove unused account events
fulleni Sep 16, 2025
67a4a9a
refactor(account): remove UserContentPreferences handling
fulleni Sep 16, 2025
e7393d4
refactor(account): remove account bloc and related files
fulleni Sep 16, 2025
6ae8a53
refactor(account): migrate saved headlines from AccountBloc to AppBloc
fulleni Sep 16, 2025
f0712bb
refactor(account): replace AccountBloc with AppBloc in country manage…
fulleni Sep 16, 2025
5b8df18
refactor(account): migrate followed countries page to AppBloc
fulleni Sep 16, 2025
4336f88
refactor(account): move source following functionality to app bloc
fulleni Sep 16, 2025
4a27a1f
refactor(account): migrate FollowedSourcesListPage to AppBloc
fulleni Sep 16, 2025
079a66e
refactor(account): replace AccountBloc with AppBloc in topic management
fulleni Sep 16, 2025
d4a1a72
refactor(account): replace AccountBloc with AppBloc in followed topic…
fulleni Sep 16, 2025
06ed630
refactor(ads): use simplified theme data in interstitial ad manager
fulleni Sep 17, 2025
721e177
refactor(ads): simplify headline image style retrieval
fulleni Sep 17, 2025
86c08e4
feat(app_state): add headlineImageStyle property
fulleni Sep 17, 2025
0e2a81e
perf(ads): optimize ad loader widget performance
fulleni Sep 17, 2025
7d444f2
feat(theme): make text scaling, font weight, and family configurable
fulleni Sep 17, 2025
355c0a0
refactor(entity_details): remove unused user preferences event
fulleni Sep 17, 2025
b6366f3
refactor(entity-details): remove AccountBloc and streamline user pref…
fulleni Sep 17, 2025
25160dd
refactor(entity_details): optimize AppBloc state access
fulleni Sep 17, 2025
556455b
refactor(router): remove shared AccountBloc instance
fulleni Sep 17, 2025
0b3a971
style: format misc
fulleni Sep 17, 2025
61949e3
refactor(headline-details): replace AccountBloc with AppBloc for stat…
fulleni Sep 17, 2025
da31af8
lint: misc
fulleni Sep 17, 2025
bc58d36
refactor(headlines-feed): remove unused countries filter logic
fulleni Sep 17, 2025
3ac09f3
refactor(headlines-feed): remove followed countries from filter state
fulleni Sep 17, 2025
d3546c5
refactor(headlines-feed): simplify user preferences retrieval and sta…
fulleni Sep 17, 2025
471b887
refactor(headlines-feed): remove unused user content preferences func…
fulleni Sep 17, 2025
f6cb77a
refactor(headlines-feed): improve SourcesFilterApplyFollowedRequested…
fulleni Sep 17, 2025
1cde4c5
refactor(headlines-feed): remove followed sources from filter state
fulleni Sep 17, 2025
3ae57f5
refactor(topics-filter): remove followed topics functionality
fulleni Sep 17, 2025
087bf6f
refactor(headlines-feed): remove followed topics from TopicsFilterState
fulleni Sep 17, 2025
03b539f
refactor(country-filter): update logic and remove BLoC listener
fulleni Sep 17, 2025
78ae116
refactor(headlines-feed): improve source filter page logic and UI
fulleni Sep 17, 2025
5e3a556
refactor(headlines-feed): remove unused AppBloc dependency
fulleni Sep 17, 2025
a091694
refactor(headlines-feed): remove unused event class
fulleni Sep 17, 2025
11ab33a
refactor(headlines-feed): remove unused dependencies in SourcesFilter…
fulleni Sep 17, 2025
d40975b
refactor(headlines-feed): remove unused SourceFilterFollowedApplied e…
fulleni Sep 17, 2025
c475cc1
refactor(headlines-feed): remove unused appBloc dependency
fulleni Sep 17, 2025
8a40741
refactor(headlines-feed): remove unused TopicsFilterApplyFollowedRequ…
fulleni Sep 17, 2025
7b94785
refactor(headlines-feed): remove CountriesFilterBloc from country fil…
fulleni Sep 17, 2025
c2a8406
refactor(headlines-feed): update topic filter page logic
fulleni Sep 17, 2025
3089c69
refactor(headlines-feed): replace AccountBloc with AppBloc in feed page
fulleni Sep 17, 2025
f571bac
refactor(headlines-feed): simplify followed filters logic
fulleni Sep 17, 2025
32f57d9
chore: deleted absolete files
fulleni Sep 17, 2025
ed98b8f
feat(headlines-feed): implement filter event classes
fulleni Sep 17, 2025
ddb7852
feat(headlines-feed): implement HeadlinesFilterState for filter feature
fulleni Sep 17, 2025
b381539
feat(headlines-feed): implement HeadlinesFilterBloc
fulleni Sep 17, 2025
7dc5dce
refactor(headlines-feed): migrate CountryFilterPage to HeadlinesFilte…
fulleni Sep 17, 2025
800b77f
refactor(headlines-feed): remove unnecessary code in headlines feed page
fulleni Sep 17, 2025
9e0ac84
refactor(headlines-feed): migrate SourceFilterPage to HeadlinesFilter…
fulleni Sep 17, 2025
fa60c98
refactor(headlines-feed): migrate TopicFilterPage to use HeadlinesFil…
fulleni Sep 17, 2025
fe33f62
refactor(headlines-feed): implement HeadlinesFilterBloc for state man…
fulleni Sep 17, 2025
7b5e44b
feat(l10n): add loading headline for filters page in headlines feed
fulleni Sep 17, 2025
7a59f9d
refactor(router): remove unused BlocProvider wrappers
fulleni Sep 17, 2025
e95e5b2
refactor(headlines-search): improve HeadlinesSearchBloc documentation…
fulleni Sep 17, 2025
5edcb6e
refactor(headlines-search): improve HeadlinesSearchPage implementation
fulleni Sep 17, 2025
56a41d0
refactor(router): remove redundant AccountBloc provider
fulleni Sep 18, 2025
1777c90
style: format misc
fulleni Sep 18, 2025
6584a42
chore: set app environment to production
fulleni Sep 18, 2025
071d5f2
fix: Prevent "Loading Settings" for unauthenticated users
fulleni Sep 18, 2025
cad13fa
refactor(headline-details): use List.from instead of List.of
fulleni Sep 18, 2025
d902974
refactor(app): improve user data loading logic and state handling
fulleni Sep 18, 2025
6f84e56
chore: switch app environment to demo
fulleni Sep 18, 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
492 changes: 0 additions & 492 deletions lib/account/bloc/account_bloc.dart

This file was deleted.

66 changes: 0 additions & 66 deletions lib/account/bloc/account_event.dart

This file was deleted.

37 changes: 0 additions & 37 deletions lib/account/bloc/account_state.dart

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import 'package:core/core.dart';
import 'package:data_repository/data_repository.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_news_app_mobile_client_full_source_code/account/bloc/account_bloc.dart';
import 'package:flutter_news_app_mobile_client_full_source_code/account/bloc/available_countries_bloc.dart';
import 'package:flutter_news_app_mobile_client_full_source_code/app/bloc/app_bloc.dart';
import 'package:flutter_news_app_mobile_client_full_source_code/l10n/l10n.dart';
import 'package:ui_kit/ui_kit.dart';

Expand Down Expand Up @@ -57,14 +57,14 @@ class AddCountryToFollowPage extends StatelessWidget {

final countries = countriesState.availableCountries;

return BlocBuilder<AccountBloc, AccountState>(
return BlocBuilder<AppBloc, AppState>(
buildWhen: (previous, current) =>
previous.preferences?.followedCountries !=
current.preferences?.followedCountries ||
previous.status != current.status,
builder: (context, accountState) {
previous.userContentPreferences?.followedCountries !=
current.userContentPreferences?.followedCountries,
builder: (context, appState) {
final userContentPreferences = appState.userContentPreferences;
final followedCountries =
accountState.preferences?.followedCountries ?? [];
userContentPreferences?.followedCountries ?? [];

return ListView.builder(
padding: const EdgeInsets.symmetric(
Expand Down Expand Up @@ -150,8 +150,28 @@ class AddCountryToFollowPage extends StatelessWidget {
? l10n.unfollowCountryTooltip(country.name)
: l10n.followCountryTooltip(country.name),
onPressed: () {
context.read<AccountBloc>().add(
AccountFollowCountryToggled(country: country),
if (userContentPreferences == null) return;

final updatedFollowedCountries = List<Country>.from(
followedCountries,
);
if (isFollowed) {
updatedFollowedCountries.removeWhere(
(c) => c.id == country.id,
);
} else {
updatedFollowedCountries.add(country);
}

final updatedPreferences = userContentPreferences
.copyWith(
followedCountries: updatedFollowedCountries,
);

context.read<AppBloc>().add(
AppUserContentPreferencesChanged(
preferences: updatedPreferences,
),
);
},
),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import 'package:core/core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_news_app_mobile_client_full_source_code/account/bloc/account_bloc.dart';
import 'package:flutter_news_app_mobile_client_full_source_code/ads/interstitial_ad_manager.dart';
import 'package:flutter_news_app_mobile_client_full_source_code/app/bloc/app_bloc.dart';
import 'package:flutter_news_app_mobile_client_full_source_code/l10n/l10n.dart';
import 'package:flutter_news_app_mobile_client_full_source_code/router/routes.dart';
import 'package:go_router/go_router.dart';
Expand All @@ -18,8 +18,6 @@ class FollowedCountriesListPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final l10n = AppLocalizationsX(context).l10n;
final followedCountries =
context.watch<AccountBloc>().state.preferences?.followedCountries ?? [];

return Scaffold(
appBar: AppBar(
Expand All @@ -34,33 +32,31 @@ class FollowedCountriesListPage extends StatelessWidget {
),
],
),
body: BlocBuilder<AccountBloc, AccountState>(
builder: (context, state) {
if (state.status == AccountStatus.loading &&
state.preferences == null) {
body: BlocBuilder<AppBloc, AppState>(
builder: (context, appState) {
final user = appState.user;
final userContentPreferences = appState.userContentPreferences;

if (appState.status == AppLifeCycleStatus.loadingUserData ||
userContentPreferences == null) {
return LoadingStateWidget(
icon: Icons.flag_outlined,
headline: l10n.followedCountriesLoadingHeadline,
subheadline: l10n.pleaseWait,
);
}

if (state.status == AccountStatus.failure &&
state.preferences == null) {
if (appState.initialUserPreferencesError != null) {
return FailureStateWidget(
exception:
state.error ??
OperationFailedException(l10n.followedCountriesErrorHeadline),
exception: appState.initialUserPreferencesError!,
onRetry: () {
if (state.user?.id != null) {
context.read<AccountBloc>().add(
AccountLoadUserPreferences(userId: state.user!.id),
);
}
context.read<AppBloc>().add(AppStarted(initialUser: user));
},
);
}

final followedCountries = userContentPreferences.followedCountries;

if (followedCountries.isEmpty) {
return InitialStateWidget(
icon: Icons.location_off_outlined,
Expand Down Expand Up @@ -91,8 +87,18 @@ class FollowedCountriesListPage extends StatelessWidget {
),
tooltip: l10n.unfollowCountryTooltip(country.name),
onPressed: () {
context.read<AccountBloc>().add(
AccountFollowCountryToggled(country: country),
final updatedFollowedCountries = List<Country>.from(
followedCountries,
)..removeWhere((c) => c.id == country.id);

final updatedPreferences = userContentPreferences.copyWith(
followedCountries: updatedFollowedCountries,
);

context.read<AppBloc>().add(
AppUserContentPreferencesChanged(
preferences: updatedPreferences,
),
);
},
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import 'package:core/core.dart';
import 'package:data_repository/data_repository.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_news_app_mobile_client_full_source_code/account/bloc/account_bloc.dart';
import 'package:flutter_news_app_mobile_client_full_source_code/account/bloc/available_sources_bloc.dart';
import 'package:flutter_news_app_mobile_client_full_source_code/app/bloc/app_bloc.dart';
import 'package:flutter_news_app_mobile_client_full_source_code/l10n/l10n.dart';
import 'package:ui_kit/ui_kit.dart';

Expand Down Expand Up @@ -47,14 +47,14 @@ class AddSourceToFollowPage extends StatelessWidget {
);
}

return BlocBuilder<AccountBloc, AccountState>(
return BlocBuilder<AppBloc, AppState>(
buildWhen: (previous, current) =>
previous.preferences?.followedSources !=
current.preferences?.followedSources ||
previous.status != current.status,
builder: (context, accountState) {
previous.userContentPreferences?.followedSources !=
current.userContentPreferences?.followedSources,
builder: (context, appState) {
final userContentPreferences = appState.userContentPreferences;
final followedSources =
accountState.preferences?.followedSources ?? [];
userContentPreferences?.followedSources ?? [];

return ListView.builder(
padding: const EdgeInsets.all(AppSpacing.md),
Expand All @@ -80,8 +80,28 @@ class AddSourceToFollowPage extends StatelessWidget {
? l10n.unfollowSourceTooltip(source.name)
: l10n.followSourceTooltip(source.name),
onPressed: () {
context.read<AccountBloc>().add(
AccountFollowSourceToggled(source: source),
if (userContentPreferences == null) return;

final updatedFollowedSources = List<Source>.from(
followedSources,
);
if (isFollowed) {
updatedFollowedSources.removeWhere(
(s) => s.id == source.id,
);
} else {
updatedFollowedSources.add(source);
}

final updatedPreferences = userContentPreferences
.copyWith(
followedSources: updatedFollowedSources,
);

context.read<AppBloc>().add(
AppUserContentPreferencesChanged(
preferences: updatedPreferences,
),
);
},
),
Expand Down
Loading
Loading