Skip to content

Commit

Permalink
Add Android immersive styles (aeharding#644)
Browse files Browse the repository at this point in the history
Resolves aeharding#638
  • Loading branch information
aeharding authored Aug 12, 2023
1 parent 794693d commit d5e24df
Show file tree
Hide file tree
Showing 18 changed files with 206 additions and 58 deletions.
1 change: 1 addition & 0 deletions android/app/capacitor.build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ dependencies {
implementation project(':capacitor-share')
implementation project(':capacitor-status-bar')
implementation project(':capacitor-application-context')
implementation project(':capacitor-plugin-safe-area')
implementation project(':capacitor-stash-media')

}
Expand Down
34 changes: 33 additions & 1 deletion android/app/src/main/java/app/vger/voyager/MainActivity.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,37 @@
package app.vger.voyager;

import android.os.Build;
import android.os.Bundle;
import android.view.View;

import com.getcapacitor.BridgeActivity;

public class MainActivity extends BridgeActivity {}
public class MainActivity extends BridgeActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

// https://github.com/ionic-team/capacitor/issues/2840#issuecomment-891093722
//
// Use a transparent status bar and nav bar, and place the window behind the status bar
// and nav bar. Due to a chromium bug, we need to get the height of both bars
// and add it to the safe area insets. The native plugin is used to get this info.
// See https://bugs.chromium.org/p/chromium/issues/detail?id=1094366
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
getWindow().setDecorFitsSystemWindows(false);
getWindow().setStatusBarColor(0);
getWindow().setNavigationBarColor(0);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
// On older versions of android setDecorFitsSystemWindows doesn't exist yet, but it can
// be emulated with flags.
// It still must be P or greater, as that is the min version for getting the insets
// through the native plugin.
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
getWindow().setStatusBarColor(0);
getWindow().setNavigationBarColor(0);
}
}
}
3 changes: 3 additions & 0 deletions android/capacitor.settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,8 @@ project(':capacitor-status-bar').projectDir = new File('../node_modules/.pnpm/@c
include ':capacitor-application-context'
project(':capacitor-application-context').projectDir = new File('../node_modules/.pnpm/[email protected]_@[email protected]/node_modules/capacitor-application-context/android')

include ':capacitor-plugin-safe-area'
project(':capacitor-plugin-safe-area').projectDir = new File('../node_modules/.pnpm/[email protected]_@[email protected]/node_modules/capacitor-plugin-safe-area/android')

include ':capacitor-stash-media'
project(':capacitor-stash-media').projectDir = new File('../node_modules/.pnpm/[email protected]_@[email protected]/node_modules/capacitor-stash-media/android')
3 changes: 3 additions & 0 deletions capacitor.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ const config: CapacitorConfig = {
CapacitorHttp: {
enabled: true,
},
Keyboard: {
resizeOnFullScreen: true,
},
},
};

Expand Down
1 change: 1 addition & 0 deletions ios/App/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ def capacitor_pods
pod 'CapacitorShare', :path => '../../node_modules/.pnpm/@[email protected]_@[email protected]/node_modules/@capacitor/share'
pod 'CapacitorStatusBar', :path => '../../node_modules/.pnpm/@[email protected]_@[email protected]/node_modules/@capacitor/status-bar'
pod 'CapacitorApplicationContext', :path => '../../node_modules/.pnpm/[email protected]_@[email protected]/node_modules/capacitor-application-context'
pod 'CapacitorPluginSafeArea', :path => '../../node_modules/.pnpm/[email protected]_@[email protected]/node_modules/capacitor-plugin-safe-area'
pod 'CapacitorStashMedia', :path => '../../node_modules/.pnpm/[email protected]_@[email protected]/node_modules/capacitor-stash-media'
end

Expand Down
8 changes: 7 additions & 1 deletion ios/App/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ PODS:
- Capacitor
- CapacitorKeyboard (5.0.6):
- Capacitor
- CapacitorPluginSafeArea (2.0.5):
- Capacitor
- CapacitorShare (5.0.6):
- Capacitor
- CapacitorStashMedia (0.0.3):
Expand All @@ -31,6 +33,7 @@ DEPENDENCIES:
- "CapacitorCordova (from `../../node_modules/.pnpm/@[email protected]_@[email protected]/node_modules/@capacitor/ios`)"
- "CapacitorHaptics (from `../../node_modules/.pnpm/@[email protected]_@[email protected]/node_modules/@capacitor/haptics`)"
- "CapacitorKeyboard (from `../../node_modules/.pnpm/@[email protected]_@[email protected]/node_modules/@capacitor/keyboard`)"
- "CapacitorPluginSafeArea (from `../../node_modules/.pnpm/[email protected]_@[email protected]/node_modules/capacitor-plugin-safe-area`)"
- "CapacitorShare (from `../../node_modules/.pnpm/@[email protected]_@[email protected]/node_modules/@capacitor/share`)"
- "CapacitorStashMedia (from `../../node_modules/.pnpm/[email protected]_@[email protected]/node_modules/capacitor-stash-media`)"
- "CapacitorStatusBar (from `../../node_modules/.pnpm/@[email protected]_@[email protected]/node_modules/@capacitor/status-bar`)"
Expand All @@ -54,6 +57,8 @@ EXTERNAL SOURCES:
:path: "../../node_modules/.pnpm/@[email protected]_@[email protected]/node_modules/@capacitor/haptics"
CapacitorKeyboard:
:path: "../../node_modules/.pnpm/@[email protected]_@[email protected]/node_modules/@capacitor/keyboard"
CapacitorPluginSafeArea:
:path: "../../node_modules/.pnpm/[email protected]_@[email protected]/node_modules/capacitor-plugin-safe-area"
CapacitorShare:
:path: "../../node_modules/.pnpm/@[email protected]_@[email protected]/node_modules/@capacitor/share"
CapacitorStashMedia:
Expand All @@ -69,11 +74,12 @@ SPEC CHECKSUMS:
CapacitorCordova: 3773395d5331add072300ff6041ca2cf7b93cb0b
CapacitorHaptics: 1fffc1217c7e64a472d7845be50fb0c2f7d4204c
CapacitorKeyboard: b978154b024a5f65e044908e37d15b7de58b9d12
CapacitorPluginSafeArea: bfdd714827dbd89fb44fea286beec996e1b0c5c4
CapacitorShare: cd41743331cb71d217c029de54b681cbd91e0fcc
CapacitorStashMedia: c2a4d719906c1862007f3562194018dfeda87451
CapacitorStatusBar: 565c0a1ebd79bb40d797606a8992b4a105885309
SDWebImage: 750adf017a315a280c60fde706ab1e552a3ae4e9

PODFILE CHECKSUM: 99b010f7612ca41b433f9bfe805a71822374b276
PODFILE CHECKSUM: 64aed244866097bf21833d6fbb682b5d31e29b18

COCOAPODS: 1.12.1
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
"@vitejs/plugin-legacy": "^4.0.5",
"@vitejs/plugin-react": "^4.0.1",
"capacitor-application-context": "^0.0.1",
"capacitor-plugin-safe-area": "^2.0.5",
"capacitor-set-version": "^2.0.13",
"capacitor-stash-media": "^0.0.3",
"date-fns": "^2.30.0",
Expand Down
11 changes: 11 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 32 additions & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import "@ionic/react/css/flex-utils.css";
import "@ionic/react/css/display.css";

import { StoreProvider } from "./store";
import { isInstalled } from "./helpers/device";
import { isAndroid, isInstalled, isNative } from "./helpers/device";
import TabbedRoutes from "./TabbedRoutes";
import Auth from "./Auth";
import { AppContextProvider } from "./features/auth/AppContext";
Expand All @@ -27,13 +27,44 @@ import { UpdateContextProvider } from "./pages/settings/update/UpdateContext";
import GlobalStyles from "./GlobalStyles";
import ConfigProvider from "./services/app";
import { getDeviceMode } from "./features/settings/settingsSlice";
import { SafeArea, SafeAreaInsets } from "capacitor-plugin-safe-area";
import { StatusBar } from "@capacitor/status-bar";
import { Keyboard } from "@capacitor/keyboard";

setupIonicReact({
rippleEffect: false,
mode: getDeviceMode(),
swipeBackEnabled: isInstalled() && getDeviceMode() === "ios",
});

// Android safe area inset management is bad, we have to do it manually
if (isNative() && isAndroid()) {
let keyboardShowing = false;

const updateInsets = ({ insets }: SafeAreaInsets) => {
for (const [key, value] of Object.entries(insets)) {
document.documentElement.style.setProperty(
`--ion-safe-area-${key}`,
// if keyboard open, assume no safe area inset
`${keyboardShowing && key === "bottom" ? 0 : value}px`
);
}
};

SafeArea.getSafeAreaInsets().then(updateInsets);
SafeArea.addListener("safeAreaChanged", updateInsets);
StatusBar.setOverlaysWebView({ overlay: true });

Keyboard.addListener("keyboardWillShow", () => {
keyboardShowing = true;
SafeArea.getSafeAreaInsets().then(updateInsets);
});
Keyboard.addListener("keyboardWillHide", () => {
keyboardShowing = false;
SafeArea.getSafeAreaInsets().then(updateInsets);
});
}

export default function App() {
return (
<ConfigProvider>
Expand Down
1 change: 0 additions & 1 deletion src/GlobalStyles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ export default function GlobalStyles({ children }: GlobalStylesProps) {
useEffect(() => {
if (!isNative()) return;

StatusBar.setBackgroundColor({ color: isDark ? "#000000" : "#f7f7f7" }); // android only
StatusBar.setStyle({ style: isDark ? Style.Dark : Style.Light });
}, [isDark]);

Expand Down
14 changes: 7 additions & 7 deletions src/features/comment/compose/shared.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import MarkdownToolbar, {
} from "../../shared/markdown/editing/MarkdownToolbar";
import { IonContent } from "@ionic/react";
import { preventPhotoswipeGalleryFocusTrap } from "../../gallery/GalleryImg";
import useKeyboardHeight from "../../../helpers/useKeyboardHeight";
import React, { Dispatch, SetStateAction, useRef } from "react";
import TextareaAutosizedForOnScreenKeyboard from "../../shared/TextareaAutosizedForOnScreenKeyboard";
import { css } from "@emotion/react";
import useKeyboardOpen from "../../../helpers/useKeyboardOpen";

export const Container = styled.div<{ keyboardHeight: number }>`
export const Container = styled.div<{ keyboardOpen: boolean }>`
min-height: 100%;
display: flex;
Expand All @@ -19,10 +19,10 @@ export const Container = styled.div<{ keyboardHeight: number }>`
padding-bottom: ${TOOLBAR_HEIGHT};
@media screen and (max-width: 767px) {
padding-bottom: ${({ keyboardHeight }) =>
keyboardHeight
padding-bottom: ${({ keyboardOpen }) =>
keyboardOpen
? TOOLBAR_HEIGHT
: `calc(${TOOLBAR_HEIGHT} + env(safe-area-inset-bottom))`};
: `calc(${TOOLBAR_HEIGHT} + var(--ion-safe-area-bottom, env(safe-area-inset-bottom)))`};
}
`;

Expand Down Expand Up @@ -58,13 +58,13 @@ export default function CommentContent({
setText,
children,
}: CommentContentProps) {
const keyboardHeight = useKeyboardHeight();
const keyboardOpen = useKeyboardOpen();
const textareaRef = useRef<HTMLTextAreaElement>(null);

return (
<>
<IonContent {...preventPhotoswipeGalleryFocusTrap}>
<Container keyboardHeight={keyboardHeight}>
<Container keyboardOpen={keyboardOpen}>
<Textarea
ref={textareaRef}
value={text}
Expand Down
4 changes: 3 additions & 1 deletion src/features/gallery/GalleryProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ const Container = styled.div`
left: 0;
padding: 1rem;
padding-top: 4rem;
padding-bottom: calc(1rem + env(safe-area-inset-bottom, 0));
padding-bottom: calc(
1rem + var(--ion-safe-area-bottom, env(safe-area-inset-bottom, 0))
);
color: white;
background: linear-gradient(0deg, rgba(0, 0, 0, 1), transparent);
Expand Down
14 changes: 7 additions & 7 deletions src/features/post/new/NewPostText.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,22 @@ import { Dispatch, SetStateAction, useEffect, useRef, useState } from "react";
import { Centered, Spinner } from "../../auth/Login";
import { css } from "@emotion/react";
import TextareaAutosizedForOnScreenKeyboard from "../../shared/TextareaAutosizedForOnScreenKeyboard";
import useKeyboardHeight from "../../../helpers/useKeyboardHeight";
import MarkdownToolbar, {
TOOLBAR_HEIGHT,
TOOLBAR_TARGET_ID,
} from "../../shared/markdown/editing/MarkdownToolbar";
import useKeyboardOpen from "../../../helpers/useKeyboardOpen";

const Container = styled.div<{ keyboardHeight: number }>`
const Container = styled.div<{ keyboardOpen: boolean }>`
min-height: 100%;
display: flex;
flex-direction: column;
padding-bottom: ${({ keyboardHeight }) =>
keyboardHeight
padding-bottom: ${({ keyboardOpen }) =>
keyboardOpen
? TOOLBAR_HEIGHT
: `calc(${TOOLBAR_HEIGHT} + env(safe-area-inset-bottom))`};
: `calc(${TOOLBAR_HEIGHT} + var(--ion-safe-area-bottom, env(safe-area-inset-bottom)))`};
`;

const Textarea = styled(TextareaAutosizedForOnScreenKeyboard)`
Expand Down Expand Up @@ -63,7 +63,7 @@ export default function NewPostText({
}: NewPostTextProps) {
const [loading, setLoading] = useState(false);

const keyboardHeight = useKeyboardHeight();
const keyboardOpen = useKeyboardOpen();
const textareaRef = useRef<HTMLTextAreaElement>(null);

const [text, setText] = useState(value);
Expand Down Expand Up @@ -103,7 +103,7 @@ export default function NewPostText({
</IonToolbar>
</IonHeader>
<IonContent>
<Container keyboardHeight={keyboardHeight}>
<Container keyboardOpen={keyboardOpen}>
<Textarea
id={TOOLBAR_TARGET_ID}
ref={textareaRef}
Expand Down
20 changes: 11 additions & 9 deletions src/features/shared/markdown/editing/MarkdownToolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import {
link,
} from "ionicons/icons";
import "@github/markdown-toolbar-element";
import useKeyboardHeight from "../../../../helpers/useKeyboardHeight";
import PreviewModal from "./PreviewModal";
import {
Dispatch,
Expand All @@ -30,6 +29,7 @@ import { uploadImage } from "../../../../services/lemmy";
import { useAppSelector } from "../../../../store";
import { jwtSelector, urlSelector } from "../../../auth/authSlice";
import { insert } from "../../../../helpers/string";
import useKeyboardOpen from "../../../../helpers/useKeyboardOpen";

export const TOOLBAR_TARGET_ID = "toolbar-target";
export const TOOLBAR_HEIGHT = "50px";
Expand All @@ -41,7 +41,7 @@ const ToolbarContainer = styled.div`
pointer-events: none;
`;

const Toolbar = styled.div<{ keyboardHeight: number }>`
const Toolbar = styled.div<{ keyboardOpen: boolean }>`
pointer-events: all;
position: absolute;
Expand All @@ -50,12 +50,14 @@ const Toolbar = styled.div<{ keyboardHeight: number }>`
height: ${TOOLBAR_HEIGHT};
@media screen and (max-width: 767px) {
height: ${({ keyboardHeight }) =>
!keyboardHeight
? `calc(${TOOLBAR_HEIGHT} + env(safe-area-inset-bottom))`
height: ${({ keyboardOpen }) =>
!keyboardOpen
? `calc(${TOOLBAR_HEIGHT} + var(--ion-safe-area-bottom, env(safe-area-inset-bottom)))`
: TOOLBAR_HEIGHT};
padding-bottom: ${({ keyboardHeight }) =>
!keyboardHeight ? "env(safe-area-inset-bottom)" : 0};
padding-bottom: ${({ keyboardOpen }) =>
!keyboardOpen
? "var(--ion-safe-area-bottom, env(safe-area-inset-bottom))"
: 0};
}
width: 100%;
Expand Down Expand Up @@ -105,7 +107,7 @@ export default function MarkdownToolbar({
}: MarkdownToolbarProps) {
const [presentActionSheet] = useIonActionSheet();
const [presentAlert] = useIonToast();
const keyboardHeight = useKeyboardHeight();
const keyboardOpen = useKeyboardOpen();
const [imageUploading, setImageUploading] = useState(false);
const jwt = useAppSelector(jwtSelector);
const instanceUrl = useAppSelector(urlSelector);
Expand Down Expand Up @@ -181,7 +183,7 @@ export default function MarkdownToolbar({
<IonLoading isOpen={imageUploading} message="Uploading image..." />

<ToolbarContainer className="fixed-toolbar-container" slot={slot}>
<Toolbar keyboardHeight={keyboardHeight} ref={toolbarRef}>
<Toolbar keyboardOpen={keyboardOpen} ref={toolbarRef}>
<markdown-toolbar for={TOOLBAR_TARGET_ID}>
<label htmlFor="photo-upload">
<Button as="div" onClick={() => textareaRef.current?.focus()}>
Expand Down
Loading

0 comments on commit d5e24df

Please sign in to comment.