Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
f7aef7f
feat: Avatar on push notifications (#6853)
diegolmello Jan 6, 2026
b990e60
feat: render timestamp markdown (#6266)
Rohit3523 Jan 7, 2026
1fe0bf7
fix(Android): Push notification on killed apps and deep link (#6888)
diegolmello Jan 8, 2026
c21d91e
fix: push notification titles and avatars for discussions and threads…
diegolmello Jan 9, 2026
ede2569
fix(iOS): official target missing build phases (#6905)
diegolmello Jan 9, 2026
41823b8
fix: pass tmid to show typing status in threads (#6894)
Rohit3523 Jan 16, 2026
ad951f9
fix: timestamp bug fixes (#6910)
Rohit3523 Jan 16, 2026
508b720
fix: chat fails to load older messages when scrolling to the top (#6861)
Rohit3523 Jan 16, 2026
c52af04
fix: Keep connecting label on header while logging in (#6920)
Rohit3523 Jan 16, 2026
7b483e6
chore: changelog in beta release (#6899)
Rohit3523 Jan 16, 2026
ad2f552
chore: added concurrency on develop action (#6921)
Rohit3523 Jan 16, 2026
c079de0
chore(Android): fix CI generated changelog (#6922)
Rohit3523 Jan 16, 2026
12fb458
fix (android): unable to send files in E2EE channel using action menu…
Rohit3523 Jan 18, 2026
2afa9ee
fix(iOS): app crashing on render image (#6908)
OtavioStasiak Jan 19, 2026
88eb8b3
fix: review button visibility issue on voice recording screen (#6941)
Rohit3523 Jan 23, 2026
ef13690
fix: Click on Show more on ModalActions breaks the app (#6942)
OtavioStasiak Jan 23, 2026
e1af190
fix: default browser setting (#6929)
Rohit3523 Jan 23, 2026
6a14ef9
chore: Bump version to 4.70.0 (#6967)
diegolmello Feb 4, 2026
5fa4072
chore: remove skip ci (#6950)
OtavioStasiak Feb 4, 2026
1410088
chore(iOS): update Podfile.lock for MobileCrypto (#6968)
Rohit3523 Feb 5, 2026
2038d6d
fix(Android): remove notification from collection when notification i…
Rohit3523 Feb 5, 2026
bfe97f5
fix: katex array breaking the app (#6963)
OtavioStasiak Feb 5, 2026
d2aa920
fix: forwarding a message twice does not render the attachment (#6960)
OtavioStasiak Feb 5, 2026
047660f
fix: remove getAvatarSuggestion deprecated method (#6948)
OtavioStasiak Feb 5, 2026
3f4da80
fix: Prevent username text overflow in room invitation screen (#6972)
aleksandernsilva Feb 9, 2026
97008fe
fix: room member search to use server data instead of local data (#6938)
Rohit3523 Feb 9, 2026
5fa845b
fix: reactions disabled when editing room (#6969)
Rohit3523 Feb 9, 2026
725b2eb
fix(i18n): Update ta-IN, hi-IN and te-IN translations (#6890)
Yaddalapalli-Charan-Kumar-Naidu Feb 10, 2026
1bb9b44
fix: two factor modal alignment on tablet (#6840)
deepak0x Feb 10, 2026
95f10dc
fix: changes to foreground and background logic (#6958)
Rohit3523 Feb 10, 2026
294fbb2
fix(Android): prevent image edit action buttons from overlapping syst…
Rohit3523 Feb 10, 2026
acf48d4
fix: collapsible attachment with text duplicating the content (#6956)
OtavioStasiak Feb 11, 2026
09ec94d
chore(iOS): bump deployment target to iOS 26 (#6974)
Rohit3523 Feb 12, 2026
757ea73
fix: prevent SVG crash on iOS and enable rendering on Android (#6949)
Rohit3523 Feb 12, 2026
61a5d44
fix flaky behaviour (#6979)
Rohit3523 Feb 13, 2026
0b93f25
test: use setPermissions before launching the app (#6975)
Rohit3523 Feb 13, 2026
ae5e663
build(deps): upgrade some dependencies (#6962)
tassoevan Feb 19, 2026
895ebf0
fix: Text input fields on ModalBlockView fail to accept user input (#…
OtavioStasiak Feb 21, 2026
4415a07
fix: add headers to download the PDF (#6978)
OtavioStasiak Feb 23, 2026
57137f3
feat: Support message with multiple attachments (#6068)
diegolmello Feb 23, 2026
566e100
fix(android): correct accessibility focus order in inverted FlatList …
OtavioStasiak Feb 23, 2026
ab6a711
Merge branch 'master' into 4.70.0-master
diegolmello Mar 2, 2026
75e5164
chore: format code and fix lint issues
diegolmello Mar 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/actions/build-ios/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ runs:
- name: Set up Xcode
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: '16.4'
xcode-version: '26.2.0'

- name: Set up Ruby
uses: ruby/setup-ruby@v1
Expand Down
2 changes: 1 addition & 1 deletion .github/actions/upload-ios/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ runs:
- name: Set up Xcode
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: '16.2'
xcode-version: '26.2.0'

- name: Set up Ruby
uses: ruby/setup-ruby@v1
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/build-ios.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:

build-ios:
name: Build
runs-on: macos-15
runs-on: macos-26
needs: [build-hold]
if: ${{ inputs.type == 'experimental' && (always() && (needs.build-hold.result == 'success' || needs.build-hold.result == 'skipped')) }}
steps:
Expand Down Expand Up @@ -62,7 +62,7 @@ jobs:

upload-ios:
name: Upload
runs-on: macos-15
runs-on: macos-26
needs: [build-ios]
if: ${{ inputs.type == 'experimental' && (always() && (needs.build-ios.result == 'success')) }}
steps:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/build-official-ios.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:

build-ios:
name: Build
runs-on: macos-15
runs-on: macos-26
needs: [build-hold]
if: ${{ inputs.type == 'official' && (always() && (needs.build-hold.result == 'success' || needs.build-hold.result == 'skipped')) }}
steps:
Expand Down Expand Up @@ -72,7 +72,7 @@ jobs:

upload-ios:
name: Upload
runs-on: macos-15
runs-on: macos-26
needs: [upload-hold]
if: ${{ inputs.type == 'official' && (always() && (needs.upload-hold.result == 'success' || needs.upload-hold.result == 'skipped')) }}
steps:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/e2e-build-ios.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ on:

jobs:
ios-build:
runs-on: macos-15
runs-on: macos-26

steps:
- name: Checkout repository
Expand All @@ -34,7 +34,7 @@ jobs:
- name: Set up Xcode
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: '16.4'
xcode-version: '26.2.0'

- name: Set up Ruby
uses: ruby/setup-ruby@v1
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/prettier.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,5 @@ jobs:
git config user.name "${{ github.actor }}"
git config user.email "${{ github.actor }}@users.noreply.github.com"
git add .
git commit -m "chore: format code and fix lint issues [skip ci]"
git commit -m "chore: format code and fix lint issues"
git push origin ${{ github.ref_name }}
21 changes: 3 additions & 18 deletions .maestro/helpers/login-with-deeplink.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ tags:
true: CLEAR_STATE
commands:
- clearState: chat.rocket.reactnative
- setPermissions:
permissions:
all: allow
- evalScript: ${output.login = output.utils.login(USERNAME, PASSWORD)}
- runFlow:
file: 'open-deeplink.yaml'
Expand All @@ -24,24 +27,6 @@ tags:
visible: '.*Pixel Launcher.*'
commands:
- tapOn: 'Close App'
- extendedWaitUntil:
visible:
text: '.*Allow.*'
timeout: 30000
optional: true
- tapOn:
text: '.*Allow.*'
optional: true
- assertNotVisible:
text: '.*Allow.*'
optional: true
- runFlow:
when:
visible: '.*Would like to send you notifications.*'
platform: iOS
commands:
- tapOn:
point: 65%,60%
- extendedWaitUntil:
visible:
id: 'rooms-list-view'
Expand Down
7 changes: 5 additions & 2 deletions .maestro/tests/room/ignoreuser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ tags:
id: 'username-header-${output.otherUser.username}'
timeout: 60000
- tapOn:
id: 'username-header-${output.otherUser.username}'
text: ${output.otherUser.username}
index: 1
retryTapIfNoChange: true
- extendedWaitUntil:
visible:
Expand Down Expand Up @@ -210,7 +211,9 @@ tags:
visible:
text: ${output.otherUser.username}
timeout: 60000
- tapOn: ${output.otherUser.username}
- tapOn:
text: ${output.otherUser.username}
index: 1
- extendedWaitUntil:
visible:
id: 'room-info-view'
Expand Down
91 changes: 91 additions & 0 deletions .maestro/tests/room/search-member.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
appId: chat.rocket.reactnative
name: Search Member
onFlowStart:
- runFlow: '../../helpers/setup.yaml'
tags:
- test-13

---
- evalScript: ${output.user = output.utils.createUser()}

- runFlow:
file: '../../helpers/login-with-deeplink.yaml'
env:
USERNAME: ${output.user.username}
PASSWORD: ${output.user.password}

- runFlow:
file: '../../helpers/navigate-to-room.yaml'
env:
ROOM: 'general'
- tapOn:
id: room-header
- extendedWaitUntil:
visible:
id: 'room-actions-view'
timeout: 60000
- tapOn:
id: 'room-actions-members'
- extendedWaitUntil:
visible:
id: 'room-members-view-search'
timeout: 60000

# should search in all users
- tapOn:
id: room-members-view-search
- inputText: rohit.bansal
- extendedWaitUntil:
visible:
id: 'room-members-view-item-rohit.bansal'
timeout: 60000

# use online status and it should use the text filter
- tapOn:
id: room-members-view-filter
- extendedWaitUntil:
visible:
id: 'room-members-view-toggle-status-online'
timeout: 60000
- tapOn:
id: room-members-view-toggle-status-online
- extendedWaitUntil:
visible:
text: 'No members found'
timeout: 60000

# use all status again and it should use text filter
- tapOn:
id: room-members-view-filter
- extendedWaitUntil:
visible:
id: 'room-members-view-toggle-status-all'
timeout: 60000
- tapOn:
id: room-members-view-toggle-status-all
- extendedWaitUntil:
visible:
id: 'room-members-view-item-rohit.bansal'
timeout: 60000
- tapOn:
id: clear-text-input

- evalScript: ${output.secondUser = output.utils.createUser()}

# should search for new user in all list
- tapOn:
id: room-members-view-search
- inputText: ${output.secondUser.username}
- extendedWaitUntil:
visible:
id: 'room-members-view-item-${output.secondUser.username}'
timeout: 60000

# Verify "No members found" message appears correctly when search returns no results
- tapOn:
id: room-members-view-search
- inputText: nonexistentuser12345
- extendedWaitUntil:
visible:
text: 'No members found'
timeout: 60000
2 changes: 1 addition & 1 deletion android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode VERSIONCODE as Integer
versionName "4.69.0"
versionName "4.70.0"
vectorDrawables.useSupportLibrary = true
manifestPlaceholders = [BugsnagAPIKey: BugsnagAPIKey as String]
resValue "string", "rn_config_reader_custom_package", "chat.rocket.reactnative"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import chat.rocket.reactnative.storage.MMKVKeyManager;
import chat.rocket.reactnative.storage.SecureStoragePackage;
import chat.rocket.reactnative.notification.VideoConfTurboPackage
import chat.rocket.reactnative.notification.PushNotificationTurboPackage
import chat.rocket.reactnative.scroll.InvertedScrollPackage

/**
* Main Application class.
Expand All @@ -44,6 +45,7 @@ open class MainApplication : Application(), ReactApplication {
add(VideoConfTurboPackage())
add(PushNotificationTurboPackage())
add(SecureStoragePackage())
add(InvertedScrollPackage())
}

override fun getJSMainModuleName(): String = "index"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,20 @@ class NotificationIntentHandler {
}

try {
val notId = extras.getString("notId")

// Clear the notification messages from the static map to prevent stacking
if (!notId.isNullOrEmpty()) {
try {
val notIdInt = notId.toIntOrNull()
if (notIdInt != null) {
CustomPushNotification.clearMessages(notIdInt)
}
} catch (e: Exception) {
Log.e(TAG, "Error clearing notification messages for ID $notId: ${e.message}", e)
}
}

// Extract all notification data from Intent extras
// Only include serializable types to avoid JSON serialization errors
val notificationData = mutableMapOf<String, Any?>()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package chat.rocket.reactnative.scroll;

import android.view.View;
import com.facebook.react.views.view.ReactViewGroup;
import java.util.ArrayList;
import java.util.Collections;

/**
* Content view for inverted FlatLists. Reports its children to accessibility in reversed order so
* TalkBack traversal matches the visual order (newest-first) when used inside InvertedScrollView.
*/
public class InvertedScrollContentView extends ReactViewGroup {

public InvertedScrollContentView(android.content.Context context) {
super(context);
}

@Override
public void addChildrenForAccessibility(ArrayList<View> outChildren) {
super.addChildrenForAccessibility(outChildren);
Collections.reverse(outChildren);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package chat.rocket.reactnative.scroll;

import com.facebook.react.module.annotations.ReactModule;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.views.view.ReactViewManager;

/**
* View manager for InvertedScrollContentView. Behaves like a View but reports children in reversed
* order for accessibility so TalkBack matches the visual order in inverted lists.
*/
@ReactModule(name = InvertedScrollContentViewManager.REACT_CLASS)
public class InvertedScrollContentViewManager extends ReactViewManager {

public static final String REACT_CLASS = "InvertedScrollContentView";

@Override
public String getName() {
return REACT_CLASS;
}

@Override
public InvertedScrollContentView createViewInstance(ThemedReactContext context) {
return new InvertedScrollContentView(context);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package chat.rocket.reactnative.scroll;

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.Collections;
import java.util.List;

public class InvertedScrollPackage implements ReactPackage {

@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
return Collections.emptyList();
}

@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
List<ViewManager> managers = new java.util.ArrayList<>();
managers.add(new InvertedScrollViewManager());
managers.add(new InvertedScrollContentViewManager());
return managers;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package chat.rocket.reactnative.scroll;

import android.view.View;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.views.scroll.ReactScrollView;
import java.util.ArrayList;
import java.util.Collections;

// When a FlatList is inverted (inverted={true}), React Native uses scaleY: -1 transform which
// visually inverts the list but Android still reports children in array order. This view overrides
// addChildrenForAccessibility to reverse the order so TalkBack matches the visual order.

public class InvertedScrollView extends ReactScrollView {

private boolean mIsInvertedVirtualizedList = false;

public InvertedScrollView(ReactContext context) {
super(context);
}


// Set whether this ScrollView is used for an inverted virtualized list. When true, we reverse the
// accessibility traversal order to match the visual order.

public void setIsInvertedVirtualizedList(boolean isInverted) {
mIsInvertedVirtualizedList = isInverted;
}

@Override
public void addChildrenForAccessibility(ArrayList<View> outChildren) {
super.addChildrenForAccessibility(outChildren);
if (mIsInvertedVirtualizedList) {
Collections.reverse(outChildren);
}
}
}
Loading