Compare commits

...

4 commits

Author SHA1 Message Date
Mario Vitale
d208c6c3b7
Manual cherrypick of #7915 (#7916)
Some checks failed
github-release / test (push) Has been cancelled
github-release / build-ios-unsigned (push) Has been cancelled
github-release / build-android-unsigned (push) Has been cancelled
github-release / release (push) Has been cancelled
2024-04-19 15:21:46 +02:00
Mattermost Build
409b3d2932
Fix channel members list not fully loaded (#7896) (#7908)
* Load more users when reaching bottom of the list

Fix mattermost issue when typing quickly within search input

* Update: logic to load next users on bottom list reached

* Update: logic refactored

---------

Co-authored-by: Philippe Ka <philippe.karle@infomaniak.com>
(cherry picked from commit 02261eb8c0)

Co-authored-by: Philippe Karle <32866015+Pkarle@users.noreply.github.com>
2024-04-17 10:09:43 +02:00
Mattermost Build
a0053607eb
[MM-56585]Show only unreads filter stays active after changing the 'Group unreads' setting (#7790) (#7909)
* showing unread and threads, of group unread setting in on

* using third variable to maintain state for showing categories

* removed useState from useMemo

* Removed state, return orderctegroies if onlyUnreads & unreadsOnTop is true

* test cases updates

* removed onlyUnreads props from threads

* removed onlyUnreads

* test cases updated

* removed unnecessary changes

* removed onlyUnreads from dep

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
(cherry picked from commit 6dcefaf1e4)

Co-authored-by: Aditya Pratap Singh Hada <49001649+apshada@users.noreply.github.com>
2024-04-17 10:09:07 +02:00
Mattermost Build
5cb50fb47c
Add missing privacy requirements (#7902) (#7906)
(cherry picked from commit 65e59724f1)

Co-authored-by: Daniel Espino García <larkox@gmail.com>
2024-04-16 07:55:48 +08:00
15 changed files with 85 additions and 176 deletions

View file

@ -111,8 +111,8 @@ android {
applicationId "com.mattermost.rnbeta"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 514
versionName "2.15.0"
versionCode 518
versionName "2.16.0"
testBuildType System.getProperty('testBuildType', 'debug')
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
}

View file

@ -189,98 +189,3 @@ exports[`Thread item in the channel list Threads Component should match snapshot
</View>
</View>
`;
exports[`Thread item in the channel list Threads Component should match snapshot with only unreads filter 1`] = `null`;
exports[`Thread item in the channel list Threads Component should match snapshot, groupUnreadsSeparately false, always show 1`] = `
<View
accessibilityState={
{
"busy": undefined,
"checked": undefined,
"disabled": undefined,
"expanded": undefined,
"selected": undefined,
}
}
accessibilityValue={
{
"max": undefined,
"min": undefined,
"now": undefined,
"text": undefined,
}
}
accessible={true}
collapsable={false}
focusable={true}
onClick={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
style={
{
"opacity": 1,
}
}
testID="channel_list.threads.button"
>
<View
style={
[
{
"alignItems": "center",
"flexDirection": "row",
},
false,
undefined,
undefined,
{
"minHeight": 40,
},
]
}
>
<Icon
name="message-text-outline"
style={
[
{
"color": "rgba(255,255,255,0.5)",
"fontSize": 24,
"marginRight": 12,
},
false,
undefined,
]
}
/>
<Text
style={
[
{
"flex": 1,
},
{
"fontFamily": "OpenSans",
"fontSize": 16,
"fontWeight": "400",
"lineHeight": 24,
},
{
"color": "rgba(255,255,255,0.72)",
},
false,
undefined,
undefined,
]
}
>
Threads
</Text>
</View>
</View>
`;

View file

@ -2,31 +2,20 @@
// See LICENSE.txt for license information.
import {withDatabase, withObservables} from '@nozbe/watermelondb/react';
import {of as of$} from 'rxjs';
import {switchMap} from 'rxjs/operators';
import Preferences from '@constants/preferences';
import {getSidebarPreferenceAsBool} from '@helpers/api/preference';
import {querySidebarPreferences} from '@queries/servers/preference';
import {observeCurrentChannelId, observeCurrentTeamId, observeOnlyUnreads} from '@queries/servers/system';
import {observeCurrentChannelId, observeCurrentTeamId} from '@queries/servers/system';
import {observeUnreadsAndMentionsInTeam} from '@queries/servers/thread';
import ThreadsButton from './threads_button';
import type {WithDatabaseArgs} from '@typings/database/database';
import type PreferenceModel from '@typings/database/models/servers/preference';
const enhanced = withObservables([], ({database}: WithDatabaseArgs) => {
const currentTeamId = observeCurrentTeamId(database);
return {
currentChannelId: observeCurrentChannelId(database),
groupUnreadsSeparately: querySidebarPreferences(database, Preferences.CHANNEL_SIDEBAR_GROUP_UNREADS).
observeWithColumns(['value']).
pipe(
switchMap((prefs: PreferenceModel[]) => of$(getSidebarPreferenceAsBool(prefs, Preferences.CHANNEL_SIDEBAR_GROUP_UNREADS))),
),
onlyUnreads: observeOnlyUnreads(database),
unreadsAndMentions: currentTeamId.pipe(
switchMap(
(teamId) => observeUnreadsAndMentionsInTeam(database, teamId),

View file

@ -9,8 +9,6 @@ import Threads from './threads_button';
const baseProps = {
currentChannelId: 'someChannelId',
groupUnreadsSeparately: true,
onlyUnreads: false,
unreadsAndMentions: {
unreads: false,
mentions: 0,
@ -25,17 +23,6 @@ describe('Thread item in the channel list', () => {
expect(toJSON()).toMatchSnapshot();
});
test('Threads Component should match snapshot with only unreads filter', () => {
const {toJSON} = renderWithIntlAndTheme(
<Threads
{...baseProps}
onlyUnreads={true}
/>,
);
expect(toJSON()).toMatchSnapshot();
});
test('Threads Component should match snapshot with onCenterBg', () => {
const {toJSON} = renderWithIntlAndTheme(
<Threads
@ -46,16 +33,4 @@ describe('Thread item in the channel list', () => {
expect(toJSON()).toMatchSnapshot();
});
test('Threads Component should match snapshot, groupUnreadsSeparately false, always show', () => {
const {toJSON} = renderWithIntlAndTheme(
<Threads
{...baseProps}
groupUnreadsSeparately={false}
onlyUnreads={true}
/>,
);
expect(toJSON()).toMatchSnapshot();
});
});

View file

@ -39,9 +39,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
type Props = {
currentChannelId: string;
groupUnreadsSeparately: boolean;
onCenterBg?: boolean;
onlyUnreads: boolean;
onPress?: () => void;
shouldHighlighActive?: boolean;
unreadsAndMentions: {
@ -53,9 +51,7 @@ type Props = {
const ThreadsButton = ({
currentChannelId,
groupUnreadsSeparately,
onCenterBg,
onlyUnreads,
onPress,
unreadsAndMentions,
shouldHighlighActive = false,
@ -113,10 +109,6 @@ const ThreadsButton = ({
return [container, icon, text, badge];
}, [customStyles, isActive, onCenterBg, styles, unreads, isOnHome]);
if (groupUnreadsSeparately && (onlyUnreads && !isActive && !unreads && !mentions)) {
return null;
}
return (
<TouchableOpacity
onPress={handlePress}

View file

@ -49,17 +49,21 @@ const Categories = ({
const isTablet = useIsTablet();
const switchingTeam = useTeamSwitch();
const teamId = categories[0]?.teamId;
const showOnlyUnreadsCategory = onlyUnreads && !unreadsOnTop;
const categoriesToShow = useMemo(() => {
if (onlyUnreads && !unreadsOnTop) {
if (showOnlyUnreadsCategory) {
return ['UNREADS' as const];
}
const orderedCategories = [...categories];
orderedCategories.sort((a, b) => a.sortOrder - b.sortOrder);
if (unreadsOnTop) {
return ['UNREADS' as const, ...orderedCategories];
}
return orderedCategories;
}, [categories, onlyUnreads, unreadsOnTop]);
}, [categories, unreadsOnTop, showOnlyUnreadsCategory]);
const [initiaLoad, setInitialLoad] = useState(!categoriesToShow.length);
@ -74,7 +78,7 @@ const Categories = ({
currentTeamId={teamId}
isTablet={isTablet}
onChannelSwitch={onChannelSwitch}
onlyUnreads={onlyUnreads}
onlyUnreads={showOnlyUnreadsCategory}
/>
);
}
@ -89,7 +93,7 @@ const Categories = ({
/>
</>
);
}, [teamId, intl.locale, isTablet, onChannelSwitch, onlyUnreads]);
}, [teamId, intl.locale, isTablet, onChannelSwitch, showOnlyUnreadsCategory]);
useEffect(() => {
const t = setTimeout(() => {
@ -105,17 +109,17 @@ const Categories = ({
return (
<>
{!switchingTeam && !initiaLoad && onlyUnreads &&
{!switchingTeam && !initiaLoad && showOnlyUnreadsCategory &&
<View style={styles.mainList}>
<UnreadCategories
currentTeamId={teamId}
isTablet={isTablet}
onChannelSwitch={onChannelSwitch}
onlyUnreads={onlyUnreads}
onlyUnreads={showOnlyUnreadsCategory}
/>
</View>
}
{!switchingTeam && !initiaLoad && !onlyUnreads && (
{!switchingTeam && !initiaLoad && !showOnlyUnreadsCategory && (
<FlatList
data={categoriesToShow}
ref={listRef}

View file

@ -84,10 +84,11 @@ export default function ManageChannelMembers({
const searchTimeoutId = useRef<NodeJS.Timeout | null>(null);
const mounted = useRef(false);
const hasMoreProfiles = useRef(true);
const pageRef = useRef(0);
const [isManageMode, setIsManageMode] = useState(false);
const [profiles, setProfiles] = useState<UserProfile[]>(EMPTY);
const hasMoreProfiles = useRef(false);
const [channelMembers, setChannelMembers] = useState<ChannelMembership[]>(EMPTY_MEMBERS);
const [searchResults, setSearchResults] = useState<UserProfile[]>(EMPTY);
const [loading, setLoading] = useState(true);
@ -97,6 +98,9 @@ export default function ManageChannelMembers({
const clearSearch = useCallback(() => {
setTerm('');
setSearchResults(EMPTY);
if (searchTimeoutId.current) {
clearTimeout(searchTimeoutId.current);
}
}, []);
const close = useCallback(() => {
@ -231,23 +235,38 @@ export default function ManageChannelMembers({
useNavButtonPressed(MANAGE_BUTTON, componentId, toggleManageEnabled, [toggleManageEnabled]);
const getFetchChannelMembers = useCallback(async () => {
const options: GetUsersOptions = {sort: 'admin', active: true, per_page: PER_PAGE_DEFAULT, page: pageRef.current};
const {users, members} = await fetchChannelMemberships(serverUrl, channelId, options, true);
if (!mounted.current) {
return;
}
if (users.length < PER_PAGE_DEFAULT) {
hasMoreProfiles.current = false;
}
if (users.length) {
setChannelMembers((prev) => [...prev, ...members]);
setProfiles((prev) => [...prev, ...users]);
}
setLoading(false);
}, [serverUrl, channelId]);
const handleReachedBottom = useCallback(() => {
if (hasMoreProfiles.current && !loading && !searchedTerm) {
pageRef.current += 1;
setLoading(true);
getFetchChannelMembers();
}
}, [loading, searchedTerm, getFetchChannelMembers]);
useEffect(() => {
mounted.current = true;
const options: GetUsersOptions = {sort: 'admin', active: true, per_page: PER_PAGE_DEFAULT};
fetchChannelMemberships(serverUrl, channelId, options, true).then(({users, members}) => {
if (!mounted.current) {
return;
}
getFetchChannelMembers();
if (users.length >= PER_PAGE_DEFAULT) {
hasMoreProfiles.current = true;
}
if (users.length) {
setProfiles(users);
setChannelMembers(members);
}
setLoading(false);
});
return () => {
mounted.current = false;
};
@ -301,6 +320,7 @@ export default function ManageChannelMembers({
testID='manage_members.user_list'
tutorialWatched={tutorialWatched}
includeUserMargin={true}
fetchMore={handleReachedBottom}
/>
</SafeAreaView>
);

View file

@ -1947,7 +1947,7 @@
CODE_SIGN_ENTITLEMENTS = Mattermost/Mattermost.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 514;
CURRENT_PROJECT_VERSION = 518;
DEVELOPMENT_TEAM = UQ8HT4Q2XM;
ENABLE_BITCODE = NO;
HEADER_SEARCH_PATHS = (
@ -1991,7 +1991,7 @@
CODE_SIGN_ENTITLEMENTS = Mattermost/Mattermost.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 514;
CURRENT_PROJECT_VERSION = 518;
DEVELOPMENT_TEAM = UQ8HT4Q2XM;
ENABLE_BITCODE = NO;
HEADER_SEARCH_PATHS = (
@ -2134,7 +2134,7 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 514;
CURRENT_PROJECT_VERSION = 518;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = UQ8HT4Q2XM;
GCC_C_LANGUAGE_STANDARD = gnu11;
@ -2183,7 +2183,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 514;
CURRENT_PROJECT_VERSION = 518;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = UQ8HT4Q2XM;
GCC_C_LANGUAGE_STANDARD = gnu11;

View file

@ -21,7 +21,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>2.15.0</string>
<string>2.16.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
@ -37,7 +37,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>514</string>
<string>518</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSRequiresIPhoneOS</key>

View file

@ -19,9 +19,9 @@
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>2.15.0</string>
<string>2.16.0</string>
<key>CFBundleVersion</key>
<string>514</string>
<string>518</string>
<key>UIAppFonts</key>
<array>
<string>OpenSans-Bold.ttf</string>

View file

@ -19,9 +19,9 @@
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>2.15.0</string>
<string>2.16.0</string>
<key>CFBundleVersion</key>
<string>514</string>
<string>518</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionPointIdentifier</key>

View file

@ -20,6 +20,14 @@
<string>AC6B.1</string>
</array>
</dict>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>3B52.1</string>
</array>
</dict>
</array>
</dict>
</plist>

View file

@ -20,6 +20,22 @@
<string>3B52.1</string>
</array>
</dict>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategorySystemBootTime</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>35F9.1</string>
</array>
</dict>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>AC6B.1</string>
</array>
</dict>
</array>
</dict>
</plist>

2
package-lock.json generated
View file

@ -1,6 +1,6 @@
{
"name": "mattermost-mobile",
"version": "2.15.0",
"version": "2.16.0",
"lockfileVersion": 3,
"requires": true,
"packages": {

View file

@ -1,6 +1,6 @@
{
"name": "mattermost-mobile",
"version": "2.15.0",
"version": "2.16.0",
"description": "Mattermost Mobile with React Native",
"repository": "git@github.com:mattermost/mattermost-mobile.git",
"author": "Mattermost, Inc.",