expo-dev-launcher 2.4.2 → 2.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/android/build.gradle +1 -1
- package/android/src/debug/assets/expo_dev_launcher_android.bundle +243 -241
- package/android/src/debug/res/drawable-mdpi/_expodevclientcomponents_assets_buildingicon.png +0 -0
- package/android/src/debug/res/drawable-xhdpi/_expodevclientcomponents_assets_buildingicon.png +0 -0
- package/android/src/debug/res/drawable-xxhdpi/_expodevclientcomponents_assets_buildingicon.png +0 -0
- package/bundle/components/AppHeader.tsx +12 -20
- package/bundle/components/Avatar.tsx +96 -0
- package/bundle/functions/getUserProfileAsync.ts +6 -7
- package/bundle/screens/UserProfileScreen.tsx +14 -10
- package/ios/assets/_expo-dev-client-components/assets/building-icon.png +0 -0
- package/ios/assets/_expo-dev-client-components/assets/building-icon@2x.png +0 -0
- package/ios/assets/_expo-dev-client-components/assets/building-icon@3x.png +0 -0
- package/ios/main.jsbundle +243 -241
- package/package.json +5 -5
|
Binary file
|
|
Binary file
|
package/android/src/debug/res/drawable-xxhdpi/_expodevclientcomponents_assets_buildingicon.png
ADDED
|
Binary file
|
|
@@ -16,6 +16,7 @@ import { useWindowDimensions } from 'react-native';
|
|
|
16
16
|
import { SafeAreaTop } from '../components/SafeAreaTop';
|
|
17
17
|
import { useBuildInfo } from '../providers/BuildInfoProvider';
|
|
18
18
|
import { useUser } from '../providers/UserContextProvider';
|
|
19
|
+
import { Avatar } from './Avatar';
|
|
19
20
|
|
|
20
21
|
export function AppHeader({ navigation }) {
|
|
21
22
|
const buildInfo = useBuildInfo();
|
|
@@ -29,7 +30,7 @@ export function AppHeader({ navigation }) {
|
|
|
29
30
|
};
|
|
30
31
|
|
|
31
32
|
const isAuthenticated = userData != null;
|
|
32
|
-
const selectedUserImage = selectedAccount?.
|
|
33
|
+
const selectedUserImage = selectedAccount?.ownerUserActor?.profilePhoto ?? null;
|
|
33
34
|
|
|
34
35
|
return (
|
|
35
36
|
<>
|
|
@@ -69,11 +70,16 @@ export function AppHeader({ navigation }) {
|
|
|
69
70
|
<View>
|
|
70
71
|
{isAuthenticated ? (
|
|
71
72
|
<View rounded="full" padding="small">
|
|
72
|
-
<
|
|
73
|
-
{selectedUserImage
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
73
|
+
<Avatar
|
|
74
|
+
profilePhoto={selectedUserImage}
|
|
75
|
+
name={
|
|
76
|
+
selectedAccount?.ownerUserActor?.fullName
|
|
77
|
+
? selectedAccount.ownerUserActor.fullName
|
|
78
|
+
: selectedAccount?.name
|
|
79
|
+
}
|
|
80
|
+
isOrganization={selectedAccount?.ownerUserActor === null}
|
|
81
|
+
size="xl"
|
|
82
|
+
/>
|
|
77
83
|
</View>
|
|
78
84
|
) : (
|
|
79
85
|
<View mx="small">
|
|
@@ -84,20 +90,6 @@ export function AppHeader({ navigation }) {
|
|
|
84
90
|
)}
|
|
85
91
|
</View>
|
|
86
92
|
</Button.HighlightOnPressContainer>
|
|
87
|
-
{!selectedUserImage && (
|
|
88
|
-
<Row
|
|
89
|
-
style={{
|
|
90
|
-
height: scale[2],
|
|
91
|
-
flexWrap: 'wrap',
|
|
92
|
-
maxWidth: scale[16],
|
|
93
|
-
paddingRight: scale[2],
|
|
94
|
-
transform: [{ translateY: -scale[2] }],
|
|
95
|
-
}}>
|
|
96
|
-
<Text numberOfLines={1} size="small" align="center" weight="medium">
|
|
97
|
-
{selectedAccount?.name}
|
|
98
|
-
</Text>
|
|
99
|
-
</Row>
|
|
100
|
-
)}
|
|
101
93
|
</View>
|
|
102
94
|
</Row>
|
|
103
95
|
</View>
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { iconSize, palette } from '@expo/styleguide-native';
|
|
2
|
+
import { View, Image, scale, BuildingIcon, UserIcon } from 'expo-dev-client-components';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { StyleSheet } from 'react-native';
|
|
5
|
+
|
|
6
|
+
type Props = {
|
|
7
|
+
name?: string;
|
|
8
|
+
profilePhoto?: string;
|
|
9
|
+
isOrganization?: boolean;
|
|
10
|
+
size?: React.ComponentProps<typeof Image>['size'];
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export function Avatar({ profilePhoto, size = 'large', name = '', isOrganization = false }: Props) {
|
|
14
|
+
const firstLetter = name?.charAt(0).toLowerCase();
|
|
15
|
+
const viewSize = getViewSize(size);
|
|
16
|
+
|
|
17
|
+
if (isOrganization) {
|
|
18
|
+
const { backgroundColor, tintColor } = getOrganizationColor(firstLetter);
|
|
19
|
+
return (
|
|
20
|
+
<View
|
|
21
|
+
style={{
|
|
22
|
+
height: viewSize,
|
|
23
|
+
width: viewSize,
|
|
24
|
+
backgroundColor,
|
|
25
|
+
}}
|
|
26
|
+
rounded="full"
|
|
27
|
+
align="centered"
|
|
28
|
+
bg="secondary">
|
|
29
|
+
<BuildingIcon resizeMode="center" style={styles.icon} tintColor={tintColor} />
|
|
30
|
+
</View>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (!profilePhoto || !firstLetter) {
|
|
35
|
+
return (
|
|
36
|
+
<View
|
|
37
|
+
style={{ height: viewSize, width: viewSize }}
|
|
38
|
+
rounded="full"
|
|
39
|
+
align="centered"
|
|
40
|
+
bg="secondary">
|
|
41
|
+
<UserIcon resizeMode="center" style={styles.icon} />
|
|
42
|
+
</View>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
let _profilePhoto = profilePhoto;
|
|
47
|
+
if (profilePhoto.match('gravatar.com')) {
|
|
48
|
+
const defaultProfilePhoto = encodeURIComponent(
|
|
49
|
+
`https://storage.googleapis.com/expo-website-default-avatars-2023/${firstLetter}.png`
|
|
50
|
+
);
|
|
51
|
+
_profilePhoto = `${profilePhoto}&d=${defaultProfilePhoto}`;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<View rounded="full" bg="secondary">
|
|
56
|
+
<Image rounded="full" source={{ uri: _profilePhoto }} size={size} />
|
|
57
|
+
</View>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function getOrganizationColor(firstLetter?: string) {
|
|
62
|
+
if (firstLetter?.match(/[a-d]/)) {
|
|
63
|
+
return { backgroundColor: palette.light.blue[200], tintColor: palette.light.blue[900] };
|
|
64
|
+
} else if (firstLetter?.match(/[e-h]/)) {
|
|
65
|
+
return { backgroundColor: palette.light.green[200], tintColor: palette.light.green[900] };
|
|
66
|
+
} else if (firstLetter?.match(/[i-l]/)) {
|
|
67
|
+
return { backgroundColor: palette.light.yellow[400], tintColor: palette.light.yellow[900] };
|
|
68
|
+
} else if (firstLetter?.match(/[m-p]/)) {
|
|
69
|
+
return { backgroundColor: palette.light.orange[200], tintColor: palette.light.orange[900] };
|
|
70
|
+
} else if (firstLetter?.match(/[q-t]/)) {
|
|
71
|
+
return { backgroundColor: palette.light.red[200], tintColor: palette.light.red[900] };
|
|
72
|
+
} else if (firstLetter?.match(/[u-z]/)) {
|
|
73
|
+
return { backgroundColor: palette.light.pink[200], tintColor: palette.light.pink[900] };
|
|
74
|
+
} else {
|
|
75
|
+
return { backgroundColor: palette.light.purple[200], tintColor: palette.light.purple[900] };
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function getViewSize(size?: React.ComponentProps<typeof Image>['size']) {
|
|
80
|
+
switch (size) {
|
|
81
|
+
case 'tiny':
|
|
82
|
+
return scale.small;
|
|
83
|
+
case 'small':
|
|
84
|
+
return iconSize.small;
|
|
85
|
+
case 'large':
|
|
86
|
+
return iconSize.large;
|
|
87
|
+
case 'xl':
|
|
88
|
+
return scale.xl;
|
|
89
|
+
default:
|
|
90
|
+
return iconSize.large;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const styles = StyleSheet.create({
|
|
95
|
+
icon: { width: '45%', height: '45%' },
|
|
96
|
+
});
|
|
@@ -5,7 +5,6 @@ import { apiClient } from '../apiClient';
|
|
|
5
5
|
export type UserData = {
|
|
6
6
|
id: string;
|
|
7
7
|
appCount: number;
|
|
8
|
-
email: string;
|
|
9
8
|
username: string;
|
|
10
9
|
profilePhoto: string;
|
|
11
10
|
accounts: UserAccount[];
|
|
@@ -15,19 +14,18 @@ export type UserData = {
|
|
|
15
14
|
export type UserAccount = {
|
|
16
15
|
id: string;
|
|
17
16
|
name: string;
|
|
18
|
-
|
|
17
|
+
ownerUserActor?: {
|
|
19
18
|
username: string;
|
|
20
19
|
fullName?: string;
|
|
21
|
-
profilePhoto
|
|
20
|
+
profilePhoto: string;
|
|
22
21
|
};
|
|
23
22
|
};
|
|
24
23
|
|
|
25
24
|
const query = gql`
|
|
26
25
|
{
|
|
27
|
-
|
|
26
|
+
meUserActor {
|
|
28
27
|
id
|
|
29
28
|
appCount
|
|
30
|
-
email
|
|
31
29
|
profilePhoto
|
|
32
30
|
username
|
|
33
31
|
isExpoAdmin
|
|
@@ -35,7 +33,7 @@ const query = gql`
|
|
|
35
33
|
accounts {
|
|
36
34
|
id
|
|
37
35
|
name
|
|
38
|
-
|
|
36
|
+
ownerUserActor {
|
|
39
37
|
username
|
|
40
38
|
fullName
|
|
41
39
|
profilePhoto
|
|
@@ -46,5 +44,6 @@ const query = gql`
|
|
|
46
44
|
`;
|
|
47
45
|
|
|
48
46
|
export async function getUserProfileAsync() {
|
|
49
|
-
|
|
47
|
+
const data = await apiClient.request(query);
|
|
48
|
+
return data.meUserActor as UserData;
|
|
50
49
|
}
|
|
@@ -14,6 +14,7 @@ import * as React from 'react';
|
|
|
14
14
|
import { ActivityIndicator, ScrollView } from 'react-native';
|
|
15
15
|
import { SafeAreaView } from 'react-native-safe-area-context';
|
|
16
16
|
|
|
17
|
+
import { Avatar } from '../components/Avatar';
|
|
17
18
|
import { LogoutConfirmationModal } from '../components/LogoutConfirmationModal';
|
|
18
19
|
import { UserAccount, UserData } from '../functions/getUserProfileAsync';
|
|
19
20
|
import { useModalStack } from '../providers/ModalStackProvider';
|
|
@@ -186,8 +187,8 @@ function UserAccountSelector({
|
|
|
186
187
|
const orgs: UserAccount[] = [];
|
|
187
188
|
|
|
188
189
|
for (const account of userData.accounts) {
|
|
189
|
-
if (account
|
|
190
|
-
if (account.
|
|
190
|
+
if (account) {
|
|
191
|
+
if (account.ownerUserActor) {
|
|
191
192
|
accounts.push(account);
|
|
192
193
|
} else {
|
|
193
194
|
orgs.push(account);
|
|
@@ -213,17 +214,20 @@ function UserAccountSelector({
|
|
|
213
214
|
roundedBottom={isLast ? 'large' : 'none'}
|
|
214
215
|
roundedTop={isFirst ? 'large' : 'none'}>
|
|
215
216
|
<Row align="center" py="small" px="medium" bg="default">
|
|
216
|
-
<
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
217
|
+
<Avatar
|
|
218
|
+
profilePhoto={account?.ownerUserActor?.profilePhoto}
|
|
219
|
+
name={
|
|
220
|
+
account?.ownerUserActor?.fullName
|
|
221
|
+
? account.ownerUserActor.fullName
|
|
222
|
+
: account?.name
|
|
223
|
+
}
|
|
224
|
+
isOrganization={account?.ownerUserActor === null}
|
|
225
|
+
size="large"
|
|
226
|
+
/>
|
|
223
227
|
<Spacer.Horizontal size="small" />
|
|
224
228
|
|
|
225
229
|
<View>
|
|
226
|
-
<Heading>{account.
|
|
230
|
+
<Heading>{account.ownerUserActor?.username ?? account.name}</Heading>
|
|
227
231
|
</View>
|
|
228
232
|
|
|
229
233
|
<Spacer.Vertical />
|
|
Binary file
|