Eject to bare workflow
@@ -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
|
||||
@@ -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>
|
||||
|
||||
@@ -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",
|
||||
],
|
||||
)
|
||||
@@ -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)
|
||||
@@ -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,
|
||||
)
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
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>
|
||||
|
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>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 876 B |
|
After Width: | Height: | Size: 876 B |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
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>
|
||||
@@ -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' }
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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" "$@"
|
||||
@@ -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
|
||||
@@ -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'
|
||||
@@ -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": {
|
||||
|
||||
@@ -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);
|
||||
@@ -0,0 +1,4 @@
|
||||
// Learn more https://docs.expo.io/guides/customizing-metro
|
||||
const { getDefaultConfig } = require('expo/metro-config');
|
||||
|
||||
module.exports = getDefaultConfig(__dirname);
|
||||
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
import { NativeModules } from "react-native";
|
||||
module.exports = NativeModules.FullScreen;
|
||||
@@ -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}
|
||||
/>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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 : ""} `;
|
||||
|
||||
@@ -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, "");
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
});
|
||||
@@ -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;
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}}
|
||||
/>
|
||||
));
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -54,6 +54,7 @@ const initialState = {
|
||||
showDownloadBadges: true,
|
||||
showUnreadBadges: true,
|
||||
showNumberOfNovels: false,
|
||||
showScrollPercentage: true,
|
||||
};
|
||||
|
||||
const settingsReducer = (state = initialState, action) => {
|
||||
|
||||