fix: Refactor and fixes

This commit is contained in:
Jacques 2024-01-25 13:36:56 +01:00
parent e99e81c907
commit 73ac508622
8 changed files with 100 additions and 50 deletions

View file

@ -14,6 +14,7 @@ var options = TimelineOptions(
textInputBuilder: null,
padding: const EdgeInsets.all(20).copyWith(top: 28),
allowAllDeletion: true,
categoriesOptions: CategoriesOptions(
categoriesBuilder: (context) => [
const TimelineCategory(
key: null,
@ -31,6 +32,7 @@ var options = TimelineOptions(
icon: SizedBox.shrink(),
),
],
),
);
void createPost(BuildContext context, TimelineService service,

View file

@ -30,6 +30,8 @@ Widget _timelineScreenRoute(
onUserTap: (userId) {
configuration.onUserTap?.call(context, userId);
},
filterEnabled: configuration.filterEnabled,
postWidgetBuilder: configuration.postWidgetBuilder,
);
Widget _postDetailScreenRoute(

View file

@ -26,6 +26,8 @@ List<GoRoute> getTimelineStoryRoutes(
await context.push(
TimelineUserStoryRoutes.timelineViewPath(post.id),
),
filterEnabled: configuration.filterEnabled,
postWidgetBuilder: configuration.postWidgetBuilder,
);
return buildScreenWithoutTransition(

View file

@ -17,6 +17,8 @@ class TimelineUserStoryConfiguration {
this.onPostTap,
this.onUserTap,
this.onPostDelete,
this.filterEnabled = false,
this.postWidgetBuilder,
});
final String userId;
@ -34,4 +36,8 @@ class TimelineUserStoryConfiguration {
final Function(BuildContext context, TimelinePost post)? onPostTap;
final Widget Function(BuildContext context, TimelinePost post)? onPostDelete;
final bool filterEnabled;
final Widget Function(TimelinePost post)? postWidgetBuilder;
}

View file

@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: 2023 Iconica
//
// SPDX-License-Identifier: BSD-3-Clause
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:flutter_image_picker/flutter_image_picker.dart';
import 'package:flutter_timeline_interface/flutter_timeline_interface.dart';
@ -9,7 +10,7 @@ import 'package:flutter_timeline_view/src/config/timeline_translations.dart';
import 'package:intl/intl.dart';
class TimelineOptions {
TimelineOptions({
const TimelineOptions({
this.theme = const TimelineTheme(),
this.translations = const TimelineTranslations.empty(),
this.imagePickerConfig = const ImagePickerConfig(),
@ -40,13 +41,8 @@ class TimelineOptions {
this.iconSize = 26,
this.postWidgetheight,
this.postPadding = const EdgeInsets.all(12.0),
this.categoriesBuilder,
this.categoryButtonBuilder,
this.categorySelectorHorizontalPadding,
this.filterEnabled = false,
this.initialFilterWord,
this.searchBarBuilder,
this.postWidget,
this.filterOptions = const FilterOptions(),
this.categoriesOptions = const CategoriesOptions(),
});
/// Theming options for the timeline
@ -120,6 +116,18 @@ class TimelineOptions {
/// Padding of each post
final EdgeInsets postPadding;
final FilterOptions filterOptions;
final CategoriesOptions categoriesOptions;
}
class CategoriesOptions {
const CategoriesOptions({
this.categoriesBuilder,
this.categoryButtonBuilder,
this.categorySelectorHorizontalPadding,
});
/// List of categories that the user can select.
/// If this is null no categories will be shown.
final List<TimelineCategory> Function(BuildContext context)?
@ -136,22 +144,39 @@ class TimelineOptions {
/// Overides the standard horizontal padding of the whole category selector.
final double? categorySelectorHorizontalPadding;
/// if true the filter textfield is enabled.
bool filterEnabled;
TimelineCategory? getCategoryByKey(
BuildContext context,
String? key,
) {
if (categoriesBuilder == null) {
return null;
}
return categoriesBuilder!
.call(context)
.firstWhereOrNull((category) => category.key == key);
}
}
class FilterOptions {
const FilterOptions({
this.initialFilterWord,
this.searchBarBuilder,
this.onFilterEnabledChange,
});
/// Set a value to search through posts. When set the searchbar is shown.
/// If null no searchbar is shown.
final String? initialFilterWord;
// Possibilty to override the standard search bar.
final Widget Function(
Future<List<TimelinePost>> Function(
String filterWord,
Map<String, dynamic> options,
) search,
)? searchBarBuilder;
/// Override the standard postwidget
final Widget Function(TimelinePost post)? postWidget;
final void Function({required bool filterEnabled})? onFilterEnabledChange;
}
typedef ButtonBuilder = Widget Function(

View file

@ -18,6 +18,8 @@ class TimelineScreen extends StatefulWidget {
this.onUserTap,
this.posts,
this.timelineCategory,
this.postWidgetBuilder,
this.filterEnabled = false,
super.key,
});
@ -46,21 +48,28 @@ class TimelineScreen extends StatefulWidget {
/// If this is not null, the user can tap on the user avatar or name
final Function(String userId)? onUserTap;
/// Override the standard postwidget
final Widget Function(TimelinePost post)? postWidgetBuilder;
/// if true the filter textfield is enabled.
final bool filterEnabled;
@override
State<TimelineScreen> createState() => _TimelineScreenState();
}
class _TimelineScreenState extends State<TimelineScreen> {
late ScrollController controller;
late var textFieldController =
TextEditingController(text: widget.options.initialFilterWord);
late var textFieldController = TextEditingController(
text: widget.options.filterOptions.initialFilterWord,
);
late var service = widget.service;
bool isLoading = true;
late var category = widget.timelineCategory;
late var filterWord = widget.options.initialFilterWord;
late var filterWord = widget.options.filterOptions.initialFilterWord;
@override
void initState() {
@ -81,13 +90,7 @@ class _TimelineScreenState extends State<TimelineScreen> {
builder: (context, _) {
var posts = widget.posts ?? service.getPosts(category);
posts = posts
.where(
(p) => category == null || p.category == category,
)
.toList();
if (widget.options.filterEnabled && filterWord != null) {
if (widget.filterEnabled && filterWord != null) {
if (service is TimelineFilterService?) {
posts =
(service as TimelineFilterService).filterPosts(filterWord!, {});
@ -97,6 +100,12 @@ class _TimelineScreenState extends State<TimelineScreen> {
}
}
posts = posts
.where(
(p) => category == null || p.category == category,
)
.toList();
// sort posts by date
if (widget.options.sortPostsAscending != null) {
posts.sort(
@ -112,7 +121,7 @@ class _TimelineScreenState extends State<TimelineScreen> {
SizedBox(
height: widget.options.padding.top,
),
if (widget.options.filterEnabled) ...[
if (widget.filterEnabled) ...[
Padding(
padding: EdgeInsets.symmetric(
horizontal: widget.options.padding.horizontal,
@ -151,8 +160,9 @@ class _TimelineScreenState extends State<TimelineScreen> {
onTap: () {
setState(() {
textFieldController.clear();
widget.options.filterEnabled = false;
filterWord = null;
widget.options.filterOptions.onFilterEnabledChange
?.call(filterEnabled: false);
});
},
child: const Padding(
@ -191,7 +201,7 @@ class _TimelineScreenState extends State<TimelineScreen> {
...posts.map(
(post) => Padding(
padding: widget.options.postPadding,
child: widget.options.postWidget?.call(post) ??
child: widget.postWidgetBuilder?.call(post) ??
TimelinePostWidget(
service: widget.service,
userId: widget.userId,

View file

@ -17,22 +17,23 @@ class CategorySelector extends StatelessWidget {
@override
Widget build(BuildContext context) {
if (options.categoriesBuilder == null) {
if (options.categoriesOptions.categoriesBuilder == null) {
return const SizedBox.shrink();
}
var categories = options.categoriesBuilder!(context);
var categories = options.categoriesOptions.categoriesBuilder!(context);
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [
SizedBox(
width: options.categorySelectorHorizontalPadding ??
width:
options.categoriesOptions.categorySelectorHorizontalPadding ??
max(options.padding.horizontal - 4, 0),
),
for (var category in categories) ...[
options.categoryButtonBuilder?.call(
options.categoriesOptions.categoryButtonBuilder?.call(
categoryKey: category.key,
categoryName: category.title,
onTap: () => onTapCategory(category.key),
@ -48,7 +49,8 @@ class CategorySelector extends StatelessWidget {
),
],
SizedBox(
width: options.categorySelectorHorizontalPadding ??
width:
options.categoriesOptions.categorySelectorHorizontalPadding ??
max(options.padding.horizontal - 4, 0),
),
],

View file

@ -29,6 +29,7 @@ dependencies:
git:
url: https://github.com/Iconica-Development/flutter_image_picker
ref: 1.0.4
collection: any
dev_dependencies:
flutter_lints: ^2.0.0