Skip to content

Commit

Permalink
chore: Merge 4.52.0 into master (#5880)
Browse files Browse the repository at this point in the history
  • Loading branch information
diegolmello authored Sep 26, 2024
2 parents 92ebf5e + bc47e13 commit b161e11
Show file tree
Hide file tree
Showing 131 changed files with 1,404 additions and 1,843 deletions.
7 changes: 0 additions & 7 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -383,8 +383,6 @@ jobs:
docker:
- image: cimg/node:lts
resource_class: large
environment:
CODECOV_TOKEN: caa771ab-3d45-4756-8e2a-e1f25996fef6

steps:
- checkout
Expand All @@ -403,11 +401,6 @@ jobs:
command: |
yarn test --runInBand
- run:
name: Codecov
command: |
yarn codecov
- save_cache: *save-npm-cache-linux

# Android builds
Expand Down
2 changes: 1 addition & 1 deletion android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode VERSIONCODE as Integer
versionName "4.51.0"
versionName "4.52.0"
vectorDrawables.useSupportLibrary = true
if (!isFoss) {
manifestPlaceholders = [BugsnagAPIKey: BugsnagAPIKey as String]
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package chat.rocket.reactnative.share

import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import java.io.File
import java.io.FileOutputStream
import java.util.*

class ShareActivity : AppCompatActivity() {

private val appScheme = "rocketchat"

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
handleIntent(intent)
}

private fun handleIntent(intent: Intent?) {
// Check if the intent contains shared content
if (intent?.action == Intent.ACTION_SEND || intent?.action == Intent.ACTION_SEND_MULTIPLE) {
when {
intent.type?.startsWith("text/") == true -> handleText(intent)
intent.type?.startsWith("image/") == true -> handleMedia(intent, "data")
intent.type?.startsWith("video/") == true -> handleMedia(intent, "data")
intent.type?.startsWith("application/") == true -> handleMedia(intent, "data")
intent.type == "*/*" -> handleMedia(intent, "data")
intent.type == "text/plain" -> handleText(intent)
else -> completeRequest() // No matching type, complete the request
}
} else {
completeRequest() // No relevant intent action, complete the request
}
}

private fun handleText(intent: Intent) {
// Handle sharing text
val sharedText = intent.getStringExtra(Intent.EXTRA_TEXT)
if (sharedText != null) {
val encoded = Uri.encode(sharedText)
val url = Uri.parse("$appScheme://shareextension?text=$encoded")
openURL(url)
}
completeRequest()
}

private fun handleMedia(intent: Intent, type: String) {
val mediaUris = StringBuilder()
var valid = true

val uris = when (intent.action) {
Intent.ACTION_SEND -> listOf(intent.getParcelableExtra(Intent.EXTRA_STREAM) as Uri?)
Intent.ACTION_SEND_MULTIPLE -> intent.getParcelableArrayListExtra<Uri>(Intent.EXTRA_STREAM)
else -> null
}

uris?.forEachIndexed { index, uri ->
val mediaUri = uri?.let { handleMediaUri(it, type) }
if (mediaUri != null) {
mediaUris.append(mediaUri)
if (index < uris.size - 1) {
mediaUris.append(",")
}
} else {
valid = false
}
}

if (valid) {
val encoded = Uri.encode(mediaUris.toString())
val url = Uri.parse("$appScheme://shareextension?mediaUris=$encoded")
openURL(url)
}
completeRequest()
}

private fun handleMediaUri(uri: Uri, type: String): String? {
return try {
val inputStream = contentResolver.openInputStream(uri)
val originalFilename = getFileName(uri)
val filename = originalFilename ?: UUID.randomUUID().toString() + getFileExtension(uri, type)
val fileUri = saveDataToCacheDir(inputStream?.readBytes(), filename)
fileUri?.toString()
} catch (e: Exception) {
Log.e("ShareRocketChat", "Failed to process media", e)
null
}
}

private fun getFileName(uri: Uri): String? {
// Attempt to get the original filename from the Uri
val cursor = contentResolver.query(uri, null, null, null, null)
return cursor?.use {
if (it.moveToFirst()) {
val nameIndex = it.getColumnIndex("_display_name")
if (nameIndex != -1) it.getString(nameIndex) else null
} else null
}
}

private fun getFileExtension(uri: Uri, type: String): String {
// Determine the file extension based on the mime type, with fallbacks
val mimeType = contentResolver.getType(uri)
return when {
mimeType?.startsWith("image/") == true -> ".jpeg"
mimeType?.startsWith("video/") == true -> ".mp4"
else -> "" // Ignore the file if the type is not recognized
}
}

private fun saveDataToCacheDir(data: ByteArray?, filename: String): Uri? {
// Save the shared data to the app's cache directory and return the file URI
return try {
val file = File(cacheDir, filename)
FileOutputStream(file).use { it.write(data) }
Uri.fromFile(file) // Return the file URI with file:// scheme
} catch (e: Exception) {
Log.e("ShareRocketChat", "Failed to save data", e)
null
}
}

private fun openURL(uri: Uri) {
// Open the custom URI in the associated app
val intent = Intent(Intent.ACTION_VIEW, uri)
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)
}
}

private fun completeRequest() {
// Finish the share activity
finish()
}
}

This file was deleted.

4 changes: 1 addition & 3 deletions app.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
{
"name": "RocketChatRN",
"share": "ShareRocketChatRN",
"displayName": "RocketChatRN"
"name": "RocketChatRN"
}
8 changes: 7 additions & 1 deletion app/AppContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import SetUsernameView from './views/SetUsernameView';
import OutsideStack from './stacks/OutsideStack';
import InsideStack from './stacks/InsideStack';
import MasterDetailStack from './stacks/MasterDetailStack';
import ShareExtensionStack from './stacks/ShareExtensionStack';
import { ThemeContext } from './theme';
import { setCurrentScreen } from './lib/methods/helpers/log';

Expand Down Expand Up @@ -57,13 +58,18 @@ const App = memo(({ root, isMasterDetail }: { root: string; isMasterDetail: bool
Navigation.routeNameRef.current = currentRouteName;
}}>
<Stack.Navigator screenOptions={{ headerShown: false, animationEnabled: false }}>
{root === RootEnum.ROOT_LOADING ? <Stack.Screen name='AuthLoading' component={AuthLoadingView} /> : null}
{root === RootEnum.ROOT_LOADING || root === RootEnum.ROOT_LOADING_SHARE_EXTENSION ? (
<Stack.Screen name='AuthLoading' component={AuthLoadingView} />
) : null}
{root === RootEnum.ROOT_OUTSIDE ? <Stack.Screen name='OutsideStack' component={OutsideStack} /> : null}
{root === RootEnum.ROOT_INSIDE && isMasterDetail ? (
<Stack.Screen name='MasterDetailStack' component={MasterDetailStack} />
) : null}
{root === RootEnum.ROOT_INSIDE && !isMasterDetail ? <Stack.Screen name='InsideStack' component={InsideStack} /> : null}
{root === RootEnum.ROOT_SET_USERNAME ? <Stack.Screen name='SetUsernameStack' component={SetUsernameStack} /> : null}
{root === RootEnum.ROOT_SHARE_EXTENSION ? (
<Stack.Screen name='ShareExtensionStack' component={ShareExtensionStack} />
) : null}
</Stack.Navigator>
</NavigationContainer>
);
Expand Down
2 changes: 1 addition & 1 deletion app/actions/actionsTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ function createRequestTypes(base = {}, types = defaultTypes): Record<string, str

// Login events
export const LOGIN = createRequestTypes('LOGIN', [...defaultTypes, 'SET_SERVICES', 'SET_PREFERENCE', 'SET_LOCAL_AUTHENTICATED']);
export const SHARE = createRequestTypes('SHARE', ['SELECT_SERVER', 'SET_USER', 'SET_SETTINGS', 'SET_SERVER_INFO']);
export const SHARE = createRequestTypes('SHARE', ['SET_PARAMS']);
export const USER = createRequestTypes('USER', ['SET', 'CLEAR']);
export const ROOMS = createRequestTypes('ROOMS', [
...defaultTypes,
Expand Down
36 changes: 7 additions & 29 deletions app/actions/share.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,17 @@
import { Action } from 'redux';

import { IShareServer, IShareUser, TShareSettings } from '../reducers/share';
import { TShareParams } from '../reducers/share';
import { SHARE } from './actionsTypes';

interface IShareSelectServer extends Action {
server: IShareServer;
interface IShareSetParams extends Action {
params: TShareParams;
}

interface IShareSetSettings extends Action {
settings: TShareSettings;
}

interface IShareSetUser extends Action {
user: IShareUser;
}

export type TActionsShare = IShareSelectServer & IShareSetSettings & IShareSetUser;

export function shareSelectServer(server: IShareServer): IShareSelectServer {
return {
type: SHARE.SELECT_SERVER,
server
};
}

export function shareSetSettings(settings: TShareSettings): IShareSetSettings {
return {
type: SHARE.SET_SETTINGS,
settings
};
}
export type TActionsShare = IShareSetParams;

export function shareSetUser(user: IShareUser): IShareSetUser {
export function shareSetParams(params: TShareParams): IShareSetParams {
return {
type: SHARE.SET_USER,
user
type: SHARE.SET_PARAMS,
params
};
}
11 changes: 4 additions & 7 deletions app/containers/Avatar/AvatarContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ const AvatarContainer = ({
isStatic,
rid
}: IAvatar): React.ReactElement => {
const server = useSelector((state: IApplicationState) => state.share.server.server || state.server.server);
const serverVersion = useSelector((state: IApplicationState) => state.share.server.version || state.server.version);
const server = useSelector((state: IApplicationState) => state.server.server);
const serverVersion = useSelector((state: IApplicationState) => state.server.version);
const { id, token, username } = useSelector(
(state: IApplicationState) => ({
id: getUserSelector(state).id,
Expand All @@ -38,11 +38,8 @@ const AvatarContainer = ({
cdnPrefix: state.settings.CDN_PREFIX as string
}));
const blockUnauthenticatedAccess = useSelector(
(state: IApplicationState) =>
(state.share.settings?.Accounts_AvatarBlockUnauthenticatedAccess as boolean) ??
state.settings.Accounts_AvatarBlockUnauthenticatedAccess ??
true
);
(state: IApplicationState) => state.settings.Accounts_AvatarBlockUnauthenticatedAccess ?? true
) as boolean;

const { avatarETag } = useAvatarETag({ username, text, type, rid, id });

Expand Down
2 changes: 1 addition & 1 deletion app/containers/Button/Button.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Button from '.';

const buttonProps = {
title: 'Press me!',
type: 'primary',
type: 'primary' as const,
onPress: () => {},
testID: 'testButton'
};
Expand Down
4 changes: 2 additions & 2 deletions app/containers/Button/Button.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const onPressMock = jest.fn();

const testProps = {
title: 'Press me!',
type: 'primary',
type: 'primary' as const,
onPress: onPressMock,
testID: 'testButton',
initialText: 'Initial text',
Expand All @@ -19,7 +19,7 @@ const TestButton = ({ loading = false, disabled = false }) => (
<View>
<Button
title={testProps.title}
type={testProps.title}
type={testProps.type}
onPress={testProps.onPress}
testID={testProps.testID}
accessibilityLabel={testProps.title}
Expand Down
2 changes: 1 addition & 1 deletion app/containers/Button/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import ActivityIndicator from '../ActivityIndicator';
interface IButtonProps extends PlatformTouchableProps {
title: string;
onPress: () => void;
type?: string; // primary | secondary
type?: 'primary' | 'secondary';
backgroundColor?: string;
loading?: boolean;
color?: string;
Expand Down
2 changes: 1 addition & 1 deletion app/containers/CallHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export const CallHeader = ({ mic, cam, setCam, setMic, title, avatar, uid, name,
if (enabled) return { button: colors.buttonBackgroundSecondaryDisabled, icon: colors.strokeExtraDark };
return { button: 'transparent', icon: colors.strokeLight };
}
if (enabled) return { button: colors.strokeHighlight, icon: colors.surfaceLight };
if (enabled) return { button: colors.buttonBackgroundPrimaryDefault, icon: colors.surfaceLight };
return { button: 'transparent', icon: colors.strokeExtraDark };
};

Expand Down
2 changes: 1 addition & 1 deletion app/containers/Check.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const styles = StyleSheet.create({

const Check = React.memo(() => {
const { theme } = useTheme();
return <CustomIcon style={styles.icon} color={themes[theme].badgeBackgroundLevel2} size={22} name='check' />;
return <CustomIcon style={styles.icon} color={themes[theme].fontInfo} size={22} name='check' />;
});

export default Check;
2 changes: 1 addition & 1 deletion app/containers/EmojiPicker/CustomEmoji.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ interface ICustomEmojiProps {

const CustomEmoji = React.memo(
({ emoji, style }: ICustomEmojiProps) => {
const baseUrl = useAppSelector(state => state.share.server.server || state.server.server);
const baseUrl = useAppSelector(state => state.server.server);
return (
<FastImage
style={style}
Expand Down
Loading

0 comments on commit b161e11

Please sign in to comment.