Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/stream_feeds/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## unreleased
- [BREAKING] Change `queryFollowSuggestions` return type to `List<FeedSuggestionData>`.
- [BREAKING] Remove `activitySelectorOptions` from `FeedQuery`.
- Add `activityFeedback` method to `Feed` and `Activity` for submitting activity feedback.
- Add `hidden` and `preview` fields to `ActivityData`.
- Update follower and following counts on the feed state when receiving follow websocket events.
- Fix FeedsReactionData id for updating reactions in the feed state.
Expand Down
4 changes: 4 additions & 0 deletions packages/stream_feeds/dart_test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
tags:
feed:
activity:
activity-list:
Original file line number Diff line number Diff line change
Expand Up @@ -248,4 +248,20 @@ class ActivitiesRepository {
return PaginationResult(items: reactions, pagination: pagination);
});
}

/// Submits activity feedback.
///
/// Submits feedback for the activity with the specified [activityId] using
/// the provided [request].
///
/// Returns a [Result] containing void or an error.
Future<Result<void>> activityFeedback(
String activityId,
api.ActivityFeedbackRequest request,
) {
return _api.activityFeedback(
activityId: activityId,
activityFeedbackRequest: request,
);
}
}
1 change: 1 addition & 0 deletions packages/stream_feeds/lib/src/state.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export 'state/activity.dart';
export 'state/activity_comment_list.dart';
export 'state/activity_list.dart';
export 'state/comment_list.dart';
export 'state/comment_reaction_list.dart';
export 'state/comment_reply_list.dart';
Expand Down
22 changes: 21 additions & 1 deletion packages/stream_feeds/lib/src/state/activity.dart
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,13 @@ class Activity with Disposable {
);

// Attach event handlers for real-time updates
final handler = ActivityEventHandler(fid: fid, state: _stateNotifier);
final handler = ActivityEventHandler(
fid: fid,
state: _stateNotifier,
activityId: activityId,
currentUserId: currentUserId,
);

_eventsSubscription = eventsEmitter.listen(handler.handleEvent);
}

Expand Down Expand Up @@ -117,6 +123,20 @@ class Activity with Disposable {
return result;
}

/// Submits feedback for this activity.
///
/// Submits feedback for this activity using the provided [activityFeedbackRequest].
///
/// Returns a [Result] indicating success or failure of the operation.
Future<Result<void>> activityFeedback({
required api.ActivityFeedbackRequest activityFeedbackRequest,
}) {
return activitiesRepository.activityFeedback(
activityId,
activityFeedbackRequest,
);
}

/// Queries the comments for this activity.
///
/// Returns a [Result] containing a list of [ThreadedCommentData] or an error.
Expand Down
2 changes: 2 additions & 0 deletions packages/stream_feeds/lib/src/state/activity_list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,10 @@ class ActivityList with Disposable {
final handler = ActivityListEventHandler(
query: query,
state: _stateNotifier,
currentUserId: currentUserId,
capabilitiesRepository: capabilitiesRepository,
);

_eventsSubscription = eventsEmitter.listen(handler.handleEvent);
}

Expand Down
14 changes: 14 additions & 0 deletions packages/stream_feeds/lib/src/state/activity_list_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,20 @@ class ActivityListStateNotifier extends StateNotifier<ActivityListState> {
state = state.copyWith(activities: updatedActivities);
}

/// Handles updates to the activity list state when an activity is hidden.
void onActivityHidden({
required String activityId,
required bool hidden,
}) {
final updatedActivities = state.activities.map((activity) {
if (activity.id != activityId) return activity;
// Update the hidden status of the activity
return activity.copyWith(hidden: hidden);
}).toList();

state = state.copyWith(activities: updatedActivities);
}

/// Handles the addition of a bookmark.
void onBookmarkAdded(BookmarkData bookmark) {
final updatedActivities = state.activities.map((activity) {
Expand Down
10 changes: 10 additions & 0 deletions packages/stream_feeds/lib/src/state/activity_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,16 @@ class ActivityStateNotifier extends StateNotifier<ActivityState> {
);
}

/// Handles updates to the activity's hidden status.
void onActivityHidden({
required bool hidden,
}) {
final currentActivity = state.activity;
final updatedActivity = currentActivity?.copyWith(hidden: hidden);

state = state.copyWith(activity: updatedActivity);
}

/// Handles when a poll is closed.
void onPollClosed(PollData poll) {
if (state.poll?.id != poll.id) return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,14 @@ class ActivityEventHandler implements StateEventHandler {
const ActivityEventHandler({
required this.fid,
required this.state,
required this.activityId,
required this.currentUserId,
});

final FeedId fid;
final ActivityStateNotifier state;
final String activityId;
final String currentUserId;

@override
void handleEvent(WsEvent event) {
Expand Down Expand Up @@ -68,6 +72,21 @@ class ActivityEventHandler implements StateEventHandler {
return state.onPollVoteRemoved(vote, poll);
}

if (event is api.ActivityFeedbackEvent) {
final payload = event.activityFeedback;

// Only process events for this activity and current user
if (payload.activityId != activityId) return;
if (payload.user.id != currentUserId) return;

// Only handle hide action for now
if (payload.action == api.ActivityFeedbackEventPayloadAction.hide) {
return state.onActivityHidden(
hidden: payload.value == 'true',
);
}
}

// Handle other activity events here as needed
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@ class ActivityListEventHandler
const ActivityListEventHandler({
required this.query,
required this.state,
required this.currentUserId,
required this.capabilitiesRepository,
});

final ActivitiesQuery query;
final ActivityListStateNotifier state;
final String currentUserId;

@override
final CapabilitiesRepository capabilitiesRepository;
Expand Down Expand Up @@ -112,6 +114,21 @@ class ActivityListEventHandler
return state.onCommentRemoved(event.comment.toModel());
}

if (event is api.ActivityFeedbackEvent) {
final payload = event.activityFeedback;

// Only process events for the current user
if (payload.user.id != currentUserId) return;

// Only handle hide action for now
if (payload.action == api.ActivityFeedbackEventPayloadAction.hide) {
return state.onActivityHidden(
activityId: payload.activityId,
hidden: payload.value == 'true',
);
}
}

// Handle other activity list events here as needed
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@ class FeedEventHandler with FeedCapabilitiesMixin implements StateEventHandler {
const FeedEventHandler({
required this.query,
required this.state,
required this.currentUserId,
required this.capabilitiesRepository,
});

final FeedQuery query;
final FeedStateNotifier state;
final String currentUserId;

@override
final CapabilitiesRepository capabilitiesRepository;
Expand Down Expand Up @@ -212,6 +214,22 @@ class FeedEventHandler with FeedCapabilitiesMixin implements StateEventHandler {
);
}

if (event is api.ActivityFeedbackEvent) {
final payload = event.activityFeedback;
final userId = payload.user.id;

// Only process events for the current user
if (userId != currentUserId) return;

// Only handle hide action for now
if (payload.action == api.ActivityFeedbackEventPayloadAction.hide) {
return state.onActivityHidden(
activityId: payload.activityId,
hidden: payload.value == 'true',
);
}
}

// Handle other events if necessary
}
}
17 changes: 17 additions & 0 deletions packages/stream_feeds/lib/src/state/feed.dart
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class Feed with Disposable {
final handler = FeedEventHandler(
query: query,
state: _stateNotifier,
currentUserId: currentUserId,
capabilitiesRepository: capabilitiesRepository,
);

Expand Down Expand Up @@ -218,6 +219,22 @@ class Feed with Disposable {
);
}

/// Submits feedback for an activity.
///
/// Submits feedback for the activity with the specified [activityId] using
/// the provided [activityFeedbackRequest].
///
/// Returns a [Result] indicating success or failure of the operation.
Future<Result<void>> activityFeedback({
required String activityId,
required api.ActivityFeedbackRequest activityFeedbackRequest,
}) {
return activitiesRepository.activityFeedback(
activityId,
activityFeedbackRequest,
);
}

/// Marks an activity as read or unread.
///
/// [request] The request containing the mark activity data.
Expand Down
23 changes: 23 additions & 0 deletions packages/stream_feeds/lib/src/state/feed_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,29 @@ class FeedStateNotifier extends StateNotifier<FeedState> {
);
}

/// Handles updates to the feed state when an activity is hidden.
void onActivityHidden({
required String activityId,
required bool hidden,
}) {
// Update the activity to mark it as hidden
final updatedActivities = state.activities.map((activity) {
if (activity.id != activityId) return activity;
return activity.copyWith(hidden: hidden);
}).toList();

// Update pinned activities as well
final updatedPinnedActivities = state.pinnedActivities.map((pin) {
if (pin.activity.id != activityId) return pin;
return pin.copyWith(activity: pin.activity.copyWith(hidden: hidden));
}).toList();

state = state.copyWith(
activities: updatedActivities,
pinnedActivities: updatedPinnedActivities,
);
}

/// Handles updates to the feed state when an activity is pinned.
void onActivityPinned(ActivityPinData activityPin) {
// Upsert the pinned activity into the existing pinned activities list
Expand Down
Loading