-
Notifications
You must be signed in to change notification settings - Fork 49
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
20 changed files
with
1,771 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,18 +2,18 @@ | |
"name": "mobile", | ||
"version": "1.0.0", | ||
"main": "index.js", | ||
"packageManager": "[email protected]", | ||
"packageManager": "[email protected]", | ||
"scripts": { | ||
"dev": "expo start", | ||
"build:web": "npx expo export --platform web", | ||
"start": "expo start", | ||
"start:tunnel": "expo start --tunnel", | ||
"android": "expo run:android", | ||
"build:android": "expo build:android", | ||
"build:android:eas":"eas build -p android", | ||
"build:android:eas": "eas build -p android", | ||
"ios": "expo run:ios", | ||
"build:ios": "expo build:ios", | ||
"build:ios:eas":"eas build -p ios", | ||
"build:ios:eas": "eas build -p ios", | ||
"web": "expo start --web", | ||
"postinstall": "patch-package", | ||
"format": "prettier --write \"src/**/*.{ts,tsx}\"", | ||
|
@@ -75,6 +75,7 @@ | |
"expo": "~51.0.28", | ||
"expo-application": "^5.9.1", | ||
"expo-auth-session": "^5.5.2", | ||
"expo-av": "~14.0.7", | ||
"expo-camera": "^15.0.16", | ||
"expo-clipboard": "~6.0.3", | ||
"expo-constants": "^16.0.2", | ||
|
@@ -146,4 +147,4 @@ | |
"typescript": "~5.3.3" | ||
}, | ||
"private": true | ||
} | ||
} |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
import {NostrEvent} from '@nostr-dev-kit/ndk'; | ||
import {ResizeMode, Video} from 'expo-av'; | ||
import React, {useEffect, useState} from 'react'; | ||
import {Pressable, TouchableOpacity, View} from 'react-native'; | ||
|
||
import {BookmarkIcon, LikeIcon, RepostIcon} from '../../assets/icons'; | ||
import {useStyles} from '../../hooks'; | ||
import stylesheet from './styles'; | ||
|
||
const NostrVideo = ({item, shouldPlay}: {shouldPlay: boolean; item: NostrEvent}) => { | ||
const video = React.useRef<Video | null>(null); | ||
const [status, setStatus] = useState<any>(null); | ||
const styles = useStyles(stylesheet); | ||
|
||
useEffect(() => { | ||
if (!video.current) return; | ||
|
||
if (shouldPlay) { | ||
video.current.playAsync(); | ||
} else { | ||
video.current.pauseAsync(); | ||
video.current.setPositionAsync(0); | ||
} | ||
}, [shouldPlay]); | ||
|
||
const extractVideoURL = (event: NostrEvent) => { | ||
return event?.tags?.find((tag) => tag?.[0] === 'url')?.[1] || ''; | ||
}; | ||
|
||
const handleLike = () => { | ||
console.log('like'); | ||
//todo: integrate hook | ||
}; | ||
|
||
const handleRepost = () => { | ||
console.log('like'); | ||
//todo: integrate hook | ||
}; | ||
|
||
const handleBookmark = () => { | ||
console.log('like'); | ||
//todo: integrate hook | ||
}; | ||
|
||
return ( | ||
<> | ||
<Pressable | ||
onPress={() => | ||
status.isPlaying ? video.current?.pauseAsync() : video.current?.playAsync() | ||
} | ||
> | ||
<View style={styles.videoContainer}> | ||
<Video | ||
ref={video} | ||
source={{uri: extractVideoURL(item)}} | ||
style={styles.video} | ||
isLooping | ||
resizeMode={ResizeMode.COVER} | ||
useNativeControls={false} | ||
onPlaybackStatusUpdate={(status) => setStatus(() => status)} | ||
videoStyle={styles.innerVideo} | ||
/> | ||
</View> | ||
</Pressable> | ||
<View style={styles.actionsContainer}> | ||
<TouchableOpacity onPress={handleLike}> | ||
<LikeIcon width={20} height={20} color="white" /> | ||
</TouchableOpacity> | ||
<TouchableOpacity onPress={handleRepost}> | ||
<RepostIcon width={20} height={20} color="white" /> | ||
</TouchableOpacity> | ||
<TouchableOpacity style={{width: 15}} onPress={handleBookmark}> | ||
<BookmarkIcon width={15} height={20} color="white" /> | ||
</TouchableOpacity> | ||
</View> | ||
</> | ||
); | ||
}; | ||
|
||
export default NostrVideo; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import {Dimensions} from 'react-native'; | ||
|
||
import {ThemedStyleSheet} from '../../styles'; | ||
|
||
export default ThemedStyleSheet(() => ({ | ||
videoContainer: { | ||
width: Dimensions.get('window').width, | ||
height: Dimensions.get('window').height - 60, | ||
}, | ||
video: { | ||
width: '100%', | ||
height: '100%', | ||
}, | ||
innerVideo: { | ||
height: Dimensions.get('window').height - 60, | ||
}, | ||
actionsContainer: { | ||
position: 'absolute', | ||
right: 20, | ||
bottom: 40, | ||
display: 'flex', | ||
flexDirection: 'column', | ||
gap: 20, | ||
alignItems: 'center', | ||
}, | ||
})); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import {createContext, useCallback, useContext, useRef} from 'react'; | ||
|
||
import {Modalize} from '../components'; | ||
import TokenSwapView from '../modules/Swap'; | ||
|
||
// Create a context for Swap | ||
export const SwapModalContext = createContext<{ | ||
showSwap: () => void; | ||
hideSwap: () => void; | ||
} | null>(null); | ||
|
||
export const SwapModalEVMProvider: React.FC<React.PropsWithChildren> = ({children}) => { | ||
const modalizeRef = useRef<Modalize | any>(null); | ||
|
||
const showSwap = useCallback(() => { | ||
modalizeRef?.current.open(); | ||
}, []); | ||
|
||
const hideSwap = useCallback(() => { | ||
modalizeRef?.current.close(); | ||
}, [modalizeRef]); | ||
|
||
return ( | ||
<SwapModalContext.Provider | ||
value={{ | ||
showSwap, | ||
hideSwap, | ||
}} | ||
> | ||
{children} | ||
|
||
<Modalize | ||
modalStyle={{ | ||
maxWidth: 500, | ||
width: '100%', | ||
marginLeft: 'auto', | ||
marginRight: 'auto', | ||
marginBottom: 20, | ||
borderRadius: 20, | ||
}} | ||
ref={modalizeRef} | ||
adjustToContentHeight | ||
> | ||
<TokenSwapView showHeader /> | ||
</Modalize> | ||
</SwapModalContext.Provider> | ||
); | ||
}; | ||
|
||
export const useSwapModal = () => { | ||
const context = useContext(SwapModalContext); | ||
if (!context) { | ||
throw new Error('useSwap must be used within a SwapProvider'); | ||
} | ||
|
||
return context; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import {NostrEvent} from '@nostr-dev-kit/ndk'; | ||
import {useGetVideos} from 'afk_nostr_sdk'; | ||
import React, {useRef, useState} from 'react'; | ||
import {FlatList, Text, View} from 'react-native'; | ||
|
||
import {InfoIcon} from '../../assets/icons'; | ||
import NostrVideo from '../../components/NostrVideo'; | ||
import {useStyles, useTheme} from '../../hooks'; | ||
import {mockEvents} from '../../utils/dummyData'; | ||
import stylesheet from './styles'; | ||
|
||
const ShortVideosModule = () => { | ||
const styles = useStyles(stylesheet); | ||
const {theme} = useTheme(); | ||
const [currentViewableItemIndex, setCurrentViewableItemIndex] = useState(0); | ||
const viewabilityConfig = {viewAreaCoveragePercentThreshold: 50}; | ||
const videos = useGetVideos(); | ||
const [videosEvents, setVideosEvents] = useState<NostrEvent[]>( | ||
videos?.data?.pages?.flat() as NostrEvent[], | ||
); | ||
|
||
const fetchNostrEvents = async () => { | ||
// This mock should be replaced with actual implementation (hook integration to get videos) | ||
setVideosEvents(mockEvents); | ||
}; | ||
|
||
const onViewableItemsChanged = ({viewableItems}: any) => { | ||
if (viewableItems.length > 0) { | ||
setCurrentViewableItemIndex(viewableItems[0].index ?? 0); | ||
} | ||
}; | ||
|
||
const viewabilityConfigCallbackPairs = useRef([{viewabilityConfig, onViewableItemsChanged}]); | ||
|
||
return ( | ||
<View style={styles.container}> | ||
{videosEvents.length > 0 ? ( | ||
<FlatList | ||
style={styles.list} | ||
data={videosEvents} | ||
renderItem={({item, index}) => ( | ||
<NostrVideo item={item} shouldPlay={index === currentViewableItemIndex} /> | ||
)} | ||
keyExtractor={(item, index) => item.content + index} | ||
pagingEnabled | ||
horizontal={false} | ||
showsVerticalScrollIndicator={false} | ||
viewabilityConfigCallbackPairs={viewabilityConfigCallbackPairs.current} | ||
/> | ||
) : ( | ||
<View style={styles.noDataContainer}> | ||
<InfoIcon width={30} height={30} color={theme.colors.primary} /> | ||
<Text style={styles.noDataText}>No videos uploaded yet.</Text> | ||
</View> | ||
)} | ||
</View> | ||
); | ||
}; | ||
|
||
export default ShortVideosModule; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import {ThemedStyleSheet} from '../../styles'; | ||
|
||
export default ThemedStyleSheet((theme) => ({ | ||
container: { | ||
flex: 1, | ||
height: '100%', | ||
}, | ||
list: { | ||
height: '100%', | ||
}, | ||
noDataContainer: { | ||
display: 'flex', | ||
flexDirection: 'column', | ||
alignItems: 'center', | ||
gap: 20, | ||
marginTop: 20, | ||
}, | ||
noDataText: { | ||
color: theme.colors.text, | ||
textAlign: 'center', | ||
fontSize: 14, | ||
fontWeight: 'bold', | ||
}, | ||
})); |
Oops, something went wrong.