Switch to autogenerated avis for now
parent
eceef67d46
commit
fd6a2b1b40
|
@ -6,7 +6,7 @@ import {FontAwesomeIcon, Props} from '@fortawesome/react-native-fontawesome'
|
||||||
import {NotificationsViewItemModel} from '../../../state/models/notifications-view'
|
import {NotificationsViewItemModel} from '../../../state/models/notifications-view'
|
||||||
import {s, colors} from '../../lib/styles'
|
import {s, colors} from '../../lib/styles'
|
||||||
import {ago, pluralize} from '../../lib/strings'
|
import {ago, pluralize} from '../../lib/strings'
|
||||||
import {DEF_AVATER} from '../../lib/assets'
|
import {UserAvatar} from '../util/UserAvatar'
|
||||||
import {PostText} from '../post/PostText'
|
import {PostText} from '../post/PostText'
|
||||||
import {Post} from '../post/Post'
|
import {Post} from '../post/Post'
|
||||||
import {Link} from '../util/Link'
|
import {Link} from '../util/Link'
|
||||||
|
@ -114,7 +114,11 @@ export const FeedItem = observer(function FeedItem({
|
||||||
key={author.href}
|
key={author.href}
|
||||||
href={author.href}
|
href={author.href}
|
||||||
title={`@${author.name}`}>
|
title={`@${author.name}`}>
|
||||||
<Image style={styles.avi} source={DEF_AVATER} />
|
<UserAvatar
|
||||||
|
size={30}
|
||||||
|
displayName={author.displayName}
|
||||||
|
name={author.name}
|
||||||
|
/>
|
||||||
</Link>
|
</Link>
|
||||||
))}
|
))}
|
||||||
{authors.length > MAX_AUTHORS ? (
|
{authors.length > MAX_AUTHORS ? (
|
||||||
|
@ -197,12 +201,6 @@ const styles = StyleSheet.create({
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
},
|
},
|
||||||
avi: {
|
|
||||||
width: 30,
|
|
||||||
height: 30,
|
|
||||||
borderRadius: 15,
|
|
||||||
resizeMode: 'cover',
|
|
||||||
},
|
|
||||||
aviExtraCount: {
|
aviExtraCount: {
|
||||||
fontWeight: 'bold',
|
fontWeight: 'bold',
|
||||||
paddingLeft: 6,
|
paddingLeft: 6,
|
||||||
|
|
|
@ -1,22 +1,14 @@
|
||||||
import React, {useState, useEffect} from 'react'
|
import React, {useState, useEffect} from 'react'
|
||||||
import {observer} from 'mobx-react-lite'
|
import {observer} from 'mobx-react-lite'
|
||||||
import {
|
import {ActivityIndicator, FlatList, StyleSheet, Text, View} from 'react-native'
|
||||||
ActivityIndicator,
|
|
||||||
FlatList,
|
|
||||||
Image,
|
|
||||||
StyleSheet,
|
|
||||||
Text,
|
|
||||||
TouchableOpacity,
|
|
||||||
View,
|
|
||||||
} from 'react-native'
|
|
||||||
import {
|
import {
|
||||||
LikedByViewModel,
|
LikedByViewModel,
|
||||||
LikedByViewItemModel,
|
LikedByViewItemModel,
|
||||||
} from '../../../state/models/liked-by-view'
|
} from '../../../state/models/liked-by-view'
|
||||||
import {Link} from '../util/Link'
|
import {Link} from '../util/Link'
|
||||||
|
import {UserAvatar} from '../util/UserAvatar'
|
||||||
import {useStores} from '../../../state'
|
import {useStores} from '../../../state'
|
||||||
import {s, colors} from '../../lib/styles'
|
import {s, colors} from '../../lib/styles'
|
||||||
import {DEF_AVATER} from '../../lib/assets'
|
|
||||||
|
|
||||||
export const PostLikedBy = observer(function PostLikedBy({uri}: {uri: string}) {
|
export const PostLikedBy = observer(function PostLikedBy({uri}: {uri: string}) {
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
|
@ -78,7 +70,11 @@ const LikedByItem = ({item}: {item: LikedByViewItemModel}) => {
|
||||||
<Link style={styles.outer} href={`/profile/${item.name}`} title={item.name}>
|
<Link style={styles.outer} href={`/profile/${item.name}`} title={item.name}>
|
||||||
<View style={styles.layout}>
|
<View style={styles.layout}>
|
||||||
<View style={styles.layoutAvi}>
|
<View style={styles.layoutAvi}>
|
||||||
<Image style={styles.avi} source={DEF_AVATER} />
|
<UserAvatar
|
||||||
|
size={40}
|
||||||
|
displayName={item.displayName}
|
||||||
|
name={item.name}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.layoutContent}>
|
<View style={styles.layoutContent}>
|
||||||
<Text style={[s.f15, s.bold]}>{item.displayName}</Text>
|
<Text style={[s.f15, s.bold]}>{item.displayName}</Text>
|
||||||
|
|
|
@ -12,10 +12,10 @@ import {
|
||||||
RepostedByViewModel,
|
RepostedByViewModel,
|
||||||
RepostedByViewItemModel,
|
RepostedByViewItemModel,
|
||||||
} from '../../../state/models/reposted-by-view'
|
} from '../../../state/models/reposted-by-view'
|
||||||
|
import {UserAvatar} from '../util/UserAvatar'
|
||||||
import {Link} from '../util/Link'
|
import {Link} from '../util/Link'
|
||||||
import {useStores} from '../../../state'
|
import {useStores} from '../../../state'
|
||||||
import {s, colors} from '../../lib/styles'
|
import {s, colors} from '../../lib/styles'
|
||||||
import {DEF_AVATER} from '../../lib/assets'
|
|
||||||
|
|
||||||
export const PostRepostedBy = observer(function PostRepostedBy({
|
export const PostRepostedBy = observer(function PostRepostedBy({
|
||||||
uri,
|
uri,
|
||||||
|
@ -83,7 +83,11 @@ const RepostedByItem = ({item}: {item: RepostedByViewItemModel}) => {
|
||||||
<Link style={styles.outer} href={`/profile/${item.name}`} title={item.name}>
|
<Link style={styles.outer} href={`/profile/${item.name}`} title={item.name}>
|
||||||
<View style={styles.layout}>
|
<View style={styles.layout}>
|
||||||
<View style={styles.layoutAvi}>
|
<View style={styles.layoutAvi}>
|
||||||
<Image style={styles.avi} source={DEF_AVATER} />
|
<UserAvatar
|
||||||
|
size={40}
|
||||||
|
displayName={item.displayName}
|
||||||
|
name={item.name}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.layoutContent}>
|
<View style={styles.layoutContent}>
|
||||||
<Text style={[s.f15, s.bold]}>{item.displayName}</Text>
|
<Text style={[s.f15, s.bold]}>{item.displayName}</Text>
|
||||||
|
|
|
@ -10,9 +10,9 @@ import {ComposePostModel} from '../../../state/models/shell'
|
||||||
import {Link} from '../util/Link'
|
import {Link} from '../util/Link'
|
||||||
import {RichText} from '../util/RichText'
|
import {RichText} from '../util/RichText'
|
||||||
import {PostDropdownBtn} from '../util/DropdownBtn'
|
import {PostDropdownBtn} from '../util/DropdownBtn'
|
||||||
|
import {UserAvatar} from '../util/UserAvatar'
|
||||||
import {s, colors} from '../../lib/styles'
|
import {s, colors} from '../../lib/styles'
|
||||||
import {ago, pluralize} from '../../lib/strings'
|
import {ago, pluralize} from '../../lib/strings'
|
||||||
import {DEF_AVATER} from '../../lib/assets'
|
|
||||||
import {useStores} from '../../../state'
|
import {useStores} from '../../../state'
|
||||||
|
|
||||||
const PARENT_REPLY_LINE_LENGTH = 8
|
const PARENT_REPLY_LINE_LENGTH = 8
|
||||||
|
@ -116,7 +116,11 @@ export const PostThreadItem = observer(function PostThreadItem({
|
||||||
<View style={styles.outer}>
|
<View style={styles.outer}>
|
||||||
<View style={styles.layout}>
|
<View style={styles.layout}>
|
||||||
<Link style={styles.layoutAvi} href={authorHref} title={authorTitle}>
|
<Link style={styles.layoutAvi} href={authorHref} title={authorTitle}>
|
||||||
<Image style={styles.avi} source={DEF_AVATER} />
|
<UserAvatar
|
||||||
|
size={50}
|
||||||
|
displayName={item.author.displayName}
|
||||||
|
name={item.author.name}
|
||||||
|
/>
|
||||||
</Link>
|
</Link>
|
||||||
<View style={styles.layoutContent}>
|
<View style={styles.layoutContent}>
|
||||||
<View style={[styles.meta, s.mt5]}>
|
<View style={[styles.meta, s.mt5]}>
|
||||||
|
@ -231,7 +235,11 @@ export const PostThreadItem = observer(function PostThreadItem({
|
||||||
)}
|
)}
|
||||||
<View style={styles.layout}>
|
<View style={styles.layout}>
|
||||||
<Link style={styles.layoutAvi} href={authorHref} title={authorTitle}>
|
<Link style={styles.layoutAvi} href={authorHref} title={authorTitle}>
|
||||||
<Image style={styles.avi} source={DEF_AVATER} />
|
<UserAvatar
|
||||||
|
size={50}
|
||||||
|
displayName={item.author.displayName}
|
||||||
|
name={item.author.name}
|
||||||
|
/>
|
||||||
</Link>
|
</Link>
|
||||||
<View style={styles.layoutContent}>
|
<View style={styles.layoutContent}>
|
||||||
{item.replyingToAuthor &&
|
{item.replyingToAuthor &&
|
||||||
|
@ -321,12 +329,6 @@ const styles = StyleSheet.create({
|
||||||
paddingTop: 10,
|
paddingTop: 10,
|
||||||
paddingBottom: 10,
|
paddingBottom: 10,
|
||||||
},
|
},
|
||||||
avi: {
|
|
||||||
width: 50,
|
|
||||||
height: 50,
|
|
||||||
borderRadius: 25,
|
|
||||||
resizeMode: 'cover',
|
|
||||||
},
|
|
||||||
layoutContent: {
|
layoutContent: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
paddingRight: 10,
|
paddingRight: 10,
|
||||||
|
|
|
@ -4,7 +4,6 @@ import {AtUri} from '../../../third-party/uri'
|
||||||
import * as PostType from '../../../third-party/api/src/types/app/bsky/post'
|
import * as PostType from '../../../third-party/api/src/types/app/bsky/post'
|
||||||
import {
|
import {
|
||||||
ActivityIndicator,
|
ActivityIndicator,
|
||||||
Image,
|
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
Text,
|
Text,
|
||||||
TouchableOpacity,
|
TouchableOpacity,
|
||||||
|
@ -16,10 +15,10 @@ import {ComposePostModel} from '../../../state/models/shell'
|
||||||
import {Link} from '../util/Link'
|
import {Link} from '../util/Link'
|
||||||
import {UserInfoText} from '../util/UserInfoText'
|
import {UserInfoText} from '../util/UserInfoText'
|
||||||
import {RichText} from '../util/RichText'
|
import {RichText} from '../util/RichText'
|
||||||
|
import {UserAvatar} from '../util/UserAvatar'
|
||||||
import {useStores} from '../../../state'
|
import {useStores} from '../../../state'
|
||||||
import {s, colors} from '../../lib/styles'
|
import {s, colors} from '../../lib/styles'
|
||||||
import {ago} from '../../lib/strings'
|
import {ago} from '../../lib/strings'
|
||||||
import {DEF_AVATER} from '../../lib/assets'
|
|
||||||
|
|
||||||
export const Post = observer(function Post({uri}: {uri: string}) {
|
export const Post = observer(function Post({uri}: {uri: string}) {
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
|
@ -91,7 +90,11 @@ export const Post = observer(function Post({uri}: {uri: string}) {
|
||||||
<Link style={styles.outer} href={itemHref} title={itemTitle}>
|
<Link style={styles.outer} href={itemHref} title={itemTitle}>
|
||||||
<View style={styles.layout}>
|
<View style={styles.layout}>
|
||||||
<Link style={styles.layoutAvi} href={authorHref} title={authorTitle}>
|
<Link style={styles.layoutAvi} href={authorHref} title={authorTitle}>
|
||||||
<Image style={styles.avi} source={DEF_AVATER} />
|
<UserAvatar
|
||||||
|
size={50}
|
||||||
|
displayName={item.author.displayName}
|
||||||
|
name={item.author.name}
|
||||||
|
/>
|
||||||
</Link>
|
</Link>
|
||||||
<View style={styles.layoutContent}>
|
<View style={styles.layoutContent}>
|
||||||
<View style={styles.meta}>
|
<View style={styles.meta}>
|
||||||
|
@ -185,12 +188,6 @@ const styles = StyleSheet.create({
|
||||||
layoutAvi: {
|
layoutAvi: {
|
||||||
width: 60,
|
width: 60,
|
||||||
},
|
},
|
||||||
avi: {
|
|
||||||
width: 50,
|
|
||||||
height: 50,
|
|
||||||
borderRadius: 25,
|
|
||||||
resizeMode: 'cover',
|
|
||||||
},
|
|
||||||
layoutContent: {
|
layoutContent: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
import React, {useMemo} from 'react'
|
import React, {useMemo} from 'react'
|
||||||
import {observer} from 'mobx-react-lite'
|
import {observer} from 'mobx-react-lite'
|
||||||
import {Image, StyleSheet, Text, TouchableOpacity, View} from 'react-native'
|
import {StyleSheet, Text, TouchableOpacity, View} from 'react-native'
|
||||||
import {AtUri} from '../../../third-party/uri'
|
import {AtUri} from '../../../third-party/uri'
|
||||||
import * as PostType from '../../../third-party/api/src/types/app/bsky/post'
|
import * as PostType from '../../../third-party/api/src/types/app/bsky/post'
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||||
import {FeedViewItemModel} from '../../../state/models/feed-view'
|
import {FeedItemModel} from '../../../state/models/feed-view'
|
||||||
import {ComposePostModel, SharePostModel} from '../../../state/models/shell'
|
import {ComposePostModel, SharePostModel} from '../../../state/models/shell'
|
||||||
import {Link} from '../util/Link'
|
import {Link} from '../util/Link'
|
||||||
import {PostDropdownBtn} from '../util/DropdownBtn'
|
import {PostDropdownBtn} from '../util/DropdownBtn'
|
||||||
import {UserInfoText} from '../util/UserInfoText'
|
import {UserInfoText} from '../util/UserInfoText'
|
||||||
import {RichText} from '../util/RichText'
|
import {RichText} from '../util/RichText'
|
||||||
|
import {UserAvatar} from '../util/UserAvatar'
|
||||||
import {s, colors} from '../../lib/styles'
|
import {s, colors} from '../../lib/styles'
|
||||||
import {ago} from '../../lib/strings'
|
import {ago} from '../../lib/strings'
|
||||||
import {DEF_AVATER} from '../../lib/assets'
|
|
||||||
import {useStores} from '../../../state'
|
import {useStores} from '../../../state'
|
||||||
|
|
||||||
export const FeedItem = observer(function FeedItem({
|
export const FeedItem = observer(function FeedItem({
|
||||||
item,
|
item,
|
||||||
}: {
|
}: {
|
||||||
item: FeedViewItemModel
|
item: FeedItemModel
|
||||||
}) {
|
}) {
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
const record = item.record as unknown as PostType.Record
|
const record = item.record as unknown as PostType.Record
|
||||||
|
@ -73,7 +73,11 @@ export const FeedItem = observer(function FeedItem({
|
||||||
style={styles.layoutAvi}
|
style={styles.layoutAvi}
|
||||||
href={authorHref}
|
href={authorHref}
|
||||||
title={item.author.name}>
|
title={item.author.name}>
|
||||||
<Image style={styles.avi} source={DEF_AVATER} />
|
<UserAvatar
|
||||||
|
size={50}
|
||||||
|
displayName={item.author.displayName}
|
||||||
|
name={item.author.name}
|
||||||
|
/>
|
||||||
</Link>
|
</Link>
|
||||||
<View style={styles.layoutContent}>
|
<View style={styles.layoutContent}>
|
||||||
<View style={styles.meta}>
|
<View style={styles.meta}>
|
||||||
|
@ -199,12 +203,6 @@ const styles = StyleSheet.create({
|
||||||
width: 60,
|
width: 60,
|
||||||
paddingTop: 5,
|
paddingTop: 5,
|
||||||
},
|
},
|
||||||
avi: {
|
|
||||||
width: 50,
|
|
||||||
height: 50,
|
|
||||||
borderRadius: 25,
|
|
||||||
resizeMode: 'cover',
|
|
||||||
},
|
|
||||||
layoutContent: {
|
layoutContent: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
},
|
},
|
||||||
|
|
|
@ -13,9 +13,9 @@ import {
|
||||||
FollowerItem,
|
FollowerItem,
|
||||||
} from '../../../state/models/user-followers-view'
|
} from '../../../state/models/user-followers-view'
|
||||||
import {Link} from '../util/Link'
|
import {Link} from '../util/Link'
|
||||||
|
import {UserAvatar} from '../util/UserAvatar'
|
||||||
import {useStores} from '../../../state'
|
import {useStores} from '../../../state'
|
||||||
import {s, colors} from '../../lib/styles'
|
import {s, colors} from '../../lib/styles'
|
||||||
import {DEF_AVATER} from '../../lib/assets'
|
|
||||||
|
|
||||||
export const ProfileFollowers = observer(function ProfileFollowers({
|
export const ProfileFollowers = observer(function ProfileFollowers({
|
||||||
name,
|
name,
|
||||||
|
@ -81,7 +81,11 @@ const User = ({item}: {item: FollowerItem}) => {
|
||||||
<Link style={styles.outer} href={`/profile/${item.name}`} title={item.name}>
|
<Link style={styles.outer} href={`/profile/${item.name}`} title={item.name}>
|
||||||
<View style={styles.layout}>
|
<View style={styles.layout}>
|
||||||
<View style={styles.layoutAvi}>
|
<View style={styles.layoutAvi}>
|
||||||
<Image style={styles.avi} source={DEF_AVATER} />
|
<UserAvatar
|
||||||
|
size={40}
|
||||||
|
displayName={item.displayName}
|
||||||
|
name={item.name}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.layoutContent}>
|
<View style={styles.layoutContent}>
|
||||||
<Text style={[s.f15, s.bold]}>{item.displayName}</Text>
|
<Text style={[s.f15, s.bold]}>{item.displayName}</Text>
|
||||||
|
@ -106,12 +110,6 @@ const styles = StyleSheet.create({
|
||||||
paddingTop: 10,
|
paddingTop: 10,
|
||||||
paddingBottom: 10,
|
paddingBottom: 10,
|
||||||
},
|
},
|
||||||
avi: {
|
|
||||||
width: 40,
|
|
||||||
height: 40,
|
|
||||||
borderRadius: 20,
|
|
||||||
resizeMode: 'cover',
|
|
||||||
},
|
|
||||||
layoutContent: {
|
layoutContent: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
paddingRight: 10,
|
paddingRight: 10,
|
||||||
|
|
|
@ -14,8 +14,8 @@ import {
|
||||||
} from '../../../state/models/user-follows-view'
|
} from '../../../state/models/user-follows-view'
|
||||||
import {useStores} from '../../../state'
|
import {useStores} from '../../../state'
|
||||||
import {Link} from '../util/Link'
|
import {Link} from '../util/Link'
|
||||||
|
import {UserAvatar} from '../util/UserAvatar'
|
||||||
import {s, colors} from '../../lib/styles'
|
import {s, colors} from '../../lib/styles'
|
||||||
import {DEF_AVATER} from '../../lib/assets'
|
|
||||||
|
|
||||||
export const ProfileFollows = observer(function ProfileFollows({
|
export const ProfileFollows = observer(function ProfileFollows({
|
||||||
name,
|
name,
|
||||||
|
@ -81,7 +81,11 @@ const User = ({item}: {item: FollowItem}) => {
|
||||||
<Link style={styles.outer} href={`/profile/${item.name}`} title={item.name}>
|
<Link style={styles.outer} href={`/profile/${item.name}`} title={item.name}>
|
||||||
<View style={styles.layout}>
|
<View style={styles.layout}>
|
||||||
<View style={styles.layoutAvi}>
|
<View style={styles.layoutAvi}>
|
||||||
<Image style={styles.avi} source={DEF_AVATER} />
|
<UserAvatar
|
||||||
|
size={40}
|
||||||
|
displayName={item.displayName}
|
||||||
|
name={item.name}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.layoutContent}>
|
<View style={styles.layoutContent}>
|
||||||
<Text style={[s.f15, s.bold]}>{item.displayName}</Text>
|
<Text style={[s.f15, s.bold]}>{item.displayName}</Text>
|
||||||
|
|
|
@ -15,8 +15,9 @@ import {useStores} from '../../../state'
|
||||||
import {EditProfileModel} from '../../../state/models/shell'
|
import {EditProfileModel} from '../../../state/models/shell'
|
||||||
import {pluralize} from '../../lib/strings'
|
import {pluralize} from '../../lib/strings'
|
||||||
import {s, gradients, colors} from '../../lib/styles'
|
import {s, gradients, colors} from '../../lib/styles'
|
||||||
import {DEF_AVATER, BANNER} from '../../lib/assets'
|
import {BANNER} from '../../lib/assets'
|
||||||
import Toast from '../util/Toast'
|
import Toast from '../util/Toast'
|
||||||
|
import {UserAvatar} from '../util/UserAvatar'
|
||||||
import {Link} from '../util/Link'
|
import {Link} from '../util/Link'
|
||||||
|
|
||||||
export const ProfileHeader = observer(function ProfileHeader({
|
export const ProfileHeader = observer(function ProfileHeader({
|
||||||
|
@ -81,7 +82,9 @@ export const ProfileHeader = observer(function ProfileHeader({
|
||||||
return (
|
return (
|
||||||
<View style={styles.outer}>
|
<View style={styles.outer}>
|
||||||
<Image style={styles.banner} source={BANNER} />
|
<Image style={styles.banner} source={BANNER} />
|
||||||
<Image style={styles.avi} source={DEF_AVATER} />
|
<View style={styles.avi}>
|
||||||
|
<UserAvatar size={80} displayName={view.displayName} name={view.name} />
|
||||||
|
</View>
|
||||||
<View style={styles.content}>
|
<View style={styles.content}>
|
||||||
<View style={[styles.displayNameLine]}>
|
<View style={[styles.displayNameLine]}>
|
||||||
<Text style={styles.displayName}>{view.displayName}</Text>
|
<Text style={styles.displayName}>{view.displayName}</Text>
|
||||||
|
@ -178,12 +181,12 @@ const styles = StyleSheet.create({
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
top: 80,
|
top: 80,
|
||||||
left: 10,
|
left: 10,
|
||||||
width: 80,
|
width: 84,
|
||||||
height: 80,
|
height: 84,
|
||||||
borderRadius: 40,
|
borderRadius: 42,
|
||||||
resizeMode: 'cover',
|
|
||||||
borderWidth: 2,
|
borderWidth: 2,
|
||||||
borderColor: colors.white,
|
borderColor: colors.white,
|
||||||
|
backgroundColor: colors.white,
|
||||||
},
|
},
|
||||||
content: {
|
content: {
|
||||||
paddingTop: 8,
|
paddingTop: 8,
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
import React from 'react'
|
||||||
|
import Svg, {Circle, Text, Defs, LinearGradient, Stop} from 'react-native-svg'
|
||||||
|
import {colors} from '../../lib/styles'
|
||||||
|
|
||||||
|
const GRADIENTS = [
|
||||||
|
[colors.pink3, colors.purple3],
|
||||||
|
[colors.purple3, colors.blue3],
|
||||||
|
[colors.blue3, colors.green3],
|
||||||
|
[colors.red3, colors.pink3],
|
||||||
|
]
|
||||||
|
|
||||||
|
export function UserAvatar({
|
||||||
|
size,
|
||||||
|
displayName,
|
||||||
|
name,
|
||||||
|
}: {
|
||||||
|
size: number
|
||||||
|
displayName: string | undefined
|
||||||
|
name: string
|
||||||
|
}) {
|
||||||
|
const initials = getInitials(displayName || name)
|
||||||
|
const gi = cyrb53(name) % GRADIENTS.length
|
||||||
|
return (
|
||||||
|
<Svg width={size} height={size} viewBox="0 0 100 100">
|
||||||
|
<Defs>
|
||||||
|
<LinearGradient id="grad" x1="0" y1="0" x2="1" y2="1">
|
||||||
|
<Stop offset="0" stopColor={GRADIENTS[gi][0]} stopOpacity="1" />
|
||||||
|
<Stop offset="1" stopColor={GRADIENTS[gi][1]} stopOpacity="1" />
|
||||||
|
</LinearGradient>
|
||||||
|
</Defs>
|
||||||
|
<Circle cx="50" cy="50" r="50" fill="url(#grad)" />
|
||||||
|
<Text
|
||||||
|
fill="white"
|
||||||
|
fontSize="50"
|
||||||
|
fontWeight="bold"
|
||||||
|
x="50"
|
||||||
|
y="67"
|
||||||
|
textAnchor="middle">
|
||||||
|
{initials}
|
||||||
|
</Text>
|
||||||
|
</Svg>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function getInitials(str: string): string {
|
||||||
|
const tokens = str
|
||||||
|
.split(' ')
|
||||||
|
.filter(Boolean)
|
||||||
|
.map(v => v.trim())
|
||||||
|
if (tokens.length >= 2 && tokens[0][0] && tokens[0][1]) {
|
||||||
|
return tokens[0][0].toUpperCase() + tokens[1][0].toUpperCase()
|
||||||
|
}
|
||||||
|
if (tokens.length === 1 && tokens[0][0]) {
|
||||||
|
return tokens[0][0].toUpperCase()
|
||||||
|
}
|
||||||
|
return 'X'
|
||||||
|
}
|
||||||
|
|
||||||
|
// deterministic string->hash
|
||||||
|
// https://stackoverflow.com/a/52171480
|
||||||
|
function cyrb53(str: string, seed = 0): number {
|
||||||
|
let h1 = 0xdeadbeef ^ seed,
|
||||||
|
h2 = 0x41c6ce57 ^ seed
|
||||||
|
for (let i = 0, ch; i < str.length; i++) {
|
||||||
|
ch = str.charCodeAt(i)
|
||||||
|
h1 = Math.imul(h1 ^ ch, 2654435761)
|
||||||
|
h2 = Math.imul(h2 ^ ch, 1597334677)
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 =
|
||||||
|
Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^
|
||||||
|
Math.imul(h2 ^ (h2 >>> 13), 3266489909)
|
||||||
|
h2 =
|
||||||
|
Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^
|
||||||
|
Math.imul(h1 ^ (h1 >>> 13), 3266489909)
|
||||||
|
|
||||||
|
return 4294967296 * (2097151 & h2) + (h1 >>> 0)
|
||||||
|
}
|
|
@ -4,8 +4,8 @@ import {observer} from 'mobx-react-lite'
|
||||||
import {useStores} from '../../state'
|
import {useStores} from '../../state'
|
||||||
import {ScreenParams} from '../routes'
|
import {ScreenParams} from '../routes'
|
||||||
import {s, colors} from '../lib/styles'
|
import {s, colors} from '../lib/styles'
|
||||||
import {DEF_AVATER} from '../lib/assets'
|
|
||||||
import {Link} from '../com/util/Link'
|
import {Link} from '../com/util/Link'
|
||||||
|
import {UserAvatar} from '../com/util/UserAvatar'
|
||||||
|
|
||||||
export const Settings = observer(function Settings({visible}: ScreenParams) {
|
export const Settings = observer(function Settings({visible}: ScreenParams) {
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
|
@ -33,8 +33,12 @@ export const Settings = observer(function Settings({visible}: ScreenParams) {
|
||||||
</View>
|
</View>
|
||||||
<Link href={`/profile/${store.me.name}`} title="Your profile">
|
<Link href={`/profile/${store.me.name}`} title="Your profile">
|
||||||
<View style={styles.profile}>
|
<View style={styles.profile}>
|
||||||
<Image style={styles.avi} source={DEF_AVATER} />
|
<UserAvatar
|
||||||
<View>
|
size={40}
|
||||||
|
displayName={store.me.displayName}
|
||||||
|
name={store.me.name || ''}
|
||||||
|
/>
|
||||||
|
<View style={[s.ml10]}>
|
||||||
<Text style={[s.f18]}>{store.me.displayName}</Text>
|
<Text style={[s.f18]}>{store.me.displayName}</Text>
|
||||||
<Text style={[s.gray5]}>@{store.me.name}</Text>
|
<Text style={[s.gray5]}>@{store.me.name}</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|
|
@ -19,6 +19,7 @@ import Animated, {
|
||||||
import {IconProp} from '@fortawesome/fontawesome-svg-core'
|
import {IconProp} from '@fortawesome/fontawesome-svg-core'
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||||
import {HomeIcon, UserGroupIcon} from '../../lib/icons'
|
import {HomeIcon, UserGroupIcon} from '../../lib/icons'
|
||||||
|
import {UserAvatar} from '../../com/util/UserAvatar'
|
||||||
import {useStores} from '../../../state'
|
import {useStores} from '../../../state'
|
||||||
import {s, colors} from '../../lib/styles'
|
import {s, colors} from '../../lib/styles'
|
||||||
import {DEF_AVATER} from '../../lib/assets'
|
import {DEF_AVATER} from '../../lib/assets'
|
||||||
|
@ -131,7 +132,13 @@ export const MainMenu = observer(
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={styles.profile}
|
style={styles.profile}
|
||||||
onPress={() => onNavigate(`/profile/${store.me.name || ''}`)}>
|
onPress={() => onNavigate(`/profile/${store.me.name || ''}`)}>
|
||||||
<Image style={styles.profileImage} source={DEF_AVATER} />
|
<View style={styles.profileImage}>
|
||||||
|
<UserAvatar
|
||||||
|
size={30}
|
||||||
|
displayName={store.me.displayName}
|
||||||
|
name={store.me.name || ''}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
<Text style={styles.profileText} numberOfLines={1}>
|
<Text style={styles.profileText} numberOfLines={1}>
|
||||||
{store.me.displayName || store.me.name || 'My profile'}
|
{store.me.displayName || store.me.name || 'My profile'}
|
||||||
</Text>
|
</Text>
|
||||||
|
@ -231,9 +238,6 @@ const styles = StyleSheet.create({
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
},
|
},
|
||||||
profileImage: {
|
profileImage: {
|
||||||
borderRadius: 15,
|
|
||||||
width: 30,
|
|
||||||
height: 30,
|
|
||||||
marginRight: 8,
|
marginRight: 8,
|
||||||
},
|
},
|
||||||
profileText: {
|
profileText: {
|
||||||
|
|
|
@ -21,7 +21,6 @@ import Swipeable from 'react-native-gesture-handler/Swipeable'
|
||||||
import LinearGradient from 'react-native-linear-gradient'
|
import LinearGradient from 'react-native-linear-gradient'
|
||||||
import {useStores} from '../../../state'
|
import {useStores} from '../../../state'
|
||||||
import {s, colors, gradients} from '../../lib/styles'
|
import {s, colors, gradients} from '../../lib/styles'
|
||||||
import {DEF_AVATER} from '../../lib/assets'
|
|
||||||
import {match} from '../../routes'
|
import {match} from '../../routes'
|
||||||
import {LinkActionsModel} from '../../../state/models/shell'
|
import {LinkActionsModel} from '../../../state/models/shell'
|
||||||
|
|
||||||
|
|
30
todos.txt
30
todos.txt
|
@ -4,11 +4,35 @@ Paul's todo list
|
||||||
- Update to RN 0.70
|
- Update to RN 0.70
|
||||||
- Cache some profile/userinfo lookups
|
- Cache some profile/userinfo lookups
|
||||||
- Cursor behaviors on all views
|
- Cursor behaviors on all views
|
||||||
- Home button should scroll to top
|
- Update swipe behaviors: edge always goes back, leftmost always goes back, main connects to selector if present
|
||||||
- Onboarding flow
|
- Onboarding flow
|
||||||
- *
|
- *
|
||||||
- Private beta
|
- Avatars
|
||||||
- Users list
|
- SVG generate
|
||||||
|
- Main menu
|
||||||
|
- Scenes list
|
||||||
|
- Create scene view
|
||||||
|
- *
|
||||||
|
- Discover scenes view
|
||||||
|
- *
|
||||||
|
- User profile
|
||||||
|
- Distinguish by declared type
|
||||||
|
- User
|
||||||
|
- List scenes
|
||||||
|
- Invite to scene
|
||||||
|
- Remove from scene
|
||||||
|
- Scene
|
||||||
|
- Trending
|
||||||
|
- Members
|
||||||
|
- Profile header
|
||||||
|
- Invite to scene
|
||||||
|
- Remove from scene
|
||||||
|
- Edit profile
|
||||||
|
- Notifications
|
||||||
|
- Scene invite
|
||||||
|
- Reply gating
|
||||||
|
- Composer
|
||||||
|
- View on post
|
||||||
- Linking
|
- Linking
|
||||||
- Web linking
|
- Web linking
|
||||||
- App linking
|
- App linking
|
||||||
|
|
Loading…
Reference in New Issue