Skip to content

Commit c32f345

Browse files
committed
feat: Display headline details directly
- Removed HeadlineDetailsBloc - Simplified page logic - Added share functionality - Improved snackbar messages
1 parent cfb14c8 commit c32f345

File tree

1 file changed

+57
-96
lines changed

1 file changed

+57
-96
lines changed

lib/headline-details/view/headline_details_page.dart

Lines changed: 57 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -4,129 +4,84 @@
44
import 'package:flutter/material.dart';
55
import 'package:flutter_bloc/flutter_bloc.dart';
66
import 'package:ht_main/account/bloc/account_bloc.dart'; // Import AccountBloc
7-
import 'package:ht_main/headline-details/bloc/headline_details_bloc.dart';
87
import 'package:ht_main/l10n/l10n.dart';
98
import 'package:ht_main/shared/shared.dart';
109
import 'package:ht_shared/ht_shared.dart'
1110
show Headline; // Import Headline model
1211
import 'package:intl/intl.dart';
12+
import 'package:share_plus/share_plus.dart'; // Import share_plus
1313
import 'package:url_launcher/url_launcher_string.dart';
1414

1515
class HeadlineDetailsPage extends StatelessWidget {
16-
const HeadlineDetailsPage({required this.headlineId, super.key});
16+
const HeadlineDetailsPage({required this.headline, super.key});
1717

18-
final String headlineId;
18+
final Headline headline;
1919

2020
@override
2121
Widget build(BuildContext context) {
2222
final l10n = context.l10n;
23-
// Keep a reference to headlineDetailsState to use in BlocListener
24-
final headlineDetailsState = context.watch<HeadlineDetailsBloc>().state;
23+
// Headline is now a direct member: this.headline
24+
// No longer need to watch HeadlineDetailsBloc or its state here.
2525

2626
return SafeArea(
2727
child: Scaffold(
28-
// Body contains the BlocBuilder which returns either state widgets
29-
// or the scroll view
3028
body: BlocListener<AccountBloc, AccountState>(
3129
listenWhen: (previous, current) {
32-
// Listen if status is failure or if the saved status of *this* headline changed
3330
if (current.status == AccountStatus.failure &&
3431
previous.status != AccountStatus.failure) {
3532
return true;
3633
}
37-
if (headlineDetailsState is HeadlineDetailsLoaded) {
38-
final currentHeadlineId = headlineDetailsState.headline.id;
39-
final wasPreviouslySaved =
40-
previous.preferences?.savedHeadlines.any(
41-
(h) => h.id == currentHeadlineId,
42-
) ??
43-
false;
44-
final isCurrentlySaved =
45-
current.preferences?.savedHeadlines.any(
46-
(h) => h.id == currentHeadlineId,
47-
) ??
48-
false;
49-
// Listen if the specific headline's saved status changed OR
50-
// if a general success occurred (e.g. after an optimistic update that might not change the list length but confirms persistence)
51-
return (wasPreviouslySaved != isCurrentlySaved) ||
52-
(current.status == AccountStatus.success &&
53-
previous.status != AccountStatus.success);
54-
}
55-
return false;
34+
final currentHeadlineId = headline.id;
35+
final wasPreviouslySaved =
36+
previous.preferences?.savedHeadlines.any(
37+
(h) => h.id == currentHeadlineId,
38+
) ??
39+
false;
40+
final isCurrentlySaved =
41+
current.preferences?.savedHeadlines.any(
42+
(h) => h.id == currentHeadlineId,
43+
) ??
44+
false;
45+
return (wasPreviouslySaved != isCurrentlySaved) ||
46+
(current.status == AccountStatus.success &&
47+
previous.status != AccountStatus.success);
5648
},
5749
listener: (context, accountState) {
58-
if (headlineDetailsState is HeadlineDetailsLoaded) {
59-
final currentHeadline = headlineDetailsState.headline;
60-
final nowIsSaved =
61-
accountState.preferences?.savedHeadlines.any(
62-
(h) => h.id == currentHeadline.id,
63-
) ??
64-
false;
50+
final nowIsSaved =
51+
accountState.preferences?.savedHeadlines.any(
52+
(h) => h.id == headline.id,
53+
) ??
54+
false;
6555

66-
if (accountState.status == AccountStatus.failure &&
67-
accountState.errorMessage != null) {
68-
ScaffoldMessenger.of(context)
69-
..hideCurrentSnackBar()
70-
..showSnackBar(
71-
SnackBar(
72-
content: Text(
73-
accountState.errorMessage ??
74-
l10n.headlineSaveErrorSnackbar,
75-
), // Use specific or generic error
76-
backgroundColor: Theme.of(context).colorScheme.error,
56+
if (accountState.status == AccountStatus.failure &&
57+
accountState.errorMessage != null) {
58+
ScaffoldMessenger.of(context)
59+
..hideCurrentSnackBar()
60+
..showSnackBar(
61+
SnackBar(
62+
content: Text(
63+
accountState.errorMessage ??
64+
l10n.headlineSaveErrorSnackbar,
7765
),
78-
);
79-
} else {
80-
// Only show success snackbar if the state isn't failure
81-
ScaffoldMessenger.of(context)
82-
..hideCurrentSnackBar()
83-
..showSnackBar(
84-
SnackBar(
85-
content: Text(
86-
nowIsSaved
87-
? l10n.headlineSavedSuccessSnackbar
88-
: l10n.headlineUnsavedSuccessSnackbar,
89-
),
90-
duration: const Duration(seconds: 2),
66+
backgroundColor: Theme.of(context).colorScheme.error,
67+
),
68+
);
69+
} else {
70+
ScaffoldMessenger.of(context)
71+
..hideCurrentSnackBar()
72+
..showSnackBar(
73+
SnackBar(
74+
content: Text(
75+
nowIsSaved
76+
? l10n.headlineSavedSuccessSnackbar
77+
: l10n.headlineUnsavedSuccessSnackbar,
9178
),
92-
);
93-
}
79+
duration: const Duration(seconds: 2),
80+
),
81+
);
9482
}
95-
},
96-
child: BlocBuilder<HeadlineDetailsBloc, HeadlineDetailsState>(
97-
// No need to re-watch headlineDetailsState here, already have it.
98-
// builder: (context, state) // state here is headlineDetailsState
99-
builder: (context, headlineDetailsBuilderState) {
100-
// Handle Loading/Initial/Failure states outside the scroll view
101-
// for better user experience.
102-
// Use headlineDetailsBuilderState for the switch
103-
return switch (headlineDetailsBuilderState) {
104-
HeadlineDetailsInitial _ => InitialStateWidget(
105-
icon: Icons.article,
106-
headline: l10n.headlineDetailsInitialHeadline,
107-
subheadline: l10n.headlineDetailsInitialSubheadline,
108-
),
109-
HeadlineDetailsLoading _ => LoadingStateWidget(
110-
icon: Icons.downloading,
111-
headline: l10n.headlineDetailsLoadingHeadline,
112-
subheadline: l10n.headlineDetailsLoadingSubheadline,
113-
),
114-
final HeadlineDetailsFailure state => FailureStateWidget(
115-
message: state.message,
116-
onRetry: () {
117-
context.read<HeadlineDetailsBloc>().add(
118-
HeadlineDetailsRequested(headlineId: headlineId),
119-
);
120-
},
121-
),
122-
final HeadlineDetailsLoaded state => _buildLoadedContent(
123-
context,
124-
state.headline,
125-
),
126-
_ => const SizedBox.shrink(), // Should not happen in practice
127-
};
128-
},
129-
),
83+
}, // Corrected: Removed extra closing brace from here
84+
child: _buildLoadedContent(context, headline),
13085
),
13186
),
13287
);
@@ -168,8 +123,14 @@ class HeadlineDetailsPage extends StatelessWidget {
168123

169124
final shareButton = IconButton(
170125
icon: const Icon(Icons.share),
126+
tooltip: l10n.shareActionTooltip, // Added tooltip
171127
onPressed: () {
172-
// TODO(fulleni): Implement share functionality
128+
// Construct the share text
129+
// Use headline.url if available, otherwise just the title
130+
final shareText = headline.url != null
131+
? '${headline.title}\n\n${headline.url}'
132+
: headline.title;
133+
Share.share(shareText);
173134
},
174135
);
175136

0 commit comments

Comments
 (0)