Compare commits

...

5 commits

Author SHA1 Message Date
65d27ce4a0 fix: reload posts when the parent widget has rebuilt on the timeline screen
This way if the service passed to us is changed we'll update our posts from it instead
of keeping the ones from the previous service.
2025-04-22 15:07:11 +02:00
3615342c64 fix: don't use TimelineService as state
Otherwise the widget won't use a new service if it has been provided by
the parent. It really isn't state anyway.
2025-04-22 15:06:56 +02:00
13ba6ada07 chore: relax the Firebase versions we support
We don't currently use API that's incompatible with the latest versions
of all Firebase packages, so let's indicate that we support them.
2025-04-22 08:50:54 +02:00
4f0c36a1cc fix: use a minimum of Dart 3.4.3 and don't use 'any' for any dep version constraints
We're very inconsistent with marking what Flutter and Dart versions we support. The .fvmrc indicates
Flutter 3.27.4 which comes with Dart 3.6.2, but the packages said 3.0 and 3.1.
This commit brings all versions in line and sets the minimum to Dart 3.4.3. This version is chosen
so it can be used as is with one of our projects that currently uses that Dart version.
2025-04-22 08:50:54 +02:00
a62935eb60 chore: add fvm configuration to gitignore 2025-02-17 15:52:52 +01:00
11 changed files with 70 additions and 52 deletions

3
.fvmrc Normal file
View file

@ -0,0 +1,3 @@
{
"flutter": "3.22.2"
}

3
.gitignore vendored
View file

@ -51,3 +51,6 @@ pubspec_overrides.yaml
**/example/windows **/example/windows
**/example/web **/example/web
**/example/README.md **/example/README.md
# FVM Version Cache
.fvm/

View file

@ -1,3 +1,8 @@
## 5.1.1
- Be honest about which Dart and Flutter versions we support
- Relax our Firebase version constraint, we also support the current newest versions
## 5.1.0 ## 5.1.0
* Added `routeToPostDetail` to the `TimelineUserStory` to allow for navigation to the post detail screen. * Added `routeToPostDetail` to the `TimelineUserStory` to allow for navigation to the post detail screen.

View file

@ -3,26 +3,27 @@
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
name: flutter_timeline name: flutter_timeline
description: Visual elements and interface combined into one package description: Visual elements and interface combined into one package
version: 5.1.0 version: 5.1.1
homepage: https://github.com/Iconica-Development/flutter_timeline
publish_to: https://forgejo.internal.iconica.nl/api/packages/internal/pub publish_to: https://forgejo.internal.iconica.nl/api/packages/internal/pub
environment: environment:
sdk: ">=3.1.3 <4.0.0" sdk: ">=3.4.3 <4.0.0"
flutter: '>=3.22.2'
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
flutter_timeline_view: flutter_timeline_view:
hosted: https://forgejo.internal.iconica.nl/api/packages/internal/pub hosted: https://forgejo.internal.iconica.nl/api/packages/internal/pub
version: ^5.1.0 version: ^5.1.1
flutter_timeline_interface: flutter_timeline_interface:
hosted: https://forgejo.internal.iconica.nl/api/packages/internal/pub hosted: https://forgejo.internal.iconica.nl/api/packages/internal/pub
version: ^5.1.0 version: ^5.1.1
collection: any collection: ^1.18.0
dev_dependencies: dev_dependencies:
flutter_lints: ^2.0.0
flutter_iconica_analysis: flutter_iconica_analysis:
git: git:
url: https://github.com/Iconica-Development/flutter_iconica_analysis url: https://github.com/Iconica-Development/flutter_iconica_analysis

View file

@ -2,9 +2,6 @@
// //
// SPDX-License-Identifier: BSD-3-Clause // SPDX-License-Identifier: BSD-3-Clause
import 'package:flutter/material.dart';
@immutable
class FirebaseTimelineOptions { class FirebaseTimelineOptions {
const FirebaseTimelineOptions({ const FirebaseTimelineOptions({
this.usersCollectionName = 'users', this.usersCollectionName = 'users',

View file

@ -2,9 +2,6 @@
// //
// SPDX-License-Identifier: BSD-3-Clause // SPDX-License-Identifier: BSD-3-Clause
import 'package:flutter/material.dart';
@immutable
class FirebaseUserDocument { class FirebaseUserDocument {
const FirebaseUserDocument({ const FirebaseUserDocument({
this.firstName, this.firstName,

View file

@ -4,26 +4,27 @@
name: flutter_timeline_firebase name: flutter_timeline_firebase
description: Implementation of the Flutter Timeline interface for Firebase. description: Implementation of the Flutter Timeline interface for Firebase.
version: 5.1.0 version: 5.1.1
homepage: https://github.com/Iconica-Development/flutter_timeline
publish_to: https://forgejo.internal.iconica.nl/api/packages/internal/pub publish_to: https://forgejo.internal.iconica.nl/api/packages/internal/pub
environment: environment:
sdk: ">=3.1.3 <4.0.0" sdk: ">=3.4.3 <4.0.0"
flutter: '>=3.22.2'
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
cloud_firestore: ^4.13.1 cloud_firestore: '>=4.13.1 <6.0.0'
firebase_core: ^2.22.0 firebase_core: '>=2.22.0 <4.0.0'
firebase_storage: ^11.5.1 firebase_storage: '>=11.5.1 <13.0.0'
uuid: ^4.2.1 uuid: ^4.2.1
collection: ^1.18.0 collection: ^1.18.0
flutter_timeline_interface: flutter_timeline_interface:
hosted: https://forgejo.internal.iconica.nl/api/packages/internal/pub hosted: https://forgejo.internal.iconica.nl/api/packages/internal/pub
version: ^5.1.0 version: ^5.1.1
dev_dependencies: dev_dependencies:
flutter_lints: ^2.0.0
flutter_iconica_analysis: flutter_iconica_analysis:
git: git:
url: https://github.com/Iconica-Development/flutter_iconica_analysis url: https://github.com/Iconica-Development/flutter_iconica_analysis

View file

@ -4,18 +4,18 @@
name: flutter_timeline_interface name: flutter_timeline_interface
description: Interface for the service of the Flutter Timeline component description: Interface for the service of the Flutter Timeline component
version: 5.1.0 version: 5.1.1
homepage: https://github.com/Iconica-Development/flutter_timeline
publish_to: https://forgejo.internal.iconica.nl/api/packages/internal/pub publish_to: https://forgejo.internal.iconica.nl/api/packages/internal/pub
environment: environment:
sdk: '>=3.1.3 <4.0.0' sdk: '>=3.4.3 <4.0.0'
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
dev_dependencies: dev_dependencies:
flutter_lints: ^2.0.0
flutter_iconica_analysis: flutter_iconica_analysis:
git: git:
url: https://github.com/Iconica-Development/flutter_iconica_analysis url: https://github.com/Iconica-Development/flutter_iconica_analysis

View file

@ -4,15 +4,14 @@
import 'dart:async'; import 'dart:async';
import 'package:collection/collection.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_timeline_interface/flutter_timeline_interface.dart'; import 'package:flutter_timeline_interface/flutter_timeline_interface.dart';
import 'package:flutter_timeline_view/flutter_timeline_view.dart'; import 'package:flutter_timeline_view/flutter_timeline_view.dart';
class TimelineScreen extends StatefulWidget { class TimelineScreen extends StatefulWidget {
const TimelineScreen({ TimelineScreen({
this.userId = 'test_user', this.userId = 'test_user',
this.service, TimelineService? service,
this.options = const TimelineOptions(), this.options = const TimelineOptions(),
this.onPostTap, this.onPostTap,
this.scrollController, this.scrollController,
@ -24,7 +23,10 @@ class TimelineScreen extends StatefulWidget {
this.filterEnabled = false, this.filterEnabled = false,
this.allowAllDeletion = false, this.allowAllDeletion = false,
super.key, super.key,
}); }) : service = service ??
TimelineService(
postService: LocalTimelinePostService(),
);
/// The user id of the current user /// The user id of the current user
final String userId; final String userId;
@ -34,7 +36,7 @@ class TimelineScreen extends StatefulWidget {
final bool allowAllDeletion; final bool allowAllDeletion;
/// The service to use for fetching and manipulating posts /// The service to use for fetching and manipulating posts
final TimelineService? service; final TimelineService service;
/// All the configuration options for the timelinescreens and widgets /// All the configuration options for the timelinescreens and widgets
final TimelineOptions options; final TimelineOptions options;
@ -73,10 +75,6 @@ class _TimelineScreenState extends State<TimelineScreen> {
late var textFieldController = TextEditingController( late var textFieldController = TextEditingController(
text: widget.options.filterOptions.initialFilterWord, text: widget.options.filterOptions.initialFilterWord,
); );
late var service = widget.service ??
TimelineService(
postService: LocalTimelinePostService(),
);
bool isLoading = true; bool isLoading = true;
@ -111,6 +109,15 @@ class _TimelineScreenState extends State<TimelineScreen> {
}); });
} }
@override
void didUpdateWidget(covariant TimelineScreen oldWidget) {
super.didUpdateWidget(oldWidget);
WidgetsBinding.instance.addPostFrameCallback((_) {
unawaited(loadPosts());
});
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (isLoading && widget.posts == null) { if (isLoading && widget.posts == null) {
@ -119,14 +126,15 @@ class _TimelineScreenState extends State<TimelineScreen> {
// Build the list of posts // Build the list of posts
return ListenableBuilder( return ListenableBuilder(
listenable: service.postService, listenable: widget.service.postService,
builder: (context, _) { builder: (context, _) {
if (!context.mounted) return const SizedBox(); if (!context.mounted) return const SizedBox();
var posts = widget.posts ?? service.postService.getPosts(category); var posts =
widget.posts ?? widget.service.postService.getPosts(category);
if (widget.filterEnabled && filterWord != null) { if (widget.filterEnabled && filterWord != null) {
if (service.postService is TimelineFilterService) { if (widget.service.postService is TimelineFilterService) {
posts = (service.postService as TimelineFilterService) posts = (widget.service.postService as TimelineFilterService)
.filterPosts(filterWord!, {}); .filterPosts(filterWord!, {});
} else { } else {
debugPrint('Timeline service needs to mixin' debugPrint('Timeline service needs to mixin'
@ -149,7 +157,7 @@ class _TimelineScreenState extends State<TimelineScreen> {
); );
} }
var categories = service.postService.categories; var categories = widget.service.postService.categories;
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -255,7 +263,7 @@ class _TimelineScreenState extends State<TimelineScreen> {
padding: widget.options.paddings.postPadding, padding: widget.options.paddings.postPadding,
child: widget.postWidgetBuilder?.call(post) ?? child: widget.postWidgetBuilder?.call(post) ??
TimelinePostWidget( TimelinePostWidget(
service: service, service: widget.service,
userId: widget.userId, userId: widget.userId,
options: widget.options, options: widget.options,
allowAllDeletion: widget.allowAllDeletion, allowAllDeletion: widget.allowAllDeletion,
@ -273,11 +281,11 @@ class _TimelineScreenState extends State<TimelineScreen> {
builder: (context) => Scaffold( builder: (context) => Scaffold(
body: TimelinePostScreen( body: TimelinePostScreen(
userId: 'test_user', userId: 'test_user',
service: service, service: widget.service,
options: widget.options, options: widget.options,
post: post, post: post,
onPostDelete: () { onPostDelete: () {
service.postService widget.service.postService
.deletePost(post); .deletePost(post);
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
@ -286,12 +294,14 @@ class _TimelineScreenState extends State<TimelineScreen> {
), ),
); );
}, },
onTapLike: () async => service.postService onTapLike: () async => widget
.service.postService
.likePost(widget.userId, post), .likePost(widget.userId, post),
onTapUnlike: () async => service.postService onTapUnlike: () async => widget
.service.postService
.unlikePost(widget.userId, post), .unlikePost(widget.userId, post),
onPostDelete: () async => onPostDelete: () async =>
service.postService.deletePost(post), widget.service.postService.deletePost(post),
onUserTap: widget.onUserTap, onUserTap: widget.onUserTap,
), ),
), ),
@ -327,8 +337,8 @@ class _TimelineScreenState extends State<TimelineScreen> {
Future<void> loadPosts() async { Future<void> loadPosts() async {
if (widget.posts != null || !context.mounted) return; if (widget.posts != null || !context.mounted) return;
try { try {
await service.postService.fetchCategories(); await widget.service.postService.fetchCategories();
await service.postService.fetchPosts(category); await widget.service.postService.fetchPosts(category);
setState(() { setState(() {
isLoading = false; isLoading = false;
}); });

View file

@ -4,29 +4,30 @@
name: flutter_timeline_view name: flutter_timeline_view
description: Visual elements of the Flutter Timeline Component description: Visual elements of the Flutter Timeline Component
version: 5.1.0 version: 5.1.1
homepage: https://github.com/Iconica-Development/flutter_timeline
publish_to: https://forgejo.internal.iconica.nl/api/packages/internal/pub publish_to: https://forgejo.internal.iconica.nl/api/packages/internal/pub
environment: environment:
sdk: ">=3.1.3 <4.0.0" sdk: ">=3.4.3 <4.0.0"
flutter: '>=3.22.2'
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
intl: any intl: ^0.19.0
cached_network_image: ^3.2.2 cached_network_image: ^3.2.2
dotted_border: ^2.1.0 dotted_border: ^2.1.0
collection: any collection: ^1.18.0
flutter_svg: ^2.0.10+1 flutter_svg: ^2.0.10+1
flutter_timeline_interface: flutter_timeline_interface:
hosted: https://forgejo.internal.iconica.nl/api/packages/internal/pub hosted: https://forgejo.internal.iconica.nl/api/packages/internal/pub
version: ^5.1.0 version: ^5.1.1
flutter_image_picker: flutter_image_picker:
hosted: https://forgejo.internal.iconica.nl/api/packages/internal/pub hosted: https://forgejo.internal.iconica.nl/api/packages/internal/pub
version: ^4.0.0 version: ^4.0.0
dev_dependencies: dev_dependencies:
flutter_lints: ^2.0.0
flutter_iconica_analysis: flutter_iconica_analysis:
git: git:
url: https://github.com/Iconica-Development/flutter_iconica_analysis url: https://github.com/Iconica-Development/flutter_iconica_analysis

View file

@ -5,6 +5,6 @@
name: flutter_timeline_workspace name: flutter_timeline_workspace
environment: environment:
sdk: '>=2.18.0 <3.0.0' sdk: '>=3.4.3 <4.0.0'
dev_dependencies: dev_dependencies:
melos: ^3.0.1 melos: ^3.0.1