Skip to content

Commit

Permalink
Merge branch 'main' into lr/app-icon-update
Browse files Browse the repository at this point in the history
  • Loading branch information
saulmc committed Sep 13, 2024
2 parents dc84e2e + c266b54 commit e9fdf77
Show file tree
Hide file tree
Showing 34 changed files with 874 additions and 559 deletions.
17 changes: 10 additions & 7 deletions android/app/src/main/java/com/converse/dev/BackendApi.kt
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,17 @@ private suspend fun makePutRequest(appContext: Context, apiURI: String, address:

suspend fun putGroupInviteRequest(appContext: Context, apiURI: String, xmtpClient: Client, joinRequestId: String, status: String) {
val groupInviteEndpoint = "$apiURI/api/groupJoinRequest/$joinRequestId"
val privateKey = PrivateKeyBuilder.buildFromSignedPrivateKey(xmtpClient.keys.identityKey)
val signature = Base64.encodeToString(PrivateKeyBuilder(privateKey).sign("XMTP_IDENTITY".toByteArray()).toByteArray(), NO_WRAP)
val address = xmtpClient.address
val body = JSONObject().apply {
put("status", status)
val secureMmkv = getSecureMmkvForAccount(appContext, xmtpClient.address)
secureMmkv?.let { mmkv ->
val apiKey = mmkv.decodeString("CONVERSE_API_KEY")
apiKey?.let { key ->
val address = xmtpClient.address
val body = JSONObject().apply {
put("status", status)
}
makePutRequest(appContext, groupInviteEndpoint, address, key, body)
}
}
print(signature)
makePutRequest(appContext, groupInviteEndpoint, address, signature, body)
}


4 changes: 2 additions & 2 deletions app.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
"expo": {
"ios": {
"version": "1.4.9",
"buildNumber": "260"
"buildNumber": "261"
},
"android": {
"version": "1.4.9",
"versionCode": 181
"versionCode": 182
}
}
}
22 changes: 22 additions & 0 deletions assets/Encrypted.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from "react";
import Svg, { Path } from "react-native-svg";

interface EncryptedProps {
width?: number;
height?: number;
color?: string;
}

const Encrypted: React.FC<EncryptedProps> = ({
width = 40,
height = 40,
color = "#000000",
}) => {
return (
<Svg width={width} height={height} viewBox="0 -960 960 960" fill={color}>
<Path d="M434.08-370h91.84l-23.43-134.15q18.84-7.67 30.55-24.07 11.7-16.4 11.7-36.65 0-26.87-18.93-45.81-18.94-18.93-45.81-18.93t-45.81 18.93q-18.93 18.94-18.93 45.81 0 20.25 11.7 36.65 11.71 16.4 30.55 24.07L434.08-370ZM480-101.18q-130.18-35.64-215.09-154.39Q180-374.31 180-519.38v-227.18l300-112.31 300 112.31v227.18q0 145.07-84.91 263.81Q610.18-136.82 480-101.18Zm0-52.67q109.28-35.3 179.51-137.48 70.23-102.18 70.23-228.05v-192.39L480-805.44l-249.74 93.67v192.39q0 125.87 70.23 228.05T480-153.85Zm0-325.77Z" />
</Svg>
);
};

export default Encrypted;
226 changes: 226 additions & 0 deletions components/Chat/ChatNullState.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
import ConverseButton from "@components/Button/Button";
import { translate } from "@i18n/index";
import {
backgroundColor,
textPrimaryColor,
textSecondaryColor,
tertiaryBackgroundColor,
itemSeparatorColor,
} from "@styles/colors";
import { BorderRadius, Paddings, Margins } from "@styles/sizes";
import React from "react";
import {
View,
Text,
StyleSheet,
useColorScheme,
Platform,
Linking,
} from "react-native";
import { useSafeAreaInsets } from "react-native-safe-area-context";

import config from "../../config";
import {
useProfilesStore,
useRecommendationsStore,
} from "../../data/store/accountsStore";
import { ShareProfileContent } from "../../screens/ShareProfile";
import {
getPreferredUsername,
getPreferredName,
getPreferredAvatar,
} from "../../utils/profile";
import Recommendations from "../Recommendations/Recommendations";

interface ChatNullStateProps {
currentAccount: string;
navigation: any;
}

const ChatNullState: React.FC<ChatNullStateProps> = ({
currentAccount,
navigation,
}) => {
const colorScheme = useColorScheme();

const styles = useStyles();

const socials = useProfilesStore((s) => s.profiles[currentAccount]?.socials);
const username = getPreferredUsername(socials);
const displayName = getPreferredName(socials, currentAccount);
const profileUrl = `https://${config.websiteDomain}/dm/${
username || currentAccount
}`;
const avatar = getPreferredAvatar(socials);

const frens = useRecommendationsStore((s) => s.frens);
const setRecommendations = useRecommendationsStore(
(s) => s.setRecommendations
);
const hasRecommendations = Object.keys(frens).length > 0;

return (
<View style={styles.container}>
<View style={styles.contentContainer}>
<View
style={[
styles.titlesContainer,
{
borderBottomWidth: hasRecommendations ? 0.5 : 0,
borderBottomColor: itemSeparatorColor(colorScheme),
},
]}
>
<Text style={styles.title}>
{hasRecommendations
? translate("connectWithYourNetwork")
: translate("shareYourQRCode")}
</Text>
<Text style={styles.subtitle}>
{hasRecommendations
? translate("findContacts")
: translate("moveOrConnect")}
</Text>
</View>
{hasRecommendations ? (
<View style={styles.recommendationsContainer}>
<Recommendations
navigation={navigation}
visibility="EMBEDDED"
showTitle={false}
/>
</View>
) : (
<View style={styles.qrCodeContainer}>
<ShareProfileContent
compact
userAddress={currentAccount}
username={username}
displayName={displayName}
avatar={avatar || ""}
profileUrl={profileUrl}
/>
</View>
)}
</View>

<View style={styles.chin}>
<View style={styles.chinContent}>
<Text style={styles.chinTitle}>{translate("alphaTestTitle")}</Text>
<Text style={styles.chinDescription}>
{translate("alphaTestDescription")}
</Text>

<ConverseButton
title={translate("joinAlphaGroup")}
variant="primary"
style={styles.alphaGroupButton}
textStyle={styles.alphaGroupButtonText}
onPress={() => {
Linking.openURL(config.alphaGroupChatUrl);
}}
/>
</View>
</View>
</View>
);
};

const useStyles = () => {
const colorScheme = useColorScheme();
const insets = useSafeAreaInsets();
return StyleSheet.create({
container: {
flex: 1,
backgroundColor: backgroundColor(colorScheme),
borderTopWidth: Platform.OS === "android" ? 0 : 1,
borderTopColor: tertiaryBackgroundColor(colorScheme),
},
contentContainer: {
flex: 1,
alignItems: "center",
justifyContent: "flex-start",
paddingTop: Paddings.large,
},
titlesContainer: {
width: "100%",
borderBottomColor: tertiaryBackgroundColor(colorScheme),
},
title: {
fontSize: 28,
fontWeight: "bold",
marginBottom: Margins.small,
color: textPrimaryColor(colorScheme),
textAlign: "center",
},
subtitle: {
fontSize: 16,
textAlign: "center",
marginBottom: Margins.large,
color: textSecondaryColor(colorScheme),
},
qrCodeContainer: {
paddingVertical: Paddings.default,
paddingHorizontal: Paddings.large,
backgroundColor: backgroundColor(colorScheme),
borderRadius: BorderRadius.large,
shadowColor: textSecondaryColor(colorScheme),
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
elevation: 3,
marginTop: Platform.OS === "android" ? Margins.large : Margins.small,
},
identityContainer: {
marginTop: Margins.large,
alignItems: "center",
},
identity: {
color: textPrimaryColor(colorScheme),
fontSize: 24,
fontWeight: "600",
textAlign: "center",
},
username: {
fontSize: 16,
color: textSecondaryColor(colorScheme),
marginTop: Margins.small,
},
recommendationsContainer: {
width: "100%",
height: "100%",
},
chin: {
borderTopWidth: 1,
borderTopColor: tertiaryBackgroundColor(colorScheme),
backgroundColor: backgroundColor(colorScheme),
paddingBottom: insets.bottom,
},
chinContent: {
alignItems: "center",
paddingHorizontal: Paddings.large,
},
chinTitle: {
color: textPrimaryColor(colorScheme),
fontSize: 15,
fontWeight: "600",
textAlign: "center",
marginTop: Margins.default,
marginBottom: Margins.small,
},
chinDescription: {
color: textSecondaryColor(colorScheme),
fontSize: 14,
textAlign: "center",
marginBottom: Margins.default,
},
alphaGroupButton: {
maxWidth: Platform.OS === "web" ? 300 : undefined,
borderRadius: 16,
marginHorizontal: 24,
},
alphaGroupButtonText: {},
});
};

export default ChatNullState;
46 changes: 28 additions & 18 deletions components/Chat/Message/MessageActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
} from "@styles/colors";
import { isFrameMessage } from "@utils/frames";
import { navigate } from "@utils/navigation";
import * as Haptics from "expo-haptics";
import React, { useCallback, useEffect, useMemo, useState } from "react";
import { Platform, StyleSheet, useColorScheme, View } from "react-native";
import { Gesture, GestureDetector } from "react-native-gesture-handler";
Expand Down Expand Up @@ -162,6 +163,7 @@ export default function ChatMessageActions({
const longPressGesture = useMemo(() => {
return Gesture.LongPress()
.onStart(() => {
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);
scaleHold();
setContextMenuShown(message.id);
})
Expand Down Expand Up @@ -271,11 +273,31 @@ export default function ChatMessageActions({
return null;
}, [message]);

const animateInStyle = useAnimatedStyle(() => {
return {
opacity: opacity.value,
transform: [{ scale: scale.value }, { translateY: translateY.value }],
};
});

const onContextCloseAnimation = useCallback(() => {
"worklet";
opacity.value = 1;
runOnJS(setIsActive)(false);
}, [setIsActive, opacity]);

const onContextClose = useCallback(() => {
onContextCloseAnimation();
}, [onContextCloseAnimation]);

const contextMenuItems = useMemo(() => {
const items: TableViewItemType[] = [];
items.push({
title: translate("reply"),
action: triggerReplyToMessage,
action: () => {
triggerReplyToMessage();
onContextClose();
},
id: ContextMenuActions.REPLY,
rightView: <TableViewPicto symbol="arrowshape.turn.up.left" />,
});
Expand All @@ -290,6 +312,9 @@ export default function ChatMessageActions({
} else if (message.contentFallback) {
Clipboard.setString(message.contentFallback);
}
setTimeout(() => {
onContextClose();
}, 200);
},
});
}
Expand All @@ -302,6 +327,7 @@ export default function ChatMessageActions({
if (frameURL) {
navigate("ShareFrame", { frameURL });
}
onContextClose();
},
});
}
Expand All @@ -313,6 +339,7 @@ export default function ChatMessageActions({
message.content,
message.contentFallback,
triggerReplyToMessage,
onContextClose,
]);

useEffect(() => {
Expand Down Expand Up @@ -348,23 +375,6 @@ export default function ChatMessageActions({
}
}, [shouldAnimateIn, hasAnimatedIn, opacity, scale, translateY]);

const animateInStyle = useAnimatedStyle(() => {
return {
opacity: opacity.value,
transform: [{ scale: scale.value }, { translateY: translateY.value }],
};
});

const onContextCloseAnimation = useCallback(() => {
"worklet";
opacity.value = 1;
runOnJS(setIsActive)(false);
}, [setIsActive, opacity]);

const onContextClose = useCallback(() => {
onContextCloseAnimation();
}, [onContextCloseAnimation]);

// We use a mix of Gesture Detector AND TouchableOpacity
// because GestureDetector is better for dual tap but if
// we add the gesture detector for long press the long press
Expand Down
Loading

0 comments on commit e9fdf77

Please sign in to comment.