Skip to content

Commit

Permalink
Merge branch 'develop' into chore.upgrade-wmdb
Browse files Browse the repository at this point in the history
  • Loading branch information
diegolmello committed Sep 19, 2024
2 parents 200b17b + 5225e5e commit 8953482
Show file tree
Hide file tree
Showing 78 changed files with 1,206 additions and 1,696 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

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/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
5 changes: 2 additions & 3 deletions app/containers/ServerItem/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,11 @@ const ServerItem = React.memo(({ item, onPress, onLongPress, hasCheck }: IServer
<Pressable
onPress={onPress}
onLongPress={() => onLongPress?.()}
testID={`rooms-list-header-server-${item.id}`}
testID={`server-item-${item.id}`}
android_ripple={{ color: themes[theme].surfaceNeutral }}
style={({ pressed }: { pressed: boolean }) => ({
backgroundColor: isIOS && pressed ? themes[theme].surfaceNeutral : themes[theme].surfaceRoom
})}
>
})}>
<View style={styles.serverItemContainer}>
{item.iconURL ? (
<FastImage
Expand Down
5 changes: 3 additions & 2 deletions app/containers/message/hooks/useMediaAutoDownload.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export const useMediaAutoDownload = ({
}

return () => {
emitter.off(`downloadMedia${id}`, downloadMediaListener);
emitter.off(`downloadMedia${url}`, downloadMediaListener);
};
}, []);

Expand All @@ -81,7 +81,8 @@ export const useMediaAutoDownload = ({
}, []);

const resumeDownload = () => {
emitter.on(`downloadMedia${id}`, downloadMediaListener);
setStatus('loading');
emitter.on(`downloadMedia${url}`, downloadMediaListener);
};

const tryAutoDownload = async () => {
Expand Down
Loading

0 comments on commit 8953482

Please sign in to comment.