Skip to content

Commit

Permalink
feat: distributed wikipedia tool
Browse files Browse the repository at this point in the history
Signed-off-by: Norman Meier <norman@berty.tech>
  • Loading branch information
n0izn0iz committed Feb 14, 2022
1 parent 960cfc8 commit 856e53c
Show file tree
Hide file tree
Showing 5 changed files with 152 additions and 0 deletions.
6 changes: 6 additions & 0 deletions rn/src/navigation/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
HTMLModule,
IPFSLogs,
Browser,
Wikipedia,
} from '@berty-labs/screens'
import { defaultColors } from '@berty-labs/styles'

Expand Down Expand Up @@ -111,6 +112,11 @@ export const Navigation: React.FC = React.memo(() => {
component={Browser}
options={{ ...screenOptions, title: 'Browser' }}
/>
<NavigationStack.Screen
name='Wikipedia'
component={Wikipedia}
options={{ ...screenOptions, title: 'Wikipedia' }}
/>
</NavigationStack.Navigator>
)
})
3 changes: 3 additions & 0 deletions rn/src/navigation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@ export type ScreensParams = {
}
IPFSLogs: undefined
Browser: undefined
Wikipedia: undefined
}

export type ScreenName = keyof ScreensParams

export type ScreenProps<T extends keyof ScreensParams> = NativeStackScreenProps<ScreensParams, T>

export type ScreenFC<T extends keyof ScreensParams> = React.FC<ScreenProps<T>>
131 changes: 131 additions & 0 deletions rn/src/screens/Wikipedia.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import React, { useState } from 'react'
import { Text } from 'react-native'
import WebView from 'react-native-webview'

import { ScreenFC } from '@berty-labs/navigation'
import {
AppScreenContainer,
Card,
LoaderCard,
LoaderScreen,
PressableCard,
} from '@berty-labs/components'
import { useGomobileIPFS } from '@berty-labs/react-redux'
import { defaultColors } from '@berty-labs/styles'
import { useAsyncTransform } from '@berty-labs/reactutil'

const PageLoader = () => <LoaderScreen text='Rendering page...' />

/*
❯ ipfs resolve /ipns/en.wikipedia-on-ipfs.org
/ipfs/bafybeiaysi4s6lnjev27ln5icwm6tueaw2vdykrtjkwiphwekaywqhcjze
❯ date
Sun Feb 13 16:25:01 CET 2022
*/
const fallbackCID = '/ipfs/bafybeiaysi4s6lnjev27ln5icwm6tueaw2vdykrtjkwiphwekaywqhcjze'
const fallbackDate = 'Sun Feb 13 16:25:01 CET 2022'

const space = 15

const cardStyle = { marginTop: space, marginHorizontal: space }

// TODO
// - Read wv navigation
// - Allow to pin specific pages to read and distribute them without internet
// - Use global state
// - Store current page and use it as first url
// - Allow to go back
// - Allow to go up
// - Allow to bookmark pages ? since no search could be really painful

export const Wikipedia: ScreenFC<'Wikipedia'> = () => {
const mobileIPFS = useGomobileIPFS()
const [localError, setLocalError] = useState('')
const [loaded, setLoaded] = useState(false)
const [showResolveError, setShowResolveError] = useState(false)
const [resolvedCID, loadedCID, resolveErr] = useAsyncTransform(
async (ac: AbortController) => {
if (!mobileIPFS.apiURL) {
return
}
setShowResolveError(true)
const reply = await fetch(
`${mobileIPFS.apiURL}/api/v0/resolve?arg=${encodeURIComponent(
'/ipns/en.wikipedia-on-ipfs.org',
)}`,
{
signal: ac.signal,
method: 'POST',
},
)
if (!reply.ok) {
throw new Error(`Unexpected status: ${reply.status}\n${await reply.text()}`)
}
const text = await reply.text()
console.log('resolved:', text)
return text
},
[mobileIPFS.apiURL],
)

const cid = resolvedCID || fallbackCID

if (mobileIPFS.status !== 'up') {
return <LoaderScreen text='Waiting for IPFS node...' />
}

return (
<AppScreenContainer>
{showResolveError && !!resolveErr && (
<PressableCard
title='Failed to resolve IPN'
style={cardStyle}
onPress={() => setShowResolveError(false)}
>
<Text style={{ color: defaultColors.text }}>
Using fallback from: {fallbackDate}
{'\n\n'}Tap to hide{`\n\n${resolveErr}`}
</Text>
</PressableCard>
)}
{!!localError && (
<Card style={cardStyle}>
<Text style={{ color: defaultColors.text }}>{`${resolveErr}`}</Text>
</Card>
)}
{!loadedCID && !resolveErr && (
<LoaderCard style={cardStyle} text='Resolving content identifier...' />
)}
{!loaded && <LoaderCard style={cardStyle} text='Loading page...' />}

<WebView
style={{
marginTop: space,
backgroundColor: defaultColors.background,
display: loaded ? undefined : 'none',
}}
source={{
uri: mobileIPFS.gatewayURL + cid,
}}
containerStyle={{ backgroundColor: defaultColors.background }}
renderError={err => (
<Text style={{ color: defaultColors.text }}>{JSON.stringify(err, null, 4)}</Text>
)}
onLoadEnd={() => setLoaded(true)}
onLoadStart={() => {
setLoaded(false)
}}
renderLoading={PageLoader}
onHttpError={err => {
setLocalError(`${err}`)
}}
onError={evt => {
setLocalError(JSON.stringify(evt.nativeEvent, null, 4))
}}
originWhitelist={['*']}
forceDarkOn={true}
allowsBackForwardNavigationGestures={true}
/>
</AppScreenContainer>
)
}
11 changes: 11 additions & 0 deletions rn/src/screens/home/ToolsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,17 @@ export const ToolsList: React.FC<{ searchText: string }> = React.memo(({ searchT

const items = React.useMemo<ToolItemParams[]>(() => {
return [
{
key: 'rn-distributed-wikipedia',
title: 'Wikipedia',
desc: 'Distributed read-only Wikipedia',
onPress: () => navigate('Wikipedia'),
avatar: (
<View style={utfIconContainerStyle}>
<Text style={utfIconStyle}>W</Text>
</View>
),
},
{
key: 'rn-ipfs-web-ui',
title: 'IPFS Web Interface',
Expand Down
1 change: 1 addition & 0 deletions rn/src/screens/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ export * from './GoModule'
export * from './HTMLModule'
export * from './IPFSLogs'
export * from './Browser'
export * from './Wikipedia'

0 comments on commit 856e53c

Please sign in to comment.