mirror of
https://github.com/Iconica-Development/flutter_timeline.git
synced 2025-05-19 02:23:46 +02:00
fix: Refactor and fixes
This commit is contained in:
parent
e99e81c907
commit
73ac508622
8 changed files with 100 additions and 50 deletions
|
@ -14,23 +14,25 @@ var options = TimelineOptions(
|
|||
textInputBuilder: null,
|
||||
padding: const EdgeInsets.all(20).copyWith(top: 28),
|
||||
allowAllDeletion: true,
|
||||
categoriesBuilder: (context) => [
|
||||
const TimelineCategory(
|
||||
key: null,
|
||||
title: 'All',
|
||||
icon: SizedBox.shrink(),
|
||||
),
|
||||
const TimelineCategory(
|
||||
key: 'category1',
|
||||
title: 'Category 1',
|
||||
icon: SizedBox.shrink(),
|
||||
),
|
||||
const TimelineCategory(
|
||||
key: 'category2',
|
||||
title: 'Category 2',
|
||||
icon: SizedBox.shrink(),
|
||||
),
|
||||
],
|
||||
categoriesOptions: CategoriesOptions(
|
||||
categoriesBuilder: (context) => [
|
||||
const TimelineCategory(
|
||||
key: null,
|
||||
title: 'All',
|
||||
icon: SizedBox.shrink(),
|
||||
),
|
||||
const TimelineCategory(
|
||||
key: 'category1',
|
||||
title: 'Category 1',
|
||||
icon: SizedBox.shrink(),
|
||||
),
|
||||
const TimelineCategory(
|
||||
key: 'category2',
|
||||
title: 'Category 2',
|
||||
icon: SizedBox.shrink(),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
void createPost(BuildContext context, TimelineService service,
|
||||
|
|
|
@ -30,6 +30,8 @@ Widget _timelineScreenRoute(
|
|||
onUserTap: (userId) {
|
||||
configuration.onUserTap?.call(context, userId);
|
||||
},
|
||||
filterEnabled: configuration.filterEnabled,
|
||||
postWidgetBuilder: configuration.postWidgetBuilder,
|
||||
);
|
||||
|
||||
Widget _postDetailScreenRoute(
|
||||
|
|
|
@ -26,6 +26,8 @@ List<GoRoute> getTimelineStoryRoutes(
|
|||
await context.push(
|
||||
TimelineUserStoryRoutes.timelineViewPath(post.id),
|
||||
),
|
||||
filterEnabled: configuration.filterEnabled,
|
||||
postWidgetBuilder: configuration.postWidgetBuilder,
|
||||
);
|
||||
|
||||
return buildScreenWithoutTransition(
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 ??
|
||||
max(options.padding.horizontal - 4, 0),
|
||||
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,8 +49,9 @@ class CategorySelector extends StatelessWidget {
|
|||
),
|
||||
],
|
||||
SizedBox(
|
||||
width: options.categorySelectorHorizontalPadding ??
|
||||
max(options.padding.horizontal - 4, 0),
|
||||
width:
|
||||
options.categoriesOptions.categorySelectorHorizontalPadding ??
|
||||
max(options.padding.horizontal - 4, 0),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue