Skip to content

Commit 0db0718

Browse files
authored
Merge pull request zingolabs#878 from Brocter/arrow_button_ui/fix
fix button fuctionality and add new ui to all components being used.
2 parents 2db844f + d3a3dba commit 0db0718

File tree

5 files changed

+676
-438
lines changed

5 files changed

+676
-438
lines changed

components/AddressBook/AddressBook.tsx

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ const AddressBook: React.FunctionComponent<AddressBookProps> = ({
6969
const [currentItem, setCurrentItem] = useState<number | null>(null);
7070
const [action, setAction] = useState<AddressBookActionEnum | null>(null);
7171
const [isAtTop, setIsAtTop] = useState<boolean>(true);
72+
const [isScrollingToTop, setIsScrollingToTop] = useState<boolean>(false);
73+
const scrollTimeoutRef = useRef<NodeJS.Timeout | null>(null);
7274
const [loading, setLoading] = useState<boolean>(true);
7375
const [filter, setFilter] = useState<FilterEnum>(FilterEnum.all);
7476

@@ -175,17 +177,48 @@ const AddressBook: React.FunctionComponent<AddressBookProps> = ({
175177
cancel();
176178
};
177179

178-
const handleScrollToTop = () => {
179-
if (scrollViewRef.current) {
180+
const handleScrollToTop = useCallback(() => {
181+
if (scrollViewRef.current && !isScrollingToTop) {
182+
setIsScrollingToTop(true);
183+
184+
// Clear any existing timeout
185+
if (scrollTimeoutRef.current) {
186+
clearTimeout(scrollTimeoutRef.current);
187+
}
188+
189+
// Force set to top immediately for UI feedback
190+
setIsAtTop(true);
191+
192+
// Scroll to top
180193
scrollViewRef.current.scrollTo({ y: 0, animated: true });
194+
195+
// Set timeout to reset scrolling state
196+
scrollTimeoutRef.current = setTimeout(() => {
197+
setIsScrollingToTop(false);
198+
// Double-check position after scroll animation
199+
if (scrollViewRef.current) {
200+
setIsAtTop(true); // For ScrollView, assume success
201+
}
202+
}, 800);
181203
}
182-
};
204+
}, [isScrollingToTop]);
183205

184-
const handleScroll = (event: NativeSyntheticEvent<NativeScrollEvent>) => {
206+
const handleScroll = useCallback((event: NativeSyntheticEvent<NativeScrollEvent>) => {
185207
const { contentOffset } = event.nativeEvent;
186-
const isTop = contentOffset.y === 0;
208+
const isTop = contentOffset.y <= 100;
209+
210+
// If we're scrolling to top and we've reached the top, stop the scrolling state
211+
if (isScrollingToTop && isTop) {
212+
setIsScrollingToTop(false);
213+
if (scrollTimeoutRef.current) {
214+
clearTimeout(scrollTimeoutRef.current);
215+
scrollTimeoutRef.current = null;
216+
}
217+
}
218+
219+
// Always update isAtTop for manual scrolling
187220
setIsAtTop(isTop);
188-
};
221+
}, [isScrollingToTop]);
189222

190223
//console.log('render Address Book - 4', currentItem, action, addressBook);
191224

@@ -453,10 +486,24 @@ const AddressBook: React.FunctionComponent<AddressBookProps> = ({
453486
)}
454487
</ScrollView>
455488
{!isAtTop && (
456-
<TouchableOpacity onPress={handleScrollToTop} style={{ position: 'absolute', bottom: 105, right: 10 }}>
489+
<TouchableOpacity
490+
onPress={handleScrollToTop}
491+
disabled={isScrollingToTop}
492+
style={{
493+
position: 'absolute',
494+
bottom: 105,
495+
right: 10,
496+
paddingHorizontal: 5,
497+
paddingVertical: 10,
498+
backgroundColor: isScrollingToTop ? colors.primaryDisabled : colors.sideMenuBackground,
499+
borderRadius: 50,
500+
borderWidth: 1,
501+
borderColor: isScrollingToTop ? colors.primaryDisabled : colors.zingo,
502+
opacity: isScrollingToTop ? 0.5 : 1,
503+
}}>
457504
<FontAwesomeIcon
458505
style={{ marginLeft: 5, marginRight: 5, marginTop: 0 }}
459-
size={50}
506+
size={20}
460507
icon={faAnglesUp}
461508
color={colors.zingo}
462509
/>

components/AddressList/AddressList.tsx

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ const AddressList: React.FunctionComponent<AddressListProps> = ({
5959
const [addressesSliced, setAddressesSliced] = useState<(UnifiedAddressClass | TransparentAddressClass)[]>([]);
6060

6161
const [isAtTop, setIsAtTop] = useState<boolean>(true);
62+
const [isScrollingToTop, setIsScrollingToTop] = useState<boolean>(false);
63+
const scrollTimeoutRef = useRef<NodeJS.Timeout | null>(null);
6264
const [loading, setLoading] = useState<boolean>(true);
6365

6466
const scrollViewRef = useRef<ScrollView>(null);
@@ -89,17 +91,48 @@ const AddressList: React.FunctionComponent<AddressListProps> = ({
8991
setNumAl(numAl + 50);
9092
}, [numAl]);
9193

92-
const handleScrollToTop = () => {
93-
if (scrollViewRef.current) {
94+
const handleScrollToTop = useCallback(() => {
95+
if (scrollViewRef.current && !isScrollingToTop) {
96+
setIsScrollingToTop(true);
97+
98+
// Clear any existing timeout
99+
if (scrollTimeoutRef.current) {
100+
clearTimeout(scrollTimeoutRef.current);
101+
}
102+
103+
// Force set to top immediately for UI feedback
104+
setIsAtTop(true);
105+
106+
// Scroll to top
94107
scrollViewRef.current.scrollTo({ y: 0, animated: true });
108+
109+
// Set timeout to reset scrolling state
110+
scrollTimeoutRef.current = setTimeout(() => {
111+
setIsScrollingToTop(false);
112+
// Double-check position after scroll animation
113+
if (scrollViewRef.current) {
114+
setIsAtTop(true); // For ScrollView, assume success
115+
}
116+
}, 800);
95117
}
96-
};
118+
}, [isScrollingToTop]);
97119

98-
const handleScroll = (event: NativeSyntheticEvent<NativeScrollEvent>) => {
120+
const handleScroll = useCallback((event: NativeSyntheticEvent<NativeScrollEvent>) => {
99121
const { contentOffset } = event.nativeEvent;
100-
const isTop = contentOffset.y === 0;
122+
const isTop = contentOffset.y <= 100;
123+
124+
// If we're scrolling to top and we've reached the top, stop the scrolling state
125+
if (isScrollingToTop && isTop) {
126+
setIsScrollingToTop(false);
127+
if (scrollTimeoutRef.current) {
128+
clearTimeout(scrollTimeoutRef.current);
129+
scrollTimeoutRef.current = null;
130+
}
131+
}
132+
133+
// Always update isAtTop for manual scrolling
101134
setIsAtTop(isTop);
102-
};
135+
}, [isScrollingToTop]);
103136

104137
//console.log('render Address Book - 4', currentItem, action, addressBook);
105138

@@ -217,10 +250,24 @@ const AddressList: React.FunctionComponent<AddressListProps> = ({
217250
)}
218251
</ScrollView>
219252
{!isAtTop && (
220-
<TouchableOpacity onPress={handleScrollToTop} style={{ position: 'absolute', bottom: 105, right: 10 }}>
253+
<TouchableOpacity
254+
onPress={handleScrollToTop}
255+
disabled={isScrollingToTop}
256+
style={{
257+
position: 'absolute',
258+
bottom: 105,
259+
right: 10,
260+
paddingHorizontal: 5,
261+
paddingVertical: 10,
262+
backgroundColor: isScrollingToTop ? colors.primaryDisabled : colors.sideMenuBackground,
263+
borderRadius: 50,
264+
borderWidth: 1,
265+
borderColor: isScrollingToTop ? colors.primaryDisabled : colors.zingo,
266+
opacity: isScrollingToTop ? 0.5 : 1,
267+
}}>
221268
<FontAwesomeIcon
222269
style={{ marginLeft: 5, marginRight: 5, marginTop: 0 }}
223-
size={50}
270+
size={20}
224271
icon={faAnglesUp}
225272
color={colors.zingo}
226273
/>

components/History/History.tsx

Lines changed: 72 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import 'moment/locale/tr';
1818

1919
import { useTheme } from '@react-navigation/native';
2020
import { FontAwesomeIcon } from '@fortawesome/react-native-fontawesome';
21-
import { faAnglesUp, faAngleUp, faArrowCircleUp, faArrowUp } from '@fortawesome/free-solid-svg-icons';
21+
import { faAngleUp } from '@fortawesome/free-solid-svg-icons';
2222

2323
import {
2424
ButtonTypeEnum,
@@ -107,6 +107,8 @@ const History: React.FunctionComponent<HistoryProps> = ({
107107
const [valueTransfersSliced, setValueTransfersSliced] = useState<ValueTransferType[]>([]);
108108
const [valueTransfersFiltered, setValueTransfersFiltered] = useState<ValueTransferType[]>([]);
109109
const [isAtTop, setIsAtTop] = useState<boolean>(true);
110+
const [isScrollingToTop, setIsScrollingToTop] = useState<boolean>(false);
111+
const scrollTimeoutRef = useRef<NodeJS.Timeout | null>(null);
110112
const [loading, setLoading] = useState<boolean>(true);
111113
const [filter, setFilter] = useState<FilterEnum>(FilterEnum.all);
112114
const [showFooter, setShowFooter] = useState<boolean>(false);
@@ -180,28 +182,80 @@ const History: React.FunctionComponent<HistoryProps> = ({
180182
setDataProvider(data => data.cloneWithRows(vtfs));
181183
}, [numVt, valueTransfersFiltered]);
182184

185+
const handleScrollToTop = useCallback(() => {
186+
if (scrollViewRef.current && !isScrollingToTop) {
187+
setIsScrollingToTop(true);
188+
189+
// Clear any existing timeout
190+
if (scrollTimeoutRef.current) {
191+
clearTimeout(scrollTimeoutRef.current);
192+
}
193+
194+
// Force set to top immediately for UI feedback
195+
setIsAtTop(true);
196+
197+
// Try multiple scroll methods for reliability
198+
try {
199+
// Method 1: Use scrollToTop
200+
scrollViewRef.current.scrollToTop(true);
201+
202+
// Method 2: Fallback to scrollToIndex if scrollToTop fails
203+
setTimeout(() => {
204+
if (scrollViewRef.current) {
205+
try {
206+
scrollViewRef.current.scrollToIndex(0, true);
207+
} catch (e) {
208+
console.log('scrollToIndex fallback failed:', e);
209+
}
210+
}
211+
}, 100);
212+
} catch (error) {
213+
console.log('scrollToTop failed:', error);
214+
}
215+
216+
// Set timeout to reset scrolling state - longer timeout for animation
217+
scrollTimeoutRef.current = setTimeout(() => {
218+
setIsScrollingToTop(false);
219+
// Double-check position after scroll animation
220+
if (scrollViewRef.current) {
221+
const offset = scrollViewRef.current.getCurrentScrollOffset();
222+
setIsAtTop(offset <= 100);
223+
}
224+
}, 800);
225+
}
226+
}, [isScrollingToTop]);
227+
183228
useEffect(() => {
184229
if (scrollToTop) {
185230
handleScrollToTop();
186231
setScrollToTop(false);
187232
}
188-
}, [scrollToTop, setScrollToTop]);
233+
}, [scrollToTop, handleScrollToTop, setScrollToTop]);
189234

190235
const loadMoreClicked = useCallback(() => {
191236
setNumVt(numVt + 50);
192237
}, [numVt]);
193238

194-
const handleScrollToTop = () => {
195-
if (scrollViewRef.current) {
196-
scrollViewRef.current.scrollToTop(true);
197-
}
198-
};
239+
const handleScroll = useCallback(
240+
(_rawEvent: ScrollEvent, _offsetX: number, offsetY: number) => {
241+
const isTop = offsetY <= 100;
199242

200-
const handleScroll = (_rawEvent: ScrollEvent, _offsetX: number, offsetY: number) => {
201-
const isTop = offsetY <= 0;
202-
setIsAtTop(isTop);
203-
setShowFooter(true);
204-
};
243+
// If we're scrolling to top and we've reached the top, stop the scrolling state
244+
if (isScrollingToTop && isTop) {
245+
setIsScrollingToTop(false);
246+
if (scrollTimeoutRef.current) {
247+
clearTimeout(scrollTimeoutRef.current);
248+
scrollTimeoutRef.current = null;
249+
}
250+
}
251+
252+
// Always update isAtTop for manual scrolling
253+
setIsAtTop(isTop);
254+
255+
setShowFooter(offsetY > 0);
256+
},
257+
[isScrollingToTop],
258+
);
205259

206260
const setValueTransferDetailModalShow = (index: number, vt: ValueTransferType) => {
207261
return magicModal.show(
@@ -447,17 +501,19 @@ const History: React.FunctionComponent<HistoryProps> = ({
447501
{!isAtTop && (
448502
<Pressable
449503
onPress={handleScrollToTop}
504+
disabled={isScrollingToTop}
450505
style={({ pressed }) => ({
451506
position: 'absolute',
452507
bottom: 30,
453508
right: 10,
454-
paddingHorizontal: 10,
455-
paddingVertical: 15,
456-
backgroundColor: colors.sideMenuBackground,
509+
paddingHorizontal: 5,
510+
paddingVertical: 10,
511+
backgroundColor: isScrollingToTop ? colors.primaryDisabled : colors.sideMenuBackground,
457512
borderRadius: 50,
458513
transform: [{ scale: pressed ? 0.9 : 1 }],
459514
borderWidth: 1,
460-
borderColor: colors.zingo,
515+
borderColor: isScrollingToTop ? colors.primaryDisabled : colors.zingo,
516+
opacity: isScrollingToTop ? 0.5 : 1,
461517
})}>
462518
<FontAwesomeIcon
463519
style={{ marginLeft: 5, marginRight: 5, marginTop: 0 }}

components/Messages/components/ContactList.tsx

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* eslint-disable react-native/no-inline-styles */
2-
import React, { useContext, useState, useEffect, useRef } from 'react';
2+
import React, { useContext, useState, useEffect, useRef, useCallback } from 'react';
33
import {
44
View,
55
ScrollView,
@@ -89,6 +89,8 @@ const ContactList: React.FunctionComponent<ContactListProps> = ({
8989

9090
const [contacts, setContacts] = useState<ContactType[]>([]);
9191
const [isAtTop, setIsAtTop] = useState<boolean>(true);
92+
const [isScrollingToTop, setIsScrollingToTop] = useState<boolean>(false);
93+
const scrollTimeoutRef = useRef<NodeJS.Timeout | null>(null);
9294
const [loading, setLoading] = useState<boolean>(true);
9395
const [filter, setFilter] = useState<FilterEnum>(FilterEnum.all);
9496
const [searchMode, setSearchMode] = useState<boolean>(false);
@@ -266,11 +268,22 @@ const ContactList: React.FunctionComponent<ContactListProps> = ({
266268
}
267269
};
268270

269-
const handleScroll = (event: NativeSyntheticEvent<NativeScrollEvent>) => {
271+
const handleScroll = useCallback((event: NativeSyntheticEvent<NativeScrollEvent>) => {
270272
const { contentOffset } = event.nativeEvent;
271-
const isTop = contentOffset.y === 0;
273+
const isTop = contentOffset.y <= 100;
274+
275+
// Always update isAtTop for manual scrolling
272276
setIsAtTop(isTop);
273-
};
277+
278+
// If we're scrolling to top and we've reached the top, stop the scrolling state
279+
if (isScrollingToTop && isTop) {
280+
setIsScrollingToTop(false);
281+
if (scrollTimeoutRef.current) {
282+
clearTimeout(scrollTimeoutRef.current);
283+
scrollTimeoutRef.current = null;
284+
}
285+
}
286+
}, [isScrollingToTop]);
274287

275288
const setMessagesAddressModalShow = (c: ContactType) => {
276289
return magicModal.show(() => <MessagesAddress
@@ -606,10 +619,24 @@ const ContactList: React.FunctionComponent<ContactListProps> = ({
606619
)}
607620
</ScrollView>
608621
{!isAtTop && (
609-
<TouchableOpacity onPress={handleScrollToTop} style={{ position: 'absolute', bottom: 30, right: 10 }}>
622+
<TouchableOpacity
623+
onPress={handleScrollToTop}
624+
disabled={isScrollingToTop}
625+
style={{
626+
position: 'absolute',
627+
bottom: 30,
628+
right: 10,
629+
paddingHorizontal: 5,
630+
paddingVertical: 10,
631+
backgroundColor: isScrollingToTop ? colors.primaryDisabled : colors.sideMenuBackground,
632+
borderRadius: 50,
633+
borderWidth: 1,
634+
borderColor: isScrollingToTop ? colors.primaryDisabled : colors.zingo,
635+
opacity: isScrollingToTop ? 0.5 : 1,
636+
}}>
610637
<FontAwesomeIcon
611638
style={{ marginLeft: 5, marginRight: 5, marginTop: 0 }}
612-
size={50}
639+
size={20}
613640
icon={faAnglesUp}
614641
color={colors.zingo}
615642
/>

0 commit comments

Comments
 (0)