Skip to content

Commit

Permalink
feat: New Profile Screen (read-only) (#1519)
Browse files Browse the repository at this point in the history
  • Loading branch information
lourou authored Jan 17, 2025
1 parent a6bdee3 commit 1f3db8e
Show file tree
Hide file tree
Showing 32 changed files with 877 additions and 1,052 deletions.
2 changes: 1 addition & 1 deletion components/TransactionPreview/TransactionResult.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const $failure: ThemedStyle<ViewStyle> = ({ spacing, borderRadius }) => ({
marginBottom: spacing.md,
padding: spacing.sm,
backgroundColor: "#FFF5F5",
borderRadius: borderRadius.xs,
borderRadius: borderRadius.xxs,
});

const styles = StyleSheet.create({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ const $failure: ThemedStyle<ViewStyle> = ({ spacing, borderRadius }) => ({
marginBottom: spacing.md,
padding: spacing.sm,
backgroundColor: "#FFF5F5",
borderRadius: borderRadius.xs,
borderRadius: borderRadius.xxs,
});
1 change: 1 addition & 0 deletions design-system/Button/Button.props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export type IButtonVariant =
| "outline"
| "fill"
| "link"
| "link.bare"
/** @deprecated */
| "secondary"
| "secondary-danger"
Expand Down
10 changes: 10 additions & 0 deletions design-system/Button/Button.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,16 @@ export const getButtonViewStyle =
size === "md" || size === "sm" ? spacing.xs : spacing.sm,
};

// Special case for bare link text buttons - no padding or other decorations
if (variant === "link.bare") {
return {
flexDirection: "row",
alignItems: "center",
justifyContent: "center",
gap: spacing.xxs,
};
}

if (action === "primary") {
switch (variant) {
case "fill":
Expand Down
6 changes: 4 additions & 2 deletions design-system/Icon/Icon.android.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export const iconRegistry: Record<
link: "link",
paperplane: "send",
account_circle: "account-circle",
pencil: "edit",
"square.and.pencil": "edit",
qrcode: "qr-code",
"message.circle.fill": "chat",
Expand Down Expand Up @@ -58,6 +59,7 @@ export const iconRegistry: Record<
"arrowshape.turn.up.left": "reply",
"arrowshape.turn.up.left.fill": "reply",
"person.crop.circle.badge.plus": "group-add",
"person.crop.circle.badge.xmark": "person-remove",
tray: "inbox",
cloud: "cloud",
"exclamationmark.triangle": "warning",
Expand Down Expand Up @@ -89,8 +91,8 @@ export function Icon(props: IIconProps) {
const iconName = icon
? iconRegistry[icon]
: picto
? iconRegistry[picto]
: null;
? iconRegistry[picto]
: null;

if (!iconName) {
logger.warn(`Invalid icon name ${icon || picto}`);
Expand Down
6 changes: 4 additions & 2 deletions design-system/Icon/Icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const iconRegistry: Record<IIconName, string> = {
link: "link",
paperplane: "paperplane",
account_circle: "person.circle",
pencil: "pencil",
"square.and.pencil": "square.and.pencil",
qrcode: "qrcode",
"message.circle.fill": "message.circle.fill",
Expand Down Expand Up @@ -55,6 +56,7 @@ export const iconRegistry: Record<IIconName, string> = {
"arrowshape.turn.up.left": "arrowshape.turn.up.left",
"arrowshape.turn.up.left.fill": "arrowshape.turn.up.left.fill",
"person.crop.circle.badge.plus": "person.crop.circle.badge.plus",
"person.crop.circle.badge.xmark": "person.crop.circle.badge.xmark",
tray: "tray",
cloud: "cloud",
"exclamationmark.triangle": "exclamationmark.triangle",
Expand Down Expand Up @@ -98,8 +100,8 @@ export function Icon(props: IIconProps) {
const iconName = icon
? iconRegistry[icon]
: picto
? iconRegistry[picto]
: null;
? iconRegistry[picto]
: null;

if (!iconName) {
logger.warn(
Expand Down
2 changes: 2 additions & 0 deletions design-system/Icon/Icon.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export type IIconName =
| "link"
| "paperplane"
| "account_circle"
| "pencil"
| "square.and.pencil"
| "qrcode"
| "message.circle.fill"
Expand Down Expand Up @@ -52,6 +53,7 @@ export type IIconName =
| "arrowshape.turn.up.left"
| "arrowshape.turn.up.left.fill"
| "person.crop.circle.badge.plus"
| "person.crop.circle.badge.xmark"
| "tray"
| "cloud"
| "exclamationmark.triangle"
Expand Down
2 changes: 1 addition & 1 deletion design-system/TextField/TextField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ const $inputWrapperStyle: ThemedStyle<ViewStyle> = ({
spacing,
}) => ({
borderWidth: borderWidth.sm,
borderRadius: borderRadius.xs,
borderRadius: borderRadius.xxs,
backgroundColor: colors.background.surface,
borderColor: colors.border.subtle,
overflow: "hidden",
Expand Down
12 changes: 8 additions & 4 deletions design-system/chip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,10 @@ export function Chip({
{avatarUrl && (
<Avatar size={theme.avatarSize.xs} uri={avatarUrl} name={text} />
)}
<Text style={themed(isActive ? $chipTextActive : $chipText)}>
<Text
preset="smaller"
style={themed(isActive ? $chipTextActive : $chipText)}
>
{text}
</Text>
</HStack>
Expand All @@ -73,9 +76,10 @@ const $chip: ThemedStyle<ViewStyle> = ({
borderWidth: borderWidth.sm,
borderColor: colors.border.subtle,
paddingVertical: spacing.xxs,
paddingHorizontal: spacing.xs,
minHeight: 36,
// ...debugBorder("orange"),
paddingHorizontal: spacing.sm,
minHeight: 36, // from Figma
justifyContent: "center",
backgroundColor: colors.background.surface,
});

const $chipActive: ThemedStyle<ViewStyle> = ({ colors }) => ({
Expand Down
80 changes: 80 additions & 0 deletions design-system/settings-list/settings-list-row.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import React, { memo } from "react";
import { View, ViewStyle, Switch, TouchableOpacity } from "react-native";
import { Text } from "@/design-system/Text";
import { useAppTheme, ThemedStyle } from "@/theme/useAppTheme";
import { HStack } from "@/design-system/HStack";
import { VStack } from "@/design-system/VStack";
import { Icon } from "@/design-system/Icon/Icon";
import { ISettingsListRow } from "./settings-list.types";

type ISettingsListRowProps = {
row: ISettingsListRow;
editMode?: boolean;
};

export const SettingsListRow = memo(function SettingsListRow({
row,
editMode,
}: ISettingsListRowProps) {
const { theme, themed } = useAppTheme();

const content = (
<HStack style={themed($innerRowContainer)}>
<VStack style={{ flex: 1 }}>
<Text color={row.isWarning ? "caution" : "primary"}>{row.label}</Text>
{row.value && (
<Text
preset="formLabel"
color={row.isWarning ? "caution" : "secondary"}
>
{row.value}
</Text>
)}
</VStack>
<View style={themed($rightContentContainer)}>
{row.isSwitch ? (
<Switch
value={!!row.value}
onValueChange={row.onValueChange}
disabled={row.disabled}
/>
) : (
<Icon
icon="chevron.right"
size={theme.iconSize.sm}
color={theme.colors.text.secondary}
/>
)}
</View>
</HStack>
);

if (row.onPress) {
return (
<TouchableOpacity style={themed($rowContainer)} onPress={row.onPress}>
{content}
</TouchableOpacity>
);
}

return <HStack style={themed($rowContainer)}>{content}</HStack>;
});

const $rowContainer: ThemedStyle<ViewStyle> = ({ spacing }) => ({
paddingVertical: spacing.md,
width: "100%",
flexDirection: "row",
alignItems: "center",
});

const $innerRowContainer: ThemedStyle<ViewStyle> = () => ({
width: "100%",
justifyContent: "space-between",
alignItems: "center",
});

const $rightContentContainer: ThemedStyle<ViewStyle> = () => ({
marginLeft: "auto",
alignItems: "flex-end",
justifyContent: "center",
});
33 changes: 33 additions & 0 deletions design-system/settings-list/settings-list.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React, { memo } from "react";
import { View, ViewStyle } from "react-native";
import { useAppTheme, ThemedStyle } from "@/theme/useAppTheme";
import { SettingsListRow } from "./settings-list-row";
import { ISettingsListRow } from "./settings-list.types";

type ISettingsListProps = {
rows: ISettingsListRow[];
editMode?: boolean;
};

export const SettingsList = memo(function SettingsList({
rows,
editMode,
}: ISettingsListProps) {
const { themed } = useAppTheme();

return (
<View style={themed($container)}>
{rows.map((row, index) => (
<SettingsListRow
key={row.label + index}
row={row}
editMode={editMode}
/>
))}
</View>
);
});

const $container: ThemedStyle<ViewStyle> = () => ({
width: "100%",
});
9 changes: 9 additions & 0 deletions design-system/settings-list/settings-list.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export type ISettingsListRow = {
label: string;
value?: string | boolean;
onPress?: () => void;
onValueChange?: (value: boolean) => void;
isWarning?: boolean;
isSwitch?: boolean;
disabled?: boolean;
};
2 changes: 1 addition & 1 deletion features/ExternalWalletPicker/ExternalWalletPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ export function ExternalWalletPicker(props: IExternalWalletPickerProps) {
style={{
width: theme.avatarSize.md,
height: theme.avatarSize.md,
borderRadius: theme.borderRadius.xs,
borderRadius: theme.borderRadius.xxs,
}}
/>
<Text preset="smaller" style={$globalStyles.flex1 as TextStyle}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ export function useHeaderWrapper() {
{
displayInline: true,
id: "app-settings",
title: translate("App settings"),
title: translate("app_settings"),
image: iconRegistry["settings"],
},
]}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ const ReplyPreviewEndContent = memo(function ReplyPreviewEndContent(props: {
style: {
height: theme.avatarSize.md,
width: theme.avatarSize.md,
borderRadius: theme.borderRadius.xs,
borderRadius: theme.borderRadius.xxs,
},
}}
/>
Expand All @@ -215,7 +215,7 @@ const ReplyPreviewEndContent = memo(function ReplyPreviewEndContent(props: {
style: {
height: theme.avatarSize.md,
width: theme.avatarSize.md,
borderRadius: theme.borderRadius.xs,
borderRadius: theme.borderRadius.xxs,
},
}}
/>
Expand Down
13 changes: 11 additions & 2 deletions features/conversation/conversation.nav.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { ConversationScreen } from "@/features/conversation/conversation.screen";
import { NativeStack } from "@/screens/Navigation/Navigation";
import type { ConversationTopic } from "@xmtp/react-native-sdk";
import { translate } from "@/i18n";
import { useAppTheme } from "@/theme/useAppTheme";
import { HStack } from "@design-system/HStack";
import { HeaderAction } from "@/design-system/Header/HeaderAction";
import { useNavigation } from "@react-navigation/native";
import { Platform } from "react-native";
import { ConversationTopic } from "@xmtp/react-native-sdk";

export type ConversationNavParams = {
topic?: ConversationTopic;
Expand All @@ -19,11 +25,14 @@ export const ConversationScreenConfig = {
};

export function ConversationNav() {
const { theme } = useAppTheme();
const navigation = useNavigation();

return (
<NativeStack.Screen
options={{
title: "",
headerBackTitle: "",
headerTitle: translate("chat"),
// headerBackVisible: false,
}}
name="Conversation"
Expand Down
51 changes: 51 additions & 0 deletions features/notifications/hooks/use-notifications-permission.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Platform, Linking } from "react-native";
import { useAppStore } from "@/data/store/appStore";
import { requestPushNotificationsPermissions } from "../utils/requestPushNotificationsPermissions";
import { useSettingsStore } from "@/data/store/accountsStore";

type UseNotificationsPermissionReturn = {
notificationsPermissionStatus: "granted" | "undetermined" | "denied";
requestPermission: () => Promise<void>;
setNotificationsSettings: (settings: {
showNotificationScreen: boolean;
}) => void;
};

export function useNotificationsPermission(): UseNotificationsPermissionReturn {
const notificationsPermissionStatus = useAppStore(
(s) => s.notificationsPermissionStatus
);
const setNotificationsPermissionStatus = useAppStore(
(s) => s.setNotificationsPermissionStatus
);
const setNotificationsSettings = useSettingsStore(
(s) => s.setNotificationsSettings
);

const requestPermission = async () => {
if (notificationsPermissionStatus === "denied") {
if (Platform.OS === "android") {
// Android 13 is always denied first so let's try to show
const newStatus = await requestPushNotificationsPermissions();
if (newStatus === "denied") {
Linking.openSettings();
} else if (newStatus) {
setNotificationsPermissionStatus(newStatus);
}
} else {
Linking.openSettings();
}
} else if (notificationsPermissionStatus === "undetermined") {
// Open popup
const newStatus = await requestPushNotificationsPermissions();
if (!newStatus) return;
setNotificationsPermissionStatus(newStatus);
}
};

return {
notificationsPermissionStatus,
requestPermission,
setNotificationsSettings,
};
}
Loading

0 comments on commit 1f3db8e

Please sign in to comment.