Revert "fix(mobile): warn when muted Solo chats are past the push lease limit"

This reverts commit 0ca4874a7d.

Signed-off-by: Tom Brow <tomb@block.xyz>
This commit is contained in:
Tom Brow
2026-10-27 13:33:46 -07:00
parent 0ca4874a7d
commit 4dfef54aec
4 changed files with 26 additions and 73 deletions

View File

@@ -25,9 +25,9 @@ class _NotificationsSection extends ConsumerWidget {
return const SizedBox.shrink();
}
final canToggle = hasCapability || community.pushNotificationsEnabled;
final overflow = community.pushNotificationsEnabled
? ref.watch(pushSubscriptionSyncProvider).value
: null;
final omittedSoloChats = community.pushNotificationsEnabled
? ref.watch(pushSubscriptionSyncProvider).value ?? 0
: 0;
void setEnabled(bool enabled) {
unawaited(
@@ -75,26 +75,15 @@ class _NotificationsSection extends ConsumerWidget {
],
),
),
if (overflow != null && overflow.chats > 0)
if (omittedSoloChats > 0)
AppListRow(
key: const ValueKey('push-solo-coverage'),
title: 'Older Solo chats notify only on mention',
subtitle: _soloOverflowText(overflow),
subtitle: omittedSoloChats == 1
? '1 chat is past this relay’s notification limit.'
: '$omittedSoloChats chats are past this relay’s notification limit.',
),
],
);
}
}
String _soloOverflowText(SoloOverflow overflow) {
final past = overflow.chats == 1
? '1 chat is past this relay’s notification limit.'
: '${overflow.chats} chats are past this relay’s notification limit.';
if (overflow.muted == 0) return past;
if (overflow.chats == 1) {
return '$past It is muted but still notifies on mention.';
}
return overflow.muted == 1
? '$past 1 of them is muted but still notifies on mention.'
: '$past ${overflow.muted} of them are muted but still notify on mention.';
}

View File

@@ -15,25 +15,25 @@ import 'push_setup_recovery.dart';
/// the active identity, joined channels, and mute state. This is desired client
/// policy only. Relay-accepted authority is introduced by lease publication.
///
/// Yields the Solo chats the lease had no room for.
final pushSubscriptionSyncProvider = FutureProvider.autoDispose<SoloOverflow>((
/// Yields how many Solo chats the lease had no room for.
final pushSubscriptionSyncProvider = FutureProvider.autoDispose<int>((
ref,
) async {
try {
if (ref.watch(authProvider).value?.status != AuthStatus.authenticated) {
return _noOverflow;
return 0;
}
final active = ref.watch(activeCommunityProvider).value;
final descriptor = ref.watch(currentRelayPushDescriptorProvider).value;
if (active == null ||
!active.pushNotificationsEnabled ||
descriptor == null) {
return _noOverflow;
return 0;
}
final channels = ref.watch(channelsProvider).value;
final mutes = ref.watch(channelMutesProvider);
if (channels == null || !mutes.isReady) {
return _noOverflow;
return 0;
}
// Legacy Solo chats are listed only in the Solo record. Wait while it
@@ -41,7 +41,7 @@ final pushSubscriptionSyncProvider = FutureProvider.autoDispose<SoloOverflow>((
// cached copy, keep DMs and mentions current; the Solo tab cannot list
// those chats either, and recovery republishes them.
final soloRecord = ref.watch(meGroupsProvider);
if (soloRecord.isLoading && !soloRecord.hasValue) return _noOverflow;
if (soloRecord.isLoading && !soloRecord.hasValue) return 0;
final desired = desiredBuzzPushSubscriptions(
community: active,
@@ -53,25 +53,19 @@ final pushSubscriptionSyncProvider = FutureProvider.autoDispose<SoloOverflow>((
if (entry.value.muted) entry.key,
],
);
if (desired == null) return _noOverflow;
if (desired == null) return 0;
await ref
.read(communityListProvider.notifier)
.updateDesiredPushSubscriptions(active.id, desired.subscriptions);
return desired.overflow;
return desired.omittedSoloChats;
} catch (error, stack) {
reportPushSetupError('subscription synchronization', error, stack);
rethrow;
}
}, retry: pushSetupRetry);
/// Solo chats a lease had no room for, and how many of those are muted.
/// Mentions in a muted one still notify, since its mute ignore did not fit.
typedef SoloOverflow = ({int chats, int muted});
const SoloOverflow _noOverflow = (chats: 0, muted: 0);
/// The desired lease, and the Solo chats it had no room for.
({List<BuzzPushSubscription> subscriptions, SoloOverflow overflow})?
/// The desired lease, and how many Solo chats it had no room for.
({List<BuzzPushSubscription> subscriptions, int omittedSoloChats})?
desiredBuzzPushSubscriptions({
required Community community,
required BuzzPushLeaseDescriptor descriptor,
@@ -118,15 +112,9 @@ desiredBuzzPushSubscriptions({
}
fitting = low;
}
final trimmed = candidates.solos.skip(fitting);
return (
subscriptions: lease(fitting),
overflow: (
chats: candidates.omitted + trimmed.length,
muted:
candidates.omittedMuted +
trimmed.where((id) => muted.contains(id.toLowerCase())).length,
),
omittedSoloChats: candidates.omitted + candidates.solos.length - fitting,
);
}
@@ -136,8 +124,7 @@ desiredBuzzPushSubscriptions({
///
/// DMs always stay, as before. Solo chats follow most recent first, within the
/// lease's channel counts; the rest push only on mention.
({List<String> dms, List<String> solos, int omitted, int omittedMuted})
_channelWideCandidates({
({List<String> dms, List<String> solos, int omitted}) _channelWideCandidates({
required String pubkey,
required Iterable<Channel> channels,
required Set<String> muted,
@@ -162,22 +149,13 @@ _channelWideCandidates({
buzzPushMaxChannelWideChannels - dms.where((id) => !isMuted(id)).length;
var mutedRoom = buzzPushMaxMutedChannels - dms.where(isMuted).length;
final solos = <String>[];
var omittedMuted = 0;
for (final solo in ordered) {
final soloMuted = isMuted(solo.id);
if ((soloMuted ? mutedRoom : unmutedRoom) <= 0) {
if (soloMuted) omittedMuted++;
continue;
}
if ((soloMuted ? mutedRoom : unmutedRoom) <= 0) continue;
solos.add(solo.id);
soloMuted ? mutedRoom-- : unmutedRoom--;
}
return (
dms: dms,
solos: solos,
omitted: ordered.length - solos.length,
omittedMuted: omittedMuted,
);
return (dms: dms, solos: solos, omitted: ordered.length - solos.length);
}
int _mostRecentFirst(Channel a, Channel b) {

View File

@@ -171,10 +171,8 @@ void main() {
savedPrefsProvider.overrideWithValue(prefs),
activeCommunityProvider.overrideWith((ref) async => community),
currentRelayPushDescriptorProvider.overrideWith((ref) => capability),
// The lease had no room for 12 older Solo chats, 3 of them muted.
pushSubscriptionSyncProvider.overrideWith(
(ref) async => (chats: 12, muted: 3),
),
// The lease had no room for 12 older Solo chats.
pushSubscriptionSyncProvider.overrideWith((ref) async => 12),
appLifecycleProvider.overrideWith(_SettingsLifecycleNotifier.new),
buzzPushAuthorizationStatusReaderProvider.overrideWithValue(
() async => BuzzPushAuthorizationStatus.authorized,
@@ -201,10 +199,7 @@ void main() {
findsOneWidget,
);
expect(
find.text(
'12 chats are past this relay’s notification limit. '
'3 of them are muted but still notify on mention.',
),
find.text('12 chats are past this relay’s notification limit.'),
findsOneWidget,
);
debugDefaultTargetPlatformOverride = null;

View File

@@ -1,5 +1,4 @@
import 'dart:async';
import 'dart:math' as math;
import 'package:buzz/features/channels/channel.dart';
import 'package:buzz/features/channels/channel_mutes/channel_mutes_provider.dart';
@@ -119,7 +118,7 @@ void main() {
expect(followed, containsAll([for (var n = 0; n < dmCount; n++) _id(n)]));
expect(followed, contains(_id(channels.length - 1)));
expect(followed, isNot(contains(_id(dmCount + dmCount - 1))));
expect(desired.overflow, (chats: dmCount, muted: 0));
expect(desired.omittedSoloChats, dmCount);
// A relay may advertise any endpoint limit; sizing must not allocate it.
expect(
@@ -146,12 +145,6 @@ void main() {
400,
100,
),
(
'content, trimming muted chats,',
_descriptor(contentLength: 24000, plaintextLength: 32768),
400,
300,
),
('muted channel count', _descriptor(), 400, 400),
('NIP-44 plaintext', _descriptor(), 600, 200),
]) {
@@ -182,10 +175,8 @@ void main() {
for (final ignore in desired.subscriptions.first.ignore.skip(1))
...?ignore.hTags,
};
final keptSolos = soloCount - desired.overflow.chats;
final keptSolos = soloCount - desired.omittedSoloChats;
expect(keptSolos, inInclusiveRange(1, soloCount - 1));
// Omitted muted chats lose their mute ignore, so Settings counts them.
expect(desired.overflow.muted, math.max(0, mutedSolos - keptSolos));
expect(kept, {
for (var n = 0; n < dmCount; n++) _id(n),
for (var n = channels.length - keptSolos; n < channels.length; n++)