Eject to bare workflow

This commit is contained in:
Rajarshee Chatterjee
2021-06-06 10:35:53 +05:30
parent 4b5ee1667c
commit 223f00ef7d
78 changed files with 3125 additions and 137 deletions
+60
View File
@@ -11,3 +11,63 @@ web-build/
# macOS
.DS_Store
# @generated expo-cli sync-2138f1e3e130677ea10ea873f6d498e3890e677b
# The following patterns were generated by expo-cli
# OSX
#
.DS_Store
# Xcode
#
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
*.moved-aside
DerivedData
*.hmap
*.ipa
*.xcuserstate
project.xcworkspace
# Android/IntelliJ
#
build/
.idea
.gradle
local.properties
*.iml
*.hprof
# node.js
#
node_modules/
npm-debug.log
yarn-error.log
# BUCK
buck-out/
\.buckd/
*.keystore
!debug.keystore
# Bundle artifacts
*.jsbundle
# CocoaPods
/ios/Pods/
# Expo
.expo/
web-build/
# @end expo-cli
+11 -2
View File
@@ -1,11 +1,15 @@
import React, { useEffect } from "react";
import { StatusBar } from "react-native";
import { useFonts } from "expo-font";
import { Provider as PaperProvider } from "react-native-paper";
import Main from "./src/Navigators/Main";
import * as SplashScreen from "expo-splash-screen";
import { Provider } from "react-redux";
import { persistor, store } from "./src/redux/store";
import { PersistGate } from "redux-persist/lib/integration/react";
import Main from "./src/Navigators/Main";
import { createDB, deleteDb } from "./src/Database/DBHelper";
import { fonts } from "./src/Theme/fonts";
@@ -14,6 +18,7 @@ const App = () => {
useEffect(() => {
createDB();
SplashScreen.hideAsync();
}, []);
if (!loaded) {
@@ -24,6 +29,10 @@ const App = () => {
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<PaperProvider>
<StatusBar
translucent={true}
backgroundColor="transparent"
/>
<Main />
</PaperProvider>
</PersistGate>
+55
View File
@@ -0,0 +1,55 @@
# To learn about Buck see [Docs](https://buckbuild.com/).
# To run your application with Buck:
# - install Buck
# - `npm start` - to start the packager
# - `cd android`
# - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"`
# - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck
# - `buck install -r android/app` - compile, install and run application
#
load(":build_defs.bzl", "create_aar_targets", "create_jar_targets")
lib_deps = []
create_aar_targets(glob(["libs/*.aar"]))
create_jar_targets(glob(["libs/*.jar"]))
android_library(
name = "all-libs",
exported_deps = lib_deps,
)
android_library(
name = "app-code",
srcs = glob([
"src/main/java/**/*.java",
]),
deps = [
":all-libs",
":build_config",
":res",
],
)
android_build_config(
name = "build_config",
package = "com.rajarsheechatterjee.LNReader",
)
android_resource(
name = "res",
package = "com.rajarsheechatterjee.LNReader",
res = "src/main/res",
)
android_binary(
name = "app",
keystore = "//android/keystores:debug",
manifest = "src/main/AndroidManifest.xml",
package_type = "debug",
deps = [
":app-code",
],
)
+219
View File
@@ -0,0 +1,219 @@
apply plugin: "com.android.application"
import com.android.build.OutputFile
/**
* The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
* and bundleReleaseJsAndAssets).
* These basically call `react-native bundle` with the correct arguments during the Android build
* cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
* bundle directly from the development server. Below you can see all the possible configurations
* and their defaults. If you decide to add a configuration block, make sure to add it before the
* `apply from: "../../node_modules/react-native/react.gradle"` line.
*
* project.ext.react = [
* // the name of the generated asset file containing your JS bundle
* bundleAssetName: "index.android.bundle",
*
* // the entry file for bundle generation. If none specified and
* // "index.android.js" exists, it will be used. Otherwise "index.js" is
* // default. Can be overridden with ENTRY_FILE environment variable.
* entryFile: "index.android.js",
*
* // https://reactnative.dev/docs/performance#enable-the-ram-format
* bundleCommand: "ram-bundle",
*
* // whether to bundle JS and assets in debug mode
* bundleInDebug: false,
*
* // whether to bundle JS and assets in release mode
* bundleInRelease: true,
*
* // whether to bundle JS and assets in another build variant (if configured).
* // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
* // The configuration property can be in the following formats
* // 'bundleIn${productFlavor}${buildType}'
* // 'bundleIn${buildType}'
* // bundleInFreeDebug: true,
* // bundleInPaidRelease: true,
* // bundleInBeta: true,
*
* // whether to disable dev mode in custom build variants (by default only disabled in release)
* // for example: to disable dev mode in the staging build type (if configured)
* devDisabledInStaging: true,
* // The configuration property can be in the following formats
* // 'devDisabledIn${productFlavor}${buildType}'
* // 'devDisabledIn${buildType}'
*
* // the root of your project, i.e. where "package.json" lives
* root: "../../",
*
* // where to put the JS bundle asset in debug mode
* jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
*
* // where to put the JS bundle asset in release mode
* jsBundleDirRelease: "$buildDir/intermediates/assets/release",
*
* // where to put drawable resources / React Native assets, e.g. the ones you use via
* // require('./image.png')), in debug mode
* resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
*
* // where to put drawable resources / React Native assets, e.g. the ones you use via
* // require('./image.png')), in release mode
* resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
*
* // by default the gradle tasks are skipped if none of the JS files or assets change; this means
* // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
* // date; if you have any other folders that you want to ignore for performance reasons (gradle
* // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
* // for example, you might want to remove it from here.
* inputExcludes: ["android/**", "ios/**"],
*
* // override which node gets called and with what additional arguments
* nodeExecutableAndArgs: ["node"],
*
* // supply additional arguments to the packager
* extraPackagerArgs: []
* ]
*/
project.ext.react = [
enableHermes: true
]
apply from: '../../node_modules/react-native-unimodules/gradle.groovy'
apply from: "../../node_modules/react-native/react.gradle"
apply from: "../../node_modules/expo-constants/scripts/get-app-config-android.gradle"
apply from: "../../node_modules/expo-updates/scripts/create-manifest-android.gradle"
/**
* Set this to true to create two separate APKs instead of one:
* - An APK that only works on ARM devices
* - An APK that only works on x86 devices
* The advantage is the size of the APK is reduced by about 4MB.
* Upload all the APKs to the Play Store and people will download
* the correct one based on the CPU architecture of their device.
*/
def enableSeparateBuildPerCPUArchitecture = false
/**
* Run Proguard to shrink the Java bytecode in release builds.
*/
def enableProguardInReleaseBuilds = false
/**
* The preferred build flavor of JavaScriptCore.
*
* For example, to use the international variant, you can use:
* `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
*
* The international variant includes ICU i18n library and necessary data
* allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
* give correct results when using with locales other than en-US. Note that
* this variant is about 6MiB larger per architecture than default.
*/
def jscFlavor = 'org.webkit:android-jsc:+'
/**
* Whether to enable the Hermes VM.
*
* This should be set on project.ext.react and mirrored here. If it is not set
* on project.ext.react, JavaScript will not be compiled to Hermes Bytecode
* and the benefits of using Hermes will therefore be sharply reduced.
*/
def enableHermes = project.ext.react.get("enableHermes", false);
android {
compileSdkVersion rootProject.ext.compileSdkVersion
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
defaultConfig {
applicationId 'com.rajarsheechatterjee.LNReader'
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionName "1.0.20"
}
splits {
abi {
reset()
enable enableSeparateBuildPerCPUArchitecture
universalApk false // If true, also generate a universal APK
include "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
}
}
signingConfigs {
debug {
storeFile file('debug.keystore')
storePassword 'android'
keyAlias 'androiddebugkey'
keyPassword 'android'
}
}
buildTypes {
debug {
signingConfig signingConfigs.debug
}
release {
// Caution! In production, you need to generate your own keystore file.
// see https://reactnative.dev/docs/signed-apk-android.
signingConfig signingConfigs.debug
minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
}
}
// applicationVariants are e.g. debug, release
applicationVariants.all { variant ->
variant.outputs.each { output ->
// For each separate APK per architecture, set a unique version code as described here:
// https://developer.android.com/studio/build/configure-apk-splits.html
def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
def abi = output.getFilter(OutputFile.ABI)
if (abi != null) { // null for the universal-debug, universal-release variants
output.versionCodeOverride =
versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
}
}
}
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
//noinspection GradleDynamicVersion
implementation "com.facebook.react:react-native:+" // From node_modules
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
exclude group:'com.facebook.fbjni'
}
debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
exclude group:'com.facebook.flipper'
exclude group:'com.squareup.okhttp3', module:'okhttp'
}
debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") {
exclude group:'com.facebook.flipper'
}
addUnimodulesDependencies()
if (enableHermes) {
def hermesPath = "../../node_modules/hermes-engine/android/";
debugImplementation files(hermesPath + "hermes-debug.aar")
releaseImplementation files(hermesPath + "hermes-release.aar")
} else {
implementation jscFlavor
}
}
// Run this once to be able to run the application with BUCK
// puts all compile dependencies into folder libs for BUCK to use
task copyDownloadableDepsToLibs(type: Copy) {
from configurations.compile
into 'libs'
}
apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
+19
View File
@@ -0,0 +1,19 @@
"""Helper definitions to glob .aar and .jar targets"""
def create_aar_targets(aarfiles):
for aarfile in aarfiles:
name = "aars__" + aarfile[aarfile.rindex("/") + 1:aarfile.rindex(".aar")]
lib_deps.append(":" + name)
android_prebuilt_aar(
name = name,
aar = aarfile,
)
def create_jar_targets(jarfiles):
for jarfile in jarfiles:
name = "jars__" + jarfile[jarfile.rindex("/") + 1:jarfile.rindex(".jar")]
lib_deps.append(":" + name)
prebuilt_jar(
name = name,
binary_jar = jarfile,
)
Binary file not shown.
+10
View File
@@ -0,0 +1,10 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
@@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<application android:usesCleartextTraffic="true" tools:targetApi="28" tools:ignore="GoogleAppIndexingWarning" />
</manifest>
@@ -0,0 +1,69 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root
* directory of this source tree.
*/
package com.lnreader;
import android.content.Context;
import com.facebook.flipper.android.AndroidFlipperClient;
import com.facebook.flipper.android.utils.FlipperUtils;
import com.facebook.flipper.core.FlipperClient;
import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin;
import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin;
import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin;
import com.facebook.flipper.plugins.inspector.DescriptorMapping;
import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin;
import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor;
import com.facebook.flipper.plugins.network.NetworkFlipperPlugin;
import com.facebook.flipper.plugins.react.ReactFlipperPlugin;
import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.modules.network.NetworkingModule;
import okhttp3.OkHttpClient;
public class ReactNativeFlipper {
public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
if (FlipperUtils.shouldEnableFlipper(context)) {
final FlipperClient client = AndroidFlipperClient.getInstance(context);
client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults()));
client.addPlugin(new ReactFlipperPlugin());
client.addPlugin(new DatabasesFlipperPlugin(context));
client.addPlugin(new SharedPreferencesFlipperPlugin(context));
client.addPlugin(CrashReporterPlugin.getInstance());
NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin();
NetworkingModule.setCustomClientBuilder(
new NetworkingModule.CustomClientBuilder() {
@Override
public void apply(OkHttpClient.Builder builder) {
builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin));
}
});
client.addPlugin(networkFlipperPlugin);
client.start();
// Fresco Plugin needs to ensure that ImagePipelineFactory is initialized
// Hence we run if after all native modules have been initialized
ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
if (reactContext == null) {
reactInstanceManager.addReactInstanceEventListener(
new ReactInstanceManager.ReactInstanceEventListener() {
@Override
public void onReactContextInitialized(ReactContext reactContext) {
reactInstanceManager.removeReactInstanceEventListener(this);
reactContext.runOnNativeModulesQueueThread(
new Runnable() {
@Override
public void run() {
client.addPlugin(new FrescoFlipperPlugin());
}
});
}
});
} else {
client.addPlugin(new FrescoFlipperPlugin());
}
}
}
}
+36
View File
@@ -0,0 +1,36 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.rajarsheechatterjee.LNReader">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
<application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="true" android:theme="@style/AppTheme">
<meta-data android:name="expo.modules.updates.EXPO_UPDATE_URL" android:value="https://exp.host/@rajarsheechatterjee/LNReader"/>
<meta-data android:name="expo.modules.updates.EXPO_SDK_VERSION" android:value="41.0.0"/>
<meta-data android:name="expo.modules.updates.ENABLED" android:value="false"/>
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH" android:value="ALWAYS"/>
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS" android:value="0"/>
<meta-data android:name="expo.modules.notifications.default_notification_icon" android:resource="@drawable/notification_icon"/>
<meta-data android:name="expo.modules.notifications.default_notification_color" android:resource="@color/notification_icon_color"/>
<activity android:name=".MainActivity" android:label="@string/app_name" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize" android:theme="@style/Theme.App.SplashScreen" android:screenOrientation="unspecified">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="lnreader"/>
<data android:scheme="com.rajarsheechatterjee.LNReader"/>
</intent-filter>
</activity>
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity"/>
</application>
</manifest>
File diff suppressed because one or more lines are too long
@@ -0,0 +1,62 @@
// FullScreenModule.java
package com.rajarsheechatterjee.LNReader;
import android.os.Build;
import android.view.View;
import android.view.WindowManager;
import android.app.Activity;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.UiThreadUtil;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
public class FullScreenModule extends ReactContextBaseJavaModule {
@Override
public String getName() {
return "FullScreen";
}
@ReactMethod
public void enable() {
UiThreadUtil.runOnUiThread(
new Runnable() {
@Override
public void run() {
getCurrentActivity().getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_FULLSCREEN |
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
);
}
}
);
}
@ReactMethod
public void disable() {
UiThreadUtil.runOnUiThread(
new Runnable() {
@Override
public void run() {
getCurrentActivity().getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
);
}
}
);
}
FullScreenModule(ReactApplicationContext reactContext) {
super(reactContext);
}
}
@@ -0,0 +1,29 @@
package com.rajarsheechatterjee.LNReader;
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 FullScreenPackage 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 FullScreenModule(reactContext));
return modules;
}
}
@@ -0,0 +1,62 @@
package com.rajarsheechatterjee.LNReader;
import android.content.res.Configuration;
import android.content.Intent;
import android.os.Bundle;
import android.view.WindowManager;
import android.os.Build;
import com.facebook.react.ReactActivity;
import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.ReactRootView;
import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView;
import expo.modules.splashscreen.singletons.SplashScreen;
import expo.modules.splashscreen.SplashScreenImageResizeMode;
public class MainActivity extends ReactActivity {
// Added automatically by Expo Config
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
Intent intent = new Intent("onConfigurationChanged");
intent.putExtra("newConfig", newConfig);
sendBroadcast(intent);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
// SplashScreen.show(...) has to be called after super.onCreate(...)
// Below line is handled by '@expo/configure-splash-screen' command and it's discouraged to modify it manually
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
layoutParams.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
getWindow().setAttributes(layoutParams);
}
super.onCreate(savedInstanceState);
SplashScreen.show(this, SplashScreenImageResizeMode.COVER, ReactRootView.class, false);
}
/**
* Returns the name of the main component registered from JavaScript.
* This is used to schedule rendering of the component.
*/
@Override
protected String getMainComponentName() {
return "main";
}
@Override
protected ReactActivityDelegate createReactActivityDelegate() {
return new ReactActivityDelegate(this, getMainComponentName()) {
@Override
protected ReactRootView createRootView() {
return new RNGestureHandlerEnabledRootView(MainActivity.this);
}
};
}
}
@@ -0,0 +1,132 @@
package com.rajarsheechatterjee.LNReader;
import android.app.Application;
import android.content.Context;
import android.net.Uri;
import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.soloader.SoLoader;
import com.rajarsheechatterjee.LNReader.generated.BasePackageList;
import org.unimodules.adapters.react.ReactAdapterPackage;
import org.unimodules.adapters.react.ModuleRegistryAdapter;
import org.unimodules.adapters.react.ReactModuleRegistryProvider;
import org.unimodules.core.interfaces.Package;
import org.unimodules.core.interfaces.SingletonModule;
import expo.modules.constants.ConstantsPackage;
import expo.modules.permissions.PermissionsPackage;
import expo.modules.filesystem.FileSystemPackage;
import expo.modules.updates.UpdatesController;
import com.facebook.react.bridge.JSIModulePackage;
import com.swmansion.reanimated.ReanimatedJSIModulePackage;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.List;
import javax.annotation.Nullable;
import com.rajarsheechatterjee.LNReader.FullScreenPackage;
public class MainApplication extends Application implements ReactApplication {
private final ReactModuleRegistryProvider mModuleRegistryProvider = new ReactModuleRegistryProvider(
new BasePackageList().getPackageList()
);
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List<ReactPackage> getPackages() {
List<ReactPackage> packages = new PackageList(this).getPackages();
packages.add(new ModuleRegistryAdapter(mModuleRegistryProvider));
packages.add(new FullScreenPackage());
return packages;
}
@Override
protected String getJSMainModuleName() {
return "index";
}
@Override
protected JSIModulePackage getJSIModulePackage() {
return new ReanimatedJSIModulePackage();
}
@Override
protected @Nullable String getJSBundleFile() {
if (BuildConfig.DEBUG) {
return super.getJSBundleFile();
} else {
return UpdatesController.getInstance().getLaunchAssetFile();
}
}
@Override
protected @Nullable String getBundleAssetName() {
if (BuildConfig.DEBUG) {
return super.getBundleAssetName();
} else {
return UpdatesController.getInstance().getBundleAssetName();
}
}
};
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
@Override
public void onCreate() {
super.onCreate();
SoLoader.init(this, /* native exopackage */ false);
if (!BuildConfig.DEBUG) {
UpdatesController.initialize(this);
}
initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
}
/**
* Loads Flipper in React Native templates. Call this in the onCreate method with something like
* initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
*
* @param context
* @param reactInstanceManager
*/
private static void initializeFlipper(
Context context, ReactInstanceManager reactInstanceManager) {
if (BuildConfig.DEBUG) {
try {
/*
We use reflection here to pick up the class that initializes Flipper,
since Flipper library is not available in release mode
*/
Class<?> aClass = Class.forName("com.rajarsheechatterjee.LNReader.ReactNativeFlipper");
aClass
.getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
.invoke(null, context, reactInstanceManager);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
@@ -0,0 +1,30 @@
package com.rajarsheechatterjee.LNReader.generated;
import java.util.Arrays;
import java.util.List;
import org.unimodules.core.interfaces.Package;
public class BasePackageList {
public List<Package> getPackageList() {
return Arrays.<Package>asList(
new expo.modules.application.ApplicationPackage(),
new expo.modules.backgroundfetch.BackgroundFetchPackage(),
new expo.modules.constants.ConstantsPackage(),
new expo.modules.documentpicker.DocumentPickerPackage(),
new expo.modules.errorrecovery.ErrorRecoveryPackage(),
new expo.modules.filesystem.FileSystemPackage(),
new expo.modules.font.FontLoaderPackage(),
new expo.modules.imageloader.ImageLoaderPackage(),
new expo.modules.keepawake.KeepAwakePackage(),
new expo.modules.lineargradient.LinearGradientPackage(),
new expo.modules.notifications.NotificationsPackage(),
new expo.modules.permissions.PermissionsPackage(),
new expo.modules.sharing.SharingPackage(),
new expo.modules.splashscreen.SplashScreenPackage(),
new expo.modules.sqlite.SQLitePackage(),
new expo.modules.taskManager.TaskManagerPackage(),
new expo.modules.updates.UpdatesPackage(),
new expo.modules.webbrowser.WebBrowserPackage()
);
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
This file was created by '@expo/configure-splash-screen' and some of it's content shouldn't be modified by hand
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/splashscreen_background"/>
</layer-list>
Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/iconBackground"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/iconBackground"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 876 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 876 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<resources>
<color name="iconBackground">#FFFFFF</color>
<color name="splashscreen_background">#000000</color>
<color name="colorPrimary">#023c69</color>
<color name="colorPrimaryDark">#00000000</color>
<color name="navigationBarColor">#000000</color>
<color name="notification_icon_color">#00adb5</color>
</resources>
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<resources>
<string name="app_name">LNReader</string>
</resources>
@@ -0,0 +1,23 @@
<?xml
version="1.0"
encoding="UTF-8"
standalone="yes"
?>
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:textColor">#000000</item>
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="android:navigationBarColor">#000000</item>
<item name="android:statusBarColor">#000000</item>
</style>
<style name="Theme.App.SplashScreen" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Below line is handled by '@expo/configure-splash-screen' command and it's discouraged to modify it manually -->
<!-- Customize your splash screen theme here -->
<item name="android:windowBackground">@drawable/splashscreen</item>
<item name="android:navigationBarColor">#000000</item>
<item name="android:statusBarColor">#000000</item>
</style>
</resources>
+38
View File
@@ -0,0 +1,38 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext {
buildToolsVersion = "29.0.3"
minSdkVersion = 21
compileSdkVersion = 30
targetSdkVersion = 30
}
repositories {
google()
jcenter()
}
dependencies {
classpath("com.android.tools.build:gradle:4.1.0")
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
mavenLocal()
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url("$rootDir/../node_modules/react-native/android")
}
maven {
// Android JSC is installed from npm
url("$rootDir/../node_modules/jsc-android/dist")
}
google()
jcenter()
maven { url 'https://www.jitpack.io' }
}
}
+29
View File
@@ -0,0 +1,29 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx10248m -XX:MaxPermSize=256m
org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true
# Version of flipper SDK to use with React Native
FLIPPER_VERSION=0.54.0
Binary file not shown.
+5
View File
@@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
+183
View File
@@ -0,0 +1,183 @@
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
exec "$JAVACMD" "$@"
+103
View File
@@ -0,0 +1,103 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
+9
View File
@@ -0,0 +1,9 @@
rootProject.name = 'LNReader'
apply from: '../node_modules/react-native-unimodules/gradle.groovy'
includeUnimodulesProjects()
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle");
applyNativeModulesSettingsGradle(settings)
include ':app'
+1 -1
View File
@@ -3,7 +3,7 @@
"name": "LNReader",
"slug": "LNReader",
"scheme": "lnreader",
"version": "1.0.19",
"version": "1.0.20",
"orientation": "default",
"icon": "./assets/icon.png",
"splash": {
+9
View File
@@ -0,0 +1,9 @@
import 'react-native-gesture-handler';
import { registerRootComponent } from 'expo';
import App from './App';
// registerRootComponent calls AppRegistry.registerComponent('main', () => App);
// It also ensures that whether you load the app in Expo Go or in a native build,
// the environment is set up appropriately
registerRootComponent(App);
+4
View File
@@ -0,0 +1,4 @@
// Learn more https://docs.expo.io/guides/customizing-metro
const { getDefaultConfig } = require('expo/metro-config');
module.exports = getDefaultConfig(__dirname);
+169 -31
View File
@@ -1,6 +1,8 @@
{
"requires": true,
"name": "lnreader-eject",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@babel/code-frame": {
"version": "7.12.13",
@@ -3426,9 +3428,9 @@
"integrity": "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw=="
},
"dayjs": {
"version": "1.10.4",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.4.tgz",
"integrity": "sha512-RI/Hh4kqRc1UKLOAf/T5zdMMX5DQIlDxwUe3wSyMMnEbGunnpENCdbUgM+dW7kXidZqCttBrmw7BhN4TMddkCw=="
"version": "1.10.5",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.5.tgz",
"integrity": "sha512-BUFis41ikLz+65iH6LHQCDm4YPMj5r1YFLdupPIyM4SGcXMmtiLQ7U37i+hGS8urIuqe7I/ou3IS1jVc4nbN4g=="
},
"debug": {
"version": "4.3.1",
@@ -3885,6 +3887,11 @@
"fontfaceobserver": "^2.1.0"
}
},
"expo-image-loader": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/expo-image-loader/-/expo-image-loader-2.1.1.tgz",
"integrity": "sha512-EeItNIsmw4g+FIb9S9AHE7FAWQkuiIguFMua/RQ2mFHKFZYa/BU32MGagY+e4LzasBVbDKWgd3NHO+EYC6XeEA=="
},
"expo-keep-awake": {
"version": "9.1.2",
"resolved": "https://registry.npmjs.org/expo-keep-awake/-/expo-keep-awake-9.1.2.tgz",
@@ -3952,10 +3959,13 @@
"resolved": "https://registry.npmjs.org/expo-sharing/-/expo-sharing-9.1.2.tgz",
"integrity": "sha512-IFBQPimeZtdqtvmqQZEmiI0D4j9xE53tSZxLFrFPplNWzgDefk+dP+flof3duf9JgCQTsvOUU2h2/XwjD3vBTA=="
},
"expo-speech": {
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/expo-speech/-/expo-speech-9.1.0.tgz",
"integrity": "sha512-5yIMVo1auAwClVnlJnCRyJqKS82IeQXzTCamP4iP4LmHDR5+9sae/D/mD5mX7KV3brWf3n0sEyFhuU7WqgMQvg=="
"expo-splash-screen": {
"version": "0.10.2",
"resolved": "https://registry.npmjs.org/expo-splash-screen/-/expo-splash-screen-0.10.2.tgz",
"integrity": "sha512-ngelW7g5yFqk3LWbyLDDxi3LYXEfgGFCJddL/Q8S/C1pMUc5foW2j9i/q+akK8i5mjYtSx3+Bk/qbyX92QIF/w==",
"requires": {
"@expo/configure-splash-screen": "0.3.4"
}
},
"expo-sqlite": {
"version": "9.1.0",
@@ -3971,6 +3981,11 @@
"resolved": "https://registry.npmjs.org/expo-status-bar/-/expo-status-bar-1.0.4.tgz",
"integrity": "sha512-s7nc496D/Zn1NGiMJ5wu6HyIdXxbgGtmZZtbHm7rpbcmLdf28GmMSNHDx7M0t00BMhky7VAurTCUo+BJs8ugsw=="
},
"expo-structured-headers": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/expo-structured-headers/-/expo-structured-headers-1.0.1.tgz",
"integrity": "sha512-U4frE8rT5x1LqZv5Ru/9CtzY8gh0wp1MfwTu5hetPydnwxXfWchuXvKgWRjEHglFU2X/29kYFY/J1UkPvCN8xg=="
},
"expo-task-manager": {
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/expo-task-manager/-/expo-task-manager-9.1.0.tgz",
@@ -3980,6 +3995,19 @@
"unimodules-app-loader": "~2.1.0"
}
},
"expo-updates": {
"version": "0.5.5",
"resolved": "https://registry.npmjs.org/expo-updates/-/expo-updates-0.5.5.tgz",
"integrity": "sha512-1R8EKkT3GoDjMRQnDaTYv31gIYIaYQGHOrjHJfwq8ai9f1W1AHux6KAH2/H6sc2o9a7roWVwjDn2kKwCm9AeHg==",
"requires": {
"@expo/config-plugins": "^1.0.18",
"@expo/metro-config": "^0.1.59",
"expo-structured-headers": "~1.0.1",
"fbemitter": "^2.1.1",
"resolve-from": "^5.0.0",
"uuid": "^3.4.0"
}
},
"expo-web-browser": {
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/expo-web-browser/-/expo-web-browser-9.1.0.tgz",
@@ -5298,9 +5326,9 @@
}
},
"jetifier": {
"version": "1.6.6",
"resolved": "https://registry.npmjs.org/jetifier/-/jetifier-1.6.6.tgz",
"integrity": "sha512-JNAkmPeB/GS2tCRqUzRPsTOHpGDah7xP18vGJfIjZC+W2sxEHbxgJxetIjIqhjQ3yYbYNEELkM/spKLtwoOSUQ=="
"version": "1.6.8",
"resolved": "https://registry.npmjs.org/jetifier/-/jetifier-1.6.8.tgz",
"integrity": "sha512-3Zi16h6L5tXDRQJTb221cnRoVG9/9OvreLdLU2/ZjRv/GILL+2Cemt0IKvkowwkDpvouAU1DQPOJ7qaiHeIdrw=="
},
"jimp": {
"version": "0.12.1",
@@ -6378,9 +6406,9 @@
"integrity": "sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg=="
},
"node-stream-zip": {
"version": "1.13.3",
"resolved": "https://registry.npmjs.org/node-stream-zip/-/node-stream-zip-1.13.3.tgz",
"integrity": "sha512-Vv95ug+8Jfug4AxcqNV7TeGEk2antNidj+YBOyP8SS8LTHJmjsE3d9h6L831eJtO8p7jesJ3CDtgkwmLO/wcSw=="
"version": "1.13.4",
"resolved": "https://registry.npmjs.org/node-stream-zip/-/node-stream-zip-1.13.4.tgz",
"integrity": "sha512-M2nPvnSWFFH+fgLIRZDqmhshmuzXcr+ce9BsHQX/30pXR+cEz/USMYmx9ZAFYy837W2QoDoNzhFtbZhfzaMk9A=="
},
"noop-fn": {
"version": "1.0.0",
@@ -7051,18 +7079,18 @@
}
},
"react-devtools-core": {
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-4.13.0.tgz",
"integrity": "sha512-KR+0pLw8wTjOVr+9AECe5ctmycaAjbmxN3bbdB0vmlwm0JkxNnKMxDzanf+4V8IuPBQWgm8qdWpbSOqhu1l14g==",
"version": "4.13.5",
"resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-4.13.5.tgz",
"integrity": "sha512-k+P5VSKM6P22Go9IQ8dJmjj9fbztvKt1iRDI/4wS5oTvd1EnytIJMYB59wZt+D3kgp64jklNX/MRmY42xAQ08g==",
"requires": {
"shell-quote": "^1.6.1",
"ws": "^7"
},
"dependencies": {
"ws": {
"version": "7.4.5",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.5.tgz",
"integrity": "sha512-xzyu3hFvomRfXKH8vOFMU3OguG6oOvhXMo3xsGy3xWExqaM2dxBbVxuD99O7m3ZUFMvvscsZDqxfgMaRr/Nr1g=="
"version": "7.4.6",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz",
"integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A=="
}
}
},
@@ -7083,13 +7111,14 @@
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
"react-native": {
"version": "https://github.com/expo/react-native/archive/sdk-41.0.0.tar.gz",
"integrity": "sha512-3jHI2YufrJi7eIABRf/DN/I2yOkmIZ0vAyezTz+PAUJiEs4v//5LLojWEU+W53AZsnuaEMcl/4fVy4bd+OuUbA==",
"version": "0.63.4",
"resolved": "https://registry.npmjs.org/react-native/-/react-native-0.63.4.tgz",
"integrity": "sha512-I4kM8kYO2mWEYUFITMcpRulcy4/jd+j9T6PbIzR0FuMcz/xwd+JwHoLPa1HmCesvR1RDOw9o4D+OFLwuXXfmGw==",
"requires": {
"@babel/runtime": "^7.0.0",
"@react-native-community/cli": "^4.14.0",
"@react-native-community/cli-platform-android": "^4.13.0",
"@react-native-community/cli-platform-ios": "^4.13.0",
"@react-native-community/cli": "^4.10.0",
"@react-native-community/cli-platform-android": "^4.10.0",
"@react-native-community/cli-platform-ios": "^4.10.0",
"abort-controller": "^3.0.0",
"anser": "^1.4.9",
"base64-js": "^1.1.2",
@@ -7409,11 +7438,21 @@
"fast-memoize": "^2.5.1"
}
},
"react-native-device-info": {
"version": "8.1.3",
"resolved": "https://registry.npmjs.org/react-native-device-info/-/react-native-device-info-8.1.3.tgz",
"integrity": "sha512-73e3wiGFL8DvIXEd8x4Aq+mO8mZvHARwfYorIEu+X0trLHY92bP5Ict8DJHDjCQ0+HtAvpA4Wda2VoUVN1zh6Q=="
},
"react-native-easing-gradient": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/react-native-easing-gradient/-/react-native-easing-gradient-0.1.2.tgz",
"integrity": "sha512-oeSJ8nSrCxiCO5mLEVc59Evva4unjvH6AQ8vJFyJ7PIKRybIV5JC+OBU8VnF+V7oQ9dnDBpx2qT5Mh+oxd+/tw=="
},
"react-native-fast-image": {
"version": "8.3.4",
"resolved": "https://registry.npmjs.org/react-native-fast-image/-/react-native-fast-image-8.3.4.tgz",
"integrity": "sha512-LpzAdjUphihUpVEBn5fEv5AILe55rHav0YiZroPZ1rumKDhAl4u2cG01ku2Pb7l8sayjTsNu7FuURAlXUUDsow=="
},
"react-native-fit-image": {
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/react-native-fit-image/-/react-native-fit-image-1.5.5.tgz",
@@ -7450,11 +7489,21 @@
}
}
},
"react-native-immersive-mode": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/react-native-immersive-mode/-/react-native-immersive-mode-2.0.0.tgz",
"integrity": "sha512-qpn7L9AckhE7rvHNaxjZlIp2RDa5QUBLmDOB5IoyatGq9Ahhx3AjH0ZtZVFcP28gS5emZ6/j9tehCEwXyLWl6Q=="
},
"react-native-iphone-x-helper": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/react-native-iphone-x-helper/-/react-native-iphone-x-helper-1.3.1.tgz",
"integrity": "sha512-HOf0jzRnq2/aFUcdCJ9w9JGzN3gdEg0zFE4FyYlp4jtidqU03D5X7ZegGKfT1EWteR0gPBGp9ye5T5FvSWi9Yg=="
},
"react-native-navigation-bar-color": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/react-native-navigation-bar-color/-/react-native-navigation-bar-color-2.0.1.tgz",
"integrity": "sha512-1kE/oxWt+HYjRxdZdvke9tJ365xaee5n3+euOQA1En8zQuSbOxiE4SYEGM7TeaWnmLJ0l37mRnPHaB2H4mGh0A=="
},
"react-native-offline": {
"version": "5.8.0",
"resolved": "https://registry.npmjs.org/react-native-offline/-/react-native-offline-5.8.0.tgz",
@@ -7467,9 +7516,9 @@
}
},
"react-native-pager-view": {
"version": "5.0.12",
"resolved": "https://registry.npmjs.org/react-native-pager-view/-/react-native-pager-view-5.0.12.tgz",
"integrity": "sha512-QmHUnQeP2qcxDofEOnKRmoUue0RaT55lhNJDfcQ1/SNuxif4Q2UyvDfqeItm1+toaE5tVnXqoreZh82FqUqnvw=="
"version": "5.1.10",
"resolved": "https://registry.npmjs.org/react-native-pager-view/-/react-native-pager-view-5.1.10.tgz",
"integrity": "sha512-sVWEPaxSyp2TOQ9yt+v+ecEdZ2lGnZ9TtoNU+WA1c6SjYdQlIvS2ZMb2hvdmgTMCnZpzKF02WH9BimGOzQRDIg=="
},
"react-native-paper": {
"version": "4.8.1",
@@ -7523,6 +7572,50 @@
"resolved": "https://registry.npmjs.org/react-native-tab-view/-/react-native-tab-view-3.0.1.tgz",
"integrity": "sha512-L7qXtYz5Z+NdWyu38zaJrlHA/8H6rNFRZXe3ydym12UEEPPoefbVZ71b9YK2O6QP0u4pUlzMpMVM/Lsz2DJ4jg=="
},
"react-native-unimodules": {
"version": "0.13.3",
"resolved": "https://registry.npmjs.org/react-native-unimodules/-/react-native-unimodules-0.13.3.tgz",
"integrity": "sha512-fjbNbAcvJHF8Ywqe77oveRW1WfaAKCQGV4a3Fxgpai17oNHq1LFwwKw0crFo0k7Njm5u7kCMVNbm9ZILNBfABQ==",
"requires": {
"@unimodules/core": "~7.1.0",
"@unimodules/react-native-adapter": "~6.2.2",
"chalk": "^2.4.2",
"expo-asset": "~8.3.1",
"expo-constants": "~10.1.3",
"expo-file-system": "~11.0.2",
"expo-image-loader": "~2.1.1",
"expo-permissions": "~12.0.1",
"find-up": "~5.0.0",
"unimodules-app-loader": "~2.1.0",
"unimodules-barcode-scanner-interface": "~6.1.0",
"unimodules-camera-interface": "~6.1.0",
"unimodules-constants-interface": "~6.1.0",
"unimodules-face-detector-interface": "~6.1.0",
"unimodules-file-system-interface": "~6.1.0",
"unimodules-font-interface": "~6.1.0",
"unimodules-image-loader-interface": "~6.1.0",
"unimodules-permissions-interface": "~6.1.0",
"unimodules-sensors-interface": "~6.1.0",
"unimodules-task-manager-interface": "~6.1.0"
},
"dependencies": {
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
}
},
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
}
}
},
"react-native-vector-icons": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-7.1.0.tgz",
@@ -7577,9 +7670,9 @@
}
},
"react-native-webview": {
"version": "11.2.3",
"resolved": "https://registry.npmjs.org/react-native-webview/-/react-native-webview-11.2.3.tgz",
"integrity": "sha512-r/K+Lf/O5aij72gRndMX2qsyQ/WLtDPiO75SS57y6JjqSKxedGASVL9Jwl1TM7fCXqUq8dgiwik/LuBHbJXAEg==",
"version": "11.6.2",
"resolved": "https://registry.npmjs.org/react-native-webview/-/react-native-webview-11.6.2.tgz",
"integrity": "sha512-7e5ltLBgqt1mX0gdTTS2nFPIjfS6y300wqJ4rLWqU71lDO+8ZeayfsF5qo83qxo2Go74CtLnSeWae4pdGwUqYw==",
"requires": {
"escape-string-regexp": "2.0.0",
"invariant": "2.2.4"
@@ -8666,11 +8759,56 @@
"resolved": "https://registry.npmjs.org/unimodules-app-loader/-/unimodules-app-loader-2.1.0.tgz",
"integrity": "sha512-W+D+hVXq6jOvBm7QVwODPENz6Lupj73QequNNG+6GCTkqn4ybq/lba9IQvJQT2QzdL3luVHin+eym18cDblMlg=="
},
"unimodules-barcode-scanner-interface": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/unimodules-barcode-scanner-interface/-/unimodules-barcode-scanner-interface-6.1.0.tgz",
"integrity": "sha512-+McBDniXReXNS8PnGDjIyDikb+cRXSfsZMLsF0gohEEV0xdA6HhPvFA0ryv65j2NKOyIiWmEHjv+yDOoewDq3w=="
},
"unimodules-camera-interface": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/unimodules-camera-interface/-/unimodules-camera-interface-6.1.0.tgz",
"integrity": "sha512-Rbszrh54kIB4vA+AzDWFXplBz1UrxQNR6Ls0eJDAKffbjDfyQIP6SgIPjUlzqGVnzknyZ1SMGiFFSFCM4BCOAw=="
},
"unimodules-constants-interface": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/unimodules-constants-interface/-/unimodules-constants-interface-6.1.0.tgz",
"integrity": "sha512-uPLFGufbdefRQeINyUfkw2mVJJg+6kH23RR4ATfUAsrD6vGLuONwduHvRwh+rcL9fzPVM4jsfH6iATrolmiatg=="
},
"unimodules-face-detector-interface": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/unimodules-face-detector-interface/-/unimodules-face-detector-interface-6.1.0.tgz",
"integrity": "sha512-L2E8a2OjMPxfVh/OGt6Y5HWbEaJ9h3Hkmvx02GCferBPKgN3dcxFMaI53d1BVV9QA3r4YuLBP6RrolG/qy/r7A=="
},
"unimodules-file-system-interface": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/unimodules-file-system-interface/-/unimodules-file-system-interface-6.1.0.tgz",
"integrity": "sha512-iJGm6nWF+PhxqFbeqC2Ku4XjglbL9z7aofkSX5S7bZ3Oi4v1NO1UOe9nczU17Ps19sfYZJgkiD4FiQaFCmAnKg=="
},
"unimodules-font-interface": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/unimodules-font-interface/-/unimodules-font-interface-6.1.0.tgz",
"integrity": "sha512-OfSeWx9ew2SNENj/HhctfPU7hqeW0bzVZYGGJ0M6RNcRRWzwA6ltawyYwtuvRe/EEU3LwrFUSKPMCi9867hLyw=="
},
"unimodules-image-loader-interface": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/unimodules-image-loader-interface/-/unimodules-image-loader-interface-6.1.0.tgz",
"integrity": "sha512-o8hZI6J6DGYyo2xSH6J+ipxME0blNfmaWU3P2Y2AUVxbEPdgjT2sVmufRWMKGhrt7gaNW4xF/JUbF9lq4Rui7w=="
},
"unimodules-permissions-interface": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/unimodules-permissions-interface/-/unimodules-permissions-interface-6.1.0.tgz",
"integrity": "sha512-jeJx/y+Vn/Cp1/4su5XJ06UBul83MpXkYEqIOAb2jwaikhmj6tNwko7HpKy9OhfGfrhddCzwtedlro8xxZUk9A=="
},
"unimodules-sensors-interface": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/unimodules-sensors-interface/-/unimodules-sensors-interface-6.1.0.tgz",
"integrity": "sha512-tJDOo3p4q4wmhyuwapNjYeON7cd5OSPYr3qDfMgPPg9m6pYM/FdQJ1PKMNb1NJUckpDgQ67Dows2jAdqkNRZSw=="
},
"unimodules-task-manager-interface": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/unimodules-task-manager-interface/-/unimodules-task-manager-interface-6.1.0.tgz",
"integrity": "sha512-wSsuX5fzd3oCCjHvrRFxysmCswhHZbJflVyAWzgSHtyMgxBOZobGN1C0UQ/plcu/JWY2+maTDPpE9OU6wzzzdg=="
},
"union-value": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
+17 -10
View File
@@ -1,9 +1,8 @@
{
"main": "node_modules/expo/AppEntry.js",
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"start": "react-native start",
"android": "react-native run-android",
"ios": "react-native run-ios",
"web": "expo start --web",
"eject": "expo eject"
},
@@ -25,39 +24,47 @@
"expo-notifications": "~0.11.6",
"expo-permissions": "^12.0.1",
"expo-sharing": "~9.1.2",
"expo-speech": "~9.1.0",
"expo-splash-screen": "~0.10.2",
"expo-sqlite": "~9.1.0",
"expo-status-bar": "~1.0.4",
"expo-task-manager": "~9.1.0",
"expo-updates": "~0.5.4",
"expo-web-browser": "~9.1.0",
"moment": "^2.29.1",
"qs": "^6.10.1",
"react": "16.13.1",
"react-dom": "16.13.1",
"react-native": "https://github.com/expo/react-native/archive/sdk-41.0.0.tar.gz",
"react-native": "~0.63.4",
"react-native-collapsible-header-views": "^1.1.2",
"react-native-device-info": "^8.1.3",
"react-native-easing-gradient": "^0.1.2",
"react-native-fast-image": "^8.3.4",
"react-native-fit-image": "^1.5.5",
"react-native-gesture-handler": "~1.10.2",
"react-native-immersive-mode": "^2.0.0",
"react-native-navigation-bar-color": "^2.0.1",
"react-native-offline": "^5.7.0",
"react-native-pager-view": "^5.1.10",
"react-native-paper": "^4.5.0",
"react-native-reanimated": "~2.1.0",
"react-native-safe-area-context": "3.2.0",
"react-native-screens": "~3.0.0",
"react-native-tab-view": "^3.0.1",
"react-native-unimodules": "~0.13.3",
"react-native-vector-icons": "^7.1.0",
"react-native-web": "~0.13.12",
"react-native-webview": "11.2.3",
"react-native-webview": "^11.6.2",
"react-redux": "^7.2.2",
"redux": "^4.0.5",
"redux-devtools-extension": "^2.13.9",
"redux-persist": "^6.0.0",
"redux-thunk": "^2.3.0",
"rn-sliding-up-panel": "^2.4.4",
"react-native-pager-view": "5.0.12"
"rn-sliding-up-panel": "^2.4.4"
},
"devDependencies": {
"@babel/core": "~7.9.0"
},
"private": true
"private": true,
"name": "lnreader-eject",
"version": "1.0.0"
}
+2
View File
@@ -0,0 +1,2 @@
import { NativeModules } from "react-native";
module.exports = NativeModules.FullScreen;
+2 -1
View File
@@ -1,5 +1,6 @@
import React from "react";
import { StyleSheet, View, Text, Image } from "react-native";
import FastImage from "react-native-fast-image";
import { TouchableRipple } from "react-native-paper";
const ListView = ({ item, downloadBadge, unreadBadge, theme, onPress }) => {
@@ -12,7 +13,7 @@ const ListView = ({ item, downloadBadge, unreadBadge, theme, onPress }) => {
onPress={onPress}
>
<>
<Image
<FastImage
source={{ uri: item.novelCover }}
style={styles.extensionIcon}
/>
+16 -15
View File
@@ -1,24 +1,27 @@
import React from "react";
import { StyleSheet, View, Text, ImageBackground, Image } from "react-native";
import { StyleSheet, View, Text, useWindowDimensions } from "react-native";
import { LinearGradient } from "expo-linear-gradient";
import { TouchableRipple } from "react-native-paper";
import { useSelector } from "react-redux";
import { useSettings, useTheme } from "../Hooks/reduxHooks";
import ListView from "./ListView";
import FastImage from "react-native-fast-image";
import { getDeviceOrientation } from "../Services/utils/helpers";
const NovelCover = ({ item, onPress, libraryStatus }) => {
const theme = useTheme();
const { displayMode, novelsPerRow, showDownloadBadges, showUnreadBadges } =
useSettings();
const height = {
1: 550,
2: 280,
3: 180,
4: 140,
5: 100,
};
const window = useWindowDimensions();
const orientation = getDeviceOrientation();
const getNovelsPerRow = () =>
orientation === "landscape" ? 6 : novelsPerRow;
const getHeight = () => (window.width / getNovelsPerRow()) * (4 / 3);
const comfortableTitle = () =>
displayMode === 1 && (
@@ -92,7 +95,7 @@ const NovelCover = ({ item, onPress, libraryStatus }) => {
);
return displayMode !== 2 ? (
<View style={{ flex: 1 / novelsPerRow }}>
<View style={{ flex: 1 / getNovelsPerRow() }}>
<TouchableRipple
borderless
centered
@@ -101,21 +104,19 @@ const NovelCover = ({ item, onPress, libraryStatus }) => {
onPress={onPress}
>
<>
<ImageBackground
<FastImage
source={{ uri: item.novelCover }}
style={{ height: height[novelsPerRow] }}
imageStyle={[
{ borderRadius: 4 },
style={[
{ height: getHeight(), borderRadius: 4 },
libraryStatus && { opacity: 0.5 },
]}
progressiveRenderingEnabled={true}
>
<View style={{ flexDirection: "row", margin: 4 }}>
{downloadBadge()}
{unreadBadge()}
</View>
{compactTitle()}
</ImageBackground>
</FastImage>
{comfortableTitle()}
</>
</TouchableRipple>
+15 -2
View File
@@ -2,6 +2,7 @@ import React from "react";
import { StyleSheet, FlatList } from "react-native";
import { useSettings } from "../Hooks/reduxHooks";
import { getDeviceOrientation } from "../Services/utils/helpers";
const NovelList = ({
data,
@@ -11,13 +12,25 @@ const NovelList = ({
}) => {
const { displayMode, novelsPerRow } = useSettings();
const getNovelsPerRow = () => (displayMode === 2 ? 1 : novelsPerRow);
const orientation = getDeviceOrientation();
const getNovelsPerRow = () => {
if (displayMode === 2) {
return 1;
}
if (orientation === "landscape") {
return 6;
} else {
return novelsPerRow;
}
};
return (
<FlatList
contentContainerStyle={styles.flatListCont}
numColumns={getNovelsPerRow()}
key={getNovelsPerRow()}
key={[orientation, getNovelsPerRow()]}
data={data}
keyExtractor={(item) => item.novelUrl}
renderItem={renderItem}
+1 -1
View File
@@ -56,7 +56,7 @@ const searchLibraryQuery = (searchText, sort, filter) =>
GROUP BY chapters.novelId
) AS D
ON novels.novelId = D.novelId
WHERE novels.followed = 1 AND novelName LIKE '%${searchText}%' OR source LIKE '%${searchText}%' ${
WHERE novels.followed = 1 AND novelName LIKE '%${searchText}%' ${
filter ? "AND " + filter : ""
}
${sort ? "ORDER BY " + sort : ""} `;
+1 -1
View File
@@ -22,7 +22,7 @@ export const githubUpdateChecker = () => {
};
const isNewVersion = (versionTag) => {
let currentVersion = "v1.0.19";
let currentVersion = "v1.0.20";
const regex = /[^\\d.]/;
let newVersion = versionTag.replace(regex, "");
+3
View File
@@ -1,7 +1,10 @@
import { setStatusBarStyle as setExpoStatusBarStyle } from "expo-status-bar";
import { useTheme } from "../Hooks/reduxHooks";
import changeNavigationBarColor from "react-native-navigation-bar-color";
export const setStatusBarStyle = () => {
const theme = useTheme();
setExpoStatusBarStyle(theme.id === 1 ? "dark" : "light");
changeNavigationBarColor(theme.colorPrimary);
};
+6
View File
@@ -20,6 +20,7 @@ import { useTheme } from "../Hooks/reduxHooks";
import { githubUpdateChecker } from "../Hooks/githubUpdateChecker";
import NewUpdateDialog from "../Components/NewUpdateDialog";
import { NavigationContainer } from "@react-navigation/native";
import BrowseMalScreen from "../Screens/Browse/BrowseMal";
const Stack = createStackNavigator();
@@ -57,6 +58,11 @@ const MainNavigator = () => {
/>
<Stack.Screen name="MoreStack" component={MoreStack} />
<Stack.Screen name="Extension" component={Extension} />
<Stack.Screen
name="BrowseMal"
component={BrowseMalScreen}
/>
<Stack.Screen
name="GlobalSearch"
component={GlobalSearch}
+11 -1
View File
@@ -2,7 +2,6 @@ import React, { useEffect, useState } from "react";
import {
StyleSheet,
View,
ScrollView,
Text,
FlatList,
ActivityIndicator,
@@ -19,6 +18,7 @@ import {
import SourceCard from "./components/SourceCard";
import { showToast } from "../../Hooks/showToast";
import { Searchbar } from "../../Components/Searchbar";
import MalCard from "./components/MalCard";
const Browse = ({ navigation }) => {
const [refreshing, setRefreshing] = useState(false);
@@ -93,6 +93,16 @@ const Browse = ({ navigation }) => {
extraData={pinned}
ListHeaderComponent={
<View>
<Text
style={{
color: theme.textColorSecondary,
paddingHorizontal: 16,
paddingVertical: 8,
}}
>
Discover
</Text>
<MalCard theme={theme} />
{pinned.length > 0 && (
<FlatList
contentContainerStyle={{ paddingBottom: 16 }}
+235
View File
@@ -0,0 +1,235 @@
import React, { useEffect, useState } from "react";
import { StyleSheet, View, ActivityIndicator, FlatList } from "react-native";
import * as WebBrowser from "expo-web-browser";
import NovelCover from "../../Components/NovelCover";
import EmptyView from "../../Components/EmptyView";
import { Searchbar } from "../../Components/Searchbar";
import { useTheme, useSettings } from "../../Hooks/reduxHooks";
import { showToast } from "../../Hooks/showToast";
import ErrorView from "../../Components/ErrorView";
import { getDeviceOrientation } from "../../Services/utils/helpers";
const BrowseMalScreen = ({ navigation, route }) => {
const theme = useTheme();
const [loading, setLoading] = useState(true);
const [novels, setNovels] = useState();
const [error, setError] = useState();
const [pageNo, setPageNo] = useState(1);
const [searchText, setSearchText] = useState("");
const getNovels = async () => {
try {
const url = `https://api.jikan.moe/v3/top/manga/1/novels`;
console.log(url);
const res = await fetch(url);
const data = await res.json();
setNovels(data.top);
setLoading(false);
} catch (error) {
setError(error.message);
setNovels([]);
setLoading(false);
setPageNo(1);
showToast(error.message);
}
};
// const getNextPage = async () => {
// try {
// const url = `https://api.jikan.moe/v3/top/manga/${pageNo}/novels`;
// console.log(url);
// const res = await fetch(url);
// const data = await res.json();
// setNovels((novels) => novels.concat(data.top));
// setPageNo((pageNo) => pageNo + 1);
// setLoading(false);
// } catch (error) {
// setError(error.message);
// setNovels([]);
// setPageNo(1);
// setLoading(false);
// showToast(error.message);
// }
// };
const clearSearchbar = () => {
getNovels();
setLoading(true);
setSearchText("");
};
const getSearchResults = () => {
setLoading(true);
console.log(
`https://api.jikan.moe/v3/search/manga?q=${searchText}&page=1&type=novel`
);
fetch(
`https://api.jikan.moe/v3/search/manga?q=${searchText}&page=1&type=novel`
)
.then((response) => response.json())
.then((json) => {
console.log(json.results);
setNovels(json.results);
setLoading(false);
})
.catch((error) => {
setNovels([]);
setLoading(false);
showToast(error.message);
});
};
// const checkIFInLibrary = (sourceId, novelUrl) => {
// return library.some(
// (obj) => obj.novelUrl === novelUrl && obj.sourceId === sourceId
// );
// };
useEffect(() => {
getNovels();
}, []);
const renderItem = ({ item }) => (
<NovelCover
item={{ novelName: item.title, novelCover: item.image_url }}
onPress={() =>
navigation.navigate("GlobalSearch", {
novelName: item.title,
})
}
/>
);
const { displayMode, novelsPerRow } = useSettings();
const orientation = getDeviceOrientation();
const getNovelsPerRow = () => {
if (displayMode === 2) {
return 1;
}
if (orientation === "landscape") {
return 6;
} else {
return novelsPerRow;
}
};
const isCloseToBottom = ({
layoutMeasurement,
contentOffset,
contentSize,
}) => {
const paddingToBottom = 0;
return (
layoutMeasurement.height + contentOffset.y >=
contentSize.height - paddingToBottom
);
};
const onScroll = ({ nativeEvent }) => {
if (isCloseToBottom(nativeEvent)) {
console.log("Close to bototm");
getNextPage();
}
};
const ListEmptyComponent = () => (
<ErrorView
error={error || "No results found"}
onRetry={() => {
getNovels();
setLoading(true);
setError();
}}
openWebView={() =>
WebBrowser.openBrowserAsync(
"https://myanimelist.net/topmanga.php?type=lightnovels"
)
}
theme={theme}
/>
);
return (
<View
style={[
styles.container,
{ backgroundColor: theme.colorPrimaryDark },
]}
>
<Searchbar
theme={theme}
placeholder="Search MyAnimeList"
left="arrow-left"
onPressLeft={() => navigation.goBack()}
searchText={searchText}
onChangeText={(text) => setSearchText(text)}
onSubmitEditing={getSearchResults}
clearSearchbar={clearSearchbar}
right="earth"
displayMenu={true}
onPressRight={() =>
WebBrowser.openBrowserAsync(
"https://myanimelist.net/topmanga.php?type=lightnovels"
)
}
/>
{loading ? (
<View style={{ flex: 1, justifyContent: "center" }}>
<ActivityIndicator size={60} color={theme.colorAccent} />
</View>
) : (
<FlatList
contentContainerStyle={styles.flatListCont}
numColumns={getNovelsPerRow()}
key={getNovelsPerRow()}
data={novels}
keyExtractor={(item) => item.mal_id.toString()}
renderItem={renderItem}
ListEmptyComponent={ListEmptyComponent}
// onScroll={onScroll}
// ListFooterComponent={
// <View
// style={{
// flex: 1,
// justifyContent: "center",
// paddingTop: 16,
// paddingBottom: 8,
// }}
// >
// <ActivityIndicator color={theme.colorAccent} />
// </View>
// }
/>
)}
{/* <Button title="Grt novels" onPress={() => console.log(novels)} /> */}
</View>
);
};
export default BrowseMalScreen;
const styles = StyleSheet.create({
container: {
flex: 1,
},
contentContainer: {
flex: 1,
},
flatListCont: {
flexGrow: 1,
paddingVertical: 8,
paddingHorizontal: 4,
},
});
+80
View File
@@ -0,0 +1,80 @@
import React from "react";
import { View, Text, Image, StyleSheet } from "react-native";
import { TouchableRipple, Button } from "react-native-paper";
import { useNavigation } from "@react-navigation/native";
const MalCard = ({ theme }) => {
const navigation = useNavigation();
const navigateToExtension = () => navigation.navigate("BrowseMal");
return (
<TouchableRipple
style={styles.extensionCard}
onPress={navigateToExtension}
rippleColor={theme.rippleColor}
>
<>
<Image
source={require("../../../../assets/mal.png")}
style={styles.extensionIcon}
resizeMode="contain"
/>
<View style={styles.extensionDetails}>
<View>
<Text
style={{
color: theme.textColorPrimary,
fontSize: 14,
}}
>
MyAnimeList
</Text>
</View>
<View
style={{ flexDirection: "row", alignItems: "center" }}
>
<Button
labelStyle={{ letterSpacing: 0 }}
uppercase={false}
color={theme.colorAccent}
onPress={navigateToExtension}
>
Browse
</Button>
</View>
</View>
</>
</TouchableRipple>
);
};
export default MalCard;
const styles = StyleSheet.create({
extensionCard: {
flexDirection: "row",
alignItems: "center",
marginVertical: 4,
paddingVertical: 8,
paddingHorizontal: 20,
},
extensionIcon: {
width: 40,
height: 40,
borderRadius: 8,
},
extensionDetails: {
flex: 1,
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
marginLeft: 16,
},
sourceStatus: {
color: "#C14033",
fontSize: 12,
marginLeft: 5,
},
});
@@ -1,5 +1,6 @@
import React from "react";
import { View, Text, Image, StyleSheet } from "react-native";
import FastImage from "react-native-fast-image";
import { TouchableRipple } from "react-native-paper";
const MigrationSourceCard = ({ item, theme, noOfNovels, onPress }) => {
@@ -12,10 +13,9 @@ const MigrationSourceCard = ({ item, theme, noOfNovels, onPress }) => {
rippleColor={theme.rippleColor}
>
<>
<Image
<FastImage
source={{ uri: sourceCover }}
style={styles.extensionIcon}
resizeMode="contain"
/>
<View style={styles.extensionDetails}>
<View>
@@ -57,7 +57,7 @@ const styles = StyleSheet.create({
extensionIcon: {
width: 40,
height: 40,
borderRadius: 8,
borderRadius: 4,
},
extensionDetails: {
flex: 1,
@@ -4,6 +4,7 @@ import { TouchableRipple, Button, IconButton } from "react-native-paper";
import { useNavigation } from "@react-navigation/native";
import { useDispatch } from "react-redux";
import { pinSourceAction } from "../../../redux/source/source.actions";
import FastImage from "react-native-fast-image";
const ExtensionCard = ({ item, theme, isPinned }) => {
const { sourceId, sourceName, sourceCover, sourceLanguage, status } = item;
+42 -11
View File
@@ -1,7 +1,13 @@
import React, { useState, useEffect, useRef } from "react";
import { StyleSheet, View, Text, ActivityIndicator } from "react-native";
import {
StyleSheet,
View,
Text,
ActivityIndicator,
StatusBar,
} from "react-native";
import { useDispatch } from "react-redux";
import { useDispatch, useSelector } from "react-redux";
import Constants from "expo-constants";
import { IconButton, Portal } from "react-native-paper";
import { CollapsibleHeaderScrollView } from "react-native-collapsible-header-views";
@@ -32,6 +38,11 @@ import ReaderSheet from "./components/ReaderSheet";
import EmptyView from "../../Components/EmptyView";
import FitImage from "react-native-fit-image";
import {
hideNavigationBar,
showNavigationBar,
} from "react-native-navigation-bar-color";
const Chapter = ({ route, navigation }) => {
const {
sourceId,
@@ -48,6 +59,10 @@ const Chapter = ({ route, navigation }) => {
const theme = useTheme();
const dispatch = useDispatch();
const reader = useReaderSettings();
const showScrollPercentage = useSelector(
(state) => state.settingsReducer.showScrollPercentage
);
const { tracker, trackedNovels } = useTrackingStatus();
const position = usePosition(novelId, chapterId);
@@ -108,6 +123,10 @@ const Chapter = ({ route, navigation }) => {
useEffect(() => {
getChapter(chapterId);
dispatch(insertHistoryAction(novelId, chapterId));
return () => {
StatusBar.setHidden(false);
showNavigationBar();
};
}, []);
const isCloseToBottom = ({
@@ -157,6 +176,8 @@ const Chapter = ({ route, navigation }) => {
};
const scrollToSavedProgress = () => {
StatusBar.setHidden(true);
hideNavigationBar();
if (position && firstLayout) {
position.percentage < 100 &&
scrollViewRef.getNode().scrollTo({
@@ -268,17 +289,23 @@ const Chapter = ({ route, navigation }) => {
bottomSheetRef={readerSheetRef}
selectText={selectText}
setSelectText={setSelectText}
showScrollPercentage={showScrollPercentage}
/>
</Portal>
</CollapsibleHeaderScrollView>
<Text
style={[
styles.scrollPercentage,
{ color: readerTextColor(reader.theme) },
]}
>
{scrollPercentage + "%"}
</Text>
{showScrollPercentage && (
<Text
style={[
styles.scrollPercentage,
{
color: readerTextColor(reader.theme),
backgroundColor: readerBackground(reader.theme),
},
]}
>
{scrollPercentage + "%"}
</Text>
)}
</>
);
};
@@ -291,8 +318,12 @@ const styles = StyleSheet.create({
paddingVertical: 10,
},
scrollPercentage: {
width: "100%",
position: "absolute",
bottom: 12,
bottom: 0,
height: 30,
textAlign: "center",
textAlignVertical: "center",
alignSelf: "center",
fontFamily: "noto-sans",
fontWeight: "bold",
+31 -5
View File
@@ -5,7 +5,10 @@ import Slider from "@react-native-community/slider";
import Bottomsheet from "rn-sliding-up-panel";
import { fonts } from "../../../Services/utils/constants";
import { setReaderSettings } from "../../../redux/settings/settings.actions";
import {
setAppSettings,
setReaderSettings,
} from "../../../redux/settings/settings.actions";
import BottomSheetHandle from "../../../Components/BottomSheetHandle";
import { Row } from "../../../Components/Common";
@@ -16,6 +19,7 @@ const ReaderSheet = ({
bottomSheetRef,
selectText,
setSelectText,
showScrollPercentage,
}) => {
const [fontMenu, setFontMenu] = useState(false);
const openFontMenu = () => setFontMenu(true);
@@ -28,8 +32,8 @@ const ReaderSheet = ({
return (
<Bottomsheet
ref={bottomSheetRef}
draggableRange={{ top: 420, bottom: 0 }}
snappingPoints={[0, 420]}
draggableRange={{ top: 450, bottom: 0 }}
snappingPoints={[0, 450]}
showBackdrop={true}
backdropOpacity={0}
>
@@ -45,7 +49,7 @@ const ReaderSheet = ({
value={reader.textSize}
minimumValue={12}
maximumValue={20}
step={2}
step={1}
minimumTrackTintColor={theme.colorAccent}
maximumTrackTintColor="#000000"
thumbTintColor={theme.colorAccent}
@@ -351,6 +355,28 @@ const ReaderSheet = ({
))}
</Menu>
</Row>
<Row
style={{
justifyContent: "space-between",
width: "100%",
paddingHorizontal: 16,
marginTop: 16,
}}
>
<ReaderSettingTitle title="Show Progress Percentage" />
<Switch
value={showScrollPercentage}
onValueChange={() =>
dispatch(
setAppSettings(
"showScrollPercentage",
!showScrollPercentage
)
)
}
color={theme.colorAccent}
/>
</Row>
<Row
style={{
justifyContent: "space-between",
@@ -389,7 +415,7 @@ const styles = StyleSheet.create({
flex: 1,
borderTopLeftRadius: 8,
borderTopRightRadius: 8,
backgroundColor: "rgba(0,0,0,0.5)",
backgroundColor: "rgba(0,0,0,0.7)",
},
readerSettingsContainer: {
flex: 1,
+4 -1
View File
@@ -46,7 +46,10 @@ const History = ({ navigation }) => {
/>
);
const clearSearchbar = () => setSearchText("");
const clearSearchbar = () => {
setSearchText("");
setSearchResults([]);
};
const onChangeText = (text) => {
setSearchText(text);
@@ -9,6 +9,7 @@ import { useDispatch } from "react-redux";
import { setNovel } from "../../../redux/novel/novel.actions";
import { parseChapterNumber } from "../../../Services/utils/helpers";
import { deleteHistoryAction } from "../../../redux/history/history.actions";
import FastImage from "react-native-fast-image";
const HistoryCard = ({ item, navigation, theme, dispatch }) => {
return (
@@ -22,7 +23,7 @@ const HistoryCard = ({ item, navigation, theme, dispatch }) => {
}}
>
<>
<Image
<FastImage
source={{ uri: item.novelCover }}
style={styles.historyCover}
/>
+2 -2
View File
@@ -17,12 +17,12 @@ const AboutScreen = ({ navigation }) => {
<ListSection>
<ListItem
title="Version"
description="Stable 1.0.19"
description="Stable 1.0.20"
theme={theme}
/>
<ListItem
title="Build Time"
description="31-05-21 21:30 PM"
description="01-06-21 13:30 PM"
theme={theme}
/>
<ListItem
@@ -39,7 +39,7 @@ const AccentColorModal = ({
defaultValue={theme.colorAccent}
onChangeText={(text) => setText(text)}
onSubmitEditing={() => {
if (text.match(/^#[0-9a-f]{3,6}$/i)) {
if (text.match(/^#([0-9a-f]{6}|[0-9a-f]{3})$/i)) {
dispatch(setAccentColor(text));
hideAccentColorModal();
} else {
+3 -1
View File
@@ -4,6 +4,7 @@ import { Portal, Modal, Checkbox } from "react-native-paper";
import { setStatusBarStyle } from "expo-status-bar";
import { setAppTheme } from "../../../redux/settings/settings.actions";
import ImmersiveMode from "react-native-immersive-mode";
const ThemeModal = ({ themeModalVisible, hidethemeModal, dispatch, theme }) => {
const themes = [
@@ -26,7 +27,8 @@ const ThemeModal = ({ themeModalVisible, hidethemeModal, dispatch, theme }) => {
color={theme.colorAccent}
onPress={() => {
dispatch(setAppTheme(item.id));
setStatusBarStyle(item.statusBar);
// setStatusBarStyle(item.statusBar);
ImmersiveMode.setBarColor(item.colorPrimary);
}}
/>
));
+3 -1
View File
@@ -155,7 +155,9 @@ const Novel = ({ route, navigation }) => {
dispatch(
markChaptersRead(
selected,
novel.novelId
novel.novelId,
sort,
filter
)
);
setSelected([]);
@@ -12,6 +12,7 @@ import { Chip, IconButton } from "react-native-paper";
import { MaterialCommunityIcons } from "@expo/vector-icons";
import { LinearGradient } from "expo-linear-gradient";
import easeGradient from "react-native-easing-gradient";
import FastImage from "react-native-fast-image";
const NovelInfoContainer = ({ children }) => (
<View style={styles.novelInfoContainer}>{children}</View>
@@ -26,7 +27,7 @@ const CoverImage = ({ children, source, theme }) => {
});
return (
<ImageBackground source={source} style={styles.coverImage}>
<FastImage source={source} style={styles.coverImage}>
<LinearGradient
colors={colors}
locations={locations}
@@ -34,12 +35,12 @@ const CoverImage = ({ children, source, theme }) => {
>
{children}
</LinearGradient>
</ImageBackground>
</FastImage>
);
};
const NovelThumbnail = ({ source }) => (
<Image source={source} style={styles.novelThumbnail} />
<FastImage source={source} style={styles.novelThumbnail} />
);
const NovelTitle = ({ theme, children, onLongPress, onPress }) => (
@@ -5,33 +5,31 @@ const NovelSummary = ({ summary, followed, theme }) => {
const [more, showMore] = useState(!followed);
return (
summary && (
<View style={styles.summaryContainer}>
<Text
style={{
color: theme.textColorSecondary,
lineHeight: 20,
}}
numberOfLines={more ? 200 : 2}
onPress={() => showMore(!more)}
ellipsizeMode="clip"
>
{summary}
</Text>
<Text
style={[
{
color: theme.colorAccent,
backgroundColor: theme.colorPrimaryDark,
},
styles.showMoreButton,
]}
onPress={() => showMore(!more)}
>
{more ? "Less" : "More"}
</Text>
</View>
)
<View style={styles.summaryContainer}>
<Text
style={{
color: theme.textColorSecondary,
lineHeight: 20,
}}
numberOfLines={more ? 200 : 2}
onPress={() => showMore(!more)}
ellipsizeMode="clip"
>
{summary}
</Text>
<Text
style={[
{
color: theme.colorAccent,
backgroundColor: theme.colorPrimaryDark,
},
styles.showMoreButton,
]}
onPress={() => showMore(!more)}
>
{more ? "Less" : "More"}
</Text>
</View>
);
};
@@ -1,5 +1,6 @@
import React from "react";
import { View, Text, Image, StyleSheet } from "react-native";
import FastImage from "react-native-fast-image";
import { TouchableRipple } from "react-native-paper";
const UpdateCard = ({ item, theme, onPress }) => {
@@ -11,7 +12,7 @@ const UpdateCard = ({ item, theme, onPress }) => {
borderless
>
<>
<Image
<FastImage
source={{ uri: item.novelCover }}
style={styles.updateIcon}
/>
+12
View File
@@ -1,3 +1,5 @@
import { useWindowDimensions } from "react-native";
export const parseChapterNumber = (chapterName) => {
chapterName = chapterName.toLowerCase();
chapterName = chapterName.replace(/volume (\d+)/, "");
@@ -13,3 +15,13 @@ export const parseChapterNumber = (chapterName) => {
return 0;
}
};
export const getDeviceOrientation = () => {
const window = useWindowDimensions();
if (window.width > window.height) {
return "landscape";
} else {
return "potrait";
}
};
+13 -15
View File
@@ -223,23 +223,21 @@ export const markPreviousChaptersReadAction =
showToast("Marked previous chapters read");
};
export const markChaptersRead = (chapters, novelId) => async (dispatch) => {
try {
const { sort = "ORDER BY chapterId ASC", filter = "" } =
store.getState().preferenceReducer.novelSettings[novelId];
export const markChaptersRead =
(chapters, novelId, sort, filter) => async (dispatch) => {
try {
chapters.map((chapter) => markChapterRead(chapter.chapterId));
chapters.map((chapter) => markChapterRead(chapter.chapterId));
const chaps = await getChapters(novelId, sort, filter);
const chaps = await getChapters(novelId, sort, filter);
dispatch({
type: GET_CHAPTERS,
payload: chaps,
});
} catch (error) {
showToast(error.message);
}
};
dispatch({
type: GET_CHAPTERS,
payload: chaps,
});
} catch (error) {
showToast(error.message);
}
};
export const markPreviousChaptersUnreadAction =
(chapterId, novelId) => async (dispatch) => {
+1
View File
@@ -54,6 +54,7 @@ const initialState = {
showDownloadBadges: true,
showUnreadBadges: true,
showNumberOfNovels: false,
showScrollPercentage: true,
};
const settingsReducer = (state = initialState, action) => {