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:
parent
5ccf45622d
commit
9b932c401a
8 changed files with 65 additions and 45 deletions
|
|
@ -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]}>
|
||||
|
|
|
|||
|
|
@ -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').
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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/>);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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/>
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue