Performance fixes and fix manual sort (#7190)

* Performance fixes and fix manual sort

* Fix test

* Use combineLatestWith

* Revert unread on top
This commit is contained in:
Daniel Espino García 2023-03-07 19:24:40 +01:00 committed by GitHub
parent 5ccf45622d
commit 9b932c401a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 65 additions and 45 deletions

View file

@ -14,7 +14,7 @@ import TeamList from './team_list';
type Props = {
iconPad?: boolean;
canJoinOtherTeams: boolean;
teamsCount: number;
hasMoreThanOneTeam: boolean;
}
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
@ -36,8 +36,8 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
};
});
export default function TeamSidebar({iconPad, canJoinOtherTeams, teamsCount}: Props) {
const initialWidth = teamsCount > 1 ? TEAM_SIDEBAR_WIDTH : 0;
export default function TeamSidebar({iconPad, canJoinOtherTeams, hasMoreThanOneTeam}: Props) {
const initialWidth = hasMoreThanOneTeam ? TEAM_SIDEBAR_WIDTH : 0;
const width = useSharedValue(initialWidth);
const marginTop = useSharedValue(iconPad ? 44 : 0);
const theme = useTheme();
@ -58,8 +58,8 @@ export default function TeamSidebar({iconPad, canJoinOtherTeams, teamsCount}: Pr
}, [iconPad]);
useEffect(() => {
width.value = teamsCount > 1 ? TEAM_SIDEBAR_WIDTH : 0;
}, [teamsCount]);
width.value = hasMoreThanOneTeam ? TEAM_SIDEBAR_WIDTH : 0;
}, [hasMoreThanOneTeam]);
return (
<Animated.View style={[styles.container, transform]}>

View file

@ -3,7 +3,7 @@
import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider';
import withObservables from '@nozbe/with-observables';
import {of as of$} from 'rxjs';
import {of as of$, Observable} from 'rxjs';
import {switchMap, combineLatestWith, distinctUntilChanged} from 'rxjs/operators';
import {Preferences} from '@constants';
@ -19,6 +19,7 @@ import CategoryBody from './category_body';
import type {WithDatabaseArgs} from '@typings/database/database';
import type CategoryModel from '@typings/database/models/servers/category';
import type ChannelModel from '@typings/database/models/servers/channel';
import type MyChannelModel from '@typings/database/models/servers/my_channel';
import type PreferenceModel from '@typings/database/models/servers/preference';
type EnhanceProps = {
@ -30,8 +31,7 @@ type EnhanceProps = {
const withUserId = withObservables([], ({database}: WithDatabaseArgs) => ({currentUserId: observeCurrentUserId(database)}));
const observeCategoryChannels = (category: CategoryModel) => {
const myChannels = category.myChannels.observeWithColumns(['last_post_at', 'is_unread']);
const observeCategoryChannels = (category: CategoryModel, myChannels: Observable<MyChannelModel[]>) => {
const channels = category.channels.observeWithColumns(['create_at', 'display_name']);
const manualSort = category.categoryChannelsBySortOrder.observeWithColumns(['sort_order']);
return myChannels.pipe(
@ -57,7 +57,8 @@ const observeCategoryChannels = (category: CategoryModel) => {
};
const enhanced = withObservables([], ({category, currentUserId, database, isTablet, locale}: EnhanceProps) => {
const channelsWithMyChannel = observeCategoryChannels(category);
const categoryMyChannels = category.myChannels.observeWithColumns(['last_post_at', 'is_unread']);
const channelsWithMyChannel = observeCategoryChannels(category, categoryMyChannels);
const currentChannelId = isTablet ? observeCurrentChannelId(database) : of$('');
const lastUnreadId = isTablet ? observeLastUnreadChannelId(database) : of$(undefined);
@ -77,9 +78,9 @@ const enhanced = withObservables([], ({category, currentUserId, database, isTabl
);
}
const notifyPropsPerChannel = channelsWithMyChannel.pipe(
const notifyPropsPerChannel = categoryMyChannels.pipe(
// eslint-disable-next-line max-nested-callbacks
switchMap((cwms) => observeNotifyPropsByChannels(database, cwms.map((c) => c.myChannel))),
switchMap((mc) => observeNotifyPropsByChannels(database, mc)),
);
const hiddenDmPrefs = queryPreferencesByCategoryAndName(database, Preferences.CATEGORIES.DIRECT_CHANNEL_SHOW, undefined, 'false').

View file

@ -4,7 +4,7 @@
import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider';
import withObservables from '@nozbe/with-observables';
import {combineLatest, of as of$} from 'rxjs';
import {switchMap} from 'rxjs/operators';
import {distinctUntilChanged, switchMap} from 'rxjs/operators';
import {Permissions} from '@constants';
import {observePermissionForTeam} from '@queries/servers/role';
@ -25,6 +25,7 @@ const enhanced = withObservables([], ({database}: WithDatabaseArgs) => {
const canJoinChannels = combineLatest([currentUser, team]).pipe(
switchMap(([u, t]) => observePermissionForTeam(database, t, u, Permissions.JOIN_PUBLIC_CHANNELS, true)),
distinctUntilChanged(),
);
const canCreatePublicChannels = combineLatest([currentUser, team]).pipe(
@ -37,6 +38,7 @@ const enhanced = withObservables([], ({database}: WithDatabaseArgs) => {
const canCreateChannels = combineLatest([canCreatePublicChannels, canCreatePrivateChannels]).pipe(
switchMap(([open, priv]) => of$(open || priv)),
distinctUntilChanged(),
);
const canAddUserToTeam = combineLatest([currentUser, team]).pipe(
@ -48,9 +50,11 @@ const enhanced = withObservables([], ({database}: WithDatabaseArgs) => {
canJoinChannels,
canInvitePeople: combineLatest([enableOpenServer, canAddUserToTeam]).pipe(
switchMap(([openServer, addUser]) => of$(openServer && addUser)),
distinctUntilChanged(),
),
displayName: team.pipe(
switchMap((t) => of$(t?.displayName)),
distinctUntilChanged(),
),
pushProxyStatus: observePushVerificationStatus(database),
};

View file

@ -33,8 +33,8 @@ describe('components/categories_list', () => {
it('should render', () => {
const wrapper = renderWithEverything(
<CategoriesList
teamsCount={1}
channelsCount={1}
moreThanOneTeam={false}
hasChannels={true}
/>,
{database},
);
@ -46,8 +46,8 @@ describe('components/categories_list', () => {
const wrapper = renderWithEverything(
<CategoriesList
isCRTEnabled={true}
teamsCount={1}
channelsCount={1}
moreThanOneTeam={false}
hasChannels={true}
/>,
{database},
);
@ -67,8 +67,8 @@ describe('components/categories_list', () => {
jest.useFakeTimers();
const wrapper = renderWithEverything(
<CategoriesList
teamsCount={0}
channelsCount={1}
moreThanOneTeam={false}
hasChannels={true}
/>,
{database},
);
@ -89,8 +89,8 @@ describe('components/categories_list', () => {
jest.useFakeTimers();
const wrapper = renderWithEverything(
<CategoriesList
teamsCount={1}
channelsCount={0}
moreThanOneTeam={true}
hasChannels={false}
/>,
{database},
);

View file

@ -27,28 +27,28 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
}));
type ChannelListProps = {
channelsCount: number;
hasChannels: boolean;
iconPad?: boolean;
isCRTEnabled?: boolean;
teamsCount: number;
moreThanOneTeam: boolean;
};
const getTabletWidth = (teamsCount: number) => {
return TABLET_SIDEBAR_WIDTH - (teamsCount > 1 ? TEAM_SIDEBAR_WIDTH : 0);
const getTabletWidth = (moreThanOneTeam: boolean) => {
return TABLET_SIDEBAR_WIDTH - (moreThanOneTeam ? TEAM_SIDEBAR_WIDTH : 0);
};
const CategoriesList = ({channelsCount, iconPad, isCRTEnabled, teamsCount}: ChannelListProps) => {
const CategoriesList = ({hasChannels, iconPad, isCRTEnabled, moreThanOneTeam}: ChannelListProps) => {
const theme = useTheme();
const styles = getStyleSheet(theme);
const {width} = useWindowDimensions();
const isTablet = useIsTablet();
const tabletWidth = useSharedValue(isTablet ? getTabletWidth(teamsCount) : 0);
const tabletWidth = useSharedValue(isTablet ? getTabletWidth(moreThanOneTeam) : 0);
useEffect(() => {
if (isTablet) {
tabletWidth.value = getTabletWidth(teamsCount);
tabletWidth.value = getTabletWidth(moreThanOneTeam);
}
}, [isTablet && teamsCount]);
}, [isTablet && moreThanOneTeam]);
const tabletStyle = useAnimatedStyle(() => {
if (!isTablet) {
@ -61,7 +61,7 @@ const CategoriesList = ({channelsCount, iconPad, isCRTEnabled, teamsCount}: Chan
}, [isTablet, width]);
const content = useMemo(() => {
if (channelsCount < 1) {
if (!hasChannels) {
return (<LoadChannelsError/>);
}

View file

@ -29,9 +29,10 @@ import Servers from './servers';
import type {LaunchType} from '@typings/launch';
type ChannelProps = {
channelsCount: number;
hasChannels: boolean;
isCRTEnabled: boolean;
teamsCount: number;
hasTeams: boolean;
hasMoreThanOneTeam: boolean;
isLicensed: boolean;
showToS: boolean;
launchType: LaunchType;
@ -126,10 +127,10 @@ const ChannelListScreen = (props: ChannelProps) => {
}, [theme, insets.top]);
useEffect(() => {
if (!props.teamsCount) {
if (!props.hasTeams) {
resetToTeams();
}
}, [Boolean(props.teamsCount)]);
}, [Boolean(props.hasTeams)]);
useEffect(() => {
const back = BackHandler.addEventListener('hardwareBackPress', handleBackPress);
@ -176,13 +177,13 @@ const ChannelListScreen = (props: ChannelProps) => {
>
<TeamSidebar
iconPad={canAddOtherServers}
teamsCount={props.teamsCount}
hasMoreThanOneTeam={props.hasMoreThanOneTeam}
/>
<CategoriesList
iconPad={canAddOtherServers && props.teamsCount <= 1}
iconPad={canAddOtherServers && !props.hasMoreThanOneTeam}
isCRTEnabled={props.isCRTEnabled}
teamsCount={props.teamsCount}
channelsCount={props.channelsCount}
moreThanOneTeam={props.hasMoreThanOneTeam}
hasChannels={props.hasChannels}
/>
{isTablet &&
<AdditionalTabletView/>

View file

@ -4,7 +4,7 @@
import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider';
import withObservables from '@nozbe/with-observables';
import {of as of$} from 'rxjs';
import {switchMap} from 'rxjs/operators';
import {distinctUntilChanged, switchMap} from 'rxjs/operators';
import {queryAllMyChannelsForTeam} from '@queries/servers/channel';
import {observeCurrentTeamId, observeLicense} from '@queries/servers/system';
@ -21,11 +21,22 @@ const enhanced = withObservables([], ({database}: WithDatabaseArgs) => {
switchMap((lcs) => (lcs ? of$(lcs.IsLicensed === 'true') : of$(false))),
);
const teamsCount = queryMyTeams(database).observeCount(false);
return {
isCRTEnabled: observeIsCRTEnabled(database),
teamsCount: queryMyTeams(database).observeCount(false),
channelsCount: observeCurrentTeamId(database).pipe(
hasTeams: teamsCount.pipe(
switchMap((v) => of$(v > 0)),
distinctUntilChanged(),
),
hasMoreThanOneTeam: teamsCount.pipe(
switchMap((v) => of$(v > 1)),
distinctUntilChanged(),
),
hasChannels: observeCurrentTeamId(database).pipe(
switchMap((id) => (id ? queryAllMyChannelsForTeam(database, id).observeCount(false) : of$(0))),
switchMap((v) => of$(v > 0)),
distinctUntilChanged(),
),
isLicensed,
showToS: observeShowToS(database),

View file

@ -3,7 +3,7 @@
import {General, Preferences} from '@constants';
import {DMS_CATEGORY} from '@constants/categories';
import {getPreferenceAsBool, getPreferenceValue} from '@helpers/api/preference';
import {getPreferenceAsBool} from '@helpers/api/preference';
import {isDMorGM} from '@utils/channel';
import {getUserIdFromChannelName} from '@utils/user';
@ -42,15 +42,18 @@ export const filterAutoclosedDMs = (
// Only autoclose DMs that haven't been assigned to a category
return channelsWithMyChannel;
}
const prefMap = preferences.reduce((acc, v) => {
const existing = acc.get(v.name);
acc.set(v.name, Math.max((v.value as unknown as number) || 0, existing || 0));
return acc;
}, new Map<string, number>());
const getLastViewedAt = (cwm: ChannelWithMyChannel) => {
// The server only ever sets the last_viewed_at to the time of the last post in channel, so we may need
// to use the preferences added for the previous version of autoclosing DMs.
const id = cwm.channel.id;
return Math.max(
cwm.myChannel.lastViewedAt,
getPreferenceValue<number>(preferences, Preferences.CATEGORIES.CHANNEL_APPROXIMATE_VIEW_TIME, id, 0),
getPreferenceValue<number>(preferences, Preferences.CATEGORIES.CHANNEL_OPEN_TIME, id, 0),
prefMap.get(id) || 0,
);
};
@ -178,7 +181,7 @@ export const sortChannels = (sorting: CategorySorting, channelsWithMyChannel: Ch
}).map((cwm) => cwm.channel);
} else if (sorting === 'manual') {
return channelsWithMyChannel.sort((cwmA, cwmB) => {
return cwmB.sortOrder - cwmA.sortOrder;
return cwmA.sortOrder - cwmB.sortOrder;
}).map((cwm) => cwm.channel);
}