Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Conversation list polished #1514

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
Binary file added assets/icons/chat-bubble-dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/icons/chat-bubble-light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 5 additions & 11 deletions components/AccountSettingsButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,17 @@ import {
useColorScheme,
} from "react-native";

import {
useAccountsStore,
useErroredAccountsMap,
} from "../data/store/accountsStore";
import { invalidateProfileSocialsQuery } from "@/queries/useProfileSocialsQuery";
import { useAccountsStore } from "../data/store/accountsStore";
import { useAppStore } from "../data/store/appStore";
import { useSelect } from "../data/store/storeHelpers";
import { NotificationPermissionStatus } from "../features/notifications/types/Notifications.types";
import { requestPushNotificationsPermissions } from "../features/notifications/utils/requestPushNotificationsPermissions";
import { useRouter } from "../navigation/useNavigation";
import { navigate } from "../utils/navigation";
import { requestPushNotificationsPermissions } from "../features/notifications/utils/requestPushNotificationsPermissions";
import Picto from "./Picto/Picto";
import { showActionSheetWithOptions } from "./StateHandlers/ActionSheetStateHandler";
import { TableViewPicto } from "./TableView/TableViewImage";
import { NotificationPermissionStatus } from "../features/notifications/types/Notifications.types";
import { invalidateProfileSocialsQuery } from "@/queries/useProfileSocialsQuery";
import { invalidateInboxProfileSocialsQuery } from "@/queries/useInboxProfileSocialsQuery";

type Props = {
account: string;
Expand All @@ -55,7 +51,6 @@ export default function AccountSettingsButton({ account }: Props) {
const { setCurrentAccount } = useAccountsStore(
useSelect(["setCurrentAccount"])
);
const erroredAccountsMap = useErroredAccountsMap();
const colorScheme = useColorScheme();
const showDisconnectActionSheet = useDisconnectActionSheet(account);

Expand Down Expand Up @@ -110,7 +105,7 @@ export default function AccountSettingsButton({ account }: Props) {

const options = Object.keys(methods);
const icons = [];
if (erroredAccountsMap[account] && isInternetReachable) {
if (isInternetReachable) {
icons.push(
<Picto
style={{
Expand Down Expand Up @@ -148,7 +143,6 @@ export default function AccountSettingsButton({ account }: Props) {
);
}, [
router,
erroredAccountsMap,
account,
isInternetReachable,
notificationsPermissionStatus,
Expand Down
36 changes: 0 additions & 36 deletions components/ErroredHeader.tsx

This file was deleted.

8 changes: 7 additions & 1 deletion components/Snackbar/SnackbarBackdrop/SnackbarBackdrop.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { useAppTheme } from "@/theme/useAppTheme";
import { hexToRGBA } from "@/utils/colors";
import { useSnackbars } from "@components/Snackbar/Snackbar.service";
import { useGradientHeight } from "@components/Snackbar/SnackbarBackdrop/SnackbarBackdrop.utils";
// import MaskedView from "@react-native-masked-view/masked-view";
Expand All @@ -18,6 +20,7 @@ import Animated, {

export const SnackbarBackdrop = memo(() => {
const snackbars = useSnackbars();
const { theme } = useAppTheme();
const { height: windowHeight } = useWindowDimensions();
const gradientHeight = useGradientHeight();

Expand All @@ -38,7 +41,10 @@ export const SnackbarBackdrop = memo(() => {
>
<LinearGradient
locations={[0, 0.55]}
colors={["rgba(255, 255,255,0.0)", "rgba(255, 255,255,1)"]}
colors={[
hexToRGBA(theme.colors.background.surface, 0),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will fix the dark mode backsplash yes?

hexToRGBA(theme.colors.background.surface, 1),
]}
style={StyleSheet.absoluteFill}
/>
{/* TODO: Maybe add back later. For now masked view can be a litte unstable and buggy */}
Expand Down
23 changes: 7 additions & 16 deletions components/StateHandlers/HydrationStateHandler.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { prefetchInboxIdQuery } from "@/queries/use-inbox-id-query";
import { fetchPersistedConversationListQuery } from "@/queries/useConversationListQuery";
import logger from "@utils/logger";
import { useEffect } from "react";
import { getAccountsList } from "@data/store/accountsStore";
import { useAppStore } from "@data/store/appStore";
import { getXmtpClient } from "@utils/xmtpRN/sync";
import logger from "@utils/logger";
import { useEffect } from "react";
import { getInstalledWallets } from "../Onboarding/ConnectViaWallet/ConnectViaWalletSupportedWallets";
import { prefetchConversationsQuery } from "@/queries/conversations-query";

export default function HydrationStateHandler() {
// Initial hydration
Expand All @@ -24,26 +23,18 @@ export default function HydrationStateHandler() {
// Fetching persisted conversation lists for all accounts
// We may want to fetch only the selected account's conversation list
// in the future, but this is simple for now, and want to get feedback to really confirm
logger.debug("[Hydration] Fetching persisted conversation list");
logger.debug(
"[Hydration] Fetching persisted conversation list for all accounts"
);
await Promise.allSettled(
accounts.map(async (account) => {
const accountStartTime = new Date().getTime();
logger.debug(
`[Hydration] Fetching persisted conversation list for ${account}`
);

const results = await Promise.allSettled([
// This will handle creating the client and setting the conversation list from persistence
fetchPersistedConversationListQuery({ account }),
]);
prefetchInboxIdQuery({ account });

const errors = results.filter(
(result) => result.status === "rejected"
);
if (errors.length > 0) {
logger.warn(`[Hydration] error for ${account}:`, errors);
}
prefetchConversationsQuery({ account });

const accountEndTime = new Date().getTime();
logger.debug(
Expand Down
11 changes: 1 addition & 10 deletions components/XmtpEngine.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,8 @@ import {
AppStateStatus,
NativeEventSubscription,
} from "react-native";

import {
getAccountsList,
getChatStore,
useAccountsStore,
} from "../data/store/accountsStore";
import { getAccountsList, useAccountsStore } from "../data/store/accountsStore";
import { useAppStore } from "../data/store/appStore";
import { getTopicsData } from "../utils/api";
import { stopStreamingConversations } from "../utils/xmtpRN/conversations";
import { syncConversationListXmtpClient } from "../utils/xmtpRN/sync";

Expand Down Expand Up @@ -131,9 +125,6 @@ class XmtpEngine {
accountsToSync.forEach((a) => {
if (!this.syncingAccounts[a]) {
logger.info(`[XmtpEngine] Syncing account ${a}`);
getTopicsData(a).then((topicsData) => {
getChatStore(a).getState().setTopicsData(topicsData, true);
});
this.syncedAccounts[a] = true;
this.syncingAccounts[a] = true;
syncConversationListXmtpClient(a)
Expand Down
1 change: 0 additions & 1 deletion components/swipeable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ export type ISwipeableRenderActionsArgs = {
progressAnimatedValue: SharedValue<number>;
dragAnimatedValue: SharedValue<number>;
swipeable: SwipeableMethods;
// caca: number;
};

export type ISwipeableProps = {
Expand Down
6 changes: 3 additions & 3 deletions data/helpers/conversations/spamScore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import {
} from "@/utils/xmtpRN/content-types/content-types";

type V3SpameScoreParams = {
message: string;
messageText: string;
contentType: IConvosContentType;
};

export const getV3SpamScore = async ({
message,
messageText,
contentType,
}: V3SpameScoreParams): Promise<number> => {
// TODO: Check if adder has been approved already
Expand All @@ -19,7 +19,7 @@ export const getV3SpamScore = async ({
// TODO: Check spam score between sender and receiver

// Check contents of last message
spamScore += computeMessageContentSpamScore(message, contentType);
spamScore += computeMessageContentSpamScore(messageText, contentType);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance spam detection accuracy.

The current implementation might generate false positives. Consider:

  1. Using weighted scores instead of binary values
  2. Adding more sophisticated patterns
  3. Implementing machine learning-based classification

Example implementation:

const SPAM_WEIGHTS = {
  url: 0.5,
  currency: 0.3,
  knownSpamPhrase: 0.8,
  // Add more indicators
};

function getUrlWeight(url: string): number {
  // Check against allowlist/blocklist
  // Parse domain reputation
  return SPAM_WEIGHTS.url;
}

return spamScore;
};

Expand Down
20 changes: 2 additions & 18 deletions data/store/accountsStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { v4 as uuidv4 } from "uuid";
import { create, StoreApi, UseBoundStore } from "zustand";
import { createJSONStorage, persist } from "zustand/middleware";

import { removeLogoutTask } from "@utils/logout";
import mmkv, { zustandMMKVStorage } from "../../utils/mmkv";
import { ChatStoreType, initChatStore } from "./chatStore";
import {
initRecommendationsStore,
Expand All @@ -18,8 +20,6 @@ import {
TransactionsStoreType,
} from "./transactionsStore";
import { initWalletStore, WalletStoreType } from "./walletStore";
import { removeLogoutTask } from "@utils/logout";
import mmkv, { zustandMMKVStorage } from "../../utils/mmkv";

type AccountStoreType = {
[K in keyof AccountStoreDataType]: UseBoundStore<
Expand Down Expand Up @@ -71,22 +71,6 @@ export const useAccountsList = () => {
return accounts.filter((a) => a && a !== TEMPORARY_ACCOUNT_NAME);
};

export const useErroredAccountsMap = () => {
const accounts = useAccountsList();
return accounts.reduce(
(acc, a) => {
const errored = getChatStore(a).getState().errored;

if (errored) {
acc[a] = errored;
}

return acc;
},
{} as { [account: string]: boolean }
);
};

// This store is global (i.e. not linked to an account)
// For now we only use a single account so we initialize it
// and don't add a setter.
Expand Down
Loading
Loading