Skip to content

Commit

Permalink
Merge pull request #4708 from EdgeApp/sam/flipinput2-android-styling
Browse files Browse the repository at this point in the history
Fix placeholder and consistent Android/iOS styling for FlipInput2
  • Loading branch information
paullinator authored Jan 13, 2024
2 parents 95d17ec + b7b86a6 commit 44ebcbf
Showing 1 changed file with 82 additions and 72 deletions.
154 changes: 82 additions & 72 deletions src/components/themed/FlipInput2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -136,35 +136,28 @@ export const FlipInput2 = React.forwardRef<FlipInputRef, Props>((props: Props, r
const zeroAmount = zeroString(amounts[fieldNum])
const primaryAmount = zeroAmount && !amountFocused ? '' : amounts[fieldNum]

const placeholderOrAmount = zeroAmount && !amountFocused ? lstrings.string_tap_to_edit : primaryAmount
const showBottomCurrency = amountFocused || !zeroAmount
const isEnterTextMode = amountFocused || !zeroAmount
const currencyName = fieldInfos[fieldNum].currencyName

return (
<BottomContainerView key="bottom">
<ValueContainerView>
<AmountAnimatedNumericInput
value={primaryAmount}
focusAnimation={focusAnimation}
maxDecimals={fieldInfos[fieldNum].maxEntryDecimals}
// HACK: For some reason there's no way to avoid the rightmost
// visual cutoff of the 'Amount' string in Android. Pad with an
// extra space.
placeholder={Platform.OS === 'android' ? placeholderOrAmount + ' ' : placeholderOrAmount}
placeholderTextColor={theme.textInputPlaceholderColor}
onChangeText={onNumericInputChange}
autoCorrect={false}
editable={editable}
returnKeyType={returnKeyType}
autoFocus={primaryField === fieldNum && keyboardVisible}
ref={inputRefs[fieldNum]}
onSubmitEditing={onNext}
inputAccessoryViewID={inputAccessoryViewID}
onFocus={handleBottomFocus}
onBlur={handleBottomBlur}
/>
{showBottomCurrency ? <CurrencySymbolAnimatedText focusAnimation={focusAnimation}>{' ' + currencyName}</CurrencySymbolAnimatedText> : null}
</ValueContainerView>
<AmountAnimatedNumericInput
value={primaryAmount}
focusAnimation={focusAnimation}
maxDecimals={fieldInfos[fieldNum].maxEntryDecimals}
onChangeText={onNumericInputChange}
autoCorrect={false}
editable={editable}
returnKeyType={returnKeyType}
autoFocus={primaryField === fieldNum && keyboardVisible}
ref={inputRefs[fieldNum]}
onSubmitEditing={onNext}
inputAccessoryViewID={inputAccessoryViewID}
onFocus={handleBottomFocus}
onBlur={handleBottomBlur}
/>
{!isEnterTextMode ? <PlaceholderAnimatedText>{lstrings.string_tap_to_edit}</PlaceholderAnimatedText> : null}
{isEnterTextMode ? <CurrencySymbolAnimatedText focusAnimation={focusAnimation}>{' ' + currencyName}</CurrencySymbolAnimatedText> : null}
</BottomContainerView>
)
}
Expand All @@ -179,9 +172,9 @@ export const FlipInput2 = React.forwardRef<FlipInputRef, Props>((props: Props, r
topText = `${topText} ${fieldInfo.currencyName}`
return (
<TouchableWithoutFeedback onPress={onToggleFlipInput} key="top">
<PlaceholderText numberOfLines={1} adjustsFontSizeToFit minimumFontScale={0.65}>
<TopAmountText numberOfLines={1} adjustsFontSizeToFit minimumFontScale={0.65}>
{topText}
</PlaceholderText>
</TopAmountText>
</TouchableWithoutFeedback>
)
}
Expand All @@ -195,16 +188,19 @@ export const FlipInput2 = React.forwardRef<FlipInputRef, Props>((props: Props, r
return (
<>
<ContainerView>
<InnerView focusAnimation={focusAnimation}>
<FrontAnimatedView animatedValue={animatedValue} pointerEvents={flipField(primaryField) ? 'auto' : 'none'}>
{renderTopRow(1)}
{renderBottomRow(0)}
</FrontAnimatedView>
<BackAnimatedView animatedValue={animatedValue} pointerEvents={primaryField ? 'auto' : 'none'}>
{renderTopRow(0)}
{renderBottomRow(1)}
</BackAnimatedView>
</InnerView>
<AmountFieldContainerTouchable accessible={false} onPress={() => inputRefs[primaryField].current?.focus()}>
<InnerView focusAnimation={focusAnimation}>
<FrontAnimatedView animatedValue={animatedValue} pointerEvents={flipField(primaryField) ? 'auto' : 'none'}>
{renderTopRow(1)}
{renderBottomRow(0)}
</FrontAnimatedView>
<BackAnimatedView animatedValue={animatedValue} pointerEvents={primaryField ? 'auto' : 'none'}>
{renderTopRow(0)}
{renderBottomRow(1)}
</BackAnimatedView>
</InnerView>
</AmountFieldContainerTouchable>

<ButtonBox onPress={onToggleFlipInput} paddingRem={[0.5, 0, 0.5, 0.5]}>
<FlipIcon color={theme.iconTappable} size={theme.rem(1.5)} />
</ButtonBox>
Expand Down Expand Up @@ -275,64 +271,78 @@ const BackAnimatedView = styled(Animated.View)<{ animatedValue: SharedValue<numb
})
])

const PlaceholderText = styled(Text)(theme => () => [
const TopAmountText = styled(Text)(theme => () => [
{
alignSelf: 'flex-start',
color: theme.textInputPlaceholderColor,
fontFamily: theme.fontFaceDefault,
fontSize: theme.rem(0.8),
includeFontPadding: false
}
])

const AmountAnimatedNumericInput = styledWithRef(AnimatedNumericInput)<{ focusAnimation: SharedValue<number> }>(theme => ({ focusAnimation }) => {
const isIos = Platform.OS === 'ios'
const interpolateTextColor = useAnimatedColorInterpolateFn(theme.textInputTextColor, theme.textInputTextColorFocused)
return [
{
paddingRight: isIos ? 0 : theme.rem(0.25),
includeFontPadding: false,
fontFamily: theme.fontFaceMedium,
fontSize: isIos ? theme.rem(1.5) : theme.rem(1.45)
},
useAnimatedStyle(() => ({
color: interpolateTextColor(focusAnimation)
}))
]
})
const AmountAnimatedNumericInput = styledWithRef(AnimatedNumericInput)<{ focusAnimation: SharedValue<number>; value: string }>(
theme =>
({ focusAnimation, value }) => {
const isAndroid = Platform.OS === 'android'
const interpolateTextColor = useAnimatedColorInterpolateFn(theme.textInputTextColor, theme.textInputTextColorFocused)
const characterLength = value.length
return [
{
includeFontPadding: false,
fontFamily: theme.fontFaceMedium,
fontSize: theme.rem(1.5),
// Android has more space added to the width of the input
// after the last character in the input. It seems to be
// setting a min-width to the input to roughly 2 characters in size.
// We can compensate for this with a negative margin when the character length
// is less then 2 characters.
marginRight: isAndroid ? -theme.rem(Math.max(0, 2 - characterLength) * 0.4) : 0,
padding: 0
},
useAnimatedStyle(() => ({
color: interpolateTextColor(focusAnimation)
}))
]
}
)

const PlaceholderAnimatedText = styled(Animated.Text)(theme => ({
position: 'absolute',
left: 0,
top: 0,
includeFontPadding: false,
color: theme.textInputPlaceholderColor,
fontFamily: theme.fontFaceMedium,
fontSize: theme.rem(1.5)
}))

const CurrencySymbolAnimatedText = styled(Animated.Text)<{ focusAnimation: SharedValue<number> }>(theme => ({ focusAnimation }) => {
const isIos = Platform.OS === 'ios'
const interpolateTextColor = useAnimatedColorInterpolateFn(theme.textInputTextColor, theme.textInputTextColorFocused)
return [
{
fontFamily: theme.fontFaceDefault,
fontSize: theme.rem(1),
includeFontPadding: false,
paddingTop: isIos ? theme.rem(0.125) : theme.rem(1),
marginLeft: isIos ? 0 : -theme.rem(0.25)
fontFamily: theme.fontFaceMedium,
fontSize: theme.rem(1.5),
includeFontPadding: false
},
useAnimatedStyle(() => ({
color: interpolateTextColor(focusAnimation)
}))
]
})

const BottomContainerView = styled(View)(theme => ({
flexDirection: 'row',
marginRight: theme.rem(1.5),
minHeight: theme.rem(2)
}))

const ValueContainerView = styled(View)(theme => {
const isIos = Platform.OS === 'ios'
const AmountFieldContainerTouchable = styled(TouchableWithoutFeedback)(theme => {
return {
flexDirection: 'row',
marginRight: theme.rem(0.5),
marginLeft: isIos ? 0 : -6,
marginTop: isIos ? 0 : -theme.rem(0.75),
marginBottom: isIos ? 0 : -theme.rem(1)
marginRight: theme.rem(1.5),
minHeight: theme.rem(2)
}
})

const BottomContainerView = styled(View)({
flexDirection: 'row',
alignItems: 'center'
})

function useAnimatedColorInterpolateFn(fromColor: string, toColor: string) {
const interpolateFn = useMemo(() => {
return (focusValue: SharedValue<number>) => {
Expand Down

0 comments on commit 44ebcbf

Please sign in to comment.