Compare commits

...

3 Commits

Author SHA1 Message Date
1f4e6cf41c fix pagination button. (#298) 2023-11-02 21:50:09 -07:00
be6ed35888 update version. (#297) 2023-11-02 21:09:55 -07:00
b2ea50cea6 add pagination. (#296) 2023-11-02 20:22:51 -07:00
8 changed files with 111 additions and 37 deletions

View File

@ -0,0 +1,5 @@
- Ability to use pagination on home screen.
- Ability to use Material 3 (experimental).
- Ability to search in thread.
- Ability to customize text scale factor.
- Ability to customize app's accent color.

View File

@ -72,6 +72,8 @@ class PreferenceState extends Equatable {
bool get material3Enabled => _isOn<Material3Preference>(); bool get material3Enabled => _isOn<Material3Preference>();
bool get paginationEnabled => _isOn<PaginationPreference>();
double get textScaleFactor => double get textScaleFactor =>
preferences.singleWhereType<TextScaleFactorPreference>().val; preferences.singleWhereType<TextScaleFactorPreference>().val;

View File

@ -334,6 +334,17 @@ class HackiApp extends StatelessWidget {
state.appColor.shade200.withOpacity(0.5), state.appColor.shade200.withOpacity(0.5),
) )
: null, : null,
outlinedButtonTheme: state.material3Enabled
? OutlinedButtonThemeData(
style: ButtonStyle(
side: MaterialStateBorderSide.resolveWith(
(_) => const BorderSide(
color: Palette.grey,
),
),
),
)
: null,
), ),
routerConfig: router, routerConfig: router,
), ),

View File

@ -37,13 +37,14 @@ abstract class Preference<T> extends Equatable with SettingsDisplayable {
const MarkReadStoriesModePreference(), const MarkReadStoriesModePreference(),
// Divider. // Divider.
const NotificationModePreference(), const NotificationModePreference(),
const SwipeGesturePreference(),
const AutoScrollModePreference(), const AutoScrollModePreference(),
const CollapseModePreference(), const CollapseModePreference(),
const ReaderModePreference(), const ReaderModePreference(),
const CustomTabPreference(), const CustomTabPreference(),
const EyeCandyModePreference(), const EyeCandyModePreference(),
const Material3Preference(), const Material3Preference(),
const PaginationPreference(),
const SwipeGesturePreference(),
], ],
); );
@ -75,6 +76,7 @@ const bool _collapseModeDefaultValue = true;
const bool _autoScrollModeDefaultValue = false; const bool _autoScrollModeDefaultValue = false;
const bool _customTabModeDefaultValue = false; const bool _customTabModeDefaultValue = false;
const bool _material3ModeDefaultValue = false; const bool _material3ModeDefaultValue = false;
const bool _paginationModeDefaultValue = false;
const double _textScaleFactorDefaultValue = 1; const double _textScaleFactorDefaultValue = 1;
final int _fetchModeDefaultValue = FetchMode.eager.index; final int _fetchModeDefaultValue = FetchMode.eager.index;
final int _commentsOrderDefaultValue = CommentsOrder.natural.index; final int _commentsOrderDefaultValue = CommentsOrder.natural.index;
@ -287,6 +289,25 @@ class EyeCandyModePreference extends BooleanPreference {
String get subtitle => 'some sort of magic.'; String get subtitle => 'some sort of magic.';
} }
class PaginationPreference extends BooleanPreference {
const PaginationPreference({bool? val})
: super(val: val ?? _paginationModeDefaultValue);
@override
PaginationPreference copyWith({required bool? val}) {
return PaginationPreference(val: val);
}
@override
String get key => 'paginationMode';
@override
String get title => 'Enable Pagination';
@override
String get subtitle => '''so you can get stuff done.''';
}
class Material3Preference extends BooleanPreference { class Material3Preference extends BooleanPreference {
const Material3Preference({bool? val}) const Material3Preference({bool? val})
: super(val: val ?? _material3ModeDefaultValue); : super(val: val ?? _material3ModeDefaultValue);

View File

@ -11,9 +11,7 @@ class InThreadSearchIconButton extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider<CommentsCubit>.value( return OpenContainer(
value: context.read<CommentsCubit>(),
child: OpenContainer(
closedColor: Palette.transparent, closedColor: Palette.transparent,
openColor: Theme.of(context).canvasColor, openColor: Theme.of(context).canvasColor,
closedShape: const CircleBorder(), closedShape: const CircleBorder(),
@ -39,7 +37,6 @@ class InThreadSearchIconButton extends StatelessWidget {
commentsCubit: context.read<CommentsCubit>(), commentsCubit: context.read<CommentsCubit>(),
action: action, action: action,
), ),
),
); );
} }
} }

View File

@ -25,10 +25,12 @@ class ItemsListView<T extends Item> extends StatelessWidget {
this.enablePullDown = true, this.enablePullDown = true,
this.markReadStories = false, this.markReadStories = false,
this.showOfflineBanner = false, this.showOfflineBanner = false,
this.loadStyle = LoadStyle.ShowWhenLoading,
this.onRefresh, this.onRefresh,
this.onLoadMore, this.onLoadMore,
this.onPinned, this.onPinned,
this.header, this.header,
this.footer,
this.onMoreTapped, this.onMoreTapped,
this.scrollController, this.scrollController,
this.itemBuilder, this.itemBuilder,
@ -43,8 +45,10 @@ class ItemsListView<T extends Item> extends StatelessWidget {
final bool markReadStories; final bool markReadStories;
final bool showOfflineBanner; final bool showOfflineBanner;
final LoadStyle loadStyle;
final List<T> items; final List<T> items;
final Widget? header; final Widget? header;
final Widget? footer;
final RefreshController refreshController; final RefreshController refreshController;
final ScrollController? scrollController; final ScrollController? scrollController;
final VoidCallback? onRefresh; final VoidCallback? onRefresh;
@ -224,6 +228,7 @@ class ItemsListView<T extends Item> extends StatelessWidget {
? Column(children: e) ? Column(children: e)
: itemBuilder!(Column(children: e), items.elementAt(index)), : itemBuilder!(Column(children: e), items.elementAt(index)),
), ),
if (footer != null) footer!,
const SizedBox( const SizedBox(
height: Dimens.pt40, height: Dimens.pt40,
), ),
@ -237,7 +242,7 @@ class ItemsListView<T extends Item> extends StatelessWidget {
backgroundColor: Theme.of(context).primaryColor, backgroundColor: Theme.of(context).primaryColor,
), ),
footer: CustomFooter( footer: CustomFooter(
loadStyle: LoadStyle.ShowWhenLoading, loadStyle: loadStyle,
builder: (BuildContext context, LoadStatus? mode) { builder: (BuildContext context, LoadStatus? mode) {
const double height = 55; const double height = 55;
late final Widget body; late final Widget body;

View File

@ -7,6 +7,7 @@ import 'package:hacki/cubits/cubits.dart';
import 'package:hacki/extensions/extensions.dart'; import 'package:hacki/extensions/extensions.dart';
import 'package:hacki/models/models.dart'; import 'package:hacki/models/models.dart';
import 'package:hacki/screens/widgets/widgets.dart'; import 'package:hacki/screens/widgets/widgets.dart';
import 'package:hacki/styles/styles.dart';
import 'package:hacki/utils/utils.dart'; import 'package:hacki/utils/utils.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart'; import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:visibility_detector/visibility_detector.dart'; import 'package:visibility_detector/visibility_detector.dart';
@ -48,7 +49,8 @@ class _StoriesListViewState extends State<StoriesListView>
return BlocBuilder<PreferenceCubit, PreferenceState>( return BlocBuilder<PreferenceCubit, PreferenceState>(
buildWhen: (PreferenceState previous, PreferenceState current) => buildWhen: (PreferenceState previous, PreferenceState current) =>
previous.complexStoryTileEnabled != current.complexStoryTileEnabled || previous.complexStoryTileEnabled != current.complexStoryTileEnabled ||
previous.metadataEnabled != current.metadataEnabled, previous.metadataEnabled != current.metadataEnabled ||
previous.paginationEnabled != current.paginationEnabled,
builder: (BuildContext context, PreferenceState preferenceState) { builder: (BuildContext context, PreferenceState preferenceState) {
return BlocConsumer<StoriesBloc, StoriesState>( return BlocConsumer<StoriesBloc, StoriesState>(
listenWhen: (StoriesState previous, StoriesState current) => listenWhen: (StoriesState previous, StoriesState current) =>
@ -70,8 +72,7 @@ class _StoriesListViewState extends State<StoriesListView>
builder: (BuildContext context, StoriesState state) { builder: (BuildContext context, StoriesState state) {
return ItemsListView<Story>( return ItemsListView<Story>(
showOfflineBanner: true, showOfflineBanner: true,
markReadStories: markReadStories: preferenceState.markReadStoriesEnabled,
context.read<PreferenceCubit>().state.markReadStoriesEnabled,
showWebPreviewOnStoryTile: showWebPreviewOnStoryTile:
preferenceState.complexStoryTileEnabled, preferenceState.complexStoryTileEnabled,
showMetadataOnStoryTile: preferenceState.metadataEnabled, showMetadataOnStoryTile: preferenceState.metadataEnabled,
@ -87,13 +88,42 @@ class _StoriesListViewState extends State<StoriesListView>
context.read<PinCubit>().refresh(); context.read<PinCubit>().refresh();
}, },
onLoadMore: () { onLoadMore: () {
context if (preferenceState.paginationEnabled) {
.read<StoriesBloc>() refreshController
.add(StoriesLoadMore(type: storyType)); ..refreshCompleted(resetFooterState: true)
..loadComplete();
} else {
loadMoreStories();
}
}, },
onTap: onStoryTapped, onTap: onStoryTapped,
onPinned: context.read<PinCubit>().pinStory, onPinned: context.read<PinCubit>().pinStory,
header: state.isOfflineReading ? null : header, header: state.isOfflineReading ? null : header,
loadStyle: LoadStyle.HideAlways,
footer: preferenceState.paginationEnabled &&
state.statusByType[widget.storyType] == Status.success &&
(state.storiesByType[widget.storyType]?.length ?? 0) <
(state.storyIdsByType[widget.storyType]?.length ?? 0)
? Padding(
padding: const EdgeInsets.only(
left: Dimens.pt48,
right: Dimens.pt48,
top: Dimens.pt36,
bottom: Dimens.pt12,
),
child: OutlinedButton(
onPressed: loadMoreStories,
style: ButtonStyle(
foregroundColor: MaterialStateColor.resolveWith(
(_) => Theme.of(context).colorScheme.onSurface,
),
),
child: Text(
'''Load Page ${(state.currentPageByType[widget.storyType] ?? 0) + 2}''',
),
),
)
: null,
onMoreTapped: onMoreTapped, onMoreTapped: onMoreTapped,
itemBuilder: (Widget child, Story story) { itemBuilder: (Widget child, Story story) {
return Slidable( return Slidable(
@ -162,4 +192,7 @@ class _StoriesListViewState extends State<StoriesListView>
}, },
); );
} }
void loadMoreStories() =>
context.read<StoriesBloc>().add(StoriesLoadMore(type: widget.storyType));
} }

View File

@ -1,6 +1,6 @@
name: hacki name: hacki
description: A Hacker News reader. description: A Hacker News reader.
version: 2.1.0+127 version: 2.2.0+128
publish_to: none publish_to: none
environment: environment: