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()}