[Gekidou] Exclude muted channels from unread badges (#6208)

* Exclude muted channels from unread badges

* Gekidou unreads mention fix (#6221)

* Removes muted channels without mentions from grouped unreads

* show channel if unread and have no mentions when unread up top

Co-authored-by: Elias Nahum <nahumhbl@gmail.com>

Co-authored-by: Shaz MJ <shaz.amjad@mattermost.com>
This commit is contained in:
Elias Nahum 2022-05-04 09:51:14 -04:00 committed by GitHub
parent 588491f582
commit ecfbb934a8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 71 additions and 27 deletions

View file

@ -59,7 +59,7 @@ const enhance = withObservables(['channel', 'isUnreads', 'showTeamName'], ({chan
return of$(u);
}
return u ? of$(!mc.isUnread) : of$(true);
return u ? of$(!mc.isUnread || !mc.mentionsCount) : of$(true);
}),
);

View file

@ -3,10 +3,9 @@
import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider';
import withObservables from '@nozbe/with-observables';
import {of as of$} from 'rxjs';
import {switchMap} from 'rxjs/operators';
import {combineLatestWith, map} from 'rxjs/operators';
import {queryMyChannelsByTeam} from '@queries/servers/channel';
import {observeAllMyChannelNotifyProps, queryMyChannelsByTeam} from '@queries/servers/channel';
import {observeCurrentTeamId} from '@queries/servers/system';
import {observeMentionCount} from '@queries/servers/team';
@ -21,9 +20,14 @@ type WithTeamsArgs = WithDatabaseArgs & {
const enhance = withObservables(['myTeam'], ({myTeam, database}: WithTeamsArgs) => {
const myChannels = queryMyChannelsByTeam(database, myTeam.id).observeWithColumns(['mentions_count', 'is_unread']);
const notifyProps = observeAllMyChannelNotifyProps(database);
const hasUnreads = myChannels.pipe(
combineLatestWith(notifyProps),
// eslint-disable-next-line max-nested-callbacks
switchMap((val) => of$(val.reduce((acc, v) => acc || v.isUnread, false))),
map(([mycs, notify]) => mycs.reduce((acc, v) => {
const isMuted = notify?.[v.id]?.mark_unread === 'mention';
return acc || (v.isUnread && !isMuted);
}, false)),
);
return {

View file

@ -7,18 +7,29 @@ import {combineLatestWith} from 'rxjs/operators';
import {MM_TABLES} from '@constants/database';
import DatabaseManager from '@database/manager';
import {observeAllMyChannelNotifyProps} from '@queries/servers/channel';
import {queryMyTeams} from '@queries/servers/team';
import {getIsCRTEnabled, observeThreadMentionCount, queryThreads} from '@queries/servers/thread';
import MyChannelModel from '@typings/database/models/servers/my_channel';
import type MyChannelModel from '@typings/database/models/servers/my_channel';
const {SERVER: {CHANNEL, MY_CHANNEL}} = MM_TABLES;
type ObserverArgs = {
export type UnreadObserverArgs = {
myChannels: MyChannelModel[];
settings?: Record<string, Partial<ChannelNotifyProps>>;
threadMentionCount: number;
}
export const subscribeServerUnreadAndMentions = (serverUrl: string, observer: ({myChannels, threadMentionCount}: ObserverArgs) => void) => {
type ServerUnreadObserver = {
(serverUrl: string, {myChannels, settings, threadMentionCount}: UnreadObserverArgs): void;
}
type UnreadObserver = {
({myChannels, settings, threadMentionCount}: UnreadObserverArgs): void;
}
export const subscribeServerUnreadAndMentions = (serverUrl: string, observer: UnreadObserver) => {
const server = DatabaseManager.serverDatabases[serverUrl];
let subscription: Subscription|undefined;
@ -27,8 +38,9 @@ export const subscribeServerUnreadAndMentions = (serverUrl: string, observer: ({
query(Q.on(CHANNEL, Q.where('delete_at', Q.eq(0)))).
observeWithColumns(['is_unread', 'mentions_count']).
pipe(
combineLatestWith(observeAllMyChannelNotifyProps(server.database)),
combineLatestWith(observeThreadMentionCount(server.database, undefined, false)),
map$(([myChannels, threadMentionCount]) => ({myChannels, threadMentionCount})),
map$(([[myChannels, settings], threadMentionCount]) => ({myChannels, settings, threadMentionCount})),
).
subscribe(observer);
}
@ -36,7 +48,7 @@ export const subscribeServerUnreadAndMentions = (serverUrl: string, observer: ({
return subscription;
};
export const subscribeMentionsByServer = (serverUrl: string, observer: (serverUrl: string, {myChannels, threadMentionCount}: ObserverArgs) => void) => {
export const subscribeMentionsByServer = (serverUrl: string, observer: ServerUnreadObserver) => {
const server = DatabaseManager.serverDatabases[serverUrl];
let subscription: Subscription|undefined;
@ -55,7 +67,7 @@ export const subscribeMentionsByServer = (serverUrl: string, observer: (serverUr
return subscription;
};
export const subscribeUnreadAndMentionsByServer = (serverUrl: string, observer: (serverUrl: string, {myChannels, threadMentionCount}: ObserverArgs) => void) => {
export const subscribeUnreadAndMentionsByServer = (serverUrl: string, observer: ServerUnreadObserver) => {
const server = DatabaseManager.serverDatabases[serverUrl];
let subscription: Subscription|undefined;
@ -64,8 +76,9 @@ export const subscribeUnreadAndMentionsByServer = (serverUrl: string, observer:
query(Q.on(CHANNEL, Q.where('delete_at', Q.eq(0)))).
observeWithColumns(['mentions_count', 'is_unread']).
pipe(
combineLatestWith(observeAllMyChannelNotifyProps(server.database)),
combineLatestWith(observeThreadMentionCount(server.database, undefined, false)),
map$(([myChannels, threadMentionCount]) => ({myChannels, threadMentionCount})),
map$(([[myChannels, settings], threadMentionCount]) => ({myChannels, settings, threadMentionCount})),
).
subscribe(observer.bind(undefined, serverUrl));
}

View file

@ -3,7 +3,7 @@
import {Database, Model, Q, Query, Relation} from '@nozbe/watermelondb';
import {of as of$, Observable} from 'rxjs';
import {switchMap, distinctUntilChanged} from 'rxjs/operators';
import {map as map$, switchMap, distinctUntilChanged} from 'rxjs/operators';
import {General, Permissions} from '@constants';
import {MM_TABLES} from '@constants/database';
@ -367,6 +367,10 @@ export const observeChannelInfo = (database: Database, channelId: string) => {
);
};
export const queryAllMyChannelSettings = (database: Database) => {
return database.get<MyChannelSettingsModel>(MY_CHANNEL_SETTINGS).query();
};
export const queryMyChannelSettingsByIds = (database: Database, ids: string[]) => {
return database.get<MyChannelSettingsModel>(MY_CHANNEL_SETTINGS).
query(
@ -374,6 +378,15 @@ export const queryMyChannelSettingsByIds = (database: Database, ids: string[]) =
);
};
export const observeAllMyChannelNotifyProps = (database: Database) => {
return queryAllMyChannelSettings(database).observeWithColumns(['notify_props']).pipe(
map$((settings) => settings.reduce<Record<string, Partial<ChannelNotifyProps>>>((obj, setting) => {
obj[setting.id] = setting.notifyProps;
return obj;
}, {})),
);
};
export const queryChannelsByNames = (database: Database, names: string[]) => {
return database.get<ChannelModel>(CHANNEL).query(Q.where('name', Q.oneOf(names)));
};

View file

@ -4,11 +4,12 @@
import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider';
import withObservables from '@nozbe/with-observables';
import {of as of$, combineLatest} from 'rxjs';
import {concatAll, map, switchMap} from 'rxjs/operators';
import {combineLatestWith, concatAll, map, switchMap} from 'rxjs/operators';
import {MyChannelModel} from '@app/database/models/server';
import {Preferences} from '@constants';
import {getPreferenceAsBool} from '@helpers/api/preference';
import {getChannelById, queryMyChannelUnreads} from '@queries/servers/channel';
import {getChannelById, observeAllMyChannelNotifyProps, queryMyChannelUnreads} from '@queries/servers/channel';
import {queryPreferencesByCategoryAndName} from '@queries/servers/preference';
import {observeLastUnreadChannelId} from '@queries/servers/system';
@ -31,6 +32,16 @@ const concatenateChannelsArray = ([a, b]: CA) => {
return of$(b ? a.filter((c) => c && c.id !== b.id).concat(b) : a);
};
type NotifyProps = {
[key: string]: Partial<ChannelNotifyProps>;
}
const filterMutedFromMyChannels = ([myChannels, notifyProps]: [MyChannelModel[], NotifyProps]) => {
return myChannels.filter(
(myChannel) => notifyProps[myChannel.id]?.mark_unread !== 'mention' || myChannel.mentionsCount > 0, // Muted with Mentions should still go through
);
};
const enhanced = withObservables(['currentTeamId'], ({currentTeamId, database}: WithDatabaseProps) => {
const unreadsOnTop = queryPreferencesByCategoryAndName(database, Preferences.CATEGORY_SIDEBAR_SETTINGS, Preferences.CHANNEL_SIDEBAR_GROUP_UNREADS).
observeWithColumns(['value']).
@ -45,8 +56,11 @@ const enhanced = withObservables(['currentTeamId'], ({currentTeamId, database}:
const lastUnread = observeLastUnreadChannelId(database).pipe(
switchMap(getC),
);
const notifyProps = observeAllMyChannelNotifyProps(database);
const unreads = queryMyChannelUnreads(database, currentTeamId).observe().pipe(
combineLatestWith(notifyProps),
map(filterMutedFromMyChannels),
map(getChannelsFromRelation),
concatAll(),
);

View file

@ -9,14 +9,13 @@ import ServerIcon from '@components/server_icon';
import {useServerUrl} from '@context/server';
import {useTheme} from '@context/theme';
import {subscribeAllServers} from '@database/subscription/servers';
import {subscribeUnreadAndMentionsByServer} from '@database/subscription/unreads';
import {subscribeUnreadAndMentionsByServer, UnreadObserverArgs} from '@database/subscription/unreads';
import {useIsTablet} from '@hooks/device';
import {bottomSheet} from '@screens/navigation';
import ServerList from './servers_list';
import type ServersModel from '@typings/database/models/app/servers';
import type MyChannelModel from '@typings/database/models/servers/my_channel';
import type {UnreadMessages, UnreadSubscription} from '@typings/database/subscriptions';
const subscriptions: Map<string, UnreadSubscription> = new Map();
@ -70,14 +69,15 @@ const Servers = React.forwardRef<ServersRef>((props, ref) => {
setTotal({mentions, unread});
};
const unreadsSubscription = (serverUrl: string, {myChannels, threadMentionCount}: {myChannels: MyChannelModel[]; threadMentionCount: number}) => {
const unreadsSubscription = (serverUrl: string, {myChannels, settings, threadMentionCount}: UnreadObserverArgs) => {
const unreads = subscriptions.get(serverUrl);
if (unreads) {
let mentions = 0;
let unread = false;
for (const myChannel of myChannels) {
const isMuted = settings?.[myChannel.id]?.mark_unread === 'mention';
mentions += myChannel.mentionsCount;
unread = unread || myChannel.isUnread;
unread = unread || (myChannel.isUnread && !isMuted);
}
unreads.mentions = mentions + threadMentionCount;

View file

@ -20,7 +20,7 @@ import TutorialSwipeLeft from '@components/tutorial_highlight/swipe_left';
import {Events} from '@constants';
import {useTheme} from '@context/theme';
import DatabaseManager from '@database/manager';
import {subscribeServerUnreadAndMentions} from '@database/subscription/unreads';
import {subscribeServerUnreadAndMentions, UnreadObserverArgs} from '@database/subscription/unreads';
import {useIsTablet} from '@hooks/device';
import {dismissBottomSheet} from '@screens/navigation';
import {alertServerError, alertServerLogout, alertServerRemove, editServer, loginToServer} from '@utils/server';
@ -32,7 +32,6 @@ import Options from './options';
import WebSocket from './websocket';
import type ServersModel from '@typings/database/models/app/servers';
import type MyChannelModel from '@typings/database/models/servers/my_channel';
import type {Subscription} from 'rxjs';
type Props = {
@ -138,12 +137,13 @@ const ServerItem = ({highlight, isActive, server, tutorialWatched}: Props) => {
displayName = intl.formatMessage({id: 'servers.default', defaultMessage: 'Default Server'});
}
const unreadsSubscription = ({myChannels, threadMentionCount}: {myChannels: MyChannelModel[]; threadMentionCount: number}) => {
const unreadsSubscription = ({myChannels, settings, threadMentionCount}: UnreadObserverArgs) => {
let mentions = 0;
let isUnread = false;
for (const myChannel of myChannels) {
const isMuted = settings?.[myChannel.id]?.mark_unread === 'mention';
mentions += myChannel.mentionsCount;
isUnread = isUnread || myChannel.isUnread;
isUnread = isUnread || (myChannel.isUnread && !isMuted);
}
mentions += threadMentionCount;

View file

@ -8,11 +8,10 @@ import Badge from '@components/badge';
import CompassIcon from '@components/compass_icon';
import {BOTTOM_TAB_ICON_SIZE} from '@constants/view';
import {subscribeAllServers} from '@database/subscription/servers';
import {subscribeUnreadAndMentionsByServer} from '@database/subscription/unreads';
import {subscribeUnreadAndMentionsByServer, UnreadObserverArgs} from '@database/subscription/unreads';
import {changeOpacity} from '@utils/theme';
import type ServersModel from '@typings/database/models/app/servers';
import type MyChannelModel from '@typings/database/models/servers/my_channel';
import type {UnreadMessages, UnreadSubscription} from '@typings/database/subscriptions';
type Props = {
@ -51,14 +50,15 @@ const Home = ({isFocused, theme}: Props) => {
setTotal({mentions, unread});
};
const unreadsSubscription = (serverUrl: string, {myChannels, threadMentionCount}: {myChannels: MyChannelModel[]; threadMentionCount: number}) => {
const unreadsSubscription = (serverUrl: string, {myChannels, settings, threadMentionCount}: UnreadObserverArgs) => {
const unreads = subscriptions.get(serverUrl);
if (unreads) {
let mentions = 0;
let unread = false;
for (const myChannel of myChannels) {
const isMuted = settings?.[myChannel.id]?.mark_unread === 'mention';
mentions += myChannel.mentionsCount;
unread = unread || myChannel.isUnread;
unread = unread || (myChannel.isUnread && !isMuted);
}
unreads.mentions = mentions + threadMentionCount;