Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(Navigation): Improve navigation using bottom nav bar on mobile #926

Merged
merged 22 commits into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
f778187
feat(sidebar): add slide transition for sidebar visibility
lgmarchi Dec 6, 2024
e5f5538
feat(sidebar): enhance sidebar layout with improved positioning and t…
lgmarchi Dec 6, 2024
691fc34
feat(sidebar): add configurable slide duration for sidebar transitions
lgmarchi Dec 6, 2024
c176888
Merge branch 'dev' into improve-sidebar-animation
stavares843 Dec 6, 2024
3691e46
feat(routes): refactor route enums and add getRoute function for impr…
lgmarchi Dec 6, 2024
e4662e6
Merge remote-tracking branch 'origin/dev' into fix-bottom-nav-bar-on-…
lgmarchi Dec 6, 2024
63e10f7
Merge branch 'dev' into improve-sidebar-animation
lgmarchi Dec 6, 2024
453e990
Merge branch 'dev' into fix-bottom-nav-bar-on-mobile
luisecm Dec 6, 2024
20920fe
fix(modal): increase z-index for modal to ensure proper stacking order
lgmarchi Dec 6, 2024
0f8fff6
Merge branch 'improve-sidebar-animation' into fix-bottom-nav-bar-on-m…
lgmarchi Dec 6, 2024
817da87
Merge branch 'dev' into improve-sidebar-animation
phillsatellite Dec 9, 2024
de7d3bb
Merge branch 'dev' into fix-bottom-nav-bar-on-mobile
phillsatellite Dec 9, 2024
22cef04
Merge branch 'dev' into improve-sidebar-animation
phillsatellite Dec 9, 2024
2b376ef
Merge branch 'dev' into fix-bottom-nav-bar-on-mobile
phillsatellite Dec 9, 2024
cea70d5
fix(sidebar): change sidebar height to 100% for better responsiveness
lgmarchi Dec 10, 2024
29b3d19
Merge branch 'improve-sidebar-animation' into fix-bottom-nav-bar-on-m…
lgmarchi Dec 10, 2024
4aec8a8
Merge branch 'dev' into fix-bottom-nav-bar-on-mobile
stavares843 Dec 10, 2024
d4c6fef
feat(BottomNavBarMobile): enhance visibility based on keyboard and si…
lgmarchi Dec 12, 2024
db2d919
feat(BottomNavBarMobile): improve keyboard handling and change positi…
lgmarchi Dec 12, 2024
1cc21a1
Merge remote-tracking branch 'origin/dev' into fix-bottom-nav-bar-on-…
lgmarchi Dec 12, 2024
b072572
Merge branch 'dev' into fix-bottom-nav-bar-on-mobile
luisecm Dec 12, 2024
be006da
Merge branch 'dev' into fix-bottom-nav-bar-on-mobile
lgmarchi Dec 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/lib/enums/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export const enum EmojiFont {
Fluent = "Fluent",
}

export const enum Route {
export enum Route {
Home = "/",
Chat = "/chat",
Files = "/files",
Expand All @@ -101,6 +101,10 @@ export const enum Route {
Pre = "/pre",
}

export function getRoute(value: string): Route {
return value.startsWith("/settings") ? Route.Settings : Object.values(Route).find(route => route === value) || Route.Home
}

export const enum FilesItemKind {
File,
Folder,
Expand Down
99 changes: 68 additions & 31 deletions src/lib/layouts/BottomNavBarMobile.svelte
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
<script lang="ts">
import { Keyboard } from "@capacitor/keyboard"
import { page } from "$app/stores"
import { Button, Icon, Text } from "$lib/elements"
import { Appearance, CommunitySettingsRoute, Route, SettingsRoute } from "$lib/enums"
import { VoiceRTCInstance } from "$lib/media/Voice"
Expand All @@ -7,8 +9,9 @@
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 { afterNavigate, onNavigate } from "$app/navigation"

export let routes: NavRoute[] = []
export let activeRoute: Route | SettingsRoute | CommunitySettingsRoute = Route.Home
Expand Down Expand Up @@ -56,7 +59,6 @@
// Avoid keyboard when navigate to chat preview list
}
}

dispatch("navigate", route.to.toString())
}

Expand All @@ -67,6 +69,47 @@
if (route.to === Route.Settings) return true
}

if (isAndroidOriOS()) {
Keyboard.addListener("keyboardWillShow", () => {
showBottomNavBar = checkIfCanShowBottomNavBar(get(UIStore.state.sidebarOpen), null, true)
})

Keyboard.addListener("keyboardWillHide", () => {
showBottomNavBar = checkIfCanShowBottomNavBar(get(UIStore.state.sidebarOpen), null, false)
})
}

UIStore.state.sidebarOpen.subscribe(open => {
showBottomNavBar = checkIfCanShowBottomNavBar(open, null, false)
})

onNavigate(async e => {
const routeId = e.to?.route.id
showBottomNavBar = checkIfCanShowBottomNavBar(get(UIStore.state.sidebarOpen), routeId, false)
})

function checkIfCanShowBottomNavBar(sidebarOpen: boolean, routeId: string | null | undefined, isMobileKeyboardOpened: boolean): boolean {
let currentRoute = routeId ?? $page.route.id

if (isAndroidOriOS() && !isMobileKeyboardOpened) {
if (currentRoute === "/chat" && sidebarOpen) {
return true
}
if (currentRoute === "/friends") {
return true
}
if (currentRoute?.includes("/settings")) {
return true
}
if (currentRoute === "/files") {
return true
}
}
return false
}

$: showBottomNavBar = checkIfCanShowBottomNavBar(get(UIStore.state.sidebarOpen), null, false)

// Clean up subscriptions when component is destroyed
onDestroy(() => {
setTimeout(() => {
Expand All @@ -81,36 +124,30 @@
$: settings = SettingsStore.state
</script>

<div class="content"></div>

<div class="navigation {vertical ? 'vertical' : 'horizontal'} {icons ? 'icons' : ''}">
{#each routes as route}
<div class="navigation-control {!icons ? 'fill' : ''}">
<Button
hook="button-{route.name}"
badge={badgeCounts[route.to]}
fill={!icons}
tooltip={route.name}
icon={icons}
outline={activeRoute !== route.to && !icons}
appearance={activeRoute === route.to ? Appearance.Primary : Appearance.Alt}
on:click={() => handleNavigate(route)}>
<Icon alt={activeRoute === route.to} icon={route.icon} />
{#if !icons}
<Text appearance={activeRoute !== route.to ? Appearance.Default : Appearance.Alt}>{route.name}</Text>
{/if}
</Button>
</div>
{/each}
</div>
{#if showBottomNavBar}
<div id="bottom-nav-bar-mobile" class="navigation {vertical ? 'vertical' : 'horizontal'} {icons ? 'icons' : ''}">
{#each routes as route}
<div class="navigation-control {!icons ? 'fill' : ''}">
<Button
hook="button-{route.name}"
badge={badgeCounts[route.to]}
fill={!icons}
tooltip={route.name}
icon={icons}
outline={activeRoute !== route.to && !icons}
appearance={activeRoute === route.to ? Appearance.Primary : Appearance.Alt}
on:click={() => handleNavigate(route)}>
<Icon alt={activeRoute === route.to} icon={route.icon} />
{#if !icons}
<Text appearance={activeRoute !== route.to ? Appearance.Default : Appearance.Alt}>{route.name}</Text>
{/if}
</Button>
</div>
{/each}
</div>
{/if}

<style lang="scss">
.content {
height: 60px;
pointer-events: none;
background: transparent;
border: none;
}
.navigation {
display: inline-flex;
gap: var(--gap);
Expand All @@ -121,7 +158,7 @@
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
z-index: 1000;
position: fixed;
position: sticky;
bottom: 0;
left: 0;
right: 0;
Expand Down
17 changes: 15 additions & 2 deletions src/routes/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import GamepadListener from "$lib/components/ui/GamepadListener.svelte"
import KeyboardListener from "$lib/components/ui/KeyboardListener.svelte"
import { playSound, Sounds } from "$lib/components/utils/SoundHandler"
import { EmojiFont, KeybindAction, KeybindState } from "$lib/enums"
import { EmojiFont, getRoute, KeybindAction, KeybindState, Route } from "$lib/enums"
import { VoiceRTCInstance } from "$lib/media/Voice"
import { SettingsStore } from "$lib/state"
import { checkIfUserIsLogged } from "$lib/state/auth"
Expand All @@ -28,6 +28,9 @@
import Market from "$lib/components/market/Market.svelte"
import { swipe } from "$lib/components/ui/Swipe"
import { ScreenOrientation } from "@capacitor/screen-orientation"
import BottomNavBarMobile from "$lib/layouts/BottomNavBarMobile.svelte"
import { goto, onNavigate } from "$app/navigation"
import { routes } from "$lib/defaults/routes"
import { fetchDeviceInfo, isAndroid, isAndroidOriOS } from "$lib/utils/Mobile"
import { changeSafeAreaColorsOnAndroid } from "$lib/plugins/safeAreaColorAndroid"

Expand Down Expand Up @@ -289,7 +292,7 @@

onMount(async () => {
await fetchDeviceInfo()
if (await isAndroidOriOS()) {
if (isAndroidOriOS()) {
lockOrientation()
}

Expand All @@ -298,6 +301,8 @@
buildStyle()
changeSafeAreaColors()
})

$: activeRoute = getRoute($page.route.id!)
</script>

{#if isLocaleSet}
Expand All @@ -324,6 +329,14 @@
<Market on:close={() => UIStore.toggleMarket()} />
<InstallBanner />
<slot></slot>
<BottomNavBarMobile
icons
routes={routes}
activeRoute={activeRoute}
on:navigate={e => {
activeRoute = e.detail
goto(e.detail)
}} />
</div>
{:else}
<CircularProgressIndicator />
Expand Down
8 changes: 0 additions & 8 deletions src/routes/chat/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,6 @@
import ShareFile from "$lib/components/files/ShareFile.svelte"
import { ToastMessage } from "$lib/state/ui/toast"
import AddMembers from "$lib/components/group/AddMembers.svelte"
import { routes } from "$lib/defaults/routes"
import BottomNavBarMobile from "$lib/layouts/BottomNavBarMobile.svelte"

enum Permission {
UNDEFINED,
Expand Down Expand Up @@ -644,9 +642,6 @@
<ChatPreview slot="content" let:open on:contextmenu={open} chat={chat} loading={loading} cta={$activeChat === chat} />
</ContextMenu>
{/each}
{#if isAndroidOriOS()}
<BottomNavBarMobile icons routes={routes} activeRoute={Route.Chat} on:navigate={e => goto(e.detail)} />
{/if}
</Sidebar>

<div class="content">
Expand Down Expand Up @@ -1068,9 +1063,6 @@
</div>
{/if}
</div>
{#if isAndroidOriOS() && $activeChat.users.length === 0}
<BottomNavBarMobile icons routes={routes} activeRoute={Route.Chat} on:navigate={e => goto(e.detail)} />
{/if}

<style lang="scss">
#page {
Expand Down
6 changes: 0 additions & 6 deletions src/routes/files/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@
import { Store } from "$lib/state/Store"
import path from "path"
import { MultipassStoreInstance } from "$lib/wasm/MultipassStore"
import { routes } from "$lib/defaults/routes"
import { isAndroidOriOS } from "$lib/utils/Mobile"
import BottomNavBarMobile from "$lib/layouts/BottomNavBarMobile.svelte"

export let browseFilesForChatMode: boolean = false

Expand Down Expand Up @@ -809,9 +806,6 @@
</div>
</div>
</div>
{#if isAndroidOriOS()}
<BottomNavBarMobile icons routes={routes} activeRoute={Route.Files} on:navigate={e => goto(e.detail)} />
{/if}

<style lang="scss">
#page {
Expand Down
7 changes: 1 addition & 6 deletions src/routes/friends/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@
import { CommonInputRules } from "$lib/utils/CommonInputRules"
import CreateGroup from "$lib/components/group/CreateGroup.svelte"
import { onDestroy } from "svelte"
import { isAndroidOriOS } from "$lib/utils/Mobile"
import { routes } from "$lib/defaults/routes"
import BottomNavBarMobile from "$lib/layouts/BottomNavBarMobile.svelte"

import { Clipboard } from "@capacitor/clipboard"

let loading: boolean = false
Expand Down Expand Up @@ -464,9 +462,6 @@
</Modal>
{/if}
</div>
{#if isAndroidOriOS()}
<BottomNavBarMobile icons routes={routes} activeRoute={Route.Friends} on:navigate={e => goto(e.detail)} />
{/if}

<style lang="scss">
#page {
Expand Down
5 changes: 0 additions & 5 deletions src/routes/settings/+layout.svelte
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
<script lang="ts">
import { goto } from "$app/navigation"
import { page } from "$app/stores"
import { routes } from "$lib/defaults/routes"
import { Route, SettingsRoute, Shape } from "$lib/enums"
import BottomNavBarMobile from "$lib/layouts/BottomNavBarMobile.svelte"

import Navigation from "$lib/layouts/Navigation.svelte"
import Sidebar from "$lib/layouts/Sidebar.svelte"
Expand Down Expand Up @@ -208,9 +206,6 @@
</div>
</div>
</div>
{#if isAndroidOriOS()}
<BottomNavBarMobile icons routes={routes} activeRoute={Route.Settings} on:navigate={e => goto(e.detail)} />
{/if}

<style lang="scss">
#settings {
Expand Down
Loading