mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
Signed-off-by: Tyler Longwell <tlongwell@block.xyz> Co-authored-by: npub1qyvc0c5kl4gqv2fd97fsk46tu378sqgy35vc83rvgfwne90sel7s0ed67d <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@sprout-oss.stage.blox.sqprod.co> Co-authored-by: Max <d8473ee32b973aa31a21a65adddcc4b69cc2a8a4dee8121ecd51926e0cddbc02@sprout-oss.stage.blox.sqprod.co> Co-authored-by: Mari <95cae996907d7cab9f5dbf43c0f53edeac6ab0b032a6feae4abfd784e467b3f5@sprout-oss.stage.blox.sqprod.co> Co-authored-by: Quinn <96f056ad5f2305c8ddf637dc65d048aa4c12d7daeb8867690e34fca46b0ef64c@sprout-oss.stage.blox.sqprod.co> Co-authored-by: Sami <f4a42a97e594b77bdbd8ee35191c8b28a94a4cb871d96f32921558275421fb68@sprout-oss.stage.blox.sqprod.co> Co-authored-by: Perci <5a968df9a7494b4e019b9ecf739e088ba61097b4312124e9a88ae5b42e3f5f3e@sprout-oss.stage.blox.sqprod.co> Co-authored-by: Tyler Longwell <tlongwell@block.xyz>
127 lines
3.5 KiB
Dart
127 lines
3.5 KiB
Dart
import 'package:flutter/foundation.dart';
|
|
|
|
@immutable
|
|
class FeedItem {
|
|
final String id;
|
|
final int kind;
|
|
final String pubkey;
|
|
final String content;
|
|
final int createdAt;
|
|
final String? channelId;
|
|
final String channelName;
|
|
final List<List<String>> tags;
|
|
final String
|
|
category; // "mention", "needs_action", "activity", "agent_activity"
|
|
|
|
const FeedItem({
|
|
required this.id,
|
|
required this.kind,
|
|
required this.pubkey,
|
|
required this.content,
|
|
required this.createdAt,
|
|
required this.channelId,
|
|
required this.channelName,
|
|
required this.tags,
|
|
required this.category,
|
|
});
|
|
|
|
factory FeedItem.fromJson(Map<String, dynamic> json) => FeedItem(
|
|
id: json['id'] as String,
|
|
kind: json['kind'] as int,
|
|
pubkey: json['pubkey'] as String,
|
|
content: json['content'] as String,
|
|
createdAt: json['created_at'] as int,
|
|
channelId: json['channel_id'] as String?,
|
|
channelName: (json['channel_name'] as String?) ?? '',
|
|
tags:
|
|
(json['tags'] as List<dynamic>?)
|
|
?.map((t) => (t as List<dynamic>).map((e) => e as String).toList())
|
|
.toList() ??
|
|
const [],
|
|
category: json['category'] as String,
|
|
);
|
|
|
|
/// Human-readable headline based on event kind and category.
|
|
String get headline {
|
|
switch (kind) {
|
|
case 45001:
|
|
return 'Forum post';
|
|
case 45003:
|
|
return 'Forum reply';
|
|
case 46010:
|
|
return 'Approval requested';
|
|
case 43001:
|
|
return 'Job requested';
|
|
case 43002:
|
|
return 'Job accepted';
|
|
case 43003:
|
|
return 'Progress update';
|
|
case 43004:
|
|
return 'Job result';
|
|
case 43005:
|
|
return 'Job cancelled';
|
|
case 43006:
|
|
return 'Job failed';
|
|
default:
|
|
if (category == 'mention') return 'Mention';
|
|
if (category == 'agent_activity') return 'Agent update';
|
|
return 'Channel update';
|
|
}
|
|
}
|
|
|
|
/// Trimmed content, with a fallback for empty events.
|
|
String get displayContent {
|
|
final trimmed = content.trim();
|
|
if (trimmed.isNotEmpty) return trimmed;
|
|
if (kind == 46010) return 'A workflow is waiting for approval.';
|
|
return 'No additional details.';
|
|
}
|
|
}
|
|
|
|
/// Parsed response from GET /api/feed.
|
|
@immutable
|
|
class HomeFeedResponse {
|
|
final List<FeedItem> mentions;
|
|
final List<FeedItem> needsAction;
|
|
final List<FeedItem> activity;
|
|
final List<FeedItem> agentActivity;
|
|
|
|
HomeFeedResponse({
|
|
required this.mentions,
|
|
required this.needsAction,
|
|
required this.activity,
|
|
required this.agentActivity,
|
|
});
|
|
|
|
factory HomeFeedResponse.fromJson(Map<String, dynamic> json) {
|
|
final feed = json['feed'] as Map<String, dynamic>;
|
|
return HomeFeedResponse(
|
|
mentions: _parseItems(feed['mentions']),
|
|
needsAction: _parseItems(feed['needs_action']),
|
|
activity: _parseItems(feed['activity']),
|
|
agentActivity: _parseItems(feed['agent_activity']),
|
|
);
|
|
}
|
|
|
|
/// All items merged into a single list, sorted newest-first.
|
|
late final List<FeedItem> all = () {
|
|
final items = [...mentions, ...needsAction, ...activity, ...agentActivity];
|
|
items.sort((a, b) => b.createdAt.compareTo(a.createdAt));
|
|
return List<FeedItem>.unmodifiable(items);
|
|
}();
|
|
|
|
bool get isEmpty =>
|
|
mentions.isEmpty &&
|
|
needsAction.isEmpty &&
|
|
activity.isEmpty &&
|
|
agentActivity.isEmpty;
|
|
}
|
|
|
|
List<FeedItem> _parseItems(dynamic json) {
|
|
if (json == null) return const [];
|
|
return (json as List<dynamic>)
|
|
.cast<Map<String, dynamic>>()
|
|
.map(FeedItem.fromJson)
|
|
.toList();
|
|
}
|