Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add feature flag to hide community features in chat #697

Merged
merged 1 commit into from
Feb 13, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import 'package:ion/app/features/auth/providers/auth_provider.c.dart';
import 'package:ion/app/features/chat/community/models/community_join_requests_state.c.dart';
import 'package:ion/app/features/chat/community/models/entities/community_join_data.c.dart';
import 'package:ion/app/features/chat/model/database/chat_database.c.dart';
import 'package:ion/app/features/core/model/feature_flags.dart';
import 'package:ion/app/features/core/providers/feature_flags_provider.c.dart';
import 'package:ion/app/features/ion_connect/ion_connect.dart';
import 'package:ion/app/features/ion_connect/providers/ion_connect_notifier.c.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
Expand All @@ -21,6 +23,16 @@ part 'community_join_requests_provider.c.g.dart';
///
@riverpod
FutureOr<CommunityJoinRequestsState> communityJoinRequests(Ref ref) async {
final hideCommunity =
ref.watch(featureFlagsProvider.notifier).get(HideCommunityFeatureFlag.hideCommunity);

if (hideCommunity) {
return const CommunityJoinRequestsState(
accepted: [],
waitingApproval: [],
);
}

final currentPubkey = ref.watch(currentPubkeySelectorProvider).valueOrNull;

if (currentPubkey == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import 'package:ion/app/features/chat/community/providers/community_join_requests_provider.c.dart';
import 'package:ion/app/features/chat/community/providers/community_metadata_provider.c.dart';
import 'package:ion/app/features/chat/model/database/chat_database.c.dart';
import 'package:ion/app/features/core/model/feature_flags.dart';
import 'package:ion/app/features/core/providers/feature_flags_provider.c.dart';
import 'package:ion/app/features/feed/data/models/entities/modifiable_post_data.c.dart';
import 'package:ion/app/features/ion_connect/ion_connect.dart';
import 'package:ion/app/features/ion_connect/model/action_source.dart';
Expand All @@ -16,6 +18,13 @@ part 'community_messages_subscriber_provider.c.g.dart';
class CommunityMessagesSubscriber extends _$CommunityMessagesSubscriber {
@override
Stream<void> build() async* {
final hideCommunity =
ref.watch(featureFlagsProvider.notifier).get(HideCommunityFeatureFlag.hideCommunity);

if (hideCommunity) {
yield null;
}

final joinedCommunities = await ref.watch(communityJoinRequestsProvider.future);

final communityIds = joinedCommunities.accepted.map((e) => e.data.uuid).toList();
Expand Down
11 changes: 11 additions & 0 deletions lib/app/features/chat/model/conversation_type.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import 'package:flutter/material.dart';
import 'package:ion/app/extensions/build_context.dart';
import 'package:ion/app/extensions/theme_data.dart';
import 'package:ion/app/router/app_routes.c.dart';
import 'package:ion/app/router/model/main_modal_list_item.dart';
import 'package:ion/generated/assets.gen.dart';

Expand Down Expand Up @@ -46,4 +47,14 @@ enum ConversationType implements MainModalListItem {
ConversationType.channel => Assets.svg.iconSearchChannel,
};
}

String get subRouteLocation {
return switch (this) {
ConversationType.private => NewChatModalRoute().location,
ConversationType.group => CreateGroupModalRoute().location,
ConversationType.channel => NewChannelModalRoute().location,
};
}

bool get isCommunity => this != ConversationType.private;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,27 @@

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:ion/app/components/separated/separator.dart';
import 'package:ion/app/extensions/extensions.dart';
import 'package:ion/app/features/chat/model/conversation_type.dart';
import 'package:ion/app/router/app_routes.c.dart';
import 'package:ion/app/features/core/model/feature_flags.dart';
import 'package:ion/app/features/core/providers/feature_flags_provider.c.dart';
import 'package:ion/app/router/components/navigation_app_bar/navigation_app_bar.dart';
import 'package:ion/app/router/components/sheet_content/main_modal_item.dart';
import 'package:ion/app/router/components/sheet_content/sheet_content.dart';

class ChatMainModalPage extends StatelessWidget {
class ChatMainModalPage extends ConsumerWidget {
const ChatMainModalPage({super.key});

static const List<ConversationType> menuItems = ConversationType.values;

@override
Widget build(BuildContext context) {
Widget build(BuildContext context, WidgetRef ref) {
final hideCommunity =
ref.watch(featureFlagsProvider.notifier).get(HideCommunityFeatureFlag.hideCommunity);

final menuItems =
ConversationType.values.where((type) => !hideCommunity || !type.isCommunity).toList();

return SheetContent(
backgroundColor: context.theme.appColors.secondaryBackground,
body: Column(
Expand All @@ -32,25 +38,16 @@ class ChatMainModalPage extends StatelessWidget {
separatorBuilder: (_, __) => const HorizontalSeparator(),
itemCount: menuItems.length,
itemBuilder: (BuildContext context, int index) {
final type = menuItems[index];
final conversationType = menuItems[index];

final createFlowRouteLocation = _getSubRouteLocation(type);
return MainModalItem(
item: type,
onTap: () => context.pushReplacement(createFlowRouteLocation),
item: conversationType,
onTap: () => context.pushReplacement(conversationType.subRouteLocation),
);
},
),
],
),
);
}

String _getSubRouteLocation(ConversationType type) {
return switch (type) {
ConversationType.private => NewChatModalRoute().location,
ConversationType.channel => NewChannelModalRoute().location,
ConversationType.group => CreateGroupModalRoute().location,
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:ion/app/components/button/button.dart';
import 'package:ion/app/extensions/extensions.dart';
import 'package:ion/app/features/core/model/feature_flags.dart';
import 'package:ion/app/features/core/providers/feature_flags_provider.c.dart';
import 'package:ion/app/features/user/model/user_metadata.c.dart';
import 'package:ion/app/features/user/pages/user_picker_sheet/user_picker_sheet.dart';
import 'package:ion/app/router/app_routes.c.dart';
Expand All @@ -29,6 +31,9 @@ class NewChatModal extends HookConsumerWidget {
},
);

final hideCommunity =
ref.watch(featureFlagsProvider.notifier).get(HideCommunityFeatureFlag.hideCommunity);

return SheetContent(
topPadding: 0,
body: UserPickerSheet(
Expand All @@ -38,30 +43,39 @@ class NewChatModal extends HookConsumerWidget {
actions: const [NavigationCloseButton()],
),
onUserSelected: onUserSelected,
header: Row(
children: [
_HeaderButton(
icon: Assets.svg.iconSearchGroups,
title: context.i18n.new_chat_modal_new_group_button,
onTap: () {
AddParticipantsToGroupModalRoute().push<void>(context);
},
),
SizedBox(width: 20.0.s),
_HeaderButton(
icon: Assets.svg.iconSearchChannel,
title: context.i18n.new_chat_modal_new_channel_button,
onTap: () {
NewChannelModalRoute().replace(context);
},
),
],
),
header: hideCommunity ? null : const _HeaderSection(),
),
);
}
}

class _HeaderSection extends StatelessWidget {
const _HeaderSection();

@override
Widget build(BuildContext context) {
return Row(
children: [
_HeaderButton(
icon: Assets.svg.iconSearchGroups,
title: context.i18n.new_chat_modal_new_group_button,
onTap: () {
AddParticipantsToGroupModalRoute().push<void>(context);
},
),
SizedBox(width: 20.0.s),
_HeaderButton(
icon: Assets.svg.iconSearchChannel,
title: context.i18n.new_chat_modal_new_channel_button,
onTap: () {
NewChannelModalRoute().replace(context);
},
),
],
);
}
}

class _HeaderButton extends StatelessWidget {
const _HeaderButton({
required this.icon,
Expand Down
6 changes: 6 additions & 0 deletions lib/app/features/core/model/feature_flags.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,9 @@ final class HideCreatorsWithoutPicture extends FeatureFlag {
static const hideCreatorsWithoutPicture =
HideCreatorsWithoutPicture._(key: 'hideCreatorsWithoutPicture');
}

final class HideCommunityFeatureFlag extends FeatureFlag {
const HideCommunityFeatureFlag._({required super.key});

static const hideCommunity = HideCommunityFeatureFlag._(key: 'hideCommunity');
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class FeatureFlags extends _$FeatureFlags {
FeedFeatureFlag.showTrendingVideo: false,
FeedFeatureFlag.showMentionsSuggestions: true,
HideCreatorsWithoutPicture.hideCreatorsWithoutPicture: true,
HideCommunityFeatureFlag.hideCommunity: true,

/// Log flags
if (ref.watch(envProvider.notifier).get(EnvVariable.SHOW_DEBUG_INFO)) ...{
Expand Down
8 changes: 8 additions & 0 deletions lib/app/features/search/model/advanced_search_category.dart
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,12 @@ enum AdvancedSearchCategory {
_ => false,
};
}

bool get isCommunity {
return switch (this) {
AdvancedSearchCategory.groups => true,
AdvancedSearchCategory.channels => true,
_ => false,
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:ion/app/components/screen_offset/screen_top_offset.dart';
import 'package:ion/app/extensions/extensions.dart';
import 'package:ion/app/features/core/model/feature_flags.dart';
import 'package:ion/app/features/core/providers/feature_flags_provider.c.dart';
import 'package:ion/app/features/feed/views/components/list_separator/list_separator.dart';
import 'package:ion/app/features/search/model/advanced_search_category.dart';
import 'package:ion/app/features/search/views/components/advanced_search_channels/advanced_search_channels.dart';
Expand All @@ -23,18 +25,26 @@ class ChatAdvancedSearchPage extends HookConsumerWidget {

@override
Widget build(BuildContext context, WidgetRef ref) {
final hideCommunity =
ref.watch(featureFlagsProvider.notifier).get(HideCommunityFeatureFlag.hideCommunity);

final categories = useMemoized(
() {
return AdvancedSearchCategory.values.where((category) => category.isChat).toList();
return AdvancedSearchCategory.values
.where(
(category) => category.isChat && (!hideCommunity || !category.isCommunity),
)
.toList();
},
[],
[hideCommunity],
);

return Scaffold(
body: ScreenTopOffset(
child: DefaultTabController(
length: categories.length,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AdvancedSearchNavigation(
query: query,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:ion/app/components/screen_offset/screen_top_offset.dart';
import 'package:ion/app/extensions/extensions.dart';
import 'package:ion/app/features/core/model/feature_flags.dart';
import 'package:ion/app/features/core/providers/feature_flags_provider.c.dart';
import 'package:ion/app/features/search/providers/chat_search_history_provider.c.dart'
show chatSearchHistoryProvider;
import 'package:ion/app/features/search/providers/chat_search_users_provider.c.dart';
Expand All @@ -26,6 +28,9 @@ class ChatSimpleSearchPage extends ConsumerWidget {
final history = ref.watch(chatSearchHistoryProvider);
final usersSearchResults = ref.watch(chatSearchUsersProvider(query));

final hideCommunity =
ref.watch(featureFlagsProvider.notifier).get(HideCommunityFeatureFlag.hideCommunity);

return Scaffold(
body: ScreenTopOffset(
child: Column(
Expand All @@ -45,7 +50,9 @@ class ChatSimpleSearchPage extends ConsumerWidget {
data: (pubKeys) => pubKeys == null
? history.pubKeys.isEmpty && history.queries.isEmpty
? SearchHistoryEmpty(
title: context.i18n.chat_search_empty,
title: hideCommunity
? context.i18n.chat_search_no_community_empty
: context.i18n.chat_search_empty,
)
: SearchHistory(
itemCount: history.pubKeys.length,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ class FollowingUsers extends ConsumerWidget {

return followList.maybeWhen(
data: (data) {
final pubkeys = data?.data.list.map((e) => e.pubkey).toList() ?? [];
if (data == null || data.data.list.isEmpty) return const NoUserView();

final pubkeys = data.data.list.map((e) => e.pubkey).toList();
return ListView.separated(
itemBuilder: (context, index) {
return SelectableUserListItem(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
// SPDX-License-Identifier: ice License 1.0

import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:ion/app/components/screen_offset/screen_side_offset.dart';
import 'package:ion/app/extensions/extensions.dart';
import 'package:ion/app/features/core/model/feature_flags.dart';
import 'package:ion/app/features/core/providers/feature_flags_provider.c.dart';
import 'package:ion/generated/assets.gen.dart';

class NoUserView extends StatelessWidget {
class NoUserView extends ConsumerWidget {
const NoUserView({
super.key,
});

@override
Widget build(BuildContext context) {
Widget build(BuildContext context, WidgetRef ref) {
final hideCommunity =
ref.watch(featureFlagsProvider.notifier).get(HideCommunityFeatureFlag.hideCommunity);

return Expanded(
child: ScreenSideOffset.small(
child: Column(
Expand All @@ -25,7 +31,9 @@ class NoUserView extends StatelessWidget {
Padding(
padding: EdgeInsets.symmetric(vertical: 8.0.s, horizontal: 78.0.s),
child: Text(
context.i18n.new_chat_modal_description,
hideCommunity
? context.i18n.new_chat_modal_no_community_description
: context.i18n.new_chat_modal_description,
style: context.theme.appTextThemes.caption2.copyWith(
color: context.theme.appColors.onTertararyBackground,
),
Expand Down
2 changes: 2 additions & 0 deletions lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -636,13 +636,15 @@
"chat_profile_share_modal_title": "Share profile",
"new_chat_modal_title": "New Chat",
"new_chat_modal_description": "Search above for users, groups, and channels...",
"new_chat_modal_no_community_description": "Search above for users, chats...",
"new_chat_modal_new_group_button": "New group",
"new_chat_modal_new_channel_button": "New channel",
"chat_read": "Read",
"chat_read_all": "Read All",
"chat_delete_modal_title": "Delete chat?",
"chat_delete_modal_description": "Are you sure you want to delete all selected chats?",
"chat_search_empty": "Search here for users, chats, groups, and channels...",
"chat_search_no_community_empty": "Search here for users, chats...",
"chat_money_request_title": "Money requested",
"chat_money_received_title": "Money received",
"chat_money_received_button": "View transaction",
Expand Down