diff --git a/src/lib/components/ui/ContextMenu.svelte b/src/lib/components/ui/ContextMenu.svelte
index e0c591f84..42b09ac61 100644
--- a/src/lib/components/ui/ContextMenu.svelte
+++ b/src/lib/components/ui/ContextMenu.svelte
@@ -1,4 +1,5 @@
@@ -9,8 +10,10 @@
import { clickoutside } from "@svelte-put/clickoutside"
import { Appearance } from "$lib/enums"
import type { ContextItem } from "$lib/types"
- import { createEventDispatcher, tick } from "svelte"
+ import { createEventDispatcher, onMount, tick } from "svelte"
import { log } from "$lib/utils/Logger"
+ import type { PluginListenerHandle } from "@capacitor/core"
+ import { isAndroidOriOS } from "$lib/utils/Mobile"
let visible: boolean = false
let coords: [number, number] = [0, 0]
@@ -31,7 +34,7 @@
const { width, height } = context.getBoundingClientRect()
const offsetX = evt.pageX
- const offsetY = evt.pageY
+ const offsetY = evt.pageY - keyboardHeight / 2.5
const screenWidth = evt.view!.innerWidth
const screenHeight = evt.view!.innerHeight
@@ -42,9 +45,7 @@
// Calculate Y position, prioritizing space above the cursor if not enough below
const adjustedY = offsetY - height
- const topY = screenHeight - offsetY < height + 30
- ? Math.max(5, adjustedY)
- : Math.max(5, overFlowY ? offsetY - height : offsetY)
+ const topY = screenHeight - offsetY < height + 30 ? Math.max(5, adjustedY) : Math.max(5, overFlowY ? offsetY - height : offsetY)
return [topX, topY]
}
@@ -60,6 +61,29 @@
await tick()
coords = calculatePos(evt)
}
+ let keyboardHeight = 0
+ onMount(() => {
+ let mobileKeyboardListener01: PluginListenerHandle | undefined
+ let mobileKeyboardListener02: PluginListenerHandle | undefined
+
+ async function setupListeners() {
+ mobileKeyboardListener01 = await Keyboard.addListener("keyboardWillShow", info => {
+ keyboardHeight = info.keyboardHeight
+ })
+
+ mobileKeyboardListener02 = await Keyboard.addListener("keyboardWillHide", () => {
+ keyboardHeight = 0
+ })
+ }
+ if (isAndroidOriOS()) {
+ setupListeners()
+ }
+
+ return () => {
+ if (mobileKeyboardListener01) mobileKeyboardListener01.remove()
+ if (mobileKeyboardListener02) mobileKeyboardListener02.remove()
+ }
+ })
function handleItemClick(e: MouseEvent, item: ContextItem) {
e.stopPropagation()
@@ -74,13 +98,7 @@
{#if visible}
-
{#if errorMessage}
diff --git a/src/lib/layouts/BottomNavBarMobile.svelte b/src/lib/layouts/BottomNavBarMobile.svelte
index b74b60e9b..5ae627f75 100644
--- a/src/lib/layouts/BottomNavBarMobile.svelte
+++ b/src/lib/layouts/BottomNavBarMobile.svelte
@@ -7,8 +7,10 @@
import { UIStore } from "$lib/state/ui"
import type { FriendRequest, NavRoute } from "$lib/types"
import { checkMobile, isAndroidOriOS } from "$lib/utils/Mobile"
- import { createEventDispatcher, onDestroy } from "svelte"
+ import { createEventDispatcher, onDestroy, onMount } from "svelte"
import { get } from "svelte/store"
+ import { Keyboard } from "@capacitor/keyboard"
+ import type { PluginListenerHandle } from "@capacitor/core"
export let routes: NavRoute[] = []
export let activeRoute: Route | SettingsRoute | CommunitySettingsRoute = Route.Home
@@ -67,8 +69,22 @@
if (route.to === Route.Settings) return true
}
+ let mobileKeyboardListener01: PluginListenerHandle | undefined
+ let mobileKeyboardListener02: PluginListenerHandle | undefined
+ $: isKeyboardOpened = false
+
+ onMount(async () => {
+ mobileKeyboardListener01 = await Keyboard.addListener("keyboardWillShow", () => {
+ isKeyboardOpened = true
+ })
+
+ mobileKeyboardListener02 = await Keyboard.addListener("keyboardWillHide", () => {
+ isKeyboardOpened = false
+ })
+ })
+
// Clean up subscriptions when component is destroyed
- onDestroy(() => {
+ onDestroy(async () => {
setTimeout(() => {
if (get(Store.state.activeCall)) {
Store.setActiveCall(Store.getCallingChat(VoiceRTCInstance.channel!)!)
@@ -77,32 +93,36 @@
unsubscribeStore()
unsubscribeUIStore()
+ await mobileKeyboardListener01?.remove()
+ await mobileKeyboardListener02?.remove()
})
$: settings = SettingsStore.state
-
-
-
- {#each routes as route}
-
-
-
- {/each}
-
+{#if !isKeyboardOpened}
+
+
+
+ {#each routes as route}
+
+
+
+ {/each}
+
+{/if}
`}
diff --git a/src/routes/chat/+page.svelte b/src/routes/chat/+page.svelte
index cccf2da9f..f31be6537 100644
--- a/src/routes/chat/+page.svelte
+++ b/src/routes/chat/+page.svelte
@@ -5,22 +5,7 @@
import { animationDuration } from "$lib/globals/animations"
import { slide } from "svelte/transition"
import { Chatbar, Sidebar, Topbar, Profile } from "$lib/layouts"
- import {
- ImageEmbed,
- ChatPreview,
- Conversation,
- Message as MessageComponent,
- MessageGroup,
- MessageReactions,
- MessageReplyContainer,
- ProfilePicture,
- Modal,
- ProfilePictureMany,
- ChatFilter,
- ContextMenu,
- EmojiGroup,
- ChatIcon,
- } from "$lib/components"
+ import { ImageEmbed, ChatPreview, Conversation, Message as MessageComponent, MessageGroup, MessageReactions, MessageReplyContainer, Modal, ChatFilter, ContextMenu, EmojiGroup, ChatIcon } from "$lib/components"
import CreateTransaction from "$lib/components/wallet/CreateTransaction.svelte"
import { Button, FileInput, Icon, Label, Text } from "$lib/elements"
import CallScreen from "$lib/components/calling/CallScreen.svelte"
@@ -49,7 +34,7 @@
import { debounce, getTimeAgo } from "$lib/utils/Functions"
import Controls from "$lib/layouts/Controls.svelte"
import { tempCDN } from "$lib/utils/CommonVariables"
- import { checkMobile, isAndroidOriOS } from "$lib/utils/Mobile"
+ import { checkMobile, isAndroidOriOS, isiOSMobile } from "$lib/utils/Mobile"
import BrowseFiles from "../files/BrowseFiles.svelte"
import AttachmentRenderer from "$lib/components/messaging/AttachmentRenderer.svelte"
import ShareFile from "$lib/components/files/ShareFile.svelte"
@@ -57,6 +42,7 @@
import AddMembers from "$lib/components/group/AddMembers.svelte"
import { routes } from "$lib/defaults/routes"
import BottomNavBarMobile from "$lib/layouts/BottomNavBarMobile.svelte"
+ import { Keyboard } from "@capacitor/keyboard"
enum Permission {
UNDEFINED,
diff --git a/src/routes/settings/profile/+page.svelte b/src/routes/settings/profile/+page.svelte
index 55dffe412..e305c7983 100644
--- a/src/routes/settings/profile/+page.svelte
+++ b/src/routes/settings/profile/+page.svelte
@@ -23,6 +23,9 @@
import { log } from "$lib/utils/Logger"
import Modal from "$lib/components/ui/Modal.svelte"
import PinInput from "$lib/components/PinInput.svelte"
+ import { isiOSMobile } from "$lib/utils/Mobile"
+ import { Keyboard } from "@capacitor/keyboard"
+ import type { PluginListenerHandle } from "@capacitor/core"
enum SeedState {
Hidden,
@@ -173,14 +176,31 @@
let statusMessage: string = { ...get(Store.state.user) }.profile.status_message
let seedWarning = false
- onMount(() => {
+ let mobileKeyboardListener: PluginListenerHandle | undefined
+
+ onMount(async () => {
userReference = { ...get(Store.state.user) }
statusMessage = { ...get(Store.state.user) }.profile.status_message
+
+ if (isiOSMobile()) {
+ mobileKeyboardListener = await Keyboard.addListener("keyboardWillShow", _ => {
+ const focusedElement = document.activeElement
+ if (focusedElement && (focusedElement.tagName === "INPUT" || focusedElement.tagName === "TEXTAREA")) {
+ setTimeout(() => {
+ focusedElement.scrollIntoView({
+ behavior: "smooth",
+ block: "center",
+ })
+ }, 100)
+ }
+ })
+ }
})
- onDestroy(() => {
+ onDestroy(async () => {
Store.setUsername(userReference.name)
Store.setStatusMessage(userReference.profile.status_message)
+ await mobileKeyboardListener?.remove()
})
$: user = Store.state.user
@@ -352,7 +372,7 @@
{/if}
-