diff --git a/src/state/models/shell-ui.ts b/src/state/models/shell-ui.ts
index bb4bf1ff..3199e421 100644
--- a/src/state/models/shell-ui.ts
+++ b/src/state/models/shell-ui.ts
@@ -1,7 +1,7 @@
import {makeAutoObservable} from 'mobx'
import {ProfileViewModel} from './profile-view'
-export class ConfirmModel {
+export class ConfirmModal {
name = 'confirm'
constructor(
@@ -13,7 +13,7 @@ export class ConfirmModel {
}
}
-export class EditProfileModel {
+export class EditProfileModal {
name = 'edit-profile'
constructor(
@@ -24,7 +24,7 @@ export class EditProfileModel {
}
}
-export class CreateSceneModel {
+export class CreateSceneModal {
name = 'create-scene'
constructor() {
@@ -32,7 +32,7 @@ export class CreateSceneModel {
}
}
-export class InviteToSceneModel {
+export class InviteToSceneModal {
name = 'invite-to-scene'
constructor(public profileView: ProfileViewModel) {
@@ -40,7 +40,7 @@ export class InviteToSceneModel {
}
}
-export class ServerInputModel {
+export class ServerInputModal {
name = 'server-input'
constructor(
@@ -51,6 +51,13 @@ export class ServerInputModel {
}
}
+export class ProfileImageLightbox {
+ name = 'profile-image'
+ constructor(public profileView: ProfileViewModel) {
+ makeAutoObservable(this)
+ }
+}
+
export interface ComposerOptsPostRef {
uri: string
cid: string
@@ -70,11 +77,13 @@ export class ShellUiModel {
isMainMenuOpen = false
isModalActive = false
activeModal:
- | ConfirmModel
- | EditProfileModel
- | CreateSceneModel
- | ServerInputModel
+ | ConfirmModal
+ | EditProfileModal
+ | CreateSceneModal
+ | ServerInputModal
| undefined
+ isLightboxActive = false
+ activeLightbox: ProfileImageLightbox | undefined
isComposerActive = false
composerOpts: ComposerOpts | undefined
@@ -88,10 +97,10 @@ export class ShellUiModel {
openModal(
modal:
- | ConfirmModel
- | EditProfileModel
- | CreateSceneModel
- | ServerInputModel,
+ | ConfirmModal
+ | EditProfileModal
+ | CreateSceneModal
+ | ServerInputModal,
) {
this.isModalActive = true
this.activeModal = modal
@@ -102,6 +111,16 @@ export class ShellUiModel {
this.activeModal = undefined
}
+ openLightbox(lightbox: ProfileImageLightbox) {
+ this.isLightboxActive = true
+ this.activeLightbox = lightbox
+ }
+
+ closeLightbox() {
+ this.isLightboxActive = false
+ this.activeLightbox = undefined
+ }
+
openComposer(opts: ComposerOpts) {
this.isComposerActive = true
this.composerOpts = opts
diff --git a/src/view/com/lightbox/Lightbox.tsx b/src/view/com/lightbox/Lightbox.tsx
new file mode 100644
index 00000000..9432f015
--- /dev/null
+++ b/src/view/com/lightbox/Lightbox.tsx
@@ -0,0 +1,62 @@
+import React from 'react'
+import {StyleSheet, TouchableOpacity, View} from 'react-native'
+import {observer} from 'mobx-react-lite'
+import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
+import {useStores} from '../../../state'
+
+import * as models from '../../../state/models/shell-ui'
+
+import * as ProfileImageLightbox from './ProfileImage'
+
+export const Lightbox = observer(function Lightbox() {
+ const store = useStores()
+
+ const onClose = () => {
+ store.shell.closeLightbox()
+ }
+
+ if (!store.shell.isLightboxActive) {
+ return
+ }
+
+ let element
+ if (store.shell.activeLightbox?.name === 'profile-image') {
+ element = (
+
+ )
+ } else {
+ return
+ }
+
+ return (
+ <>
+
+
+
+
+ {element}
+ >
+ )
+})
+
+const styles = StyleSheet.create({
+ bg: {
+ position: 'absolute',
+ top: 0,
+ left: 0,
+ bottom: 0,
+ right: 0,
+ backgroundColor: '#000',
+ opacity: 0.9,
+ },
+ xIcon: {
+ position: 'absolute',
+ top: 30,
+ right: 30,
+ },
+ container: {
+ position: 'absolute',
+ },
+})
diff --git a/src/view/com/lightbox/ProfileImage.tsx b/src/view/com/lightbox/ProfileImage.tsx
new file mode 100644
index 00000000..f9c4ae73
--- /dev/null
+++ b/src/view/com/lightbox/ProfileImage.tsx
@@ -0,0 +1,26 @@
+import React from 'react'
+import {StyleSheet, useWindowDimensions, View} from 'react-native'
+import {UserAvatar} from '../util/UserAvatar'
+import {ProfileViewModel} from '../../../state/models/profile-view'
+
+export function Component({profileView}: {profileView: ProfileViewModel}) {
+ const winDim = useWindowDimensions()
+ const top = winDim.height / 2 - (winDim.width - 40) / 2 - 100
+ return (
+
+
+
+ )
+}
+
+const styles = StyleSheet.create({
+ container: {
+ position: 'absolute',
+ left: 20,
+ },
+})
diff --git a/src/view/com/modals/Modal.tsx b/src/view/com/modals/Modal.tsx
index 47b62743..610d30eb 100644
--- a/src/view/com/modals/Modal.tsx
+++ b/src/view/com/modals/Modal.tsx
@@ -43,14 +43,14 @@ export const Modal = observer(function Modal() {
snapPoints = ConfirmModal.snapPoints
element = (
)
} else if (store.shell.activeModal?.name === 'edit-profile') {
snapPoints = EditProfileModal.snapPoints
element = (
)
} else if (store.shell.activeModal?.name === 'create-scene') {
@@ -60,14 +60,14 @@ export const Modal = observer(function Modal() {
snapPoints = InviteToSceneModal.snapPoints
element = (
)
} else if (store.shell.activeModal?.name === 'server-input') {
snapPoints = ServerInputModal.snapPoints
element = (
)
} else {
diff --git a/src/view/com/notifications/InviteAccepter.tsx b/src/view/com/notifications/InviteAccepter.tsx
index 85274400..767c57e3 100644
--- a/src/view/com/notifications/InviteAccepter.tsx
+++ b/src/view/com/notifications/InviteAccepter.tsx
@@ -4,7 +4,7 @@ import LinearGradient from 'react-native-linear-gradient'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import * as apilib from '../../../state/lib/api'
import {NotificationsViewItemModel} from '../../../state/models/notifications-view'
-import {ConfirmModel} from '../../../state/models/shell-ui'
+import {ConfirmModal} from '../../../state/models/shell-ui'
import {useStores} from '../../../state'
import {ProfileCard} from '../profile/ProfileCard'
import * as Toast from '../util/Toast'
@@ -17,7 +17,7 @@ export function InviteAccepter({item}: {item: NotificationsViewItemModel}) {
confirmationUri !== '' || store.me.memberships?.isMemberOf(item.author.did)
const onPressAccept = async () => {
store.shell.openModal(
- new ConfirmModel(
+ new ConfirmModal(
'Join this scene?',
() => (
diff --git a/src/view/com/profile/ProfileHeader.tsx b/src/view/com/profile/ProfileHeader.tsx
index eb0a7477..a998a461 100644
--- a/src/view/com/profile/ProfileHeader.tsx
+++ b/src/view/com/profile/ProfileHeader.tsx
@@ -7,9 +7,10 @@ import {AtUri} from '../../../third-party/uri'
import {ProfileViewModel} from '../../../state/models/profile-view'
import {useStores} from '../../../state'
import {
- ConfirmModel,
- EditProfileModel,
- InviteToSceneModel,
+ ConfirmModal,
+ EditProfileModal,
+ InviteToSceneModal,
+ ProfileImageLightbox,
} from '../../../state/models/shell-ui'
import {pluralize} from '../../../lib/strings'
import {s, colors} from '../../lib/styles'
@@ -35,11 +36,8 @@ export const ProfileHeader = observer(function ProfileHeader({
[view.myState.member],
)
- const onPressBack = () => {
- store.nav.tab.goBack()
- }
- const onPressSearch = () => {
- store.nav.navigate(`/search`)
+ const onPressAvi = () => {
+ store.shell.openLightbox(new ProfileImageLightbox(view))
}
const onPressToggleFollow = () => {
view?.toggleFollowing().then(
@@ -54,7 +52,7 @@ export const ProfileHeader = observer(function ProfileHeader({
)
}
const onPressEditProfile = () => {
- store.shell.openModal(new EditProfileModel(view, onRefreshAll))
+ store.shell.openModal(new EditProfileModal(view, onRefreshAll))
}
const onPressFollowers = () => {
store.nav.navigate(`/profile/${view.handle}/followers`)
@@ -66,11 +64,11 @@ export const ProfileHeader = observer(function ProfileHeader({
store.nav.navigate(`/profile/${view.handle}/members`)
}
const onPressInviteMembers = () => {
- store.shell.openModal(new InviteToSceneModel(view))
+ store.shell.openModal(new InviteToSceneModal(view))
}
const onPressLeaveScene = () => {
store.shell.openModal(
- new ConfirmModel(
+ new ConfirmModal(
'Leave this scene?',
`You'll be able to come back unless your invite is revoked.`,
onPressConfirmLeaveScene,
@@ -153,14 +151,6 @@ export const ProfileHeader = observer(function ProfileHeader({
return (
-
-
-
{isMe ? (
@@ -304,6 +294,14 @@ export const ProfileHeader = observer(function ProfileHeader({
) : undefined}
+
+
+
)
})
diff --git a/src/view/com/util/DropdownBtn.tsx b/src/view/com/util/DropdownBtn.tsx
index b38a6ed9..d2b82c91 100644
--- a/src/view/com/util/DropdownBtn.tsx
+++ b/src/view/com/util/DropdownBtn.tsx
@@ -15,7 +15,7 @@ import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {colors} from '../../lib/styles'
import {toShareUrl} from '../../../lib/strings'
import {useStores} from '../../../state'
-import {ConfirmModel} from '../../../state/models/shell-ui'
+import {ConfirmModal} from '../../../state/models/shell-ui'
import {TABS_ENABLED} from '../../../build-flags'
const HITSLOP = {left: 10, top: 10, right: 10, bottom: 10}
@@ -122,7 +122,7 @@ export function PostDropdownBtn({
label: 'Delete post',
onPress() {
store.shell.openModal(
- new ConfirmModel(
+ new ConfirmModal(
'Delete this post?',
'Are you sure? This can not be undone.',
onDeletePost,
diff --git a/src/view/screens/Login.tsx b/src/view/screens/Login.tsx
index 38c2c1c7..20b30fe0 100644
--- a/src/view/screens/Login.tsx
+++ b/src/view/screens/Login.tsx
@@ -24,7 +24,7 @@ import {
} from '../../lib/strings'
import {useStores, DEFAULT_SERVICE} from '../../state'
import {ServiceDescription} from '../../state/models/session'
-import {ServerInputModel} from '../../state/models/shell-ui'
+import {ServerInputModal} from '../../state/models/shell-ui'
import {ComAtprotoAccountCreate} from '../../third-party/api/index'
import {isNetworkError} from '../../lib/errors'
@@ -149,7 +149,7 @@ const Signin = ({onPressBack}: {onPressBack: () => void}) => {
}, [serviceUrl])
const onPressSelectService = () => {
- store.shell.openModal(new ServerInputModel(serviceUrl, setServiceUrl))
+ store.shell.openModal(new ServerInputModal(serviceUrl, setServiceUrl))
}
const onPressNext = async () => {
@@ -309,7 +309,7 @@ const CreateAccount = ({onPressBack}: {onPressBack: () => void}) => {
}, [serviceUrl])
const onPressSelectService = () => {
- store.shell.openModal(new ServerInputModel(serviceUrl, setServiceUrl))
+ store.shell.openModal(new ServerInputModal(serviceUrl, setServiceUrl))
}
const onPressNext = async () => {
diff --git a/src/view/screens/Profile.tsx b/src/view/screens/Profile.tsx
index 14a9af4c..93a7147b 100644
--- a/src/view/screens/Profile.tsx
+++ b/src/view/screens/Profile.tsx
@@ -7,7 +7,7 @@ import {ScreenParams} from '../routes'
import {ProfileUiModel, Sections} from '../../state/models/profile-ui'
import {MembershipItem} from '../../state/models/memberships-view'
import {useStores} from '../../state'
-import {ConfirmModel} from '../../state/models/shell-ui'
+import {ConfirmModal} from '../../state/models/shell-ui'
import {ProfileHeader} from '../com/profile/ProfileHeader'
import {FeedItem} from '../com/posts/FeedItem'
import {ProfileCard} from '../com/profile/ProfileCard'
@@ -73,7 +73,7 @@ export const Profile = observer(({navIdx, visible, params}: ScreenParams) => {
}
const onPressRemoveMember = (membership: MembershipItem) => {
store.shell.openModal(
- new ConfirmModel(
+ new ConfirmModal(
`Remove ${membership.displayName || membership.handle}?`,
`You'll be able to invite them again if you change your mind.`,
async () => {
diff --git a/src/view/shell/mobile/Menu.tsx b/src/view/shell/mobile/Menu.tsx
index 793b0527..d57447d4 100644
--- a/src/view/shell/mobile/Menu.tsx
+++ b/src/view/shell/mobile/Menu.tsx
@@ -18,7 +18,7 @@ import {
MagnifyingGlassIcon,
} from '../../lib/icons'
import {UserAvatar} from '../../com/util/UserAvatar'
-import {CreateSceneModel} from '../../../state/models/shell-ui'
+import {CreateSceneModal} from '../../../state/models/shell-ui'
export const Menu = ({
visible,
@@ -53,7 +53,7 @@ export const Menu = ({
}
const onPressCreateScene = () => {
onClose()
- store.shell.openModal(new CreateSceneModel())
+ store.shell.openModal(new CreateSceneModal())
}
// rendering
diff --git a/src/view/shell/mobile/index.tsx b/src/view/shell/mobile/index.tsx
index ef980066..4567ab67 100644
--- a/src/view/shell/mobile/index.tsx
+++ b/src/view/shell/mobile/index.tsx
@@ -28,6 +28,7 @@ import {Menu} from './Menu'
import {Onboard} from '../../screens/Onboard'
import {HorzSwipe} from '../../com/util/gestures/HorzSwipe'
import {Modal} from '../../com/modals/Modal'
+import {Lightbox} from '../../com/lightbox/Lightbox'
import {TabsSelector} from './TabsSelector'
import {Composer} from './Composer'
import {s, colors} from '../../lib/styles'
@@ -420,6 +421,7 @@ export const MobileShell: React.FC = observer(() => {
/>
+
store.shell.closeComposer()}