diff --git a/CHANGELOG.md b/CHANGELOG.md index 745d2f0..4b2be3e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 3.0.0 + +- Reorder of all parameters of TimelineOptions +- Updated Flutter Image Picker form 1.0.4 to 3.0.0 + ## 2.1.0 - Fixed multiline textfield not being dismissible. diff --git a/packages/flutter_timeline/example/lib/main.dart b/packages/flutter_timeline/example/lib/main.dart index 9f32ce9..5d73e94 100644 --- a/packages/flutter_timeline/example/lib/main.dart +++ b/packages/flutter_timeline/example/lib/main.dart @@ -1,6 +1,6 @@ // import 'package:example/apps/go_router/app.dart'; -// import 'package:example/apps/navigator/app.dart'; -import 'package:example/apps/widgets/app.dart'; +import 'package:example/apps/navigator/app.dart'; +// import 'package:example/apps/widgets/app.dart'; import 'package:flutter/material.dart'; import 'package:intl/date_symbol_data_local.dart'; @@ -9,7 +9,7 @@ void main() { // Uncomment any, but only one, of these lines to run the example with specific navigation. - runApp(const WidgetApp()); - // runApp(const NavigatorApp()); + // runApp(const WidgetApp()); + runApp(const NavigatorApp()); // runApp(const GoRouterApp()); } diff --git a/packages/flutter_timeline/pubspec.yaml b/packages/flutter_timeline/pubspec.yaml index d756f7b..0754611 100644 --- a/packages/flutter_timeline/pubspec.yaml +++ b/packages/flutter_timeline/pubspec.yaml @@ -3,7 +3,7 @@ # SPDX-License-Identifier: GPL-3.0-or-later name: flutter_timeline description: Visual elements and interface combined into one package -version: 2.1.0 +version: 3.0.0 publish_to: none diff --git a/packages/flutter_timeline_firebase/pubspec.yaml b/packages/flutter_timeline_firebase/pubspec.yaml index 801453b..de1243d 100644 --- a/packages/flutter_timeline_firebase/pubspec.yaml +++ b/packages/flutter_timeline_firebase/pubspec.yaml @@ -4,7 +4,7 @@ name: flutter_timeline_firebase description: Implementation of the Flutter Timeline interface for Firebase. -version: 2.1.0 +version: 3.0.0 publish_to: none diff --git a/packages/flutter_timeline_interface/pubspec.yaml b/packages/flutter_timeline_interface/pubspec.yaml index 5c1ceb3..05b3d0a 100644 --- a/packages/flutter_timeline_interface/pubspec.yaml +++ b/packages/flutter_timeline_interface/pubspec.yaml @@ -4,7 +4,7 @@ name: flutter_timeline_interface description: Interface for the service of the Flutter Timeline component -version: 2.1.0 +version: 3.0.0 publish_to: none diff --git a/packages/flutter_timeline_view/lib/flutter_timeline_view.dart b/packages/flutter_timeline_view/lib/flutter_timeline_view.dart index 1a63bf4..6d98148 100644 --- a/packages/flutter_timeline_view/lib/flutter_timeline_view.dart +++ b/packages/flutter_timeline_view/lib/flutter_timeline_view.dart @@ -4,6 +4,11 @@ /// library flutter_timeline_view; +export 'src/config/icon_timeline_theme.dart'; +export 'src/config/post_config.dart'; +export 'src/config/post_creation_config.dart'; +export 'src/config/post_theme.dart'; +export 'src/config/timeline_config.dart'; export 'src/config/timeline_options.dart'; export 'src/config/timeline_styles.dart'; export 'src/config/timeline_theme.dart'; diff --git a/packages/flutter_timeline_view/lib/src/config/icon_timeline_theme.dart b/packages/flutter_timeline_view/lib/src/config/icon_timeline_theme.dart new file mode 100644 index 0000000..c81d24e --- /dev/null +++ b/packages/flutter_timeline_view/lib/src/config/icon_timeline_theme.dart @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: 2023 Iconica +// +// SPDX-License-Identifier: BSD-3-Clause + +import 'package:flutter/material.dart'; + +@immutable +class IconTimelineTheme { + const IconTimelineTheme({ + this.iconColor, + this.likeIcon, + this.commentIcon, + this.likedIcon, + this.sendIcon, + this.moreIcon, + this.deleteIcon, + this.likeAndDislikeIconsForDoubleTap = const ( + Icon( + Icons.favorite_rounded, + color: Color(0xFFC3007A), + ), + null, + ), + }); + + final Color? iconColor; + + /// The icon to display when the post is not yet liked + final Widget? likeIcon; + + /// The icon to display to indicate that a post has comments enabled + final Widget? commentIcon; + + /// The icon to display when the post is liked + final Widget? likedIcon; + + /// The icon to display to submit a comment + final Widget? sendIcon; + + /// The icon for more actions (open delete menu) + final Widget? moreIcon; + + /// The icon for delete action (delete post) + final Widget? deleteIcon; + + /// The icons to display when double tap to like is enabled + final (Icon?, Icon?) likeAndDislikeIconsForDoubleTap; +} diff --git a/packages/flutter_timeline_view/lib/src/config/post_config.dart b/packages/flutter_timeline_view/lib/src/config/post_config.dart new file mode 100644 index 0000000..d9fb415 --- /dev/null +++ b/packages/flutter_timeline_view/lib/src/config/post_config.dart @@ -0,0 +1,12 @@ +// SPDX-FileCopyrightText: 2024 Iconica +// +// SPDX-License-Identifier: BSD-3-Clause + +class TimelinePostConfig { + const TimelinePostConfig({ + this.doubleTapTolike = false, + }); + + /// Whether to allow double tap to like + final bool doubleTapTolike; +} diff --git a/packages/flutter_timeline_view/lib/src/config/post_creation_config.dart b/packages/flutter_timeline_view/lib/src/config/post_creation_config.dart new file mode 100644 index 0000000..e12fb80 --- /dev/null +++ b/packages/flutter_timeline_view/lib/src/config/post_creation_config.dart @@ -0,0 +1,28 @@ +// SPDX-FileCopyrightText: 2024 Iconica +// +// SPDX-License-Identifier: BSD-3-Clause + +class TimelinePostCreationConfig { + const TimelinePostCreationConfig({ + this.requireImageForPost = false, + this.minTitleLength, + this.maxTitleLength, + this.minContentLength, + this.maxContentLength, + }); + + /// Require image for post + final bool requireImageForPost; + + /// Minimum length of the title + final int? minTitleLength; + + /// Maximum length of the title + final int? maxTitleLength; + + /// Minimum length of the post content + final int? minContentLength; + + /// Maximum length of the post content + final int? maxContentLength; +} diff --git a/packages/flutter_timeline_view/lib/src/config/post_creation_theme.dart b/packages/flutter_timeline_view/lib/src/config/post_creation_theme.dart new file mode 100644 index 0000000..0c26495 --- /dev/null +++ b/packages/flutter_timeline_view/lib/src/config/post_creation_theme.dart @@ -0,0 +1,20 @@ +// SPDX-FileCopyrightText: 2024 Iconica +// +// SPDX-License-Identifier: BSD-3-Clause + +import 'package:flutter/material.dart'; +import 'package:flutter_timeline_view/src/config/timeline_options.dart'; + +class TimelinePostCreationTheme { + const TimelinePostCreationTheme({ + this.buttonBuilder, + this.textInputBuilder, + this.pagePadding = const EdgeInsets.all(20), + }); + + final ButtonBuilder? buttonBuilder; + + final TextInputBuilder? textInputBuilder; + + final EdgeInsets pagePadding; +} diff --git a/packages/flutter_timeline_view/lib/src/config/post_theme.dart b/packages/flutter_timeline_view/lib/src/config/post_theme.dart new file mode 100644 index 0000000..7d53661 --- /dev/null +++ b/packages/flutter_timeline_view/lib/src/config/post_theme.dart @@ -0,0 +1,63 @@ +// SPDX-FileCopyrightText: 2024 Iconica +// +// SPDX-License-Identifier: BSD-3-Clause + +import 'package:flutter/material.dart'; +import 'package:flutter_timeline_interface/flutter_timeline_interface.dart'; +import 'package:flutter_timeline_view/flutter_timeline_view.dart'; +import 'package:intl/intl.dart'; + +class TimelinePostTheme { + const TimelinePostTheme({ + this.timelinePostHeight, + this.iconsWithValues = false, + this.itemInfoBuilder, + this.dateFormat, + this.timeFormat, + this.userAvatarBuilder, + this.anonymousAvatarBuilder, + this.nameBuilder, + this.iconSize = 26, + this.postWidgetHeight, + this.postPadding = const EdgeInsets.all(12.0), + this.pagePadding = const EdgeInsets.all(20), + this.iconTheme = const IconTimelineTheme(), + }); + + /// The height of a post in the timeline + final double? timelinePostHeight; + + /// Whether to display the icons with values + final bool iconsWithValues; + + /// The builder for the item info, all below the like and comment buttons + final Widget Function({required TimelinePost post})? itemInfoBuilder; + + /// The format to display the post date in + final DateFormat? dateFormat; + + /// The format to display the post time in + final DateFormat? timeFormat; + + final UserAvatarBuilder? userAvatarBuilder; + + /// When the imageUrl is null this anonymousAvatarBuilder will be used + /// You can use it to display a default avatarW + final UserAvatarBuilder? anonymousAvatarBuilder; + + final String Function(TimelinePosterUserModel?)? nameBuilder; + + /// Size of icons like the comment and like icons. Dafualts to 26 + final double iconSize; + + /// Sets a predefined height for the postWidget. + final double? postWidgetHeight; + + /// Padding of each post + final EdgeInsets postPadding; + + final EdgeInsets pagePadding; + + /// Theming options for the icons within timeline + final IconTimelineTheme iconTheme; +} diff --git a/packages/flutter_timeline_view/lib/src/config/timeline_config.dart b/packages/flutter_timeline_view/lib/src/config/timeline_config.dart new file mode 100644 index 0000000..f3d7937 --- /dev/null +++ b/packages/flutter_timeline_view/lib/src/config/timeline_config.dart @@ -0,0 +1,21 @@ +// SPDX-FileCopyrightText: 2024 Iconica +// +// SPDX-License-Identifier: BSD-3-Clause + +class TimelineConfig { + const TimelineConfig({ + this.allowAllDeletion = false, + this.sortCommentsAscending = true, + this.sortPostsAscending, + }); + + /// Allow all posts to be deleted instead of + /// only the posts of the current user + final bool allowAllDeletion; + + /// Whether to sort comments ascending or descending + final bool sortCommentsAscending; + + /// Whether to sort posts ascending or descending + final bool? sortPostsAscending; +} diff --git a/packages/flutter_timeline_view/lib/src/config/timeline_options.dart b/packages/flutter_timeline_view/lib/src/config/timeline_options.dart index 9222071..70f8102 100644 --- a/packages/flutter_timeline_view/lib/src/config/timeline_options.dart +++ b/packages/flutter_timeline_view/lib/src/config/timeline_options.dart @@ -5,87 +5,35 @@ 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'; +import 'package:flutter_timeline_view/flutter_timeline_view.dart'; +import 'package:flutter_timeline_view/src/config/post_config.dart'; +import 'package:flutter_timeline_view/src/config/post_creation_config.dart'; +import 'package:flutter_timeline_view/src/config/post_creation_theme.dart'; +import 'package:flutter_timeline_view/src/config/post_theme.dart'; +import 'package:flutter_timeline_view/src/config/timeline_config.dart'; import 'package:flutter_timeline_view/src/config/timeline_theme.dart'; -import 'package:flutter_timeline_view/src/config/timeline_translations.dart'; -import 'package:intl/intl.dart'; class TimelineOptions { const TimelineOptions({ - this.theme = const TimelineTheme(), + this.textStyles = const TimelineTextStyles(), this.translations = const TimelineTranslations.empty(), this.imagePickerConfig = const ImagePickerConfig(), this.imagePickerTheme = const ImagePickerTheme(), - this.timelinePostHeight, - this.allowAllDeletion = false, - this.sortCommentsAscending = true, - this.sortPostsAscending, - this.doubleTapTolike = false, - this.iconsWithValues = false, - this.likeAndDislikeIconsForDoubleTap = const ( - Icon( - Icons.favorite_rounded, - color: Color(0xFFC3007A), - ), - null, - ), - this.itemInfoBuilder, - this.dateFormat, - this.timeFormat, - this.buttonBuilder, - this.textInputBuilder, - this.dividerBuilder, - this.userAvatarBuilder, - this.anonymousAvatarBuilder, - this.nameBuilder, - this.padding = const EdgeInsets.symmetric(vertical: 12.0), - this.iconSize = 26, - this.postWidgetHeight, - this.postPadding = const EdgeInsets.all(12.0), this.filterOptions = const FilterOptions(), this.categoriesOptions = const CategoriesOptions(), - this.requireImageForPost = false, - this.minTitleLength, - this.maxTitleLength, - this.minContentLength, - this.maxContentLength, + this.postTheme = const TimelinePostTheme(), + this.config = const TimelineConfig(), + this.postConfig = const TimelinePostConfig(), + this.theme = const TimelineTheme(), + this.postCreationTheme = const TimelinePostCreationTheme(), + this.postCreationConfig = const TimelinePostCreationConfig(), }); - /// Theming options for the timeline - final TimelineTheme theme; - - /// The format to display the post date in - final DateFormat? dateFormat; - - /// The format to display the post time in - final DateFormat? timeFormat; - - /// Whether to sort comments ascending or descending - final bool sortCommentsAscending; - - /// Whether to sort posts ascending or descending - final bool? sortPostsAscending; - - /// Allow all posts to be deleted instead of - /// only the posts of the current user - final bool allowAllDeletion; - - /// The height of a post in the timeline - final double? timelinePostHeight; + /// Parameter to set all textstyles within timeline + final TimelineTextStyles textStyles; final TimelineTranslations translations; - final ButtonBuilder? buttonBuilder; - - final TextInputBuilder? textInputBuilder; - - final UserAvatarBuilder? userAvatarBuilder; - - /// When the imageUrl is null this anonymousAvatarBuilder will be used - /// You can use it to display a default avatarW - final UserAvatarBuilder? anonymousAvatarBuilder; - - final String Function(TimelinePosterUserModel?)? nameBuilder; - /// ImagePickerTheme can be used to change the UI of the /// Image Picker Widget to change the text/icons to your liking. final ImagePickerTheme imagePickerTheme; @@ -94,53 +42,20 @@ class TimelineOptions { /// size and quality for the uploaded image. final ImagePickerConfig imagePickerConfig; - /// Whether to allow double tap to like - final bool doubleTapTolike; - - /// The icons to display when double tap to like is enabled - final (Icon?, Icon?) likeAndDislikeIconsForDoubleTap; - - /// Whether to display the icons with values - final bool iconsWithValues; - - /// The builder for the item info, all below the like and comment buttons - final Widget Function({required TimelinePost post})? itemInfoBuilder; - - /// The builder for the divider - final Widget Function()? dividerBuilder; - - /// The padding between posts in the timeline - final EdgeInsets padding; - - /// Size of icons like the comment and like icons. Dafualts to 26 - final double iconSize; - - /// Sets a predefined height for the postWidget. - final double? postWidgetHeight; - - /// Padding of each post - final EdgeInsets postPadding; - /// Options for filtering final FilterOptions filterOptions; /// Options for using the category selector. final CategoriesOptions categoriesOptions; - /// Require image for post - final bool requireImageForPost; + final TimelineConfig config; + final TimelineTheme theme; - /// Minimum length of the title - final int? minTitleLength; + final TimelinePostConfig postConfig; + final TimelinePostTheme postTheme; - /// Maximum length of the title - final int? maxTitleLength; - - /// Minimum length of the post content - final int? minContentLength; - - /// Maximum length of the post content - final int? maxContentLength; + final TimelinePostCreationTheme postCreationTheme; + final TimelinePostCreationConfig postCreationConfig; } class CategoriesOptions { diff --git a/packages/flutter_timeline_view/lib/src/config/timeline_theme.dart b/packages/flutter_timeline_view/lib/src/config/timeline_theme.dart index a2bb2c0..12cafb5 100644 --- a/packages/flutter_timeline_view/lib/src/config/timeline_theme.dart +++ b/packages/flutter_timeline_view/lib/src/config/timeline_theme.dart @@ -1,42 +1,17 @@ -// SPDX-FileCopyrightText: 2023 Iconica +// SPDX-FileCopyrightText: 2024 Iconica // // SPDX-License-Identifier: BSD-3-Clause import 'package:flutter/material.dart'; -import 'package:flutter_timeline_view/src/config/timeline_styles.dart'; -@immutable class TimelineTheme { const TimelineTheme({ - this.iconColor, - this.likeIcon, - this.commentIcon, - this.likedIcon, - this.sendIcon, - this.moreIcon, - this.deleteIcon, - this.textStyles = const TimelineTextStyles(), + this.dividerBuilder, + this.pagePadding = const EdgeInsets.all(20), }); - final Color? iconColor; + /// The builder for the divider + final Widget Function()? dividerBuilder; - /// The icon to display when the post is not yet liked - final Widget? likeIcon; - - /// The icon to display to indicate that a post has comments enabled - final Widget? commentIcon; - - /// The icon to display when the post is liked - final Widget? likedIcon; - - /// The icon to display to submit a comment - final Widget? sendIcon; - - /// The icon for more actions (open delete menu) - final Widget? moreIcon; - - /// The icon for delete action (delete post) - final Widget? deleteIcon; - - final TimelineTextStyles textStyles; + final EdgeInsets pagePadding; } diff --git a/packages/flutter_timeline_view/lib/src/screens/timeline_post_creation_screen.dart b/packages/flutter_timeline_view/lib/src/screens/timeline_post_creation_screen.dart index 6d82ff0..6dc9dc6 100644 --- a/packages/flutter_timeline_view/lib/src/screens/timeline_post_creation_screen.dart +++ b/packages/flutter_timeline_view/lib/src/screens/timeline_post_creation_screen.dart @@ -69,24 +69,28 @@ class _TimelinePostCreationScreenState setState(() { editingDone = titleController.text.isNotEmpty && contentController.text.isNotEmpty; - if (widget.options.requireImageForPost) { + if (widget.options.postCreationConfig.requireImageForPost) { editingDone = editingDone && image != null; } - if (widget.options.minTitleLength != null) { + if (widget.options.postCreationConfig.minTitleLength != null) { editingDone = editingDone && - titleController.text.length >= widget.options.minTitleLength!; + titleController.text.length >= + widget.options.postCreationConfig.minTitleLength!; } - if (widget.options.maxTitleLength != null) { + if (widget.options.postCreationConfig.maxTitleLength != null) { editingDone = editingDone && - titleController.text.length <= widget.options.maxTitleLength!; + titleController.text.length <= + widget.options.postCreationConfig.maxTitleLength!; } - if (widget.options.minContentLength != null) { + if (widget.options.postCreationConfig.minContentLength != null) { editingDone = editingDone && - contentController.text.length >= widget.options.minContentLength!; + contentController.text.length >= + widget.options.postCreationConfig.minContentLength!; } - if (widget.options.maxContentLength != null) { + if (widget.options.postCreationConfig.maxContentLength != null) { editingDone = editingDone && - contentController.text.length <= widget.options.maxContentLength!; + contentController.text.length <= + widget.options.postCreationConfig.maxContentLength!; } }); } @@ -119,7 +123,7 @@ class _TimelinePostCreationScreenState return GestureDetector( onTap: () => FocusScope.of(context).unfocus(), child: Padding( - padding: widget.options.padding, + padding: widget.options.postCreationTheme.pagePadding, child: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, @@ -129,7 +133,7 @@ class _TimelinePostCreationScreenState widget.options.translations.title, style: theme.textTheme.displaySmall, ), - widget.options.textInputBuilder?.call( + widget.options.postCreationTheme.textInputBuilder?.call( titleController, null, '', @@ -185,8 +189,8 @@ class _TimelinePostCreationScreenState padding: const EdgeInsets.all(8.0), color: theme.colorScheme.background, child: ImagePicker( - imagePickerConfig: widget.options.imagePickerConfig, - imagePickerTheme: widget.options.imagePickerTheme, + config: widget.options.imagePickerConfig, + theme: widget.options.imagePickerTheme, ), ), ); @@ -271,8 +275,8 @@ class _TimelinePostCreationScreenState ), Align( alignment: Alignment.bottomCenter, - child: (widget.options.buttonBuilder != null) - ? widget.options.buttonBuilder!( + child: (widget.options.postCreationTheme.buttonBuilder != null) + ? widget.options.postCreationTheme.buttonBuilder!( context, onPostCreated, widget.options.translations.checkPost, diff --git a/packages/flutter_timeline_view/lib/src/screens/timeline_post_screen.dart b/packages/flutter_timeline_view/lib/src/screens/timeline_post_screen.dart index 6f37faf..542d975 100644 --- a/packages/flutter_timeline_view/lib/src/screens/timeline_post_screen.dart +++ b/packages/flutter_timeline_view/lib/src/screens/timeline_post_screen.dart @@ -86,15 +86,16 @@ class _TimelinePostScreenState extends State<_TimelinePostScreen> { TimelinePost? post; bool isLoading = true; - late var textInputBuilder = widget.options.textInputBuilder ?? - (controller, suffixIcon, hintText) => TextField( - textCapitalization: TextCapitalization.sentences, - controller: controller, - decoration: InputDecoration( - hintText: hintText, - suffixIcon: suffixIcon, - ), - ); + late var textInputBuilder = + widget.options.postCreationTheme.textInputBuilder ?? + (controller, suffixIcon, hintText) => TextField( + textCapitalization: TextCapitalization.sentences, + controller: controller, + decoration: InputDecoration( + hintText: hintText, + suffixIcon: suffixIcon, + ), + ); @override void initState() { @@ -129,9 +130,9 @@ class _TimelinePostScreenState extends State<_TimelinePostScreen> { @override Widget build(BuildContext context) { var theme = Theme.of(context); - var dateFormat = widget.options.dateFormat ?? + var dateFormat = widget.options.postTheme.dateFormat ?? DateFormat('dd/MM/yyyy', Localizations.localeOf(context).languageCode); - var timeFormat = widget.options.timeFormat ?? DateFormat('HH:mm'); + var timeFormat = widget.options.postTheme.timeFormat ?? DateFormat('HH:mm'); if (isLoading) { const Center( @@ -142,13 +143,13 @@ class _TimelinePostScreenState extends State<_TimelinePostScreen> { return Center( child: Text( widget.options.translations.postLoadingError, - style: widget.options.theme.textStyles.errorTextStyle, + style: widget.options.textStyles.errorTextStyle, ), ); } var post = this.post!; post.reactions?.sort( - (a, b) => widget.options.sortCommentsAscending + (a, b) => widget.options.config.sortCommentsAscending ? a.createdAt.compareTo(b.createdAt) : b.createdAt.compareTo(a.createdAt), ); @@ -167,7 +168,7 @@ class _TimelinePostScreenState extends State<_TimelinePostScreen> { }, child: SingleChildScrollView( child: Padding( - padding: widget.options.padding, + padding: widget.options.postTheme.pagePadding, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -182,7 +183,8 @@ class _TimelinePostScreenState extends State<_TimelinePostScreen> { child: Row( children: [ if (post.creator!.imageUrl != null) ...[ - widget.options.userAvatarBuilder?.call( + widget.options.postTheme.userAvatarBuilder + ?.call( post.creator!, 40, ) ?? @@ -194,7 +196,8 @@ class _TimelinePostScreenState extends State<_TimelinePostScreen> { ), ), ] else ...[ - widget.options.anonymousAvatarBuilder?.call( + widget.options.postTheme.anonymousAvatarBuilder + ?.call( post.creator!, 40, ) ?? @@ -207,11 +210,11 @@ class _TimelinePostScreenState extends State<_TimelinePostScreen> { ], const SizedBox(width: 10), Text( - widget.options.nameBuilder + widget.options.postTheme.nameBuilder ?.call(post.creator) ?? post.creator?.fullName ?? widget.options.translations.anonymousUser, - style: widget.options.theme.textStyles + style: widget.options.textStyles .postCreatorTitleStyle ?? theme.textTheme.titleMedium, ), @@ -219,7 +222,7 @@ class _TimelinePostScreenState extends State<_TimelinePostScreen> { ), ), const Spacer(), - if (widget.options.allowAllDeletion || + if (widget.options.config.allowAllDeletion || post.creator?.userId == widget.userId) PopupMenuButton( onSelected: (value) => widget.onPostDelete(), @@ -231,24 +234,27 @@ class _TimelinePostScreenState extends State<_TimelinePostScreen> { children: [ Text( widget.options.translations.deletePost, - style: widget.options.theme.textStyles + style: widget.options.textStyles .deletePostStyle ?? theme.textTheme.bodyMedium, ), const SizedBox(width: 8), - widget.options.theme.deleteIcon ?? + widget.options.postTheme.iconTheme + .deleteIcon ?? Icon( Icons.delete, - color: widget.options.theme.iconColor, + color: widget.options.postTheme + .iconTheme.iconColor, ), ], ), ), ], - child: widget.options.theme.moreIcon ?? + child: widget.options.postTheme.iconTheme.moreIcon ?? Icon( Icons.more_horiz_rounded, - color: widget.options.theme.iconColor, + color: widget + .options.postTheme.iconTheme.iconColor, ), ), ], @@ -258,10 +264,10 @@ class _TimelinePostScreenState extends State<_TimelinePostScreen> { const SizedBox(height: 8), ClipRRect( borderRadius: const BorderRadius.all(Radius.circular(8)), - child: widget.options.doubleTapTolike + child: widget.options.postConfig.doubleTapTolike ? TappableImage( - likeAndDislikeIcon: widget - .options.likeAndDislikeIconsForDoubleTap, + likeAndDislikeIcon: widget.options.postTheme + .iconTheme.likeAndDislikeIconsForDoubleTap, post: post, userId: widget.userId, onLike: ({required bool liked}) async { @@ -314,11 +320,13 @@ class _TimelinePostScreenState extends State<_TimelinePostScreen> { }, child: Container( color: Colors.transparent, - child: widget.options.theme.likedIcon ?? - Icon( - Icons.thumb_up_rounded, - color: widget.options.theme.iconColor, - ), + child: + widget.options.postTheme.iconTheme.likedIcon ?? + Icon( + Icons.thumb_up_rounded, + color: widget.options.postTheme.iconTheme + .iconColor, + ), ), ), ] else ...[ @@ -333,49 +341,50 @@ class _TimelinePostScreenState extends State<_TimelinePostScreen> { }, child: Container( color: Colors.transparent, - child: widget.options.theme.likeIcon ?? - Icon( - Icons.thumb_up_alt_outlined, - color: widget.options.theme.iconColor, - size: widget.options.iconSize, - ), + child: + widget.options.postTheme.iconTheme.likeIcon ?? + Icon( + Icons.thumb_up_alt_outlined, + color: widget.options.postTheme.iconTheme + .iconColor, + size: widget.options.postTheme.iconSize, + ), ), ), ], const SizedBox(width: 8), if (post.reactionEnabled) - widget.options.theme.commentIcon ?? + widget.options.postTheme.iconTheme.commentIcon ?? Icon( Icons.chat_bubble_outline_rounded, - color: widget.options.theme.iconColor, - size: widget.options.iconSize, + color: + widget.options.postTheme.iconTheme.iconColor, + size: widget.options.postTheme.iconSize, ), ], ), const SizedBox(height: 8), Text( '${post.likes} ${widget.options.translations.likesTitle}', - style: widget - .options.theme.textStyles.postLikeTitleAndAmount ?? + style: widget.options.textStyles.postLikeTitleAndAmount ?? theme.textTheme.titleSmall ?.copyWith(color: Colors.black), ), const SizedBox(height: 4), Text.rich( TextSpan( - text: widget.options.nameBuilder?.call(post.creator) ?? + text: widget.options.postTheme.nameBuilder + ?.call(post.creator) ?? post.creator?.fullName ?? widget.options.translations.anonymousUser, - style: widget - .options.theme.textStyles.postCreatorNameStyle ?? + style: widget.options.textStyles.postCreatorNameStyle ?? theme.textTheme.titleSmall, children: [ const TextSpan(text: ' '), TextSpan( text: post.title, - style: - widget.options.theme.textStyles.postTitleStyle ?? - theme.textTheme.bodyMedium, + style: widget.options.textStyles.postTitleStyle ?? + theme.textTheme.bodyMedium, ), ], ), @@ -427,7 +436,7 @@ class _TimelinePostScreenState extends State<_TimelinePostScreen> { GestureDetector( onLongPressStart: (details) async { if (reaction.creatorId == widget.userId || - widget.options.allowAllDeletion) { + widget.options.config.allowAllDeletion) { var overlay = Overlay.of(context) .context .findRenderObject()! as RenderBox; @@ -467,7 +476,7 @@ class _TimelinePostScreenState extends State<_TimelinePostScreen> { children: [ if (reaction.creator?.imageUrl != null && reaction.creator!.imageUrl!.isNotEmpty) ...[ - widget.options.userAvatarBuilder?.call( + widget.options.postTheme.userAvatarBuilder?.call( reaction.creator!, 25, ) ?? @@ -478,7 +487,8 @@ class _TimelinePostScreenState extends State<_TimelinePostScreen> { ), ), ] else ...[ - widget.options.anonymousAvatarBuilder?.call( + widget.options.postTheme.anonymousAvatarBuilder + ?.call( reaction.creator!, 25, ) ?? @@ -496,7 +506,7 @@ class _TimelinePostScreenState extends State<_TimelinePostScreen> { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - widget.options.nameBuilder + widget.options.postTheme.nameBuilder ?.call(post.creator) ?? reaction.creator?.fullName ?? widget.options.translations @@ -517,7 +527,7 @@ class _TimelinePostScreenState extends State<_TimelinePostScreen> { Expanded( child: Text.rich( TextSpan( - text: widget.options.nameBuilder + text: widget.options.postTheme.nameBuilder ?.call(post.creator) ?? reaction.creator?.fullName ?? widget @@ -565,8 +575,8 @@ class _TimelinePostScreenState extends State<_TimelinePostScreen> { padding: const EdgeInsets.all(8.0), color: theme.colorScheme.background, child: ImagePicker( - imagePickerConfig: widget.options.imagePickerConfig, - imagePickerTheme: widget.options.imagePickerTheme, + config: widget.options.imagePickerConfig, + theme: widget.options.imagePickerTheme, ), ), ); @@ -598,7 +608,7 @@ class _TimelinePostScreenState extends State<_TimelinePostScreen> { ), ), translations: widget.options.translations, - iconColor: widget.options.theme.iconColor, + iconColor: widget.options.postTheme.iconTheme.iconColor, ), ), ], diff --git a/packages/flutter_timeline_view/lib/src/screens/timeline_screen.dart b/packages/flutter_timeline_view/lib/src/screens/timeline_screen.dart index 9bd5a82..643e27b 100644 --- a/packages/flutter_timeline_view/lib/src/screens/timeline_screen.dart +++ b/packages/flutter_timeline_view/lib/src/screens/timeline_screen.dart @@ -110,9 +110,9 @@ class _TimelineScreenState extends State { .toList(); // sort posts by date - if (widget.options.sortPostsAscending != null) { + if (widget.options.config.sortPostsAscending != null) { posts.sort( - (a, b) => widget.options.sortPostsAscending! + (a, b) => widget.options.config.sortPostsAscending! ? a.createdAt.compareTo(b.createdAt) : b.createdAt.compareTo(a.createdAt), ); @@ -122,12 +122,12 @@ class _TimelineScreenState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( - height: widget.options.padding.top, + height: widget.options.postTheme.postPadding.top, ), if (widget.filterEnabled) ...[ Padding( padding: EdgeInsets.symmetric( - horizontal: widget.options.padding.horizontal, + horizontal: widget.options.postTheme.postPadding.horizontal, ), child: Row( crossAxisAlignment: CrossAxisAlignment.end, @@ -203,7 +203,7 @@ class _TimelineScreenState extends State { children: [ ...posts.map( (post) => Padding( - padding: widget.options.postPadding, + padding: widget.options.postTheme.postPadding, child: widget.postWidgetBuilder?.call(post) ?? TimelinePostWidget( service: service, @@ -253,7 +253,7 @@ class _TimelineScreenState extends State { category == null ? widget.options.translations.noPosts : widget.options.translations.noPostsWithFilter, - style: widget.options.theme.textStyles.noPostsStyle, + style: widget.options.textStyles.noPostsStyle, ), ), ), @@ -262,7 +262,7 @@ class _TimelineScreenState extends State { ), ), SizedBox( - height: widget.options.padding.bottom, + height: widget.options.postTheme.postPadding.bottom, ), ], ); diff --git a/packages/flutter_timeline_view/lib/src/screens/timeline_selection_screen.dart b/packages/flutter_timeline_view/lib/src/screens/timeline_selection_screen.dart index 789923e..c68d222 100644 --- a/packages/flutter_timeline_view/lib/src/screens/timeline_selection_screen.dart +++ b/packages/flutter_timeline_view/lib/src/screens/timeline_selection_screen.dart @@ -31,9 +31,8 @@ class TimelineSelectionScreen extends StatelessWidget { padding: EdgeInsets.only(top: size.height * 0.05, bottom: 8), child: Text( options.translations.timelineSelectionDescription, - style: - options.theme.textStyles.categorySelectionDescriptionStyle ?? - theme.textTheme.displayMedium, + style: options.textStyles.categorySelectionDescriptionStyle ?? + theme.textTheme.displayMedium, ), ), const SizedBox(height: 4), @@ -55,7 +54,7 @@ class TimelineSelectionScreen extends StatelessWidget { margin: const EdgeInsets.symmetric(vertical: 8), child: Text( category.title, - style: options.theme.textStyles.categorySelectionTitleStyle ?? + style: options.textStyles.categorySelectionTitleStyle ?? theme.textTheme.displaySmall, ), ), diff --git a/packages/flutter_timeline_view/lib/src/widgets/category_selector.dart b/packages/flutter_timeline_view/lib/src/widgets/category_selector.dart index 858d0b9..c314d9d 100644 --- a/packages/flutter_timeline_view/lib/src/widgets/category_selector.dart +++ b/packages/flutter_timeline_view/lib/src/widgets/category_selector.dart @@ -28,9 +28,9 @@ class CategorySelector extends StatelessWidget { child: Row( children: [ SizedBox( - width: - options.categoriesOptions.categorySelectorHorizontalPadding ?? - max(options.padding.horizontal - 4, 0), + width: options + .categoriesOptions.categorySelectorHorizontalPadding ?? + max(options.postCreationTheme.pagePadding.horizontal - 4, 0), ), for (var category in categories) ...[ options.categoriesOptions.categoryButtonBuilder?.call( @@ -49,9 +49,9 @@ class CategorySelector extends StatelessWidget { ), ], SizedBox( - width: - options.categoriesOptions.categorySelectorHorizontalPadding ?? - max(options.padding.horizontal - 4, 0), + width: options + .categoriesOptions.categorySelectorHorizontalPadding ?? + max(options.postCreationTheme.pagePadding.horizontal - 4, 0), ), ], ), diff --git a/packages/flutter_timeline_view/lib/src/widgets/timeline_post_widget.dart b/packages/flutter_timeline_view/lib/src/widgets/timeline_post_widget.dart index ff1976b..360d88b 100644 --- a/packages/flutter_timeline_view/lib/src/widgets/timeline_post_widget.dart +++ b/packages/flutter_timeline_view/lib/src/widgets/timeline_post_widget.dart @@ -50,7 +50,7 @@ class _TimelinePostWidgetState extends State { onTap: widget.onTap, child: SizedBox( height: widget.post.imageUrl != null - ? widget.options.postWidgetHeight + ? widget.options.postTheme.postWidgetHeight : null, width: double.infinity, child: Column( @@ -67,7 +67,7 @@ class _TimelinePostWidgetState extends State { child: Row( children: [ if (widget.post.creator!.imageUrl != null) ...[ - widget.options.userAvatarBuilder?.call( + widget.options.postTheme.userAvatarBuilder?.call( widget.post.creator!, 40, ) ?? @@ -78,7 +78,7 @@ class _TimelinePostWidgetState extends State { ), ), ] else ...[ - widget.options.anonymousAvatarBuilder?.call( + widget.options.postTheme.anonymousAvatarBuilder?.call( widget.post.creator!, 40, ) ?? @@ -91,19 +91,19 @@ class _TimelinePostWidgetState extends State { ], const SizedBox(width: 10), Text( - widget.options.nameBuilder + widget.options.postTheme.nameBuilder ?.call(widget.post.creator) ?? widget.post.creator?.fullName ?? widget.options.translations.anonymousUser, - style: widget.options.theme.textStyles - .postCreatorTitleStyle ?? - theme.textTheme.titleMedium, + style: + widget.options.textStyles.postCreatorTitleStyle ?? + theme.textTheme.titleMedium, ), ], ), ), const Spacer(), - if (widget.options.allowAllDeletion || + if (widget.options.config.allowAllDeletion || widget.post.creator?.userId == widget.userId) PopupMenuButton( onSelected: (value) { @@ -119,24 +119,25 @@ class _TimelinePostWidgetState extends State { children: [ Text( widget.options.translations.deletePost, - style: widget.options.theme.textStyles - .deletePostStyle ?? - theme.textTheme.bodyMedium, + style: + widget.options.textStyles.deletePostStyle ?? + theme.textTheme.bodyMedium, ), const SizedBox(width: 8), - widget.options.theme.deleteIcon ?? + widget.options.postTheme.iconTheme.deleteIcon ?? Icon( Icons.delete, - color: widget.options.theme.iconColor, + color: widget + .options.postTheme.iconTheme.iconColor, ), ], ), ), ], - child: widget.options.theme.moreIcon ?? + child: widget.options.postTheme.iconTheme.moreIcon ?? Icon( Icons.more_horiz_rounded, - color: widget.options.theme.iconColor, + color: widget.options.postTheme.iconTheme.iconColor, ), ), ], @@ -145,13 +146,13 @@ class _TimelinePostWidgetState extends State { if (widget.post.imageUrl != null) ...[ const SizedBox(height: 8), Flexible( - flex: widget.options.postWidgetHeight != null ? 1 : 0, + flex: widget.options.postTheme.postWidgetHeight != null ? 1 : 0, child: ClipRRect( borderRadius: const BorderRadius.all(Radius.circular(8)), - child: widget.options.doubleTapTolike + child: widget.options.postConfig.doubleTapTolike ? TappableImage( - likeAndDislikeIcon: - widget.options.likeAndDislikeIconsForDoubleTap, + likeAndDislikeIcon: widget.options.postTheme.iconTheme + .likeAndDislikeIconsForDoubleTap, post: widget.post, userId: widget.userId, onLike: ({required bool liked}) async { @@ -188,7 +189,7 @@ class _TimelinePostWidgetState extends State { height: 8, ), // post information - if (widget.options.iconsWithValues) + if (widget.options.postTheme.iconsWithValues) Row( children: [ TextButton.icon( @@ -210,7 +211,7 @@ class _TimelinePostWidgetState extends State { ); } }, - icon: widget.options.theme.likeIcon ?? + icon: widget.options.postTheme.iconTheme.likeIcon ?? Icon( widget.post.likedBy?.contains(widget.userId) ?? false ? Icons.favorite @@ -221,7 +222,7 @@ class _TimelinePostWidgetState extends State { if (widget.post.reactionEnabled) TextButton.icon( onPressed: widget.onTap, - icon: widget.options.theme.commentIcon ?? + icon: widget.options.postTheme.iconTheme.commentIcon ?? const Icon( Icons.chat_bubble_outline_outlined, ), @@ -238,11 +239,12 @@ class _TimelinePostWidgetState extends State { onTap: widget.onTapUnlike, child: Container( color: Colors.transparent, - child: widget.options.theme.likedIcon ?? + child: widget.options.postTheme.iconTheme.likedIcon ?? Icon( Icons.thumb_up_rounded, - color: widget.options.theme.iconColor, - size: widget.options.iconSize, + color: + widget.options.postTheme.iconTheme.iconColor, + size: widget.options.postTheme.iconSize, ), ), ), @@ -251,11 +253,12 @@ class _TimelinePostWidgetState extends State { onTap: widget.onTapLike, child: Container( color: Colors.transparent, - child: widget.options.theme.likedIcon ?? + child: widget.options.postTheme.iconTheme.likedIcon ?? Icon( Icons.thumb_up_rounded, - color: widget.options.theme.iconColor, - size: widget.options.iconSize, + color: + widget.options.postTheme.iconTheme.iconColor, + size: widget.options.postTheme.iconSize, ), ), ), @@ -264,11 +267,11 @@ class _TimelinePostWidgetState extends State { if (widget.post.reactionEnabled) ...[ Container( color: Colors.transparent, - child: widget.options.theme.commentIcon ?? + child: widget.options.postTheme.iconTheme.commentIcon ?? Icon( Icons.chat_bubble_outline_rounded, - color: widget.options.theme.iconColor, - size: widget.options.iconSize, + color: widget.options.postTheme.iconTheme.iconColor, + size: widget.options.postTheme.iconSize, ), ), ], @@ -279,33 +282,32 @@ class _TimelinePostWidgetState extends State { height: 8, ), - if (widget.options.itemInfoBuilder != null) ...[ - widget.options.itemInfoBuilder!( + if (widget.options.postTheme.itemInfoBuilder != null) ...[ + widget.options.postTheme.itemInfoBuilder!( post: widget.post, ), ] else ...[ Text( '${widget.post.likes} ' '${widget.options.translations.likesTitle}', - style: widget - .options.theme.textStyles.listPostLikeTitleAndAmount ?? + style: widget.options.textStyles.listPostLikeTitleAndAmount ?? theme.textTheme.titleSmall, ), const SizedBox(height: 4), Text.rich( TextSpan( - text: widget.options.nameBuilder?.call(widget.post.creator) ?? + text: widget.options.postTheme.nameBuilder + ?.call(widget.post.creator) ?? widget.post.creator?.fullName ?? widget.options.translations.anonymousUser, - style: widget.options.theme.textStyles.listCreatorNameStyle ?? + style: widget.options.textStyles.listCreatorNameStyle ?? theme.textTheme.titleSmall, children: [ const TextSpan(text: ' '), TextSpan( text: widget.post.title, - style: - widget.options.theme.textStyles.listPostTitleStyle ?? - theme.textTheme.bodyMedium, + style: widget.options.textStyles.listPostTitleStyle ?? + theme.textTheme.bodyMedium, ), ], ), @@ -313,12 +315,12 @@ class _TimelinePostWidgetState extends State { const SizedBox(height: 4), Text( widget.options.translations.viewPost, - style: widget.options.theme.textStyles.viewPostStyle ?? + style: widget.options.textStyles.viewPostStyle ?? theme.textTheme.bodySmall, ), ], - if (widget.options.dividerBuilder != null) - widget.options.dividerBuilder!(), + if (widget.options.theme.dividerBuilder != null) + widget.options.theme.dividerBuilder!(), ], ), ), diff --git a/packages/flutter_timeline_view/pubspec.yaml b/packages/flutter_timeline_view/pubspec.yaml index 98de79b..a7a3150 100644 --- a/packages/flutter_timeline_view/pubspec.yaml +++ b/packages/flutter_timeline_view/pubspec.yaml @@ -4,7 +4,7 @@ name: flutter_timeline_view description: Visual elements of the Flutter Timeline Component -version: 2.1.0 +version: 3.0.0 publish_to: none @@ -27,7 +27,7 @@ dependencies: flutter_image_picker: git: url: https://github.com/Iconica-Development/flutter_image_picker - ref: 1.0.4 + ref: 3.0.0 collection: any dev_dependencies: