Fix: Reader footer position & system bar (#1076)
* replace native Navigation bar by expo-navigation-bar * fix fullscreen logic * fix: navigation button color * fix: navigation color when theme changed * fix: status bar color on full screen mode * 40 is too large * no 40 is acceptable :) * refactor setBarColor * refactor: rename setStatusBarColor * no padding for landscape mode
This commit is contained in:
@@ -13,7 +13,6 @@ import com.facebook.react.defaults.DefaultReactNativeHost;
|
||||
import com.facebook.soloader.SoLoader;
|
||||
|
||||
import com.rajarsheechatterjee.EpubUtil.EpubUtilPackage;
|
||||
import com.rajarsheechatterjee.NavigationBarColor.NavigationBarColorPackage;
|
||||
import com.rajarsheechatterjee.TextFile.TextFilePackage;
|
||||
import com.rajarsheechatterjee.VolumeButtonListener.VolumeButtonListenerPackage;
|
||||
import com.rajarsheechatterjee.ZipArchive.ZipArchivePackage;
|
||||
@@ -35,7 +34,6 @@ public class MainApplication extends Application implements ReactApplication {
|
||||
@Override
|
||||
protected List<ReactPackage> getPackages() {
|
||||
List<ReactPackage> packages = new PackageList(this).getPackages();
|
||||
packages.add(new NavigationBarColorPackage());
|
||||
packages.add(new VolumeButtonListenerPackage());
|
||||
packages.add(new ZipArchivePackage());
|
||||
packages.add(new TextFilePackage());
|
||||
|
||||
-158
@@ -1,158 +0,0 @@
|
||||
package com.rajarsheechatterjee.NavigationBarColor;
|
||||
|
||||
import android.animation.ArgbEvaluator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.graphics.Color;
|
||||
import android.os.Build;
|
||||
import android.app.Activity;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.Promise;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import com.facebook.react.uimanager.IllegalViewOperationException;
|
||||
import static com.facebook.react.bridge.UiThreadUtil.runOnUiThread;
|
||||
|
||||
public class NavigationBarColorModule extends ReactContextBaseJavaModule {
|
||||
public static final String REACT_CLASS = "NavigationBarColor";
|
||||
private static final String ERROR_NO_ACTIVITY = "E_NO_ACTIVITY";
|
||||
private static final String ERROR_NO_ACTIVITY_MESSAGE = "Tried to change the navigation bar while not attached to an Activity";
|
||||
private static final int UI_FLAG_HIDE_NAV_BAR = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar
|
||||
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
|
||||
|
||||
public NavigationBarColorModule(ReactApplicationContext context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public void setNavigationBarTheme(Activity activity, Boolean light) {
|
||||
if (activity != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
Window window = activity.getWindow();
|
||||
int flags = window.getDecorView().getSystemUiVisibility();
|
||||
if (light) {
|
||||
flags |= View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
|
||||
} else {
|
||||
flags &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
|
||||
}
|
||||
window.getDecorView().setSystemUiVisibility(flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return REACT_CLASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getConstants() {
|
||||
final Map<String, Object> constants = new HashMap<>();
|
||||
constants.put("EXAMPLE_CONSTANT", "example");
|
||||
|
||||
return constants;
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void changeNavigationBarColor(final String color, final Boolean light, final Boolean animated, final Promise promise) {
|
||||
final WritableMap map = Arguments.createMap();
|
||||
if (getCurrentActivity() != null) {
|
||||
try {
|
||||
final Window window = getCurrentActivity().getWindow();
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (color.equals("transparent") || color.equals("translucent")) {
|
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
|
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
|
||||
if (color.equals("transparent")) {
|
||||
window.setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
|
||||
} else {
|
||||
window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
|
||||
}
|
||||
setNavigationBarTheme(getCurrentActivity(), light);
|
||||
map.putBoolean("success", true);
|
||||
promise.resolve(map);
|
||||
return;
|
||||
} else {
|
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
|
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
|
||||
}
|
||||
if (animated) {
|
||||
Integer colorFrom = window.getNavigationBarColor();
|
||||
Integer colorTo = Color.parseColor(color);
|
||||
//window.setNavigationBarColor(colorTo);
|
||||
ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
|
||||
colorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animator) {
|
||||
window.setNavigationBarColor((Integer) animator.getAnimatedValue());
|
||||
}
|
||||
});
|
||||
colorAnimation.start();
|
||||
} else {
|
||||
window.setNavigationBarColor(Color.parseColor(color));
|
||||
}
|
||||
setNavigationBarTheme(getCurrentActivity(), light);
|
||||
WritableMap map = Arguments.createMap();
|
||||
map.putBoolean("success", true);
|
||||
promise.resolve(map);
|
||||
}
|
||||
});
|
||||
} catch (IllegalViewOperationException e) {
|
||||
map.putBoolean("success", false);
|
||||
promise.reject("error", e);
|
||||
}
|
||||
|
||||
} else {
|
||||
promise.reject(ERROR_NO_ACTIVITY, new Throwable(ERROR_NO_ACTIVITY_MESSAGE));
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void hideNavigationBar(Promise promise) {
|
||||
try {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (getCurrentActivity() != null) {
|
||||
View decorView = getCurrentActivity().getWindow().getDecorView();
|
||||
decorView.setSystemUiVisibility(UI_FLAG_HIDE_NAV_BAR);
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (IllegalViewOperationException e) {
|
||||
WritableMap map = Arguments.createMap();
|
||||
map.putBoolean("success", false);
|
||||
promise.reject("error", e);
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void showNavigationBar(Promise promise) {
|
||||
try {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (getCurrentActivity() != null) {
|
||||
Window w = getCurrentActivity().getWindow();
|
||||
w.setStatusBarColor(Color.TRANSPARENT);
|
||||
w.setNavigationBarColor(Color.TRANSPARENT);
|
||||
View decorView = w.getDecorView();
|
||||
decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (IllegalViewOperationException e) {
|
||||
WritableMap map = Arguments.createMap();
|
||||
map.putBoolean("success", false);
|
||||
promise.reject("error", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
package com.rajarsheechatterjee.NavigationBarColor;
|
||||
import com.facebook.react.ReactPackage;
|
||||
import com.facebook.react.bridge.NativeModule;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.uimanager.ViewManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class NavigationBarColorPackage implements ReactPackage {
|
||||
@Override
|
||||
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
|
||||
List<NativeModule> modules = new ArrayList<>();
|
||||
|
||||
modules.add(new NavigationBarColorModule(reactContext));
|
||||
|
||||
return modules;
|
||||
}
|
||||
}
|
||||
Generated
+25
@@ -27,6 +27,7 @@
|
||||
"expo-linear-gradient": "~12.3.0",
|
||||
"expo-linking": "~5.0.2",
|
||||
"expo-localization": "~14.3.0",
|
||||
"expo-navigation-bar": "^2.8.1",
|
||||
"expo-notifications": "~0.20.1",
|
||||
"expo-speech": "~11.3.0",
|
||||
"expo-sqlite": "~11.3.3",
|
||||
@@ -10001,6 +10002,18 @@
|
||||
"invariant": "^2.2.4"
|
||||
}
|
||||
},
|
||||
"node_modules/expo-navigation-bar": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/expo-navigation-bar/-/expo-navigation-bar-2.8.1.tgz",
|
||||
"integrity": "sha512-aT5G+7SUsXDVPsRwp8fF940ycka1ABb4g3QKvTZN3YP6kMWvsiYEmRqMIJVy0zUr/i6bxBG1ZergkXimWrFt3w==",
|
||||
"dependencies": {
|
||||
"@react-native/normalize-color": "^2.0.0",
|
||||
"debug": "^4.3.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"expo": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/expo-notifications": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/expo-notifications/-/expo-notifications-0.20.1.tgz",
|
||||
@@ -15722,6 +15735,18 @@
|
||||
"@babel/runtime": "^7.20.6"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-dotenv/node_modules/dotenv": {
|
||||
"version": "16.4.5",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz",
|
||||
"integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://dotenvx.com"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-drawer-layout": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/react-native-drawer-layout/-/react-native-drawer-layout-3.2.2.tgz",
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
"expo-linear-gradient": "~12.3.0",
|
||||
"expo-linking": "~5.0.2",
|
||||
"expo-localization": "~14.3.0",
|
||||
"expo-navigation-bar": "^2.8.1",
|
||||
"expo-notifications": "~0.20.1",
|
||||
"expo-speech": "~11.3.0",
|
||||
"expo-sqlite": "~11.3.3",
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import { StatusBar } from 'react-native';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import color from 'color';
|
||||
import {
|
||||
changeNavigationBarColor,
|
||||
hideNavigationBar,
|
||||
showNavigationBar,
|
||||
} from '../../native/NavigationBarColor';
|
||||
import {
|
||||
useChapterGeneralSettings,
|
||||
useChapterReaderSettings,
|
||||
useTheme,
|
||||
} from '../persisted';
|
||||
import Color from 'color';
|
||||
import * as NavigationBar from 'expo-navigation-bar';
|
||||
import {
|
||||
changeNavigationBarColor,
|
||||
setStatusBarColor,
|
||||
} from '@theme/utils/setBarColor';
|
||||
|
||||
const useFullscreenMode = () => {
|
||||
const { addListener } = useNavigation();
|
||||
@@ -23,21 +22,37 @@ const useFullscreenMode = () => {
|
||||
const setImmersiveMode = useCallback(() => {
|
||||
if (fullScreenMode) {
|
||||
StatusBar.setHidden(true);
|
||||
hideNavigationBar();
|
||||
NavigationBar.setVisibilityAsync('hidden');
|
||||
} else {
|
||||
StatusBar.setBarStyle(
|
||||
color(backgroundColor).isDark() ? 'light-content' : 'dark-content',
|
||||
setStatusBarColor(Color(backgroundColor));
|
||||
changeNavigationBarColor(
|
||||
backgroundColor,
|
||||
Color(backgroundColor).isDark(),
|
||||
);
|
||||
StatusBar.setBackgroundColor(backgroundColor);
|
||||
changeNavigationBarColor(backgroundColor);
|
||||
}
|
||||
}, [backgroundColor, fullScreenMode]);
|
||||
|
||||
const showStatusAndNavBar = useCallback(() => {
|
||||
StatusBar.setHidden(false);
|
||||
showNavigationBar();
|
||||
changeNavigationBarColor(Color(theme.surface).hex(), !theme.isDark);
|
||||
}, []);
|
||||
NavigationBar.setVisibilityAsync('visible');
|
||||
|
||||
if (fullScreenMode) {
|
||||
/**
|
||||
* This is overlay of reader footer and should be transparent.
|
||||
* But in hexa, ##xxxxxx00 could be another color
|
||||
*/
|
||||
changeNavigationBarColor(
|
||||
Color(theme.surface).alpha(0.05).hexa(),
|
||||
theme.isDark,
|
||||
);
|
||||
setStatusBarColor(theme);
|
||||
} else {
|
||||
changeNavigationBarColor(
|
||||
backgroundColor,
|
||||
Color(backgroundColor).isDark(),
|
||||
);
|
||||
}
|
||||
}, [backgroundColor, fullScreenMode]);
|
||||
|
||||
useEffect(() => {
|
||||
setImmersiveMode();
|
||||
@@ -45,13 +60,10 @@ const useFullscreenMode = () => {
|
||||
|
||||
useEffect(() => {
|
||||
const unsubscribe = addListener('beforeRemove', () => {
|
||||
showStatusAndNavBar();
|
||||
StatusBar.setBarStyle(theme.isDark ? 'light-content' : 'dark-content');
|
||||
changeNavigationBarColor(
|
||||
Color(theme.surface2).hex(),
|
||||
!theme.isDark,
|
||||
true,
|
||||
);
|
||||
StatusBar.setHidden(false);
|
||||
NavigationBar.setVisibilityAsync('visible');
|
||||
setStatusBarColor(theme);
|
||||
changeNavigationBarColor(Color(theme.surface2).hex(), !theme.isDark);
|
||||
});
|
||||
|
||||
return unsubscribe;
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
import { NativeModules, Platform } from 'react-native';
|
||||
|
||||
const { NavigationBarColor } = NativeModules;
|
||||
|
||||
const changeNavigationBarColor = (
|
||||
color = '',
|
||||
light = false,
|
||||
animated = true,
|
||||
) => {
|
||||
if (Platform.OS === 'android') {
|
||||
const LightNav = light ? true : false;
|
||||
NavigationBarColor.changeNavigationBarColor(color, LightNav, animated);
|
||||
}
|
||||
};
|
||||
|
||||
const hideNavigationBar = () => {
|
||||
if (Platform.OS === 'android') {
|
||||
NavigationBarColor.hideNavigationBar();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const showNavigationBar = () => {
|
||||
if (Platform.OS === 'android') {
|
||||
NavigationBarColor.showNavigationBar();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export { changeNavigationBarColor, hideNavigationBar, showNavigationBar };
|
||||
@@ -3,7 +3,10 @@ import React, { useEffect } from 'react';
|
||||
import { NavigationContainer } from '@react-navigation/native';
|
||||
import { createStackNavigator } from '@react-navigation/stack';
|
||||
|
||||
import { setBarColor } from '@theme/utils/setBarColor';
|
||||
import {
|
||||
changeNavigationBarColor,
|
||||
setStatusBarColor,
|
||||
} from '@theme/utils/setBarColor';
|
||||
import { useAppSettings, usePlugins, useTheme } from '@hooks/persisted';
|
||||
import { useGithubUpdateChecker } from '@hooks/common/githubUpdateChecker';
|
||||
|
||||
@@ -31,7 +34,6 @@ import BrowseSettings from '../screens/browse/BrowseSettings';
|
||||
import { updateLibrary } from '@services/updates';
|
||||
import WebviewScreen from '@screens/WebviewScreen/WebviewScreen';
|
||||
import { RootStackParamList } from './types';
|
||||
import { changeNavigationBarColor } from '@native/NavigationBarColor';
|
||||
import Color from 'color';
|
||||
|
||||
const Stack = createStackNavigator<RootStackParamList>();
|
||||
@@ -43,12 +45,8 @@ const MainNavigator = () => {
|
||||
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(async () => {
|
||||
setBarColor(theme);
|
||||
changeNavigationBarColor(
|
||||
Color(theme.surface2).hex(),
|
||||
!theme.isDark,
|
||||
true,
|
||||
);
|
||||
setStatusBarColor(theme);
|
||||
changeNavigationBarColor(Color(theme.surface2).hex(), theme.isDark);
|
||||
}, 500);
|
||||
|
||||
return () => {
|
||||
|
||||
@@ -7,6 +7,7 @@ import { ThemeColors } from '@theme/types';
|
||||
import { ChapterInfo, NovelInfo } from '@database/types';
|
||||
import { BottomSheetModalMethods } from '@gorhom/bottom-sheet/lib/typescript/types';
|
||||
import { ChapterScreenProps } from '@navigators/types';
|
||||
import { useDeviceOrientation } from '@hooks/index';
|
||||
|
||||
interface ChapterFooterProps {
|
||||
theme: ThemeColors;
|
||||
@@ -38,14 +39,17 @@ const ChapterFooter = ({
|
||||
borderless: true,
|
||||
radius: 50,
|
||||
};
|
||||
|
||||
const orientation = useDeviceOrientation();
|
||||
return (
|
||||
<Animated.View
|
||||
entering={FadeIn.duration(150)}
|
||||
exiting={FadeOut.duration(150)}
|
||||
style={[
|
||||
styles.footer,
|
||||
{ backgroundColor: color(theme.surface).alpha(0.9).string() },
|
||||
{
|
||||
backgroundColor: color(theme.surface).alpha(0.9).string(),
|
||||
paddingBottom: orientation === 'potrait' ? 40 : 0,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<View style={[styles.buttonsContainer]}>
|
||||
@@ -142,7 +146,6 @@ const styles = StyleSheet.create({
|
||||
zIndex: 1,
|
||||
bottom: 0,
|
||||
width: '100%',
|
||||
paddingBottom: 16,
|
||||
},
|
||||
buttonsContainer: {
|
||||
flexDirection: 'row',
|
||||
|
||||
@@ -1,11 +1,21 @@
|
||||
import { StatusBar } from 'react-native';
|
||||
import { ThemeColors } from '@theme/types';
|
||||
import * as NavigationBar from 'expo-navigation-bar';
|
||||
import Color from 'color';
|
||||
|
||||
/**
|
||||
* Sets status and navigation bar color.
|
||||
*
|
||||
* @param theme
|
||||
*/
|
||||
export const setStatusBarColor = (color: ThemeColors | Color) => {
|
||||
if (color instanceof Color) {
|
||||
// fullscreen reader mode
|
||||
StatusBar.setBarStyle(color.isDark() ? 'light-content' : 'dark-content');
|
||||
StatusBar.setBackgroundColor(color.hexa());
|
||||
} else {
|
||||
StatusBar.setTranslucent(true);
|
||||
StatusBar.setBackgroundColor('transparent');
|
||||
StatusBar.setBarStyle(color.isDark ? 'light-content' : 'dark-content');
|
||||
}
|
||||
};
|
||||
|
||||
export const setBarColor = (theme: ThemeColors) =>
|
||||
StatusBar.setBarStyle(theme.isDark ? 'light-content' : 'dark-content');
|
||||
export const changeNavigationBarColor = (color: string, isDark = false) => {
|
||||
NavigationBar.setBackgroundColorAsync(color);
|
||||
NavigationBar.setButtonStyleAsync(isDark ? 'light' : 'dark');
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user