Skip to content

Commit

Permalink
various mobile onboarding fixes (#3128)
Browse files Browse the repository at this point in the history
* adjustments

* fix mnemonic input

* fix scrolling on secret recovery phrase

* cleanup and fix

* fix
  • Loading branch information
peterpme authored Mar 3, 2023
1 parent 663689d commit d4203f2
Show file tree
Hide file tree
Showing 6 changed files with 353 additions and 214 deletions.
2 changes: 1 addition & 1 deletion packages/app-mobile/src/components/ActionCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const styles = StyleSheet.create({
container: {
padding: 16,
borderRadius: 12,
minHeight: 120,
minHeight: 100,
},
iconContainer: {
width: 32,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import React from "react";
import { Dimensions, TextInput, ScrollView } from "react-native";

import Animated, {
useAnimatedKeyboard,
useAnimatedReaction,
runOnJS,
KeyboardState,
useAnimatedProps,
useAnimatedScrollHandler,
useSharedValue,
useAnimatedRef,
} from "react-native-reanimated";

export function withReanimatedKeyboardAwareScrollView<
T extends typeof ScrollView
>(Component: T) {
const AnimatedScrollView = Animated.createAnimatedComponent(Component);
return function KeyboardAwareReanimatedScrollView(
props: React.ComponentProps<typeof ScrollView>
) {
const scrollY = useSharedValue(0);
const keyboard = useAnimatedKeyboard();
const scrollViewRef = useAnimatedRef<ScrollView>();

const performScroll = () => {
TextInput.State.currentlyFocusedInput()?.measure(
(x, y, width, textInputHeight, pageX, textInputPageY) => {
const textinputBottomY = textInputPageY + textInputHeight;
const keyboardTopY =
Dimensions.get("screen").height - keyboard.height.value;
// check whether the text input is covered by the keyboard
if (textinputBottomY < keyboardTopY) {
return;
}

scrollViewRef?.current?.scrollTo({
y: scrollY.value + textinputBottomY - keyboardTopY,
});
}
);
};

useAnimatedReaction(
() => {
return keyboard.state.value;
},
(keyboardState) => {
if (keyboardState === KeyboardState.OPEN) {
runOnJS(performScroll)();
}
}
);

const containerPaddingStyle = useAnimatedProps(() => {
return {
paddingBottom: keyboard.height.value,
};
});

const handler = useAnimatedScrollHandler(
{
onScroll: (e) => {
scrollY.value = e.contentOffset.y;
},
},
[]
);

return (
<AnimatedScrollView
{...props}
ref={scrollViewRef}
scrollEventThrottle={16}
onScroll={handler}
>
{props.children}
<Animated.View style={containerPaddingStyle} />
</AnimatedScrollView>
);
};
}

export const KeyboardAwareAnimatedScrollView =
withReanimatedKeyboardAwareScrollView(ScrollView);
44 changes: 33 additions & 11 deletions packages/app-mobile/src/components/MnemonicInputFields.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
// function MnemonicInputFields from app-extension/.../common/Account/MnemonicInput.tsx
import { FlatList, StyleSheet, Text, TextInput, View } from "react-native";

import { useTheme } from "~hooks/useTheme";

function Item({ item, index }) {
function ItemTextInput({
word,
index,
onChangeText,
}: {
word: string;
index: number;
onChangeText: (word: string) => void;
}) {
const theme = useTheme();
return (
<View
Expand All @@ -23,7 +30,8 @@ function Item({ item, index }) {
{index + 1}
</Text>
<TextInput
value={item}
onChangeText={onChangeText}
value={word}
style={[
styles.input,
{
Expand All @@ -42,16 +50,31 @@ export function MnemonicInputFields({
mnemonicWords: string[];
onChange?: (mnemonicWords: string[]) => void;
}) {
const gap = 6;
return (
<FlatList
data={mnemonicWords}
numColumns={3}
renderItem={({ item, index }) => <Item item={item} index={index} />}
keyExtractor={(item, index) => {
return `${item}.${index}`.toString();
}}
initialNumToRender={mnemonicWords.length}
scrollEnabled={false}
keyExtractor={(_, index) => index.toString()}
contentContainerStyle={{ gap }}
columnWrapperStyle={{ gap }}
renderItem={({ item: word, index }) => {
return (
<ItemTextInput
word={word}
index={index}
onChangeText={(word) => {
if (onChange) {
const newMnemonicWords = [...mnemonicWords];
newMnemonicWords[index] = word;
onChange(newMnemonicWords);
}
}}
/>
);
}}
/>
);
}
Expand All @@ -60,18 +83,17 @@ const styles = StyleSheet.create({
container: {
flex: 1,
paddingHorizontal: 6,
paddingVertical: 12,
margin: 4,
flexDirection: "row",
alignItems: "center",
borderRadius: 8,
borderWidth: 2,
overflow: "hidden",
},
input: {
marginLeft: 4,
paddingLeft: 4,
fontWeight: "700",
fontSize: 14,
paddingBottom: 2,
width: "100%",
paddingVertical: 12,
},
});
135 changes: 123 additions & 12 deletions packages/app-mobile/src/components/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
StyleSheet,
Text,
View,
ScrollView,
} from "react-native";

import * as Clipboard from "expo-clipboard";
Expand All @@ -31,14 +32,52 @@ export { PasswordInput } from "./PasswordInput";
export { StyledTextInput } from "./StyledTextInput";
export { TokenAmountHeader } from "./TokenAmountHeader";
export { StyledTokenTextInput } from "./TokenInputField";
//
// function getRandomColor() { var letters = "0123456789ABCDEF";
// var color = "#";
// for (var i = 0; i < 6; i++) {
// color += letters[Math.floor(Math.random() * 16)];
// }
// return color;
// }

export function CallToAction({
icon,
title,
onPress,
}: {
icon: JSX.Element;
title: string;
onPress: () => void;
}) {
const theme = useTheme();
return (
<Pressable
style={[
ctaStyles.container,
{
borderColor: theme.custom.colors.borderFull,
backgroundColor: theme.custom.colors.nav,
},
]}
onPress={onPress}
>
<View style={ctaStyles.iconContainer}>{icon}</View>
<Text style={[ctaStyles.text, { color: theme.custom.colors.fontColor }]}>
{title}
</Text>
</Pressable>
);
}

const ctaStyles = StyleSheet.create({
container: {
padding: 12,
borderWidth: 2,
borderRadius: 12,
flexDirection: "row",
alignItems: "center",
},
iconContainer: {
marginRight: 8,
},
text: {
fontSize: 16,
fontWeight: "500",
},
});

export function StyledText({
children,
Expand All @@ -58,21 +97,37 @@ export function StyledText({
}

export function Screen({
scrollable,
children,
style,
}: {
scrollable?: boolean;
children: JSX.Element | JSX.Element[];
style?: StyleProp<ViewStyle>;
}) {
const theme = useTheme();
if (scrollable) {
return (
<ScrollView
contentContainerStyle={[screenStyles.scrollContainer, style]}
style={[
screenStyles.container,
{
backgroundColor: theme.custom.colors.background,
},
]}
>
{children}
</ScrollView>
);
}

return (
<View
style={[
screenStyles.container,
{
flex: 1,
backgroundColor: theme.custom.colors.background,
paddingHorizontal: 16,
paddingVertical: 16,
},
style,
]}
Expand All @@ -82,6 +137,17 @@ export function Screen({
);
}

const screenStyles = StyleSheet.create({
scrollContainer: {
flexGrow: 1,
},
container: {
flex: 1,
paddingHorizontal: 16,
paddingVertical: 16,
},
});

export function BaseButton({
label,
buttonStyle,
Expand Down Expand Up @@ -124,7 +190,7 @@ export function BaseButton({
>
{loading ? "loading..." : label}
</Text>
{icon}
{icon ? <Margin left={8}>{icon}</Margin> : null}
</Pressable>
);
}
Expand All @@ -145,6 +211,34 @@ const baseButtonStyles = StyleSheet.create({
},
});

export function LinkButton({
label,
onPress,
disabled,
loading,
...props
}: {
label: string;
onPress?: () => void;
disabled?: boolean;
loading?: boolean;
}) {
const theme = useTheme();
return (
<BaseButton
label={label}
onPress={onPress}
disabled={disabled}
loading={loading}
buttonStyle={{ backgroundColor: "transparent" }}
labelStyle={{
color: theme.custom.colors.secondaryButtonTextColor,
}}
{...props}
/>
);
}

export function PrimaryButton({
label,
onPress,
Expand Down Expand Up @@ -707,6 +801,23 @@ export function CopyButton({ text }: { text: string }): JSX.Element {
);
}

export function PasteButton({
onPaste,
}: {
onPaste: (text: string) => void;
}): JSX.Element {
return (
<SecondaryButton
label="Paste from clipboard"
icon={<ContentCopyIcon size={18} />}
onPress={async () => {
const string = await Clipboard.getStringAsync();
onPaste(string);
}}
/>
);
}

export function CopyButtonIcon({ text }: { text: string }): JSX.Element {
return (
<Pressable
Expand Down
9 changes: 9 additions & 0 deletions packages/app-mobile/src/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,12 @@ export function maybeRender(

return null;
}

export function getRandomColor() {
const letters = "0123456789ABCDEF";
let color = "#";
for (let i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
Loading

1 comment on commit d4203f2

@vercel
Copy link

@vercel vercel bot commented on d4203f2 Mar 3, 2023

Choose a reason for hiding this comment

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

Please sign in to comment.