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
31 changes: 4 additions & 27 deletions lib/app/features/feed/providers/user_holdings_provider.r.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
// SPDX-License-Identifier: ice License 1.0

import 'package:ion/app/features/feed/data/models/entities/generic_repost.f.dart';
import 'package:ion/app/features/feed/providers/user_posts_data_source_provider.r.dart';
import 'package:ion/app/features/feed/providers/user_tokenized_community_data_source_provider.r.dart';
import 'package:ion/app/features/ion_connect/model/ion_connect_entity.dart';
import 'package:ion/app/features/ion_connect/providers/entities_paged_data_provider.m.dart';
import 'package:ion/app/features/tokenized_communities/models/entities/community_token_action.f.dart';
import 'package:ion/app/features/tokenized_communities/models/entities/community_token_definition.f.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'user_holdings_provider.r.g.dart';
Expand All @@ -14,7 +11,7 @@ part 'user_holdings_provider.r.g.dart';
class UserHoldings extends _$UserHoldings with DelegatedPagedNotifier {
@override
({Iterable<IonConnectEntity>? items, bool hasMore}) build(String pubkey) {
final dataSources = ref.watch(userPostsDataSourceProvider(pubkey));
final dataSources = ref.watch(userTokenizedCommunityDataSourceProvider(pubkey));
if (dataSources == null) {
return (items: null, hasMore: false);
}
Expand All @@ -24,35 +21,15 @@ class UserHoldings extends _$UserHoldings with DelegatedPagedNotifier {
return (items: null, hasMore: false);
}

final allItems = data.data.items;
if (allItems == null) {
return (items: null, hasMore: data.hasMore);
}

// Filter to include only tokenized community entities
final holdingsItems = allItems.where(_isTokenizedCommunityEntity);

// If filtered items are empty but we've loaded data, show empty state
// (set hasMore to false to prevent infinite loading)
final hasMore = holdingsItems.isNotEmpty && data.hasMore;

return (items: holdingsItems, hasMore: hasMore);
return (items: data.data.items, hasMore: data.hasMore);
}

@override
PagedNotifier getDelegate() {
final dataSources = ref.read(userPostsDataSourceProvider(pubkey));
final dataSources = ref.read(userTokenizedCommunityDataSourceProvider(pubkey));
if (dataSources == null) {
throw StateError('Data sources not available for user holdings');
}
return ref.read(entitiesPagedDataProvider(dataSources).notifier);
}

bool _isTokenizedCommunityEntity(IonConnectEntity entity) {
return entity is CommunityTokenActionEntity ||
entity is CommunityTokenDefinitionEntity ||
(entity is GenericRepostEntity &&
(entity.data.kind == GenericRepostEntity.communityTokenDefinitionRepostKind ||
entity.data.kind == GenericRepostEntity.communityTokenActionRepostKind));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ import 'package:ion/app/features/ion_connect/model/related_event.f.dart';
import 'package:ion/app/features/ion_connect/model/related_event_marker.dart';
import 'package:ion/app/features/ion_connect/model/search_extension.dart';
import 'package:ion/app/features/ion_connect/providers/entities_paged_data_provider.m.dart';
import 'package:ion/app/features/tokenized_communities/models/entities/community_token_action.f.dart';
import 'package:ion/app/features/tokenized_communities/models/entities/community_token_definition.f.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'user_posts_data_source_provider.r.g.dart';
Expand All @@ -27,9 +25,6 @@ const requestKinds = [
ArticleEntity.kind,
GenericRepostEntity.modifiablePostRepostKind,
GenericRepostEntity.articleRepostKind,
GenericRepostEntity.communityTokenDefinitionRepostKind,
GenericRepostEntity.communityTokenActionRepostKind,
CommunityTokenActionEntity.kind,
];

const withCountersKinds = [
Expand All @@ -38,7 +33,6 @@ const withCountersKinds = [
ArticleEntity.kind,
RepostEntity.kind,
GenericRepostEntity.kind,
CommunityTokenActionEntity.kind,
];

const withTokensKinds = [
Expand Down Expand Up @@ -75,10 +69,6 @@ List<EntitiesDataSource>? userPostsDataSource(Ref ref, String pubkey) {
marker: RelatedEventMarker.reply.toShortString(),
negative: true,
),
GenericIncludeSearchExtension(
forKind: CommunityTokenActionEntity.kind,
includeKind: CommunityTokenDefinitionEntity.kind,
),
ExpirationSearchExtension(expiration: false),
]).toString();

Expand All @@ -91,9 +81,7 @@ List<EntitiesDataSource>? userPostsDataSource(Ref ref, String pubkey) {
entity is ArticleEntity ||
entity is GenericRepostEntity ||
(entity is PostEntity && entity.data.parentEvent == null) ||
entity is RepostEntity ||
entity is CommunityTokenDefinitionEntity ||
entity is CommunityTokenActionEntity),
entity is RepostEntity),
requestFilter: RequestFilter(
kinds: requestKinds,
authors: [pubkey],
Expand Down
29 changes: 1 addition & 28 deletions lib/app/features/feed/providers/user_posts_provider.r.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import 'package:ion/app/features/feed/providers/repost_notifier.r.dart';
import 'package:ion/app/features/feed/providers/user_posts_data_source_provider.r.dart';
import 'package:ion/app/features/ion_connect/model/ion_connect_entity.dart';
import 'package:ion/app/features/ion_connect/providers/entities_paged_data_provider.m.dart';
import 'package:ion/app/features/tokenized_communities/models/entities/community_token_action.f.dart';
import 'package:ion/app/features/tokenized_communities/models/entities/community_token_definition.f.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'user_posts_provider.r.g.dart';
Expand Down Expand Up @@ -41,19 +39,7 @@ class UserPosts extends _$UserPosts with DelegatedPagedNotifier {
return (items: null, hasMore: false);
}

final allItems = data.data.items;
if (allItems == null) {
return (items: null, hasMore: data.hasMore);
}

// Filter to exclude tokenized community entities (those go to Holdings tab)
final nonTokenizedItems = allItems.where((entity) => !_isTokenizedCommunityEntity(entity));

// If filtered items are empty but we've loaded data, show empty state
// (set hasMore to false to prevent infinite loading)
final hasMore = nonTokenizedItems.isNotEmpty && data.hasMore;

return (items: nonTokenizedItems, hasMore: hasMore);
return (items: data.data.items, hasMore: data.hasMore);
}

@override
Expand All @@ -70,11 +56,6 @@ class UserPosts extends _$UserPosts with DelegatedPagedNotifier {
return false;
}

// Exclude tokenized community entities (those go to Holdings tab)
if (_isTokenizedCommunityEntity(entity)) {
return false;
}

return (entity is ModifiablePostEntity &&
entity.data.parentEvent == null &&
entity.data.expiration == null) ||
Expand All @@ -85,12 +66,4 @@ class UserPosts extends _$UserPosts with DelegatedPagedNotifier {
entity is RepostEntity ||
entity is ArticleEntity;
}

bool _isTokenizedCommunityEntity(IonConnectEntity entity) {
return entity is CommunityTokenActionEntity ||
entity is CommunityTokenDefinitionEntity ||
(entity is GenericRepostEntity &&
(entity.data.kind == GenericRepostEntity.communityTokenDefinitionRepostKind ||
entity.data.kind == GenericRepostEntity.communityTokenActionRepostKind));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// SPDX-License-Identifier: ice License 1.0

import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:ion/app/features/auth/providers/auth_provider.m.dart';
import 'package:ion/app/features/feed/data/models/entities/generic_repost.f.dart';
import 'package:ion/app/features/ion_connect/ion_connect.dart';
import 'package:ion/app/features/ion_connect/model/action_source.f.dart';
import 'package:ion/app/features/ion_connect/model/search_extension.dart';
import 'package:ion/app/features/ion_connect/providers/entities_paged_data_provider.m.dart';
import 'package:ion/app/features/tokenized_communities/models/entities/community_token_action.f.dart';
import 'package:ion/app/features/tokenized_communities/models/entities/community_token_definition.f.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'user_tokenized_community_data_source_provider.r.g.dart';

const _requestKinds = [
GenericRepostEntity.communityTokenDefinitionRepostKind,
GenericRepostEntity.communityTokenActionRepostKind,
CommunityTokenActionEntity.kind,
];

const _withCountersKinds = [
CommunityTokenActionEntity.kind,
CommunityTokenDefinitionEntity.kind,
];

@riverpod
List<EntitiesDataSource>? userTokenizedCommunityDataSource(Ref ref, String pubkey) {
final currentPubkey = ref.watch(currentPubkeySelectorProvider);

if (currentPubkey == null) {
return null;
}

final search = SearchExtensions([
...[
for (final kind in _withCountersKinds)
...SearchExtensions.withCounters(forKind: kind, currentPubkey: currentPubkey).extensions,
],
...SearchExtensions.withAuthors(forKind: CommunityTokenActionEntity.kind).extensions,
...SearchExtensions.withAuthors(forKind: CommunityTokenDefinitionEntity.kind).extensions,
FollowingListSearchExtension(forKind: CommunityTokenDefinitionEntity.kind),
FollowersCountSearchExtension(forKind: CommunityTokenDefinitionEntity.kind),
GenericIncludeSearchExtension(
forKind: CommunityTokenActionEntity.kind,
includeKind: CommunityTokenDefinitionEntity.kind,
),
]).toString();

return [
EntitiesDataSource(
actionSource: ActionSourceUser(pubkey),
entityFilter: (entity) =>
entity.masterPubkey == pubkey &&
(entity is CommunityTokenDefinitionEntity ||
entity is CommunityTokenActionEntity ||
entity is GenericRepostEntity),
requestFilter: RequestFilter(
kinds: _requestKinds,
authors: [pubkey],
search: search,
limit: 10,
),
),
];
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:ion/app/features/feed/providers/user_holdings_provider.r.dart';
import 'package:ion/app/features/feed/providers/user_posts_data_source_provider.r.dart';
import 'package:ion/app/features/feed/providers/user_posts_provider.r.dart';
import 'package:ion/app/features/feed/providers/user_replies_data_source_provider.r.dart';
import 'package:ion/app/features/feed/providers/user_tokenized_community_data_source_provider.r.dart';
import 'package:ion/app/features/feed/providers/user_videos_data_source_provider.r.dart';
import 'package:ion/app/features/ion_connect/model/ion_connect_entity.dart';
import 'package:ion/app/features/ion_connect/providers/entities_paged_data_provider.m.dart';
Expand All @@ -22,9 +23,9 @@ List<EntitiesDataSource>? tabDataSource(
}) {
switch (type) {
case TabEntityType.posts:
case TabEntityType.holdings:
// Holdings uses the same data source as posts (filtering happens at provider level)
return ref.watch(userPostsDataSourceProvider(pubkey));
case TabEntityType.holdings:
return ref.watch(userTokenizedCommunityDataSourceProvider(pubkey));
case TabEntityType.articles:
return ref.watch(userArticlesDataSourceProvider(pubkey));
case TabEntityType.replies:
Expand Down