Compare commits
45 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 49e4d78c92 | |||
| c88b2e5d2a | |||
| be2dab5b5d | |||
| 2d986f263d | |||
| 684463754c | |||
| 6879d77ef1 | |||
| 41ed198a1d | |||
| 550e116be5 | |||
| 1c21c180ab | |||
| 08860c0715 | |||
| d65170c85a | |||
| cf19eb6892 | |||
| 3289f357d9 | |||
| fe2b2524a7 | |||
| 2e4ff916aa | |||
| b40e9331d7 | |||
| 84a2561c41 | |||
| 929bd2c97d | |||
| 9028a82318 | |||
| c6c41a2d1b | |||
| 9a0c08e7b8 | |||
| 0abdff25eb | |||
| f238b20f6d | |||
| cc9022cf12 | |||
| fbadd41733 | |||
| c30b884428 | |||
| 8fc9e04d97 | |||
| 84bc83b7a2 | |||
| 2bb0c28591 | |||
| 52ae111e98 | |||
| ecd383b586 | |||
| 606b2c8f12 | |||
| d9bbae444a | |||
| 2e9a7adc2c | |||
| 63909bf52e | |||
| 8fe1dacab0 | |||
| a193656cb2 | |||
| ed23040287 | |||
| c9d834a2f0 | |||
| 7faabc5d9c | |||
| 330abf25d7 | |||
| d75ef3f444 | |||
| 6e665dabf4 | |||
| 12b83f4de7 | |||
| 518f73f6fd |
@@ -8,19 +8,22 @@ jobs:
|
||||
name: Build App
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '16'
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
npm install --legacy-peer-deps
|
||||
|
||||
- name: Cache Gradle Wrapper
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.gradle/wrapper
|
||||
key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }}
|
||||
|
||||
- name: Cache Gradle Dependencies
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.gradle/caches
|
||||
key: ${{ runner.os }}-gradle-caches-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }}
|
||||
|
||||
@@ -5,19 +5,29 @@ enableFreeze(true);
|
||||
|
||||
import React, { useEffect } from 'react';
|
||||
import { StatusBar } from 'react-native';
|
||||
|
||||
import { GestureHandlerRootView } from 'react-native-gesture-handler';
|
||||
import LottieSplashScreen from 'react-native-lottie-splash-screen';
|
||||
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
||||
import { Provider as PaperProvider } from 'react-native-paper';
|
||||
import { Provider } from 'react-redux';
|
||||
import { persistor, store } from './src/redux/store';
|
||||
import { PersistGate } from 'redux-persist/lib/integration/react';
|
||||
import * as Notifications from 'expo-notifications';
|
||||
|
||||
import { createDatabase } from '@database/db';
|
||||
import { persistor, store } from '@redux/store';
|
||||
import AppErrorBoundary from '@components/AppErrorBoundary/AppErrorBoundary';
|
||||
|
||||
import Main from './src/navigators/Main';
|
||||
|
||||
import { createDatabase } from './src/database/db';
|
||||
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
||||
import LottieSplashScreen from 'react-native-lottie-splash-screen';
|
||||
import AppErrorBoundary from '@components/AppErrorBoundary/AppErrorBoundary';
|
||||
import { GestureHandlerRootView } from 'react-native-gesture-handler';
|
||||
Notifications.setNotificationHandler({
|
||||
handleNotification: async () => {
|
||||
return {
|
||||
shouldShowAlert: true,
|
||||
shouldPlaySound: true,
|
||||
shouldSetBadge: true,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
const App = () => {
|
||||
useEffect(() => {
|
||||
|
||||
+24
-5
@@ -7,6 +7,11 @@ Contributions are welcome and are greatly appreciated!
|
||||
After forking to your own github org or account, do the following steps to get started:
|
||||
|
||||
```bash
|
||||
# prerequisites
|
||||
node --version <= 16.13.1 (for version management, get nvm [recommended])
|
||||
java sdk --version <= 11 (for version management, get jenv [optional])
|
||||
android sdk (https://developer.android.com/studio)
|
||||
|
||||
# clone your fork to your local machine
|
||||
git clone https://github.com/<your-account-name>/lnreader.git
|
||||
|
||||
@@ -14,20 +19,34 @@ git clone https://github.com/<your-account-name>/lnreader.git
|
||||
cd lnreader
|
||||
|
||||
# install dependencies
|
||||
npm install
|
||||
npm install --legacy-peer-deps
|
||||
|
||||
# run metro for development
|
||||
npm start
|
||||
# build the apk (the built apk will be found in ~/lnreader/android/app/build/outputs/apk/release/)
|
||||
npm run buildRelease
|
||||
```
|
||||
|
||||
### Developing on Android
|
||||
|
||||
While the packager is running and you have an Android device or emulator connected to your computer, build and launch the Android app.
|
||||
You will need an Android device or emulator connected to your computer as well as an IDE of your choice. (eg: vscode)
|
||||
|
||||
```
|
||||
```bash
|
||||
# prerequisites
|
||||
adb (https://developer.android.com/studio/command-line/adb)
|
||||
IDE
|
||||
|
||||
# check if android device/emulator is connected
|
||||
adb devices
|
||||
|
||||
# run metro for development
|
||||
npm start
|
||||
|
||||
# then to view on your android device (new terminal)
|
||||
npm run android
|
||||
```
|
||||
|
||||
To view any changes to the app with new code, save your code and press "r" on the metro terminal to
|
||||
reload it. The app on the android device/emulator will reload shortly.
|
||||
|
||||
### Style & Linting
|
||||
|
||||
This codebase's linting rules are enforced using [ESLint](http://eslint.org/).
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
</p>
|
||||
<div align="center">
|
||||
<a href="https://github.com/LNReader/lnreader/actions/workflows/build.yml">
|
||||
<img alt="GitHub Workflow Status" src="https://img.shields.io/github/workflow/status/LNReader/lnreader/CI">
|
||||
<img alt="GitHub Workflow Status" src="https://img.shields.io/github/actions/workflow/status/LNReader/lnreader/build.yml?branch=main">
|
||||
</a>
|
||||
<a href="https://discord.gg/QdcWN4MD63">
|
||||
<img alt="Discord Chat" src="https://img.shields.io/discord/835746409357246465.svg?logo=discord&logoColor=white&logoWidth=20&labelColor=7289DA&label=Discord&color=17cf48">
|
||||
@@ -43,6 +43,10 @@ LNReader does not have any affiliation with the content providers available.
|
||||
|
||||
Source requests should be created at [LNReader/lnreader-sources](https://github.com/LNReader/lnreader-sources).
|
||||
|
||||
## Building & Contributing
|
||||
|
||||
See [CONTRIBUTING.md](./CONTRIBUTING.md)
|
||||
|
||||
## License
|
||||
|
||||
[MIT ](https://github.com/rajarsheechatterjee/lnreader/blob/main/LICENSE)
|
||||
[MIT](https://github.com/rajarsheechatterjee/lnreader/blob/main/LICENSE)
|
||||
|
||||
@@ -8,6 +8,7 @@ import android.os.Bundle;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.widget.ScrollView;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.facebook.react.ReactActivity;
|
||||
@@ -60,7 +61,7 @@ public class MainActivity extends ReactActivity {
|
||||
case KeyEvent.KEYCODE_VOLUME_UP:
|
||||
if (action == KeyEvent.ACTION_DOWN) {
|
||||
// volup
|
||||
VolumeButtonListener.up();
|
||||
VolumeButtonListener.up(VolumeButtonListener.getScrollAmount());
|
||||
if (!VolumeButtonListener.prevent)
|
||||
return super.dispatchKeyEvent(event);
|
||||
}
|
||||
@@ -68,7 +69,7 @@ public class MainActivity extends ReactActivity {
|
||||
case KeyEvent.KEYCODE_VOLUME_DOWN:
|
||||
if (action == KeyEvent.ACTION_DOWN) {
|
||||
// voldown
|
||||
VolumeButtonListener.down();
|
||||
VolumeButtonListener.down(VolumeButtonListener.getScrollAmount());
|
||||
if (!VolumeButtonListener.prevent)
|
||||
return super.dispatchKeyEvent(event);
|
||||
}
|
||||
@@ -79,7 +80,6 @@ public class MainActivity extends ReactActivity {
|
||||
}
|
||||
return super.dispatchKeyEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the main component registered from JavaScript.
|
||||
* This is used to schedule rendering of the component.
|
||||
@@ -99,4 +99,4 @@ public class MainActivity extends ReactActivity {
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+28
-7
@@ -1,11 +1,11 @@
|
||||
package com.rajarsheechatterjee.VolumeButtonListener;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.bridge.Promise;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
||||
|
||||
@@ -27,9 +27,10 @@ public class VolumeButtonListener extends ReactContextBaseJavaModule {
|
||||
|
||||
public static boolean prevent = false;
|
||||
|
||||
public static void sendEvent(boolean up) {
|
||||
public static void sendEvent(boolean up, int amount) {
|
||||
if (active) {
|
||||
WritableMap args = Arguments.createMap();
|
||||
args.putInt("scrollAmount", amount); // add scroll amount to event data
|
||||
if (up)
|
||||
appContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("VolumeUp", args);
|
||||
else
|
||||
@@ -37,12 +38,22 @@ public class VolumeButtonListener extends ReactContextBaseJavaModule {
|
||||
}
|
||||
}
|
||||
|
||||
public static void down() {
|
||||
sendEvent(false);
|
||||
public static void down(int amount) {
|
||||
sendEvent(false, amount);
|
||||
}
|
||||
|
||||
public static void up() {
|
||||
sendEvent(true);
|
||||
public static void up(int amount) {
|
||||
sendEvent(true, amount);
|
||||
}
|
||||
|
||||
private static int scrollAmount = 100;
|
||||
|
||||
public static void setScrollAmount(int amount) {
|
||||
scrollAmount = amount;
|
||||
}
|
||||
|
||||
public static int getScrollAmount() {
|
||||
return scrollAmount;
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
@@ -90,4 +101,14 @@ public class VolumeButtonListener extends ReactContextBaseJavaModule {
|
||||
public void removeListeners(Integer count) {
|
||||
// Keep: Required for RN built in Event Emitter Calls.
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void setVolumeButtonScrollAmount(int amount) {
|
||||
setScrollAmount(amount);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void getVolumeButtonScrollAmount(Promise promise) {
|
||||
promise.resolve(getScrollAmount());
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -2,4 +2,4 @@ pull_request_title: 'chore: Update translations'
|
||||
commit_message: '[ci skip]'
|
||||
files:
|
||||
- source: /strings/languages/en/strings.json
|
||||
translation: /strings/languages/%two_letters_code%/strings.json
|
||||
translation: /strings/languages/%locale_with_underscore%/strings.json
|
||||
|
||||
Generated
+101
-481
@@ -21,7 +21,6 @@
|
||||
"@react-navigation/stack": "^6.0.11",
|
||||
"@reduxjs/toolkit": "^1.7.2",
|
||||
"@shopify/flash-list": "^1.2.1",
|
||||
"buffer": "^6.0.3",
|
||||
"cheerio": "^1.0.0-rc.10",
|
||||
"color": "^4.2.3",
|
||||
"dayjs": "^1.11.4",
|
||||
@@ -37,7 +36,7 @@
|
||||
"expo-sqlite": "~9.1.0",
|
||||
"expo-web-browser": "~9.1.0",
|
||||
"i18n-js": "^3.8.0",
|
||||
"lodash": "^4.17.21",
|
||||
"lodash-es": "^4.17.21",
|
||||
"lottie-react-native": "^5.1.4",
|
||||
"prop-types": "^15.7.2",
|
||||
"qs": "^6.10.3",
|
||||
@@ -54,13 +53,11 @@
|
||||
"react-native-markdown-display": "^7.0.0-alpha.2",
|
||||
"react-native-mmkv": "^2.4.3",
|
||||
"react-native-pager-view": "^5.4.9",
|
||||
"react-native-paper": "^5.1.2",
|
||||
"react-native-paper": "^5.2.0",
|
||||
"react-native-reanimated": "^2.13.0",
|
||||
"react-native-render-html": "^6.3.4",
|
||||
"react-native-safe-area-context": "^3.2.0",
|
||||
"react-native-screens": "^3.9.0",
|
||||
"react-native-shimmer-placeholder": "^2.0.9",
|
||||
"react-native-swipe-gestures": "^1.0.5",
|
||||
"react-native-tab-view": "^3.1.1",
|
||||
"react-native-tts": "^4.1.0",
|
||||
"react-native-unimodules": "^0.13.3",
|
||||
@@ -78,7 +75,7 @@
|
||||
"@types/color": "^3.0.3",
|
||||
"@types/i18n-js": "^3.8.2",
|
||||
"@types/jest": "^27.4.0",
|
||||
"@types/lodash": "^4.14.179",
|
||||
"@types/lodash-es": "^4.17.6",
|
||||
"@types/react-native": "^0.66.15",
|
||||
"@types/react-native-vector-icons": "^6.4.10",
|
||||
"@types/react-test-renderer": "^17.0.1",
|
||||
@@ -2998,141 +2995,6 @@
|
||||
"@jridgewell/sourcemap-codec": "1.4.14"
|
||||
}
|
||||
},
|
||||
"node_modules/@jsamr/counter-style": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@jsamr/counter-style/-/counter-style-2.0.2.tgz",
|
||||
"integrity": "sha512-2mXudGVtSzVxWEA7B9jZLKjoXUeUFYDDtFrQoC0IFX9/Dszz4t1vZOmafi3JSw/FxD+udMQ+4TAFR8Qs0J3URQ=="
|
||||
},
|
||||
"node_modules/@jsamr/react-native-li": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@jsamr/react-native-li/-/react-native-li-2.3.1.tgz",
|
||||
"integrity": "sha512-Qbo4NEj48SQ4k8FZJHFE2fgZDKTWaUGmVxcIQh3msg5JezLdTMMHuRRDYctfdHI6L0FZGObmEv3haWbIvmol8w==",
|
||||
"peerDependencies": {
|
||||
"@jsamr/counter-style": "^1.0.0 || ^2.0.0",
|
||||
"react": "*",
|
||||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@native-html/css-processor": {
|
||||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@native-html/css-processor/-/css-processor-1.11.0.tgz",
|
||||
"integrity": "sha512-NnhBEbJX5M2gBGltPKOetiLlKhNf3OHdRafc8//e2ZQxXN8JaSW/Hy8cm94pnIckQxwaMKxrtaNT3x4ZcffoNQ==",
|
||||
"dependencies": {
|
||||
"css-to-react-native": "^3.0.0",
|
||||
"csstype": "^3.0.8"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@native-html/transient-render-engine": {
|
||||
"version": "11.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@native-html/transient-render-engine/-/transient-render-engine-11.2.3.tgz",
|
||||
"integrity": "sha512-zXwgA3gPUEmFs3I3syfnvDvS6WiUHXEE6jY09OBzK+trq7wkweOSFWIoyXiGkbXrozGYG0KY90YgPyr8Tg8Uyg==",
|
||||
"dependencies": {
|
||||
"@native-html/css-processor": "1.11.0",
|
||||
"@types/ramda": "^0.27.44",
|
||||
"csstype": "^3.0.9",
|
||||
"domelementtype": "^2.2.0",
|
||||
"domhandler": "^4.2.2",
|
||||
"domutils": "^2.8.0",
|
||||
"htmlparser2": "^7.1.2",
|
||||
"ramda": "^0.27.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react-native": "*",
|
||||
"react-native": "^*"
|
||||
}
|
||||
},
|
||||
"node_modules/@native-html/transient-render-engine/node_modules/dom-serializer": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz",
|
||||
"integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==",
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.0.1",
|
||||
"domhandler": "^4.2.0",
|
||||
"entities": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/@native-html/transient-render-engine/node_modules/domelementtype": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz",
|
||||
"integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/fb55"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/@native-html/transient-render-engine/node_modules/domhandler": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz",
|
||||
"integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==",
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/@native-html/transient-render-engine/node_modules/domutils": {
|
||||
"version": "2.8.0",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
|
||||
"integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
|
||||
"dependencies": {
|
||||
"dom-serializer": "^1.0.1",
|
||||
"domelementtype": "^2.2.0",
|
||||
"domhandler": "^4.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/domutils?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/@native-html/transient-render-engine/node_modules/entities": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
|
||||
"integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/@native-html/transient-render-engine/node_modules/htmlparser2": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz",
|
||||
"integrity": "sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==",
|
||||
"funding": [
|
||||
"https://github.com/fb55/htmlparser2?sponsor=1",
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/fb55"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.0.1",
|
||||
"domhandler": "^4.2.2",
|
||||
"domutils": "^2.8.0",
|
||||
"entities": "^3.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@native-html/transient-render-engine/node_modules/htmlparser2/node_modules/entities": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
|
||||
"integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==",
|
||||
"engines": {
|
||||
"node": ">=0.12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
@@ -3905,9 +3767,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@sideway/formula": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz",
|
||||
"integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg=="
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz",
|
||||
"integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg=="
|
||||
},
|
||||
"node_modules/@sideway/pinpoint": {
|
||||
"version": "2.0.0",
|
||||
@@ -4041,11 +3903,20 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/lodash": {
|
||||
"version": "4.14.179",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.179.tgz",
|
||||
"integrity": "sha512-uwc1x90yCKqGcIOAT6DwOSuxnrAbpkdPsUOZtwrXb4D/6wZs+6qG7QnIawDuZWg0sWpxl+ltIKCaLoMlna678w==",
|
||||
"version": "4.14.191",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz",
|
||||
"integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/lodash-es": {
|
||||
"version": "4.17.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.6.tgz",
|
||||
"integrity": "sha512-R+zTeVUKDdfoRxpAryaQNRKk3105Rrgx2CFRClIgRGaqDTdjsm8h6IYA8ir584W3ePzkZfst5xIgDwYrlh9HLg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/lodash": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "15.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-15.0.1.tgz",
|
||||
@@ -4056,14 +3927,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz",
|
||||
"integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ=="
|
||||
},
|
||||
"node_modules/@types/ramda": {
|
||||
"version": "0.27.66",
|
||||
"resolved": "https://registry.npmjs.org/@types/ramda/-/ramda-0.27.66.tgz",
|
||||
"integrity": "sha512-i2YW+E2U6NfMt3dp0RxNcejox+bxJUNDjB7BpYuRuoHIzv5juPHkJkNgcUOu+YSQEmaWu8cnAo/8r63C0NnuVA==",
|
||||
"dependencies": {
|
||||
"ts-toolbelt": "^6.15.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "17.0.39",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.39.tgz",
|
||||
@@ -4127,11 +3990,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
|
||||
"integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew=="
|
||||
},
|
||||
"node_modules/@types/urijs": {
|
||||
"version": "1.19.19",
|
||||
"resolved": "https://registry.npmjs.org/@types/urijs/-/urijs-1.19.19.tgz",
|
||||
"integrity": "sha512-FDJNkyhmKLw7uEvTxx5tSXfPeQpO0iy73Ry+PmYZJvQy0QIWX8a7kJ4kLWRf+EbTPJEPDSgPXHaM7pzr5lmvCg=="
|
||||
},
|
||||
"node_modules/@types/yargs": {
|
||||
"version": "15.0.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.13.tgz",
|
||||
@@ -4652,9 +4510,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@xmldom/xmldom": {
|
||||
"version": "0.7.5",
|
||||
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.5.tgz",
|
||||
"integrity": "sha512-V3BIhmY36fXZ1OtVcI9W+FxQqxVLsPKcNjWigIaa81dLC9IolJl5Mt4Cvhmr0flUnjSpTdrbMTSbXqYqV5dT6A==",
|
||||
"version": "0.7.9",
|
||||
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.9.tgz",
|
||||
"integrity": "sha512-yceMpm/xd4W2a85iqZyO09gTnHvXF6pyiWjD2jcOJs7hRoZtNNOO1eJlhHj1ixA+xip2hOyGn+LgcvLCMo5zXA==",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
@@ -5466,29 +5324,6 @@
|
||||
"node-int64": "^0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
|
||||
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer-alloc": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz",
|
||||
@@ -5604,13 +5439,19 @@
|
||||
"integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs="
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001281",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001281.tgz",
|
||||
"integrity": "sha512-1ktfDV2+4LYxOGeAZygMyvhiPBJKV1gsqPmfGGwRbwYOzDWbsQHgBFo+2lpRTMO2gWjPWJrCMLWa2fnSVnxn0A==",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/browserslist"
|
||||
}
|
||||
"version": "1.0.30001452",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001452.tgz",
|
||||
"integrity": "sha512-Lkp0vFjMkBB3GTpLR8zk4NwW5EdRdnitwYJHDOOKIU85x4ckYCPQ+9WlVvSVClHxVReefkUMtWZH2l9KGlD51w==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/browserslist"
|
||||
},
|
||||
{
|
||||
"type": "tidelift",
|
||||
"url": "https://tidelift.com/funding/github/npm/caniuse-lite"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/capture-exit": {
|
||||
"version": "2.0.0",
|
||||
@@ -5623,24 +5464,6 @@
|
||||
"node": "6.* || 8.* || >= 10.*"
|
||||
}
|
||||
},
|
||||
"node_modules/character-entities-html4": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-1.1.4.tgz",
|
||||
"integrity": "sha512-HRcDxZuZqMx3/a+qrzxdBKBPUpxWEq9xw2OPZ3a/174ihfrQKVsFhqtthBInFy1zZ9GgZyFXOatNujm8M+El3g==",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/character-entities-legacy": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz",
|
||||
"integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/cheerio": {
|
||||
"version": "1.0.0-rc.10",
|
||||
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz",
|
||||
@@ -6376,9 +6199,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/decode-uri-component": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
|
||||
"integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz",
|
||||
"integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==",
|
||||
"engines": {
|
||||
"node": ">=0.10"
|
||||
}
|
||||
@@ -10376,6 +10199,11 @@
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
},
|
||||
"node_modules/lodash-es": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
|
||||
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
|
||||
},
|
||||
"node_modules/lodash._reinterpolate": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
|
||||
@@ -10636,11 +10464,6 @@
|
||||
"loose-envify": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/lottie-ios": {
|
||||
"version": "3.2.3",
|
||||
"resolved": "https://registry.npmjs.org/lottie-ios/-/lottie-ios-3.2.3.tgz",
|
||||
"integrity": "sha512-mubYMN6+1HXa8z3EJKBvNBkl4UoVM4McjESeB2PgvRMSngmJtC5yUMRdhbbrIAn5Liu3hFGao/14s5hQIgtkRQ=="
|
||||
},
|
||||
"node_modules/lottie-react-native": {
|
||||
"version": "5.1.4",
|
||||
"resolved": "https://registry.npmjs.org/lottie-react-native/-/lottie-react-native-5.1.4.tgz",
|
||||
@@ -11427,9 +11250,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
@@ -12697,11 +12520,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/ramda": {
|
||||
"version": "0.27.2",
|
||||
"resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.2.tgz",
|
||||
"integrity": "sha512-SbiLPU40JuJniHexQSAgad32hfwd+DRUdwF2PlVuI5RZD0/vahUco7R8vD86J/tcEKKF9vZrUVwgtmGCqlCKyA=="
|
||||
},
|
||||
"node_modules/range-parser": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
||||
@@ -12911,6 +12729,11 @@
|
||||
"react-native": ">=0.57.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-lottie-splash-screen/node_modules/lottie-ios": {
|
||||
"version": "3.2.3",
|
||||
"resolved": "https://registry.npmjs.org/lottie-ios/-/lottie-ios-3.2.3.tgz",
|
||||
"integrity": "sha512-mubYMN6+1HXa8z3EJKBvNBkl4UoVM4McjESeB2PgvRMSngmJtC5yUMRdhbbrIAn5Liu3hFGao/14s5hQIgtkRQ=="
|
||||
},
|
||||
"node_modules/react-native-markdown-display": {
|
||||
"version": "7.0.0-alpha.2",
|
||||
"resolved": "https://registry.npmjs.org/react-native-markdown-display/-/react-native-markdown-display-7.0.0-alpha.2.tgz",
|
||||
@@ -12945,9 +12768,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-paper": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/react-native-paper/-/react-native-paper-5.1.2.tgz",
|
||||
"integrity": "sha512-muf70CPtji6gTukV+9ecvzOYFOflK2hi4t4GLt9y4Ynhf/YQCvXsefPTp45n7RS6bz9+ueG4jtuGg64oOY8dxA==",
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-paper/-/react-native-paper-5.2.0.tgz",
|
||||
"integrity": "sha512-FfKvfh4nBvetTusiuc1QMuNxXdNai4lthoyD+dNPM03RnIapcjoKHrhCD1EvVi5c1kBSKHrlXQ3OAW/8QCQXNw==",
|
||||
"dependencies": {
|
||||
"@callstack/react-theme-provider": "^3.0.8",
|
||||
"color": "^3.1.2",
|
||||
@@ -13004,26 +12827,6 @@
|
||||
"@babel/core": "^7.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-render-html": {
|
||||
"version": "6.3.4",
|
||||
"resolved": "https://registry.npmjs.org/react-native-render-html/-/react-native-render-html-6.3.4.tgz",
|
||||
"integrity": "sha512-H2jSMzZjidE+Wo3qCWPUMU1nm98Vs2SGCvQCz/i6xf0P3Y9uVtG/b0sDbG/cYFir2mSYBYCIlS1Dv0WC1LjYig==",
|
||||
"dependencies": {
|
||||
"@jsamr/counter-style": "^2.0.1",
|
||||
"@jsamr/react-native-li": "^2.3.0",
|
||||
"@native-html/transient-render-engine": "11.2.3",
|
||||
"@types/ramda": "^0.27.40",
|
||||
"@types/urijs": "^1.19.15",
|
||||
"prop-types": "^15.5.7",
|
||||
"ramda": "^0.27.2",
|
||||
"stringify-entities": "^3.1.0",
|
||||
"urijs": "^1.19.6"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*",
|
||||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-safe-area-context": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-3.2.0.tgz",
|
||||
@@ -13077,11 +12880,6 @@
|
||||
"react-native-linear-gradient": ">=2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-swipe-gestures": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/react-native-swipe-gestures/-/react-native-swipe-gestures-1.0.5.tgz",
|
||||
"integrity": "sha512-Ns7Bn9H/Tyw278+5SQx9oAblDZ7JixyzeOczcBK8dipQk2pD7Djkcfnf1nB/8RErAmMLL9iXgW0QHqiII8AhKw=="
|
||||
},
|
||||
"node_modules/react-native-tab-view": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-tab-view/-/react-native-tab-view-3.1.1.tgz",
|
||||
@@ -14920,20 +14718,6 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/stringify-entities": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-3.1.0.tgz",
|
||||
"integrity": "sha512-3FP+jGMmMV/ffZs86MoghGqAoqXAdxLrJP4GUdrDN1aIScYih5tuIO3eF4To5AJZ79KDZ8Fpdy7QJnK8SsL1Vg==",
|
||||
"dependencies": {
|
||||
"character-entities-html4": "^1.0.0",
|
||||
"character-entities-legacy": "^1.0.0",
|
||||
"xtend": "^4.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-ansi": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
|
||||
@@ -15331,11 +15115,6 @@
|
||||
"resolved": "https://registry.npmjs.org/ts-object-utils/-/ts-object-utils-0.0.5.tgz",
|
||||
"integrity": "sha512-iV0GvHqOmilbIKJsfyfJY9/dNHCs969z3so90dQWsO1eMMozvTpnB1MEaUbb3FYtZTGjv5sIy/xmslEz0Rg2TA=="
|
||||
},
|
||||
"node_modules/ts-toolbelt": {
|
||||
"version": "6.15.5",
|
||||
"resolved": "https://registry.npmjs.org/ts-toolbelt/-/ts-toolbelt-6.15.5.tgz",
|
||||
"integrity": "sha512-FZIXf1ksVyLcfr7M317jbB67XFJhOO1YqdTcuGaq9q5jLUoTikukZ+98TPjKiP2jC5CgmYdWWYs0s2nLSU0/1A=="
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
|
||||
@@ -15396,9 +15175,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/ua-parser-js": {
|
||||
"version": "0.7.31",
|
||||
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.31.tgz",
|
||||
"integrity": "sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ==",
|
||||
"version": "0.7.33",
|
||||
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.33.tgz",
|
||||
"integrity": "sha512-s8ax/CeZdK9R/56Sui0WM6y9OFREJarMRHqLB2EwkovemBxNQ+Bqu8GAsUnVcXKgphb++ghr/B2BZx4mahujPw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
@@ -15656,11 +15435,6 @@
|
||||
"punycode": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/urijs": {
|
||||
"version": "1.19.11",
|
||||
"resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.11.tgz",
|
||||
"integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ=="
|
||||
},
|
||||
"node_modules/urix": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
|
||||
@@ -18413,98 +18187,6 @@
|
||||
"@jridgewell/sourcemap-codec": "1.4.14"
|
||||
}
|
||||
},
|
||||
"@jsamr/counter-style": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@jsamr/counter-style/-/counter-style-2.0.2.tgz",
|
||||
"integrity": "sha512-2mXudGVtSzVxWEA7B9jZLKjoXUeUFYDDtFrQoC0IFX9/Dszz4t1vZOmafi3JSw/FxD+udMQ+4TAFR8Qs0J3URQ=="
|
||||
},
|
||||
"@jsamr/react-native-li": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@jsamr/react-native-li/-/react-native-li-2.3.1.tgz",
|
||||
"integrity": "sha512-Qbo4NEj48SQ4k8FZJHFE2fgZDKTWaUGmVxcIQh3msg5JezLdTMMHuRRDYctfdHI6L0FZGObmEv3haWbIvmol8w=="
|
||||
},
|
||||
"@native-html/css-processor": {
|
||||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@native-html/css-processor/-/css-processor-1.11.0.tgz",
|
||||
"integrity": "sha512-NnhBEbJX5M2gBGltPKOetiLlKhNf3OHdRafc8//e2ZQxXN8JaSW/Hy8cm94pnIckQxwaMKxrtaNT3x4ZcffoNQ==",
|
||||
"requires": {
|
||||
"css-to-react-native": "^3.0.0",
|
||||
"csstype": "^3.0.8"
|
||||
}
|
||||
},
|
||||
"@native-html/transient-render-engine": {
|
||||
"version": "11.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@native-html/transient-render-engine/-/transient-render-engine-11.2.3.tgz",
|
||||
"integrity": "sha512-zXwgA3gPUEmFs3I3syfnvDvS6WiUHXEE6jY09OBzK+trq7wkweOSFWIoyXiGkbXrozGYG0KY90YgPyr8Tg8Uyg==",
|
||||
"requires": {
|
||||
"@native-html/css-processor": "1.11.0",
|
||||
"@types/ramda": "^0.27.44",
|
||||
"csstype": "^3.0.9",
|
||||
"domelementtype": "^2.2.0",
|
||||
"domhandler": "^4.2.2",
|
||||
"domutils": "^2.8.0",
|
||||
"htmlparser2": "^7.1.2",
|
||||
"ramda": "^0.27.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"dom-serializer": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz",
|
||||
"integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==",
|
||||
"requires": {
|
||||
"domelementtype": "^2.0.1",
|
||||
"domhandler": "^4.2.0",
|
||||
"entities": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"domelementtype": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz",
|
||||
"integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A=="
|
||||
},
|
||||
"domhandler": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz",
|
||||
"integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==",
|
||||
"requires": {
|
||||
"domelementtype": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"domutils": {
|
||||
"version": "2.8.0",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
|
||||
"integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
|
||||
"requires": {
|
||||
"dom-serializer": "^1.0.1",
|
||||
"domelementtype": "^2.2.0",
|
||||
"domhandler": "^4.2.0"
|
||||
}
|
||||
},
|
||||
"entities": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
|
||||
"integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A=="
|
||||
},
|
||||
"htmlparser2": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz",
|
||||
"integrity": "sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==",
|
||||
"requires": {
|
||||
"domelementtype": "^2.0.1",
|
||||
"domhandler": "^4.2.2",
|
||||
"domutils": "^2.8.0",
|
||||
"entities": "^3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"entities": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
|
||||
"integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q=="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
@@ -19082,9 +18764,9 @@
|
||||
}
|
||||
},
|
||||
"@sideway/formula": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz",
|
||||
"integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg=="
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz",
|
||||
"integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg=="
|
||||
},
|
||||
"@sideway/pinpoint": {
|
||||
"version": "2.0.0",
|
||||
@@ -19211,11 +18893,20 @@
|
||||
"dev": true
|
||||
},
|
||||
"@types/lodash": {
|
||||
"version": "4.14.179",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.179.tgz",
|
||||
"integrity": "sha512-uwc1x90yCKqGcIOAT6DwOSuxnrAbpkdPsUOZtwrXb4D/6wZs+6qG7QnIawDuZWg0sWpxl+ltIKCaLoMlna678w==",
|
||||
"version": "4.14.191",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz",
|
||||
"integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/lodash-es": {
|
||||
"version": "4.17.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.6.tgz",
|
||||
"integrity": "sha512-R+zTeVUKDdfoRxpAryaQNRKk3105Rrgx2CFRClIgRGaqDTdjsm8h6IYA8ir584W3ePzkZfst5xIgDwYrlh9HLg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/lodash": "*"
|
||||
}
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "15.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-15.0.1.tgz",
|
||||
@@ -19226,14 +18917,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz",
|
||||
"integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ=="
|
||||
},
|
||||
"@types/ramda": {
|
||||
"version": "0.27.66",
|
||||
"resolved": "https://registry.npmjs.org/@types/ramda/-/ramda-0.27.66.tgz",
|
||||
"integrity": "sha512-i2YW+E2U6NfMt3dp0RxNcejox+bxJUNDjB7BpYuRuoHIzv5juPHkJkNgcUOu+YSQEmaWu8cnAo/8r63C0NnuVA==",
|
||||
"requires": {
|
||||
"ts-toolbelt": "^6.15.1"
|
||||
}
|
||||
},
|
||||
"@types/react": {
|
||||
"version": "17.0.39",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.39.tgz",
|
||||
@@ -19297,11 +18980,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
|
||||
"integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew=="
|
||||
},
|
||||
"@types/urijs": {
|
||||
"version": "1.19.19",
|
||||
"resolved": "https://registry.npmjs.org/@types/urijs/-/urijs-1.19.19.tgz",
|
||||
"integrity": "sha512-FDJNkyhmKLw7uEvTxx5tSXfPeQpO0iy73Ry+PmYZJvQy0QIWX8a7kJ4kLWRf+EbTPJEPDSgPXHaM7pzr5lmvCg=="
|
||||
},
|
||||
"@types/yargs": {
|
||||
"version": "15.0.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.13.tgz",
|
||||
@@ -19611,9 +19289,9 @@
|
||||
}
|
||||
},
|
||||
"@xmldom/xmldom": {
|
||||
"version": "0.7.5",
|
||||
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.5.tgz",
|
||||
"integrity": "sha512-V3BIhmY36fXZ1OtVcI9W+FxQqxVLsPKcNjWigIaa81dLC9IolJl5Mt4Cvhmr0flUnjSpTdrbMTSbXqYqV5dT6A=="
|
||||
"version": "0.7.9",
|
||||
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.9.tgz",
|
||||
"integrity": "sha512-yceMpm/xd4W2a85iqZyO09gTnHvXF6pyiWjD2jcOJs7hRoZtNNOO1eJlhHj1ixA+xip2hOyGn+LgcvLCMo5zXA=="
|
||||
},
|
||||
"abort-controller": {
|
||||
"version": "3.0.0",
|
||||
@@ -20235,15 +19913,6 @@
|
||||
"node-int64": "^0.4.0"
|
||||
}
|
||||
},
|
||||
"buffer": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
|
||||
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
|
||||
"requires": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"buffer-alloc": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz",
|
||||
@@ -20335,9 +20004,9 @@
|
||||
"integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs="
|
||||
},
|
||||
"caniuse-lite": {
|
||||
"version": "1.0.30001281",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001281.tgz",
|
||||
"integrity": "sha512-1ktfDV2+4LYxOGeAZygMyvhiPBJKV1gsqPmfGGwRbwYOzDWbsQHgBFo+2lpRTMO2gWjPWJrCMLWa2fnSVnxn0A=="
|
||||
"version": "1.0.30001452",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001452.tgz",
|
||||
"integrity": "sha512-Lkp0vFjMkBB3GTpLR8zk4NwW5EdRdnitwYJHDOOKIU85x4ckYCPQ+9WlVvSVClHxVReefkUMtWZH2l9KGlD51w=="
|
||||
},
|
||||
"capture-exit": {
|
||||
"version": "2.0.0",
|
||||
@@ -20347,16 +20016,6 @@
|
||||
"rsvp": "^4.8.4"
|
||||
}
|
||||
},
|
||||
"character-entities-html4": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-1.1.4.tgz",
|
||||
"integrity": "sha512-HRcDxZuZqMx3/a+qrzxdBKBPUpxWEq9xw2OPZ3a/174ihfrQKVsFhqtthBInFy1zZ9GgZyFXOatNujm8M+El3g=="
|
||||
},
|
||||
"character-entities-legacy": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz",
|
||||
"integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA=="
|
||||
},
|
||||
"cheerio": {
|
||||
"version": "1.0.0-rc.10",
|
||||
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz",
|
||||
@@ -20914,9 +20573,9 @@
|
||||
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
|
||||
},
|
||||
"decode-uri-component": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
|
||||
"integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU="
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz",
|
||||
"integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ=="
|
||||
},
|
||||
"dedent": {
|
||||
"version": "0.6.0",
|
||||
@@ -23932,6 +23591,11 @@
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
},
|
||||
"lodash-es": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
|
||||
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
|
||||
},
|
||||
"lodash._reinterpolate": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
|
||||
@@ -24139,11 +23803,6 @@
|
||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||
}
|
||||
},
|
||||
"lottie-ios": {
|
||||
"version": "3.2.3",
|
||||
"resolved": "https://registry.npmjs.org/lottie-ios/-/lottie-ios-3.2.3.tgz",
|
||||
"integrity": "sha512-mubYMN6+1HXa8z3EJKBvNBkl4UoVM4McjESeB2PgvRMSngmJtC5yUMRdhbbrIAn5Liu3hFGao/14s5hQIgtkRQ=="
|
||||
},
|
||||
"lottie-react-native": {
|
||||
"version": "5.1.4",
|
||||
"resolved": "https://registry.npmjs.org/lottie-react-native/-/lottie-react-native-5.1.4.tgz",
|
||||
@@ -24820,9 +24479,9 @@
|
||||
}
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
@@ -25750,11 +25409,6 @@
|
||||
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
|
||||
"dev": true
|
||||
},
|
||||
"ramda": {
|
||||
"version": "0.27.2",
|
||||
"resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.2.tgz",
|
||||
"integrity": "sha512-SbiLPU40JuJniHexQSAgad32hfwd+DRUdwF2PlVuI5RZD0/vahUco7R8vD86J/tcEKKF9vZrUVwgtmGCqlCKyA=="
|
||||
},
|
||||
"range-parser": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
||||
@@ -26185,6 +25839,13 @@
|
||||
"requires": {
|
||||
"lottie-ios": "3.2.3",
|
||||
"lottie-react-native": "^5.1.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"lottie-ios": {
|
||||
"version": "3.2.3",
|
||||
"resolved": "https://registry.npmjs.org/lottie-ios/-/lottie-ios-3.2.3.tgz",
|
||||
"integrity": "sha512-mubYMN6+1HXa8z3EJKBvNBkl4UoVM4McjESeB2PgvRMSngmJtC5yUMRdhbbrIAn5Liu3hFGao/14s5hQIgtkRQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"react-native-markdown-display": {
|
||||
@@ -26209,9 +25870,9 @@
|
||||
"integrity": "sha512-D6tzxpwMGdl6CXgtskGWhKRc5cJakCazESRGt7PkqnpyiH3N35ft1KmR82pCSQetAFlytFiToeu3a/dG5CELvA=="
|
||||
},
|
||||
"react-native-paper": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/react-native-paper/-/react-native-paper-5.1.2.tgz",
|
||||
"integrity": "sha512-muf70CPtji6gTukV+9ecvzOYFOflK2hi4t4GLt9y4Ynhf/YQCvXsefPTp45n7RS6bz9+ueG4jtuGg64oOY8dxA==",
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-paper/-/react-native-paper-5.2.0.tgz",
|
||||
"integrity": "sha512-FfKvfh4nBvetTusiuc1QMuNxXdNai4lthoyD+dNPM03RnIapcjoKHrhCD1EvVi5c1kBSKHrlXQ3OAW/8QCQXNw==",
|
||||
"requires": {
|
||||
"@callstack/react-theme-provider": "^3.0.8",
|
||||
"color": "^3.1.2",
|
||||
@@ -26255,22 +25916,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"react-native-render-html": {
|
||||
"version": "6.3.4",
|
||||
"resolved": "https://registry.npmjs.org/react-native-render-html/-/react-native-render-html-6.3.4.tgz",
|
||||
"integrity": "sha512-H2jSMzZjidE+Wo3qCWPUMU1nm98Vs2SGCvQCz/i6xf0P3Y9uVtG/b0sDbG/cYFir2mSYBYCIlS1Dv0WC1LjYig==",
|
||||
"requires": {
|
||||
"@jsamr/counter-style": "^2.0.1",
|
||||
"@jsamr/react-native-li": "^2.3.0",
|
||||
"@native-html/transient-render-engine": "11.2.3",
|
||||
"@types/ramda": "^0.27.40",
|
||||
"@types/urijs": "^1.19.15",
|
||||
"prop-types": "^15.5.7",
|
||||
"ramda": "^0.27.2",
|
||||
"stringify-entities": "^3.1.0",
|
||||
"urijs": "^1.19.6"
|
||||
}
|
||||
},
|
||||
"react-native-safe-area-context": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-3.2.0.tgz",
|
||||
@@ -26305,11 +25950,6 @@
|
||||
"resolved": "https://registry.npmjs.org/react-native-shimmer-placeholder/-/react-native-shimmer-placeholder-2.0.9.tgz",
|
||||
"integrity": "sha512-s2pfAAO6uaybREYM2KcaxP3c2XlZvLfHfzmhMlGEoOhSKaoM92KpA1Hx0BeC75yilkliJuowqO/hFzvLB0h7hg=="
|
||||
},
|
||||
"react-native-swipe-gestures": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/react-native-swipe-gestures/-/react-native-swipe-gestures-1.0.5.tgz",
|
||||
"integrity": "sha512-Ns7Bn9H/Tyw278+5SQx9oAblDZ7JixyzeOczcBK8dipQk2pD7Djkcfnf1nB/8RErAmMLL9iXgW0QHqiII8AhKw=="
|
||||
},
|
||||
"react-native-tab-view": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-tab-view/-/react-native-tab-view-3.1.1.tgz",
|
||||
@@ -27507,16 +27147,6 @@
|
||||
"define-properties": "^1.1.3"
|
||||
}
|
||||
},
|
||||
"stringify-entities": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-3.1.0.tgz",
|
||||
"integrity": "sha512-3FP+jGMmMV/ffZs86MoghGqAoqXAdxLrJP4GUdrDN1aIScYih5tuIO3eF4To5AJZ79KDZ8Fpdy7QJnK8SsL1Vg==",
|
||||
"requires": {
|
||||
"character-entities-html4": "^1.0.0",
|
||||
"character-entities-legacy": "^1.0.0",
|
||||
"xtend": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
|
||||
@@ -27826,11 +27456,6 @@
|
||||
"resolved": "https://registry.npmjs.org/ts-object-utils/-/ts-object-utils-0.0.5.tgz",
|
||||
"integrity": "sha512-iV0GvHqOmilbIKJsfyfJY9/dNHCs969z3so90dQWsO1eMMozvTpnB1MEaUbb3FYtZTGjv5sIy/xmslEz0Rg2TA=="
|
||||
},
|
||||
"ts-toolbelt": {
|
||||
"version": "6.15.5",
|
||||
"resolved": "https://registry.npmjs.org/ts-toolbelt/-/ts-toolbelt-6.15.5.tgz",
|
||||
"integrity": "sha512-FZIXf1ksVyLcfr7M317jbB67XFJhOO1YqdTcuGaq9q5jLUoTikukZ+98TPjKiP2jC5CgmYdWWYs0s2nLSU0/1A=="
|
||||
},
|
||||
"tslib": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
|
||||
@@ -27874,9 +27499,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"ua-parser-js": {
|
||||
"version": "0.7.31",
|
||||
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.31.tgz",
|
||||
"integrity": "sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ=="
|
||||
"version": "0.7.33",
|
||||
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.33.tgz",
|
||||
"integrity": "sha512-s8ax/CeZdK9R/56Sui0WM6y9OFREJarMRHqLB2EwkovemBxNQ+Bqu8GAsUnVcXKgphb++ghr/B2BZx4mahujPw=="
|
||||
},
|
||||
"uc.micro": {
|
||||
"version": "1.0.6",
|
||||
@@ -28078,11 +27703,6 @@
|
||||
"punycode": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"urijs": {
|
||||
"version": "1.19.11",
|
||||
"resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.11.tgz",
|
||||
"integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ=="
|
||||
},
|
||||
"urix": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
|
||||
|
||||
+3
-6
@@ -29,7 +29,6 @@
|
||||
"@react-navigation/stack": "^6.0.11",
|
||||
"@reduxjs/toolkit": "^1.7.2",
|
||||
"@shopify/flash-list": "^1.2.1",
|
||||
"buffer": "^6.0.3",
|
||||
"cheerio": "^1.0.0-rc.10",
|
||||
"color": "^4.2.3",
|
||||
"dayjs": "^1.11.4",
|
||||
@@ -45,7 +44,7 @@
|
||||
"expo-sqlite": "~9.1.0",
|
||||
"expo-web-browser": "~9.1.0",
|
||||
"i18n-js": "^3.8.0",
|
||||
"lodash": "^4.17.21",
|
||||
"lodash-es": "^4.17.21",
|
||||
"lottie-react-native": "^5.1.4",
|
||||
"prop-types": "^15.7.2",
|
||||
"qs": "^6.10.3",
|
||||
@@ -62,13 +61,11 @@
|
||||
"react-native-markdown-display": "^7.0.0-alpha.2",
|
||||
"react-native-mmkv": "^2.4.3",
|
||||
"react-native-pager-view": "^5.4.9",
|
||||
"react-native-paper": "^5.1.2",
|
||||
"react-native-paper": "^5.2.0",
|
||||
"react-native-reanimated": "^2.13.0",
|
||||
"react-native-render-html": "^6.3.4",
|
||||
"react-native-safe-area-context": "^3.2.0",
|
||||
"react-native-screens": "^3.9.0",
|
||||
"react-native-shimmer-placeholder": "^2.0.9",
|
||||
"react-native-swipe-gestures": "^1.0.5",
|
||||
"react-native-tab-view": "^3.1.1",
|
||||
"react-native-tts": "^4.1.0",
|
||||
"react-native-unimodules": "^0.13.3",
|
||||
@@ -86,7 +83,7 @@
|
||||
"@types/color": "^3.0.3",
|
||||
"@types/i18n-js": "^3.8.2",
|
||||
"@types/jest": "^27.4.0",
|
||||
"@types/lodash": "^4.14.179",
|
||||
"@types/lodash-es": "^4.17.6",
|
||||
"@types/react-native": "^0.66.15",
|
||||
"@types/react-native-vector-icons": "^6.4.10",
|
||||
"@types/react-test-renderer": "^17.0.1",
|
||||
|
||||
@@ -18,6 +18,7 @@ const getLanguageCode = language => {
|
||||
Chinese: 'cn',
|
||||
Japanese: 'jp',
|
||||
Vietnamese: 'vi',
|
||||
Korean: 'kr',
|
||||
};
|
||||
|
||||
return codes[language];
|
||||
@@ -58,7 +59,6 @@ try {
|
||||
: ''
|
||||
}
|
||||
const popularNovels = async (page: number) => {
|
||||
const totalPages = ${source.popularNovels.totalPages};
|
||||
const url = \`${source.popularNovels.url}\`;
|
||||
|
||||
const result = await fetch(url);
|
||||
@@ -102,8 +102,7 @@ try {
|
||||
}
|
||||
});
|
||||
|
||||
return { totalPages, novels };
|
||||
};
|
||||
return { novels };
|
||||
|
||||
const parseNovelAndChapters = async (novelUrl: string) => {
|
||||
const url = novelUrl;
|
||||
|
||||
@@ -8,11 +8,8 @@ import {
|
||||
View,
|
||||
ViewProps,
|
||||
} from 'react-native';
|
||||
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||
import color from 'color';
|
||||
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import { overlay } from 'react-native-paper';
|
||||
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||
|
||||
type Action = {
|
||||
icon: string;
|
||||
@@ -40,9 +37,7 @@ export const Actionbar: React.FC<ActionbarProps> = ({
|
||||
style={[
|
||||
styles.actionbarContainer,
|
||||
{
|
||||
backgroundColor: theme.isDark
|
||||
? overlay(2, theme.surface)
|
||||
: theme.secondaryContainer,
|
||||
backgroundColor: theme.surface2,
|
||||
minHeight: 80 + bottom,
|
||||
paddingBottom: bottom,
|
||||
},
|
||||
@@ -54,7 +49,7 @@ export const Actionbar: React.FC<ActionbarProps> = ({
|
||||
key={id}
|
||||
android_ripple={{
|
||||
radius: 50,
|
||||
color: color(theme.primary).alpha(0.12).string(),
|
||||
color: theme.rippleColor,
|
||||
borderless: true,
|
||||
}}
|
||||
onPress={onPress}
|
||||
|
||||
@@ -4,7 +4,6 @@ import ErrorBoundary from 'react-native-error-boundary';
|
||||
|
||||
import { Button, List } from '@components';
|
||||
import { useTheme } from '@hooks';
|
||||
import { ButtonVariation } from '@components/Button/Button';
|
||||
|
||||
interface ErrorFallbackProps {
|
||||
error: Error;
|
||||
@@ -44,11 +43,10 @@ export const ErrorFallback: React.FC<ErrorFallbackProps> = ({
|
||||
</View>
|
||||
<List.Divider theme={theme} />
|
||||
<Button
|
||||
variation={ButtonVariation.DEFAULT}
|
||||
onPress={resetError}
|
||||
title={'Restart the application'}
|
||||
style={styles.buttonCtn}
|
||||
theme={theme}
|
||||
mode="contained"
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
|
||||
@@ -2,12 +2,12 @@ import React from 'react';
|
||||
import { StatusBar } from 'react-native';
|
||||
|
||||
import { Appbar as PaperAppbar } from 'react-native-paper';
|
||||
import { MD3ThemeType } from '../../theme/types';
|
||||
import { ThemeColors } from '../../theme/types';
|
||||
|
||||
interface AppbarProps {
|
||||
title: string;
|
||||
handleGoBack: () => void;
|
||||
theme: MD3ThemeType;
|
||||
theme: ThemeColors;
|
||||
mode?: 'small' | 'medium' | 'large' | 'center-aligned';
|
||||
}
|
||||
|
||||
@@ -26,12 +26,12 @@ const Appbar: React.FC<AppbarProps> = ({
|
||||
{handleGoBack && (
|
||||
<PaperAppbar.BackAction
|
||||
onPress={handleGoBack}
|
||||
iconColor={theme.textColorPrimary}
|
||||
iconColor={theme.onSurface}
|
||||
/>
|
||||
)}
|
||||
<PaperAppbar.Content
|
||||
title={title}
|
||||
titleStyle={{ color: theme.textColorPrimary }}
|
||||
titleStyle={{ color: theme.onSurface }}
|
||||
/>
|
||||
{children}
|
||||
</PaperAppbar.Header>
|
||||
|
||||
@@ -2,14 +2,14 @@ import React, { ReactElement, Ref, useCallback } from 'react';
|
||||
import { overlay } from 'react-native-paper';
|
||||
import { default as BS, BottomSheetBackdrop } from '@gorhom/bottom-sheet';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import { MD3ThemeType } from '@theme/types';
|
||||
import { ThemeColors } from '@theme/types';
|
||||
import { StyleSheet } from 'react-native';
|
||||
|
||||
interface BottomSheetProps {
|
||||
bottomSheetRef: Ref<BS>;
|
||||
snapPoints: Array<number>;
|
||||
height: number;
|
||||
theme: MD3ThemeType;
|
||||
theme: ThemeColors;
|
||||
children: ReactElement;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,105 +1,23 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
Pressable,
|
||||
StyleProp,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TextStyle,
|
||||
View,
|
||||
ViewStyle,
|
||||
} from 'react-native';
|
||||
import React, { useMemo } from 'react';
|
||||
import color from 'color';
|
||||
Button as PaperButton,
|
||||
ButtonProps as PaperButtonProps,
|
||||
} from 'react-native-paper';
|
||||
|
||||
import { MD3ThemeType } from '../../theme/types';
|
||||
import { useTheme } from '@hooks';
|
||||
|
||||
export enum ButtonVariation {
|
||||
DEFAULT = 'default',
|
||||
OUTLINED = 'outlined',
|
||||
CLEAR = 'clear',
|
||||
interface ButtonProps extends Omit<PaperButtonProps, 'children' | 'theme'> {
|
||||
title?: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
variation?: ButtonVariation;
|
||||
title: string;
|
||||
textColor?: string;
|
||||
onPress?: () => void;
|
||||
theme: MD3ThemeType;
|
||||
style?: ViewStyle;
|
||||
labelStyle?: StyleProp<TextStyle>;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
const Button: React.FC<Props> = ({
|
||||
variation = ButtonVariation.DEFAULT,
|
||||
title,
|
||||
textColor,
|
||||
onPress,
|
||||
theme,
|
||||
style,
|
||||
disabled,
|
||||
labelStyle,
|
||||
}) => {
|
||||
const textStyles: StyleProp<TextStyle> = useMemo(
|
||||
() => ({
|
||||
color: disabled
|
||||
? theme.textColorHint
|
||||
: textColor
|
||||
? textColor
|
||||
: variation === ButtonVariation.OUTLINED
|
||||
? theme.primary
|
||||
: variation === ButtonVariation.CLEAR
|
||||
? theme.primary
|
||||
: theme.onSecondary,
|
||||
}),
|
||||
[],
|
||||
);
|
||||
const Button: React.FC<ButtonProps> = props => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
styles.button,
|
||||
variation === ButtonVariation.OUTLINED
|
||||
? {
|
||||
...styles.outlined,
|
||||
borderColor: theme.textColorHint,
|
||||
}
|
||||
: variation !== ButtonVariation.CLEAR && {
|
||||
backgroundColor: theme.secondary,
|
||||
},
|
||||
style,
|
||||
]}
|
||||
>
|
||||
<Pressable
|
||||
style={styles.pressable}
|
||||
onPress={onPress}
|
||||
android_ripple={{ color: color(theme.primary).alpha(0.12).string() }}
|
||||
disabled={disabled}
|
||||
>
|
||||
<Text style={[textStyles, labelStyle]} numberOfLines={1}>
|
||||
{title}
|
||||
</Text>
|
||||
</Pressable>
|
||||
</View>
|
||||
<PaperButton {...props} theme={{ colors: theme }}>
|
||||
{props.title || props.children}
|
||||
</PaperButton>
|
||||
);
|
||||
};
|
||||
|
||||
export default Button;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
button: {
|
||||
minHeight: 40,
|
||||
justifyContent: 'center',
|
||||
borderRadius: 50,
|
||||
overflow: 'hidden',
|
||||
},
|
||||
pressable: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
paddingVertical: 8,
|
||||
paddingHorizontal: 24,
|
||||
},
|
||||
outlined: {
|
||||
borderWidth: 1,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -9,16 +9,15 @@ import {
|
||||
} from 'react-native';
|
||||
import { Checkbox as PaperCheckbox } from 'react-native-paper';
|
||||
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||
import color from 'color';
|
||||
|
||||
import { MD3ThemeType } from '../../theme/types';
|
||||
import { ThemeColors } from '../../theme/types';
|
||||
|
||||
interface CheckboxProps {
|
||||
label: string;
|
||||
status: boolean | 'indeterminate';
|
||||
onPress?: () => void;
|
||||
disabled?: boolean;
|
||||
theme: MD3ThemeType;
|
||||
theme: ThemeColors;
|
||||
viewStyle?: StyleProp<ViewStyle>;
|
||||
labelStyle?: StyleProp<TextStyle>;
|
||||
}
|
||||
@@ -33,7 +32,7 @@ export const Checkbox: React.FC<CheckboxProps> = ({
|
||||
labelStyle,
|
||||
}) => (
|
||||
<Pressable
|
||||
android_ripple={{ color: color(theme.primary).alpha(0.12).string() }}
|
||||
android_ripple={{ color: theme.rippleColor }}
|
||||
style={[styles.pressable, viewStyle]}
|
||||
onPress={onPress}
|
||||
disabled={disabled}
|
||||
@@ -49,9 +48,9 @@ export const Checkbox: React.FC<CheckboxProps> = ({
|
||||
onPress={onPress}
|
||||
color={theme.primary}
|
||||
theme={{
|
||||
colors: { disabled: theme.textColorSecondary },
|
||||
colors: { disabled: theme.onSurfaceVariant },
|
||||
}}
|
||||
uncheckedColor={theme.textColorSecondary}
|
||||
uncheckedColor={theme.onSurfaceVariant}
|
||||
disabled={disabled}
|
||||
/>
|
||||
<Text style={[styles.defaultLabel, { color: theme.onSurface }, labelStyle]}>
|
||||
@@ -62,7 +61,7 @@ export const Checkbox: React.FC<CheckboxProps> = ({
|
||||
|
||||
export const SortItem = ({ label, status, onPress, theme }) => (
|
||||
<Pressable
|
||||
android_ripple={{ color: color(theme.primary).alpha(0.12).string() }}
|
||||
android_ripple={{ color: theme.rippleColor }}
|
||||
style={[styles.pressable, { paddingVertical: 16, paddingLeft: 64 }]}
|
||||
onPress={onPress}
|
||||
>
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import React from 'react';
|
||||
import { Pressable, StyleSheet, Text, View } from 'react-native';
|
||||
import color from 'color';
|
||||
|
||||
import { MD3ThemeType } from '../../theme/types';
|
||||
import { ThemeColors } from '../../theme/types';
|
||||
import { overlay } from 'react-native-paper';
|
||||
|
||||
interface ChipProps {
|
||||
label: string;
|
||||
theme: MD3ThemeType;
|
||||
theme: ThemeColors;
|
||||
}
|
||||
|
||||
const Chip: React.FC<ChipProps> = ({ label, theme }) => (
|
||||
@@ -22,7 +21,7 @@ const Chip: React.FC<ChipProps> = ({ label, theme }) => (
|
||||
]}
|
||||
>
|
||||
<Pressable
|
||||
android_ripple={{ color: color(theme.primary).alpha(0.12).string() }}
|
||||
android_ripple={{ color: theme.rippleColor }}
|
||||
style={styles.pressable}
|
||||
>
|
||||
<Text
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { useState } from 'react';
|
||||
import { FlatList, Pressable, StyleSheet, Text, View } from 'react-native';
|
||||
|
||||
import { Modal, overlay, Portal, TextInput } from 'react-native-paper';
|
||||
import { MD3ThemeType } from '../../theme/types';
|
||||
import { ThemeColors } from '../../theme/types';
|
||||
|
||||
interface ColorPickerModalProps {
|
||||
visible: boolean;
|
||||
@@ -10,7 +10,7 @@ interface ColorPickerModalProps {
|
||||
color: string;
|
||||
onSubmit: (val: string) => void;
|
||||
closeModal: () => void;
|
||||
theme: MD3ThemeType;
|
||||
theme: ThemeColors;
|
||||
showAccentColors?: boolean;
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ const ColorPickerModal: React.FC<ColorPickerModalProps> = ({
|
||||
{ backgroundColor: overlay(2, theme.surface) },
|
||||
]}
|
||||
>
|
||||
<Text style={[styles.modalTitle, { color: theme.textColorPrimary }]}>
|
||||
<Text style={[styles.modalTitle, { color: theme.onSurface }]}>
|
||||
{title}
|
||||
</Text>
|
||||
{showAccentColors ? (
|
||||
@@ -123,7 +123,7 @@ const ColorPickerModal: React.FC<ColorPickerModalProps> = ({
|
||||
onSubmitEditing={onSubmitEditing}
|
||||
mode="outlined"
|
||||
theme={{ colors: { ...theme } }}
|
||||
underlineColor={theme.textColorHint}
|
||||
underlineColor={theme.outline}
|
||||
dense
|
||||
error={Boolean(error)}
|
||||
/>
|
||||
|
||||
@@ -22,10 +22,8 @@ const ColorPreferenceItem: React.FC<ColorPreferenceItemProps> = ({
|
||||
onPress={onPress}
|
||||
>
|
||||
<View>
|
||||
<Text style={[styles.label, { color: theme.textColorPrimary }]}>
|
||||
{label}
|
||||
</Text>
|
||||
<Text style={{ color: theme.textColorSecondary }}>
|
||||
<Text style={[styles.label, { color: theme.onSurface }]}>{label}</Text>
|
||||
<Text style={{ color: theme.onSurfaceVariant }}>
|
||||
{description?.toUpperCase?.()}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
/* eslint-disable no-bitwise */
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { PureComponent, Children } from 'react';
|
||||
import { View, Animated, StyleSheet } from 'react-native';
|
||||
|
||||
export default class FadeView extends PureComponent {
|
||||
static defaultProps = {
|
||||
animationDuration: 225,
|
||||
|
||||
active: false,
|
||||
removeHiddenSubviews: true,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
animationDuration: PropTypes.number,
|
||||
|
||||
active: PropTypes.bool,
|
||||
removeHiddenSubviews: PropTypes.bool,
|
||||
|
||||
children: PropTypes.oneOfType([
|
||||
PropTypes.arrayOf(PropTypes.node),
|
||||
PropTypes.node,
|
||||
]),
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.renderChild = this.renderChild.bind(this);
|
||||
this.mounted = false;
|
||||
|
||||
let { active } = this.props;
|
||||
|
||||
this.state = {
|
||||
progress: new Animated.Value(Number(active)),
|
||||
animating: false,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.mounted = true;
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.mounted = false;
|
||||
}
|
||||
|
||||
UNSAFE_componentWillReceiveProps({ active, animationDuration }) {
|
||||
let { progress } = this.state;
|
||||
|
||||
if (active ^ this.props.active) {
|
||||
this.setState({ animating: true });
|
||||
|
||||
Animated.timing(progress, {
|
||||
toValue: Number(active),
|
||||
duration: animationDuration,
|
||||
useNativeDriver: true,
|
||||
}).start(() => {
|
||||
if (this.mounted) {
|
||||
this.setState({ animating: false });
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
renderChild(child, index) {
|
||||
let { active, removeHiddenSubviews } = this.props;
|
||||
let { animating, progress } = this.state;
|
||||
|
||||
let opacity = progress.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: index ? [0, 1] : [1, 0],
|
||||
});
|
||||
|
||||
let hidden = active ^ !!index;
|
||||
|
||||
if (removeHiddenSubviews) {
|
||||
if (!animating && hidden) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
let pointerEvents = hidden ? 'none' : 'box-none';
|
||||
|
||||
return (
|
||||
<Animated.View
|
||||
style={[styles.container, { opacity }]}
|
||||
pointerEvents={pointerEvents}
|
||||
>
|
||||
{child}
|
||||
</Animated.View>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
let { children, ...props } = this.props;
|
||||
|
||||
return <View {...props}>{Children.map(children, this.renderChild)}</View>;
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
// ...StyleSheet.absoluteFillObject,
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
});
|
||||
@@ -1,13 +1,13 @@
|
||||
import React from 'react';
|
||||
import { Pressable, View } from 'react-native';
|
||||
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||
import { MD3ThemeType } from '../../theme/types';
|
||||
import { ThemeColors } from '../../theme/types';
|
||||
import Color from 'color';
|
||||
|
||||
interface ToggleButtonProps {
|
||||
icon: string;
|
||||
selected: boolean;
|
||||
theme: MD3ThemeType;
|
||||
theme: ThemeColors;
|
||||
color?: string;
|
||||
onPress: () => void;
|
||||
}
|
||||
@@ -27,7 +27,7 @@ export const ToggleButton: React.FC<ToggleButtonProps> = ({
|
||||
}}
|
||||
>
|
||||
<Pressable
|
||||
android_ripple={{ color: Color(theme.primary).alpha(0.12).string() }}
|
||||
android_ripple={{ color: theme.rippleColor }}
|
||||
style={{
|
||||
padding: 8,
|
||||
alignItems: 'center',
|
||||
@@ -40,9 +40,7 @@ export const ToggleButton: React.FC<ToggleButtonProps> = ({
|
||||
>
|
||||
<MaterialCommunityIcons
|
||||
name={icon}
|
||||
color={
|
||||
selected ? theme.primary : color ? color : theme.textColorPrimary
|
||||
}
|
||||
color={selected ? theme.primary : color ? color : theme.onSurface}
|
||||
size={24}
|
||||
/>
|
||||
</Pressable>
|
||||
|
||||
@@ -4,15 +4,13 @@ import { StyleSheet, View } from 'react-native';
|
||||
import { getString } from '@strings/translations';
|
||||
|
||||
import { Dialog, Portal } from 'react-native-paper';
|
||||
import { MD3ThemeType } from '../../theme/types';
|
||||
import { ThemeColors } from '../../theme/types';
|
||||
import { Button } from '@components/index';
|
||||
import { ButtonVariation } from '@components/Button/Button';
|
||||
import { getDialogBackground } from '@theme/colors';
|
||||
|
||||
interface ConfirmationDialogProps {
|
||||
title: string;
|
||||
visible: boolean;
|
||||
theme: MD3ThemeType;
|
||||
theme: ThemeColors;
|
||||
onSubmit: () => void;
|
||||
onDismiss: () => void;
|
||||
}
|
||||
@@ -34,27 +32,14 @@ const ConfirmationDialog: React.FC<ConfirmationDialogProps> = ({
|
||||
<Dialog
|
||||
visible={visible}
|
||||
onDismiss={onDismiss}
|
||||
style={[
|
||||
styles.container,
|
||||
{ backgroundColor: getDialogBackground(theme) },
|
||||
]}
|
||||
style={[styles.container, { backgroundColor: theme.overlay3 }]}
|
||||
>
|
||||
<Dialog.Title style={[styles.title, { color: theme.textColorPrimary }]}>
|
||||
<Dialog.Title style={[styles.title, { color: theme.onSurface }]}>
|
||||
{title}
|
||||
</Dialog.Title>
|
||||
<View style={styles.buttonCtn}>
|
||||
<Button
|
||||
theme={theme}
|
||||
onPress={handleOnSubmit}
|
||||
title={getString('common.ok')}
|
||||
variation={ButtonVariation.CLEAR}
|
||||
/>
|
||||
<Button
|
||||
theme={theme}
|
||||
onPress={onDismiss}
|
||||
title={getString('common.cancel')}
|
||||
variation={ButtonVariation.CLEAR}
|
||||
/>
|
||||
<Button onPress={handleOnSubmit} title={getString('common.ok')} />
|
||||
<Button onPress={onDismiss} title={getString('common.cancel')} />
|
||||
</View>
|
||||
</Dialog>
|
||||
</Portal>
|
||||
|
||||
@@ -10,16 +10,14 @@ const EmptyView = ({ icon, description, style, children, iconStyle }) => {
|
||||
<Text
|
||||
style={[
|
||||
styles.emptyViewIcon,
|
||||
{ color: theme.textColorHint },
|
||||
{ color: theme.outline },
|
||||
style,
|
||||
iconStyle,
|
||||
]}
|
||||
>
|
||||
{icon}
|
||||
</Text>
|
||||
<Text
|
||||
style={[styles.emptyViewText, { color: theme.textColorHint }, style]}
|
||||
>
|
||||
<Text style={[styles.emptyViewText, { color: theme.outline }, style]}>
|
||||
{description}
|
||||
</Text>
|
||||
{children}
|
||||
|
||||
@@ -1,22 +1,20 @@
|
||||
import React from 'react';
|
||||
import { StyleSheet, View, Text } from 'react-native';
|
||||
|
||||
import { MD3ThemeType } from '../../theme/types';
|
||||
import { ThemeColors } from '../../theme/types';
|
||||
|
||||
interface EmptyViewProps {
|
||||
icon?: string;
|
||||
description: string;
|
||||
theme: MD3ThemeType;
|
||||
theme: ThemeColors;
|
||||
}
|
||||
|
||||
const EmptyView: React.FC<EmptyViewProps> = ({ icon, description, theme }) => (
|
||||
<View style={styles.container}>
|
||||
{icon ? (
|
||||
<Text style={[styles.icon, { color: theme.textColorHint }]}>{icon}</Text>
|
||||
<Text style={[styles.icon, { color: theme.outline }]}>{icon}</Text>
|
||||
) : null}
|
||||
<Text style={[styles.text, { color: theme.textColorHint }]}>
|
||||
{description}
|
||||
</Text>
|
||||
<Text style={[styles.text, { color: theme.outline }]}>{description}</Text>
|
||||
</View>
|
||||
);
|
||||
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
import React from 'react';
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
|
||||
import { MD3ThemeType } from '@theme/types';
|
||||
import { useTheme } from '@hooks/useTheme';
|
||||
|
||||
interface ErrorScreenProps {
|
||||
error?: string;
|
||||
theme: MD3ThemeType;
|
||||
error: string;
|
||||
onRetry?: () => void;
|
||||
retryIconColor?: string;
|
||||
}
|
||||
|
||||
const ErrorScreen: React.FC<ErrorScreenProps> = ({ error, theme }) => {
|
||||
const ErrorScreen: React.FC<ErrorScreenProps> = ({ error }) => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text style={[styles.icon, { color: theme.textColorHint }]}>ಥ_ಥ</Text>
|
||||
<Text style={[styles.error, { color: theme.textColorHint }]}>
|
||||
{error}
|
||||
</Text>
|
||||
<Text style={[styles.icon, { color: theme.outline }]}>ಥ_ಥ</Text>
|
||||
<Text style={[styles.error, { color: theme.outline }]}>{error}</Text>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -6,11 +6,11 @@ import { IconButton } from 'react-native-paper';
|
||||
|
||||
export const ErrorView = ({ errorName, actions, theme }) => (
|
||||
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
|
||||
<Text style={[styles.emptyViewIcon, { color: theme.textColorHint }]}>
|
||||
<Text style={[styles.emptyViewIcon, { color: theme.outline }]}>
|
||||
{/* {icons[Math.floor(Math.random() * 5)]} */}
|
||||
ಥ_ಥ
|
||||
</Text>
|
||||
<Text style={[styles.emptyViewText, { color: theme.textColorHint }]}>
|
||||
<Text style={[styles.emptyViewText, { color: theme.outline }]}>
|
||||
{errorName}
|
||||
</Text>
|
||||
<View style={{ flexDirection: 'row' }}>
|
||||
@@ -38,14 +38,14 @@ export const ErrorView = ({ errorName, actions, theme }) => (
|
||||
>
|
||||
<IconButton
|
||||
icon={action.icon}
|
||||
color={theme.textColorHint}
|
||||
color={theme.outline}
|
||||
size={24}
|
||||
style={{ margin: 0 }}
|
||||
/>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: 12,
|
||||
color: theme.textColorHint,
|
||||
color: theme.outline,
|
||||
}}
|
||||
>
|
||||
{action.name}
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Pressable, StyleSheet, ViewPropTypes } from 'react-native';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||
|
||||
export const IconButton = ({
|
||||
icon,
|
||||
size,
|
||||
color,
|
||||
onPress,
|
||||
containerStyle,
|
||||
theme,
|
||||
}) => (
|
||||
<Pressable
|
||||
style={[styles.container, containerStyle]}
|
||||
android_ripple={{ color: theme.rippleColor, borderless: true, radius: 20 }}
|
||||
onPress={onPress}
|
||||
>
|
||||
<MaterialCommunityIcons name={icon} size={size} color={color} />
|
||||
</Pressable>
|
||||
);
|
||||
|
||||
IconButton.defaultProps = {
|
||||
size: 24,
|
||||
color: '#FFFFFF',
|
||||
};
|
||||
|
||||
IconButton.propTypes = {
|
||||
icon: PropTypes.string.isRequired,
|
||||
size: PropTypes.number.isRequired,
|
||||
color: PropTypes.string,
|
||||
onPress: PropTypes.func,
|
||||
containerStyle: ViewPropTypes.style,
|
||||
theme: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
margin: 6,
|
||||
},
|
||||
});
|
||||
@@ -3,7 +3,7 @@ import { Pressable, StyleSheet, View, ViewStyle } from 'react-native';
|
||||
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||
import Color from 'color';
|
||||
|
||||
import { MD3ThemeType } from '../../theme/types';
|
||||
import { ThemeColors } from '../../theme/types';
|
||||
|
||||
type Props = {
|
||||
name: string;
|
||||
@@ -12,7 +12,7 @@ type Props = {
|
||||
disabled?: boolean;
|
||||
padding?: number;
|
||||
onPress?: () => void;
|
||||
theme: MD3ThemeType;
|
||||
theme: ThemeColors;
|
||||
style?: ViewStyle;
|
||||
};
|
||||
|
||||
@@ -40,7 +40,7 @@ const IconButton: React.FC<Props> = ({
|
||||
<MaterialCommunityIcons
|
||||
name={name}
|
||||
size={size}
|
||||
color={disabled ? theme.textColorHint : color || theme.textColorPrimary}
|
||||
color={disabled ? theme.outline : color || theme.onSurface}
|
||||
/>
|
||||
</Pressable>
|
||||
</View>
|
||||
|
||||
@@ -1,141 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Pressable, StyleSheet, Text, View } from 'react-native';
|
||||
import color from 'color';
|
||||
|
||||
import { List as PaperList, Divider as PaperDivider } from 'react-native-paper';
|
||||
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||
|
||||
const ListSection = ({ children }) => (
|
||||
<PaperList.Section style={styles.listSection}>{children}</PaperList.Section>
|
||||
);
|
||||
|
||||
const ListSubHeader = ({ children, theme }) => (
|
||||
<PaperList.Subheader style={[styles.listSubHeader, { color: theme.primary }]}>
|
||||
{children}
|
||||
</PaperList.Subheader>
|
||||
);
|
||||
|
||||
const ListItem = ({
|
||||
title,
|
||||
description,
|
||||
icon,
|
||||
onPress,
|
||||
theme,
|
||||
right,
|
||||
iconColor,
|
||||
titleStyle,
|
||||
style,
|
||||
}) => (
|
||||
<PaperList.Item
|
||||
title={title}
|
||||
style={[{ paddingHorizontal: 16, paddingVertical: 12 }, style]}
|
||||
titleStyle={[{ color: theme.textColorPrimary }, titleStyle]}
|
||||
description={description}
|
||||
descriptionStyle={{ color: theme.textColorSecondary }}
|
||||
descriptionNumberOfLines={1}
|
||||
left={
|
||||
icon
|
||||
? () => (
|
||||
<View style={{ justifyContent: 'center' }}>
|
||||
<PaperList.Icon
|
||||
color={theme.primary}
|
||||
icon={icon}
|
||||
style={{
|
||||
marginVertical: 0,
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
)
|
||||
: undefined
|
||||
}
|
||||
right={() =>
|
||||
right && (
|
||||
<MaterialCommunityIcons
|
||||
name={right}
|
||||
color={iconColor || '#47a84a'}
|
||||
size={23}
|
||||
style={{ marginRight: 16, textAlignVertical: 'center' }}
|
||||
/>
|
||||
)
|
||||
}
|
||||
onPress={onPress}
|
||||
rippleColor={color(theme.primary).alpha(0.12).string()}
|
||||
/>
|
||||
);
|
||||
|
||||
const Divider = ({ theme }) => (
|
||||
<PaperDivider
|
||||
style={{
|
||||
backgroundColor: color(theme.isDark ? '#FFFFFF' : '#000000')
|
||||
.alpha(0.12)
|
||||
.rgb()
|
||||
.string(),
|
||||
height: 1,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
const InfoItem = ({ title, icon, theme }) => (
|
||||
<PaperList.Item
|
||||
title={title}
|
||||
titleStyle={{ color: theme.textColorSecondary, fontSize: 14 }}
|
||||
titleNumberOfLines={5}
|
||||
left={() =>
|
||||
icon && <PaperList.Icon color={theme.textColorSecondary} icon={icon} />
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
||||
const ColorItem = ({ title, description, theme, onPress }) => (
|
||||
<Pressable
|
||||
style={{
|
||||
padding: 16,
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
android_ripple={{ color: color(theme.primary).alpha(0.12).string() }}
|
||||
onPress={onPress}
|
||||
>
|
||||
<View>
|
||||
<Text style={{ color: theme.textColorPrimary, fontSize: 16 }}>
|
||||
{title}
|
||||
</Text>
|
||||
<Text style={{ color: theme.textColorSecondary }}>{description}</Text>
|
||||
</View>
|
||||
<View
|
||||
style={{
|
||||
backgroundColor: description,
|
||||
height: 24,
|
||||
width: 24,
|
||||
borderRadius: 50,
|
||||
marginRight: 16,
|
||||
}}
|
||||
/>
|
||||
</Pressable>
|
||||
);
|
||||
|
||||
const Icon = ({ icon, theme }) => (
|
||||
<PaperList.Icon color={theme.primary} icon={icon} style={{ margin: 0 }} />
|
||||
);
|
||||
|
||||
export const List = {
|
||||
Section: ListSection,
|
||||
SubHeader: ListSubHeader,
|
||||
Item: ListItem,
|
||||
Divider,
|
||||
InfoItem,
|
||||
ColorItem,
|
||||
Icon,
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
listSection: {
|
||||
flex: 1,
|
||||
marginVertical: 0,
|
||||
},
|
||||
listSubHeader: {
|
||||
fontWeight: 'bold',
|
||||
paddingBottom: 5,
|
||||
},
|
||||
});
|
||||
@@ -1,18 +1,16 @@
|
||||
import React, { ReactNode } from 'react';
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
import color from 'color';
|
||||
import { Pressable, StyleSheet, Text, View } from 'react-native';
|
||||
import MaterialIcon from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||
|
||||
import { List as PaperList, Divider as PaperDivider } from 'react-native-paper';
|
||||
import { MD3ThemeType } from '../../theme/types';
|
||||
import { dividerColor } from '../../theme/colors';
|
||||
import { ThemeColors } from '../../theme/types';
|
||||
|
||||
interface ListItemProps {
|
||||
title: string;
|
||||
description?: string | null;
|
||||
icon?: string;
|
||||
onPress?: () => void;
|
||||
theme: MD3ThemeType;
|
||||
theme: ThemeColors;
|
||||
}
|
||||
|
||||
const Section = ({ children }: { children: ReactNode }) => (
|
||||
@@ -24,7 +22,7 @@ const SubHeader = ({
|
||||
theme,
|
||||
}: {
|
||||
children: ReactNode;
|
||||
theme: MD3ThemeType;
|
||||
theme: ThemeColors;
|
||||
}) => (
|
||||
<PaperList.Subheader style={{ color: theme.primary }}>
|
||||
{children}
|
||||
@@ -40,29 +38,28 @@ const Item: React.FC<ListItemProps> = ({
|
||||
}) => (
|
||||
<PaperList.Item
|
||||
title={title}
|
||||
titleStyle={{ color: theme.textColorPrimary }}
|
||||
titleStyle={{ color: theme.onSurface }}
|
||||
description={description}
|
||||
descriptionStyle={{ color: theme.textColorSecondary }}
|
||||
left={() => (
|
||||
<View style={styles.iconContainer}>
|
||||
{icon && (
|
||||
<PaperList.Icon
|
||||
color={theme.primary}
|
||||
icon={icon}
|
||||
style={styles.icon}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
)}
|
||||
descriptionStyle={{ color: theme.onSurfaceVariant }}
|
||||
left={
|
||||
icon
|
||||
? () => (
|
||||
<PaperList.Icon
|
||||
color={theme.primary}
|
||||
icon={icon}
|
||||
style={styles.iconCtn}
|
||||
/>
|
||||
)
|
||||
: undefined
|
||||
}
|
||||
onPress={onPress}
|
||||
rippleColor={color(theme.primary).alpha(0.12).string()}
|
||||
rippleColor={theme.rippleColor}
|
||||
style={styles.listItemCtn}
|
||||
/>
|
||||
);
|
||||
|
||||
const Divider = ({ theme }: { theme: MD3ThemeType }) => (
|
||||
<PaperDivider
|
||||
style={[styles.divider, { backgroundColor: dividerColor(theme.isDark) }]}
|
||||
/>
|
||||
const Divider = ({ theme }: { theme: ThemeColors }) => (
|
||||
<PaperDivider style={[styles.divider, { backgroundColor: theme.outline }]} />
|
||||
);
|
||||
|
||||
const InfoItem = ({
|
||||
@@ -72,7 +69,7 @@ const InfoItem = ({
|
||||
}: {
|
||||
title: string;
|
||||
icon: string;
|
||||
theme: MD3ThemeType;
|
||||
theme: ThemeColors;
|
||||
}) => (
|
||||
<View style={styles.infoCtn}>
|
||||
<MaterialIcon size={20} color={theme.onSurfaceVariant} name={icon} />
|
||||
@@ -82,10 +79,37 @@ const InfoItem = ({
|
||||
</View>
|
||||
);
|
||||
|
||||
const Icon = ({ icon, theme }: { icon: string; theme: MD3ThemeType }) => (
|
||||
const Icon = ({ icon, theme }: { icon: string; theme: ThemeColors }) => (
|
||||
<PaperList.Icon color={theme.primary} icon={icon} style={{ margin: 0 }} />
|
||||
);
|
||||
|
||||
const ColorItem = ({ title, description, theme, onPress }) => (
|
||||
<Pressable
|
||||
style={{
|
||||
padding: 16,
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
android_ripple={{ color: theme.rippleColor }}
|
||||
onPress={onPress}
|
||||
>
|
||||
<View>
|
||||
<Text style={{ color: theme.onSurface, fontSize: 16 }}>{title}</Text>
|
||||
<Text style={{ color: theme.onSurfaceVariant }}>{description}</Text>
|
||||
</View>
|
||||
<View
|
||||
style={{
|
||||
backgroundColor: description,
|
||||
height: 24,
|
||||
width: 24,
|
||||
borderRadius: 50,
|
||||
marginRight: 16,
|
||||
}}
|
||||
/>
|
||||
</Pressable>
|
||||
);
|
||||
|
||||
export default {
|
||||
Section,
|
||||
SubHeader,
|
||||
@@ -93,6 +117,7 @@ export default {
|
||||
Divider,
|
||||
InfoItem,
|
||||
Icon,
|
||||
ColorItem,
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
@@ -102,12 +127,7 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
divider: {
|
||||
height: 1,
|
||||
},
|
||||
iconContainer: {
|
||||
justifyContent: 'center',
|
||||
},
|
||||
icon: {
|
||||
marginVertical: 0,
|
||||
opacity: 0.5,
|
||||
},
|
||||
infoCtn: {
|
||||
paddingVertical: 12,
|
||||
@@ -117,4 +137,10 @@ const styles = StyleSheet.create({
|
||||
marginTop: 12,
|
||||
fontSize: 12,
|
||||
},
|
||||
iconCtn: {
|
||||
paddingLeft: 16,
|
||||
},
|
||||
listItemCtn: {
|
||||
paddingVertical: 12,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -2,7 +2,6 @@ import React from 'react';
|
||||
import { StyleSheet, View, Text, Pressable } from 'react-native';
|
||||
|
||||
import FastImage from 'react-native-fast-image';
|
||||
import { defaultCoverUri } from '../sources/helpers/constants';
|
||||
import { coverPlaceholderColor } from '../theme/colors';
|
||||
|
||||
import color from 'color';
|
||||
@@ -19,7 +18,7 @@ const ListView = ({
|
||||
}) => {
|
||||
return (
|
||||
<Pressable
|
||||
android_ripple={{ color: color(theme.primary).alpha(0.12).string() }}
|
||||
android_ripple={{ color: theme.rippleColor }}
|
||||
style={[
|
||||
styles.listView,
|
||||
isSelected && {
|
||||
@@ -36,7 +35,7 @@ const ListView = ({
|
||||
style={[styles.extensionIcon, inLibraryBadge && { opacity: 0.5 }]}
|
||||
/>
|
||||
<Text
|
||||
style={[{ color: theme.textColorPrimary }, styles.novelName]}
|
||||
style={[{ color: theme.onSurface }, styles.novelName]}
|
||||
numberOfLines={1}
|
||||
>
|
||||
{item.novelName}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React from 'react';
|
||||
import { ActivityIndicator, StyleSheet } from 'react-native';
|
||||
import { MD3ThemeType } from '../../theme/types';
|
||||
import { ThemeColors } from '../../theme/types';
|
||||
|
||||
interface Props {
|
||||
theme: MD3ThemeType;
|
||||
theme: ThemeColors;
|
||||
}
|
||||
|
||||
const LoadingMoreIndicator: React.FC<Props> = ({ theme }) => (
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React from 'react';
|
||||
import { StyleSheet, ActivityIndicator } from 'react-native';
|
||||
|
||||
import { MD3ThemeType } from '../../theme/types';
|
||||
import { ThemeColors } from '../../theme/types';
|
||||
|
||||
const LoadingScreen: React.FC<{ theme: MD3ThemeType }> = ({ theme }) => (
|
||||
const LoadingScreen: React.FC<{ theme: ThemeColors }> = ({ theme }) => (
|
||||
<ActivityIndicator size={50} color={theme.primary} style={styles.indicator} />
|
||||
);
|
||||
|
||||
|
||||
@@ -3,10 +3,10 @@ import { StyleSheet, View, Text, Dimensions } from 'react-native';
|
||||
import { Portal, Modal } from 'react-native-paper';
|
||||
import * as Linking from 'expo-linking';
|
||||
import { ScrollView } from 'react-native-gesture-handler';
|
||||
import Button, { ButtonVariation } from './Button/Button';
|
||||
import Button from './Button/Button';
|
||||
import { getString } from '@strings/translations';
|
||||
import Markdown from 'react-native-markdown-display';
|
||||
import { dividerColor, getDialogBackground } from '@theme/colors';
|
||||
|
||||
import { useTheme } from '@hooks/useTheme';
|
||||
|
||||
interface NewUpdateDialogProps {
|
||||
@@ -31,26 +31,26 @@ const NewUpdateDialog: React.FC<NewUpdateDialogProps> = ({ newVersion }) => {
|
||||
onDismiss={() => showNewUpdateDialog(false)}
|
||||
contentContainerStyle={[
|
||||
styles.containerStyle,
|
||||
{ backgroundColor: getDialogBackground(theme) },
|
||||
{ backgroundColor: theme.overlay3 },
|
||||
]}
|
||||
>
|
||||
<Text style={[styles.modalHeader, { color: theme.textColorPrimary }]}>
|
||||
<Text style={[styles.modalHeader, { color: theme.onSurface }]}>
|
||||
{`${getString('common.newUpdateAvailable')} ${newVersion.tag_name}`}
|
||||
</Text>
|
||||
<ScrollView style={{ height: modalHeight }}>
|
||||
<Markdown
|
||||
style={{
|
||||
body: {
|
||||
color: theme.textColorSecondary,
|
||||
color: theme.onSurfaceVariant,
|
||||
lineHeight: 20,
|
||||
paddingVertical: 8,
|
||||
},
|
||||
hr: {
|
||||
backgroundColor: dividerColor(theme.isDark),
|
||||
backgroundColor: theme.outline,
|
||||
marginVertical: 16,
|
||||
},
|
||||
code_inline: {
|
||||
backgroundColor: getDialogBackground(theme),
|
||||
backgroundColor: theme.overlay3,
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -60,14 +60,10 @@ const NewUpdateDialog: React.FC<NewUpdateDialogProps> = ({ newVersion }) => {
|
||||
<View style={styles.buttonCtn}>
|
||||
<Button
|
||||
title={getString('common.cancel')}
|
||||
theme={theme}
|
||||
variation={ButtonVariation.CLEAR}
|
||||
onPress={() => showNewUpdateDialog(false)}
|
||||
/>
|
||||
<Button
|
||||
title={getString('common.install')}
|
||||
theme={theme}
|
||||
variation={ButtonVariation.CLEAR}
|
||||
onPress={() => Linking.openURL(newVersion.downloadUrl)}
|
||||
/>
|
||||
</View>
|
||||
|
||||
@@ -12,7 +12,7 @@ import { LinearGradient } from 'expo-linear-gradient';
|
||||
import FastImage from 'react-native-fast-image';
|
||||
import ListView from './ListView';
|
||||
|
||||
import { useDeviceOrientation } from '../services/utils/helpers';
|
||||
import { useDeviceOrientation } from '@hooks/useDeviceOrientation';
|
||||
import { coverPlaceholderColor } from '../theme/colors';
|
||||
import { useLibrarySettings } from '@hooks/useSettings';
|
||||
import { DisplayModes } from '@screens/library/constants/constants';
|
||||
@@ -67,7 +67,7 @@ const NovelCover = ({
|
||||
]}
|
||||
>
|
||||
<Pressable
|
||||
android_ripple={{ color: color(theme.primary).alpha(0.12).string() }}
|
||||
android_ripple={{ color: theme.rippleColor }}
|
||||
style={styles.opac}
|
||||
onPress={
|
||||
selectedNovels && selectedNovels.length > 0 ? selectNovel : onPress
|
||||
@@ -158,7 +158,7 @@ const ComfortableTitle = ({ theme, novelName }) => (
|
||||
style={[
|
||||
styles.title,
|
||||
{
|
||||
color: theme.textColorPrimary,
|
||||
color: theme.onSurface,
|
||||
padding: 4,
|
||||
},
|
||||
]}
|
||||
|
||||
@@ -9,8 +9,7 @@ import {
|
||||
} from 'react-native';
|
||||
import { SourceNovelItem } from '../sources/types';
|
||||
import { LibraryNovelInfo, NovelInfo } from '../database/types';
|
||||
|
||||
import { useDeviceOrientation } from '../services/utils/helpers';
|
||||
import { useDeviceOrientation } from '@hooks/useDeviceOrientation';
|
||||
|
||||
export type NovelListRenderItem = ListRenderItem<
|
||||
LibraryNovelInfo | NovelInfo | SourceNovelItem
|
||||
|
||||
@@ -13,14 +13,10 @@ export const RadioButton = ({ value, label, theme, labelStyle }) => (
|
||||
<MaterialRadioButton
|
||||
value={value}
|
||||
color={theme.primary}
|
||||
uncheckedColor={theme.textColorSecondary}
|
||||
uncheckedColor={theme.onSurfaceVariant}
|
||||
/>
|
||||
<Text
|
||||
style={[
|
||||
styles.radioButtonLabel,
|
||||
{ color: theme.textColorPrimary },
|
||||
labelStyle,
|
||||
]}
|
||||
style={[styles.radioButtonLabel, { color: theme.onSurface }, labelStyle]}
|
||||
>
|
||||
{label}
|
||||
</Text>
|
||||
|
||||
@@ -8,8 +8,7 @@ import {
|
||||
ViewStyle,
|
||||
} from 'react-native';
|
||||
import { RadioButton as PaperRadioButton } from 'react-native-paper';
|
||||
import { MD3ThemeType } from '../../theme/types';
|
||||
import color from 'color';
|
||||
import { ThemeColors } from '../../theme/types';
|
||||
|
||||
interface Props {
|
||||
label: string;
|
||||
@@ -17,7 +16,7 @@ interface Props {
|
||||
onPress?: () => void;
|
||||
style?: StyleProp<ViewStyle>;
|
||||
labelStyle?: StyleProp<TextStyle>;
|
||||
theme: MD3ThemeType;
|
||||
theme: ThemeColors;
|
||||
}
|
||||
|
||||
export const RadioButton: React.FC<Props> = ({
|
||||
@@ -29,7 +28,7 @@ export const RadioButton: React.FC<Props> = ({
|
||||
theme,
|
||||
}) => (
|
||||
<Pressable
|
||||
android_ripple={{ color: color(theme.primary).alpha(0.12).string() }}
|
||||
android_ripple={{ color: theme.rippleColor }}
|
||||
style={[styles.pressable, style]}
|
||||
onPress={onPress}
|
||||
>
|
||||
@@ -38,7 +37,7 @@ export const RadioButton: React.FC<Props> = ({
|
||||
value={label}
|
||||
onPress={onPress}
|
||||
color={theme.primary}
|
||||
uncheckedColor={theme.textColorSecondary}
|
||||
uncheckedColor={theme.onSurfaceVariant}
|
||||
/>
|
||||
<Text style={[styles.label, labelStyle, { color: theme.onSurface }]}>
|
||||
{label}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import React, { useRef } from 'react';
|
||||
import { Pressable, StyleSheet, View, TextInput } from 'react-native';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import color from 'color';
|
||||
|
||||
import IconButtonV2 from '../IconButtonV2/IconButtonV2';
|
||||
import { MD3ThemeType } from '../../theme/types';
|
||||
import { ThemeColors } from '../../theme/types';
|
||||
|
||||
interface RightIcon {
|
||||
iconName: string;
|
||||
@@ -22,7 +21,7 @@ interface SearcbarProps {
|
||||
handleBackAction?: () => void;
|
||||
clearSearchbar: () => void;
|
||||
onLeftIconPress?: () => void;
|
||||
theme: MD3ThemeType;
|
||||
theme: ThemeColors;
|
||||
}
|
||||
|
||||
const Searchbar: React.FC<SearcbarProps> = ({
|
||||
@@ -53,13 +52,13 @@ const Searchbar: React.FC<SearcbarProps> = ({
|
||||
marginTop,
|
||||
marginRight,
|
||||
marginLeft,
|
||||
backgroundColor: color(theme.primary).alpha(0.08).string(),
|
||||
backgroundColor: theme.surface2,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Pressable
|
||||
onPress={focusSearchbar}
|
||||
android_ripple={{ color: color(theme.primary).alpha(12).toString() }}
|
||||
android_ripple={{ color: theme.rippleColor }}
|
||||
style={[styles.searchbar]}
|
||||
>
|
||||
<IconButtonV2
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Pressable, StyleSheet, View, Text } from 'react-native';
|
||||
import color from 'color';
|
||||
import { Switch, List } from 'react-native-paper';
|
||||
|
||||
const SwitchSetting = ({ label, description, onPress, theme, icon, value }) => (
|
||||
<Pressable
|
||||
android_ripple={{ color: color(theme.primary).alpha(0.12).rgb().string() }}
|
||||
style={[styles.container, { paddingVertical: description ? 16 : 12 }]}
|
||||
onPress={onPress}
|
||||
>
|
||||
<View style={{ flexDirection: 'row', flex: 1 }}>
|
||||
{icon && (
|
||||
<List.Icon color={theme.primary} icon={icon} style={{ margin: 0 }} />
|
||||
)}
|
||||
<View style={[icon && { marginLeft: 16 }]}>
|
||||
<Text
|
||||
style={{
|
||||
color: theme.textColorPrimary,
|
||||
fontSize: 16,
|
||||
flex: 1,
|
||||
textAlignVertical: 'center',
|
||||
}}
|
||||
>
|
||||
{label}
|
||||
</Text>
|
||||
{description && (
|
||||
<Text style={{ color: theme.textColorSecondary }}>{description}</Text>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
<Switch
|
||||
value={value}
|
||||
onValueChange={onPress}
|
||||
color={theme.primary}
|
||||
style={{ marginLeft: 8 }}
|
||||
/>
|
||||
</Pressable>
|
||||
);
|
||||
|
||||
export default SwitchSetting;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
paddingHorizontal: 16,
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,77 @@
|
||||
import React from 'react';
|
||||
import { Pressable, StyleSheet, View, Text } from 'react-native';
|
||||
import { Switch, List } from 'react-native-paper';
|
||||
import { ThemeColors } from '@theme/types';
|
||||
|
||||
interface SwitchProps {
|
||||
label: string;
|
||||
description?: string;
|
||||
onPress: () => void;
|
||||
theme: ThemeColors;
|
||||
icon?: string;
|
||||
value: boolean;
|
||||
}
|
||||
|
||||
const SwitchSetting: React.FC<SwitchProps> = ({
|
||||
label,
|
||||
description,
|
||||
onPress,
|
||||
theme,
|
||||
icon,
|
||||
value,
|
||||
}) => {
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
paddingHorizontal: 16,
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
paddingVertical: description ? 16 : 12,
|
||||
},
|
||||
row: {
|
||||
flexDirection: 'row',
|
||||
flex: 1,
|
||||
},
|
||||
icon: {
|
||||
margin: 0,
|
||||
},
|
||||
textContainer: {
|
||||
marginLeft: icon && 16,
|
||||
},
|
||||
text: {
|
||||
fontSize: 16,
|
||||
flex: 1,
|
||||
textAlignVertical: 'center',
|
||||
},
|
||||
switch: { marginLeft: 8 },
|
||||
});
|
||||
|
||||
return (
|
||||
<Pressable
|
||||
android_ripple={{
|
||||
color: theme.rippleColor,
|
||||
}}
|
||||
style={styles.container}
|
||||
onPress={onPress}
|
||||
>
|
||||
<View style={styles.row}>
|
||||
{icon && (
|
||||
<List.Icon color={theme.primary} icon={icon} style={styles.icon} />
|
||||
)}
|
||||
<View style={styles.textContainer}>
|
||||
<Text style={[styles.text, { color: theme.onSurface }]}>{label}</Text>
|
||||
{description && (
|
||||
<Text style={{ color: theme.onSurfaceVariant }}>{description}</Text>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
<Switch
|
||||
value={value}
|
||||
onValueChange={onPress}
|
||||
color={theme.primary}
|
||||
style={styles.switch}
|
||||
/>
|
||||
</Pressable>
|
||||
);
|
||||
};
|
||||
|
||||
export default SwitchSetting;
|
||||
@@ -1,16 +1,15 @@
|
||||
import React from 'react';
|
||||
import { Pressable, StyleSheet, View, Text } from 'react-native';
|
||||
import color from 'color';
|
||||
|
||||
import { Switch } from 'react-native-paper';
|
||||
import { MD3ThemeType } from '../../theme/types';
|
||||
import { ThemeColors } from '../../theme/types';
|
||||
|
||||
interface SwitchItemProps {
|
||||
value: boolean;
|
||||
label: string;
|
||||
description?: string;
|
||||
onPress: () => void;
|
||||
theme: MD3ThemeType;
|
||||
theme: ThemeColors;
|
||||
}
|
||||
|
||||
const SwitchItem: React.FC<SwitchItemProps> = ({
|
||||
@@ -21,16 +20,14 @@ const SwitchItem: React.FC<SwitchItemProps> = ({
|
||||
value,
|
||||
}) => (
|
||||
<Pressable
|
||||
android_ripple={{ color: color(theme.primary).alpha(0.12).string() }}
|
||||
android_ripple={{ color: theme.rippleColor }}
|
||||
style={[styles.container]}
|
||||
onPress={onPress}
|
||||
>
|
||||
<View style={styles.labelContainer}>
|
||||
<Text style={[{ color: theme.textColorPrimary }, styles.label]}>
|
||||
{label}
|
||||
</Text>
|
||||
<Text style={[{ color: theme.onSurface }, styles.label]}>{label}</Text>
|
||||
{description ? (
|
||||
<Text style={{ color: theme.textColorSecondary }}>{description}</Text>
|
||||
<Text style={{ color: theme.onSurfaceVariant }}>{description}</Text>
|
||||
) : null}
|
||||
</View>
|
||||
<Switch
|
||||
|
||||
@@ -54,7 +54,7 @@ export const ThemePicker = ({ theme, currentTheme, onPress }) => (
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
backgroundColor: theme.textColorPrimary,
|
||||
backgroundColor: theme.onSurface,
|
||||
width: 44,
|
||||
height: 10,
|
||||
marginLeft: 8,
|
||||
@@ -66,7 +66,7 @@ export const ThemePicker = ({ theme, currentTheme, onPress }) => (
|
||||
<View
|
||||
style={{
|
||||
height: 18,
|
||||
backgroundColor: theme.textColorSecondary,
|
||||
backgroundColor: theme.onSurfaceVariant,
|
||||
borderRadius: 4,
|
||||
}}
|
||||
/>
|
||||
@@ -75,7 +75,7 @@ export const ThemePicker = ({ theme, currentTheme, onPress }) => (
|
||||
style={{
|
||||
height: 10,
|
||||
width: 44,
|
||||
backgroundColor: theme.textColorPrimary,
|
||||
backgroundColor: theme.onSurface,
|
||||
borderRadius: 50,
|
||||
}}
|
||||
/>
|
||||
@@ -94,7 +94,7 @@ export const ThemePicker = ({ theme, currentTheme, onPress }) => (
|
||||
style={{
|
||||
height: 10,
|
||||
width: 24,
|
||||
backgroundColor: theme.textColorSecondary,
|
||||
backgroundColor: theme.onSurfaceVariant,
|
||||
borderRadius: 50,
|
||||
}}
|
||||
/>
|
||||
@@ -102,7 +102,7 @@ export const ThemePicker = ({ theme, currentTheme, onPress }) => (
|
||||
style={{
|
||||
height: 10,
|
||||
width: 24,
|
||||
backgroundColor: theme.textColorSecondary,
|
||||
backgroundColor: theme.onSurfaceVariant,
|
||||
borderRadius: 50,
|
||||
marginLeft: 4,
|
||||
}}
|
||||
@@ -134,7 +134,7 @@ export const ThemePicker = ({ theme, currentTheme, onPress }) => (
|
||||
height: 12,
|
||||
width: 12,
|
||||
borderRadius: 50,
|
||||
backgroundColor: theme.textColorPrimary,
|
||||
backgroundColor: theme.onSurface,
|
||||
opacity: 0.54,
|
||||
}}
|
||||
/>
|
||||
@@ -151,7 +151,7 @@ export const ThemePicker = ({ theme, currentTheme, onPress }) => (
|
||||
height: 12,
|
||||
width: 12,
|
||||
borderRadius: 50,
|
||||
backgroundColor: theme.textColorPrimary,
|
||||
backgroundColor: theme.onSurface,
|
||||
opacity: 0.54,
|
||||
}}
|
||||
/>
|
||||
@@ -161,7 +161,7 @@ export const ThemePicker = ({ theme, currentTheme, onPress }) => (
|
||||
</View>
|
||||
<Text
|
||||
style={{
|
||||
color: currentTheme.textColorPrimary,
|
||||
color: currentTheme.onSurface,
|
||||
fontSize: 12,
|
||||
paddingVertical: 4,
|
||||
}}
|
||||
|
||||
+6
-2
@@ -14,7 +14,10 @@ import {
|
||||
createHistoryTableQuery,
|
||||
createChapterIdIndexQuery,
|
||||
} from './tables/HistoryTable';
|
||||
import { createDownloadTableQuery } from './tables/DownloadTable';
|
||||
import {
|
||||
createDownloadIdIndex,
|
||||
createDownloadTableQuery,
|
||||
} from './tables/DownloadTable';
|
||||
import { createUpdatesTableQuery } from './tables/UpdateTable';
|
||||
import {
|
||||
addCategorySortColumnQuery,
|
||||
@@ -26,7 +29,7 @@ import {
|
||||
dbTxnErrorCallback,
|
||||
txnErrorCallbackWithoutToast,
|
||||
} from './utils/helpers';
|
||||
import { noop } from 'lodash';
|
||||
import { noop } from 'lodash-es';
|
||||
|
||||
const dbName = 'lnreader.db';
|
||||
|
||||
@@ -71,6 +74,7 @@ const createIndexes = () => {
|
||||
tx.executeSql(createUnreadChaptersIndexQuery);
|
||||
tx.executeSql(createChapterIdIndexQuery);
|
||||
tx.executeSql(createCategorydIndexQuery);
|
||||
tx.executeSql(createDownloadIdIndex);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as SQLite from 'expo-sqlite';
|
||||
import { noop } from 'lodash';
|
||||
import { noop } from 'lodash-es';
|
||||
import { Category } from '../types';
|
||||
import { txnErrorCallback } from '../utils/helpers';
|
||||
const db = SQLite.openDatabase('lnreader.db');
|
||||
@@ -72,8 +72,10 @@ export const isCategoryNameDuplicate = (
|
||||
tx.executeSql(
|
||||
isCategoryNameDuplicateQuery,
|
||||
[categoryName],
|
||||
(txObj, { rows: { _array } }) =>
|
||||
resolve(Boolean(_array[0]?.isDuplicate)),
|
||||
(txObj, { rows }) => {
|
||||
const { _array } = rows as any;
|
||||
resolve(Boolean(_array[0]?.isDuplicate));
|
||||
},
|
||||
txnErrorCallback,
|
||||
);
|
||||
}),
|
||||
|
||||
@@ -243,13 +243,15 @@ const createImageFolder = async (
|
||||
},
|
||||
): Promise<string> => {
|
||||
const mkdirIfNot = async (p: string) => {
|
||||
const nomediaPath =
|
||||
p + (p.charAt(p.length - 1) === '/' ? '' : '/') + '.nomedia';
|
||||
if (!(await RNFetchBlob.fs.exists(p))) {
|
||||
await RNFetchBlob.fs.mkdir(p);
|
||||
await RNFetchBlob.fs.createFile(nomediaPath, ',', 'utf8');
|
||||
}
|
||||
};
|
||||
|
||||
await mkdirIfNot(path);
|
||||
await RNFetchBlob.fs.createFile(path, '.nomedia', 'utf8');
|
||||
|
||||
if (data) {
|
||||
const { sourceId, novelId, chapterId } = data;
|
||||
@@ -269,31 +271,53 @@ const downloadImages = async (
|
||||
chapterId: number,
|
||||
): Promise<string> => {
|
||||
try {
|
||||
const headers = sourceManager(sourceId)?.headers || {};
|
||||
const loadedCheerio = cheerio.load(html);
|
||||
const imgs = loadedCheerio('img').toArray();
|
||||
for (let i = 0; i < imgs.length; i++) {
|
||||
const elem = loadedCheerio(imgs[i]);
|
||||
const url = elem.attr('src');
|
||||
if (url) {
|
||||
const imageb64 = (await RNFetchBlob.fetch('GET', url)).base64();
|
||||
const imageb64 = (
|
||||
await RNFetchBlob.fetch('GET', url, headers)
|
||||
).base64();
|
||||
const fileurl =
|
||||
(await createImageFolder(
|
||||
`${RNFetchBlob.fs.dirs.DownloadDir}/LNReader`,
|
||||
{ sourceId, novelId, chapterId },
|
||||
)) +
|
||||
).catch(() => {
|
||||
showToast(
|
||||
`Unexpected storage error!\nRemove ${fileurl} and try downloading again`,
|
||||
);
|
||||
return '--';
|
||||
})) +
|
||||
i +
|
||||
'.b64.png';
|
||||
elem.replaceWith(
|
||||
`<img type="file" src="${url}" file-src="${fileurl}" file-id="${i}">`,
|
||||
);
|
||||
const exists = await RNFetchBlob.fs.exists(fileurl);
|
||||
if (fileurl.charAt(0) === '-') {
|
||||
return loadedCheerio.html();
|
||||
}
|
||||
elem.attr('src', `file://${fileurl}`);
|
||||
const exists = await RNFetchBlob.fs.exists(fileurl).catch(() => {
|
||||
showToast(
|
||||
`Unexpected storage error!\nRemove ${fileurl} and try downloading again`,
|
||||
);
|
||||
});
|
||||
if (!exists) {
|
||||
RNFetchBlob.fs.createFile(fileurl, imageb64, 'utf8');
|
||||
RNFetchBlob.fs.createFile(fileurl, imageb64, 'base64').catch(() => {
|
||||
showToast(
|
||||
`Unexpected storage error!\nRemove ${fileurl} and try downloading again`,
|
||||
);
|
||||
});
|
||||
} else {
|
||||
RNFetchBlob.fs.writeFile(fileurl, imageb64, 'utf8');
|
||||
RNFetchBlob.fs.writeFile(fileurl, imageb64, 'base64').catch(() => {
|
||||
showToast(
|
||||
`Unexpected storage error!\nRemove ${fileurl} and try downloading again`,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
loadedCheerio('body').prepend("<input type='hidden' offline />");
|
||||
return loadedCheerio.html();
|
||||
} catch (e) {
|
||||
return html;
|
||||
@@ -350,20 +374,16 @@ const deleteDownloadedImages = async (
|
||||
chapterId: number,
|
||||
) => {
|
||||
try {
|
||||
const path = `${RNFetchBlob.fs.dirs.DownloadDir}/LNReader/`;
|
||||
const files = await RNFetchBlob.fs.ls(
|
||||
await createImageFolder(path, { sourceId, novelId, chapterId }),
|
||||
const path = await createImageFolder(
|
||||
`${RNFetchBlob.fs.dirs.DownloadDir}/LNReader`,
|
||||
{ sourceId, novelId, chapterId },
|
||||
);
|
||||
const files = await RNFetchBlob.fs.ls(path);
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const ex = /(.*?)_(.*?)#(.*?)/.exec(files[i]);
|
||||
const ex = /\.b64\.png/.exec(files[i]);
|
||||
if (ex) {
|
||||
if (
|
||||
parseInt(ex[1], 10) === sourceId &&
|
||||
parseInt(ex[2], 10) === chapterId
|
||||
) {
|
||||
if (await RNFetchBlob.fs.exists(`${path}${files[i]}`)) {
|
||||
RNFetchBlob.fs.unlink(`${path}${files[i]}`);
|
||||
}
|
||||
if (await RNFetchBlob.fs.exists(`${path}${files[i]}`)) {
|
||||
RNFetchBlob.fs.unlink(`${path}${files[i]}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +79,10 @@ export const getChapterFromDb = async (
|
||||
getChapterFromDbQuery,
|
||||
[chapterId],
|
||||
(txObj, results) => resolve(results.rows.item(0)),
|
||||
(txObj, error) => reject(error),
|
||||
(_, error) => {
|
||||
reject(error);
|
||||
return false;
|
||||
},
|
||||
);
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -6,7 +6,7 @@ import { txnErrorCallback } from '../utils/helpers';
|
||||
const db = SQLite.openDatabase('lnreader.db');
|
||||
|
||||
const getLibraryQuery = `
|
||||
SELECT novels.*, C.chaptersUnread, D.chaptersDownloaded, H.lastReadAt
|
||||
SELECT novels.*, C.chaptersUnread, D.chaptersDownloaded, H.lastReadAt, U.lastUpdatedAt
|
||||
FROM novels
|
||||
LEFT JOIN (
|
||||
SELECT chapters.novelId, COUNT(*) AS chaptersUnread
|
||||
@@ -30,6 +30,14 @@ const getLibraryQuery = `
|
||||
ORDER BY history.historyTimeRead DESC
|
||||
) AS H
|
||||
ON novels.novelId = H.novelId
|
||||
LEFT JOIN (
|
||||
SELECT updates.novelId, updateTime AS lastUpdatedAt
|
||||
FROM updates
|
||||
GROUP BY updates.novelId
|
||||
HAVING updates.updateTime = MAX(updates.updateTime)
|
||||
ORDER BY updates.updateTime DESC
|
||||
) AS U
|
||||
ON novels.novelId = U.novelId
|
||||
WHERE novels.followed = 1
|
||||
`;
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import { insertChapters } from './ChapterQueries';
|
||||
|
||||
import { showToast } from '../../hooks/showToast';
|
||||
import { txnErrorCallback } from '../utils/helpers';
|
||||
import { noop } from 'lodash';
|
||||
import { noop } from 'lodash-es';
|
||||
|
||||
const insertNovelQuery =
|
||||
'INSERT INTO novels (novelUrl, sourceUrl, sourceId, source, novelName, novelCover, novelSummary, author, artist, status, genre, categoryIds) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { noop, xor } from 'lodash';
|
||||
import { noop, xor } from 'lodash-es';
|
||||
|
||||
import * as SQLite from 'expo-sqlite';
|
||||
const db = SQLite.openDatabase('lnreader.db');
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as SQLite from 'expo-sqlite';
|
||||
import { countBy } from 'lodash';
|
||||
import { countBy } from 'lodash-es';
|
||||
import { LibraryStats } from '../types';
|
||||
import { txnErrorCallback } from '../utils/helpers';
|
||||
|
||||
|
||||
@@ -7,3 +7,6 @@ export const createDownloadTableQuery = `
|
||||
FOREIGN KEY (downloadChapterId) REFERENCES chapters(chapterId) ON DELETE CASCADE
|
||||
)
|
||||
`;
|
||||
|
||||
export const createDownloadIdIndex =
|
||||
'CREATE INDEX IF NOT EXISTS downloadChapterIdIndex ON downloads(downloadChapterId)';
|
||||
|
||||
@@ -30,6 +30,12 @@ export interface ChapterItem {
|
||||
bookmark: number;
|
||||
downloaded: number;
|
||||
}
|
||||
export interface ChapterItemExtended extends ChapterItem {
|
||||
novelId: number;
|
||||
novelUrl: string;
|
||||
sourceId: number;
|
||||
novelName: string;
|
||||
}
|
||||
|
||||
export interface DownloadedChapter {
|
||||
downloadId: number;
|
||||
|
||||
@@ -9,3 +9,4 @@ export { default as useBoolean } from './useBoolean';
|
||||
export { useTheme } from './useTheme';
|
||||
export { default as useCategories } from './useCategories';
|
||||
export { useCategorySettings, useLibrarySettings } from './useSettings';
|
||||
export { usePreviousRouteName } from './usePreviousRouteName';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import sanitize from 'sanitize-html';
|
||||
import { defaultTo } from 'lodash';
|
||||
import { defaultTo } from 'lodash-es';
|
||||
import { getChapterFromDb } from '../database/queries/DownloadQueries';
|
||||
|
||||
import { sourceManager } from '../sources/sourceManager';
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import { useWindowDimensions } from 'react-native';
|
||||
|
||||
export const useDeviceOrientation = () => {
|
||||
const window = useWindowDimensions();
|
||||
|
||||
if (window.width > window.height) {
|
||||
return 'landscape';
|
||||
} else {
|
||||
return 'potrait';
|
||||
}
|
||||
};
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
hideNavigationBar,
|
||||
showNavigationBar,
|
||||
} from '../theme/NativeModules/NavigationBarColor';
|
||||
import { readerBackground } from '../screens/reader/utils/readerStyles';
|
||||
import { useTheme } from './useTheme';
|
||||
|
||||
const useFullscreenMode = () => {
|
||||
@@ -16,7 +15,7 @@ const useFullscreenMode = () => {
|
||||
const readerSettings = useReaderSettings();
|
||||
const { fullScreenMode } = useSettingsV1();
|
||||
|
||||
const backgroundColor = readerBackground(readerSettings.theme);
|
||||
const backgroundColor = readerSettings.theme;
|
||||
|
||||
const theme = useTheme();
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import { useNavigationState } from '@react-navigation/native';
|
||||
|
||||
export const usePreviousRouteName = () => {
|
||||
return useNavigationState(state =>
|
||||
state.routes[state.index - 1]?.name
|
||||
? state.routes[state.index - 1].name
|
||||
: 'None',
|
||||
);
|
||||
};
|
||||
@@ -1,3 +1,4 @@
|
||||
import CookieManager from '@react-native-cookies/cookies';
|
||||
import { useMMKVObject } from 'react-native-mmkv';
|
||||
import { MMKVStorage } from '@utils/mmkv/mmkv';
|
||||
import { showToast } from './showToast';
|
||||
@@ -38,7 +39,8 @@ const useSourceStorage = ({ sourceId = -1 }: { sourceId?: number }) => {
|
||||
// }),
|
||||
// );
|
||||
// }
|
||||
|
||||
CookieManager.clearAll();
|
||||
CookieManager.clearAll(true); //clears cookies in webkit
|
||||
setValues({});
|
||||
showToast('Cookies cleared');
|
||||
};
|
||||
|
||||
@@ -1,57 +1,37 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useState, useEffect, useRef } from 'react';
|
||||
import Tts from 'react-native-tts';
|
||||
import { htmlToText } from '../sources/helpers/htmlToText';
|
||||
|
||||
export const useTextToSpeech = (html, markChapterAdRead) => {
|
||||
const [ttsStatus, setTtsStatus] = useState();
|
||||
const [ttsPosition, setTtsPosition] = useState({ end: 0 });
|
||||
|
||||
let text = htmlToText(html);
|
||||
|
||||
export const useTextToSpeech = (sentences, markChapterAsRead) => {
|
||||
const [ttsStatus, setTtsStatus] = useState({});
|
||||
const ttsPosition = useRef(0);
|
||||
useEffect(() => {
|
||||
Tts.addEventListener('tts-start', () => setTtsStatus('start'));
|
||||
Tts.addEventListener('tts-progress', event => {
|
||||
setTtsStatus('progress');
|
||||
setTtsPosition(event);
|
||||
});
|
||||
Tts.addEventListener('tts-finish', () => {
|
||||
setTtsStatus('finish');
|
||||
markChapterAdRead();
|
||||
if (ttsPosition.current == sentences.length - 1) {
|
||||
markChapterAsRead();
|
||||
setTtsStatus('finish');
|
||||
}
|
||||
ttsPosition.current = ttsPosition.current + 1;
|
||||
});
|
||||
Tts.addEventListener('tts-cancel', () => setTtsStatus('paused'));
|
||||
|
||||
return () => Tts.stop();
|
||||
}, []);
|
||||
return () => {
|
||||
Tts.removeAllListeners('tts-finish');
|
||||
Tts.stop();
|
||||
};
|
||||
}, [sentences.length]);
|
||||
// for the first time rendering, chapter was not loaded.
|
||||
// then htmlToText function would return
|
||||
// "Chapter is empty.\n\nReport if it's available in webview." (length = 3)
|
||||
|
||||
const startTts = () => {
|
||||
if (ttsStatus === 'progress') {
|
||||
setTtsPosition({ end: 0 });
|
||||
setTtsStatus('finish');
|
||||
setTtsStatus('paused');
|
||||
Tts.stop();
|
||||
return;
|
||||
}
|
||||
|
||||
if (text.length >= 3999) {
|
||||
const splitNChars = (txt, num) => {
|
||||
let result = [];
|
||||
for (let i = 0; i < txt.length; i += num) {
|
||||
result.push(txt.substr(i, num));
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
let splitMe = splitNChars(text, 3999);
|
||||
|
||||
splitMe.forEach(value => {
|
||||
Tts.speak(value, {
|
||||
androidParams: {
|
||||
KEY_PARAM_STREAM: 'STREAM_MUSIC',
|
||||
},
|
||||
});
|
||||
});
|
||||
} else {
|
||||
Tts.stop();
|
||||
Tts.speak(text, {
|
||||
setTtsStatus('progress');
|
||||
Tts.stop();
|
||||
for (let i = ttsPosition.current; i < sentences.length; i++) {
|
||||
Tts.speak(sentences[i], {
|
||||
androidParams: {
|
||||
KEY_PARAM_STREAM: 'STREAM_MUSIC',
|
||||
},
|
||||
@@ -59,42 +39,5 @@ export const useTextToSpeech = (html, markChapterAdRead) => {
|
||||
}
|
||||
};
|
||||
|
||||
const pauseTts = () => {
|
||||
if (ttsStatus === 'progress') {
|
||||
setTtsStatus('paused');
|
||||
Tts.stop();
|
||||
return;
|
||||
} else {
|
||||
text = text.slice(ttsPosition.end);
|
||||
|
||||
if (text.length >= 3999) {
|
||||
const splitNChars = (txt, num) => {
|
||||
let result = [];
|
||||
for (let i = 0; i < txt.length; i += num) {
|
||||
result.push(txt.substr(i, num));
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
let splitMe = splitNChars(text, 3999);
|
||||
|
||||
splitMe.forEach(value => {
|
||||
Tts.speak(value, {
|
||||
androidParams: {
|
||||
KEY_PARAM_STREAM: 'STREAM_MUSIC',
|
||||
},
|
||||
});
|
||||
});
|
||||
} else {
|
||||
Tts.stop();
|
||||
Tts.speak(text, {
|
||||
androidParams: {
|
||||
KEY_PARAM_STREAM: 'STREAM_MUSIC',
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return [ttsStatus, ttsPosition, startTts, pauseTts];
|
||||
return [ttsStatus, startTts];
|
||||
};
|
||||
|
||||
+39
-13
@@ -1,33 +1,59 @@
|
||||
import { useMemo } from 'react';
|
||||
import { Appearance } from 'react-native';
|
||||
import {
|
||||
useMMKVBoolean,
|
||||
useMMKVObject,
|
||||
useMMKVString,
|
||||
} from 'react-native-mmkv';
|
||||
import { Appearance } from 'react-native';
|
||||
import { defaultTheme } from '../theme/md3/defaultTheme';
|
||||
import { MD3ThemeType } from '../theme/types';
|
||||
import { useMemo } from 'react';
|
||||
import { overlay } from 'react-native-paper';
|
||||
import Color from 'color';
|
||||
|
||||
export const useTheme = (): MD3ThemeType => {
|
||||
const [appTheme] = useMMKVObject<MD3ThemeType>('APP_THEME');
|
||||
import { defaultTheme } from '@theme/md3/defaultTheme';
|
||||
import { ThemeColors } from '@theme/types';
|
||||
|
||||
const getElevationColor = (colors: ThemeColors, elevation: number) => {
|
||||
return Color(colors.surface)
|
||||
.mix(Color(colors.primary), elevation)
|
||||
.rgb()
|
||||
.string();
|
||||
};
|
||||
|
||||
export const useTheme = (): ThemeColors => {
|
||||
const [appTheme] = useMMKVObject<ThemeColors>('APP_THEME');
|
||||
const [isAmoledBlack] = useMMKVBoolean('AMOLED_BLACK');
|
||||
const [customAccent] = useMMKVString('CUSTOM_ACCENT_COLOR');
|
||||
|
||||
const theme: MD3ThemeType = useMemo(() => {
|
||||
let colors =
|
||||
const theme: ThemeColors = useMemo(() => {
|
||||
const isDeviveColorSchemeDark = Appearance.getColorScheme() === 'dark';
|
||||
|
||||
let colors: ThemeColors =
|
||||
appTheme ||
|
||||
((Appearance.getColorScheme() === 'dark'
|
||||
? defaultTheme.dark
|
||||
: defaultTheme.light) as MD3ThemeType);
|
||||
(isDeviveColorSchemeDark ? defaultTheme.dark : defaultTheme.light);
|
||||
|
||||
if (isAmoledBlack && colors.isDark) {
|
||||
colors = { ...colors, background: '#000000', surface: '#000000' };
|
||||
colors = {
|
||||
...colors,
|
||||
background: '#000000',
|
||||
surface: '#000000',
|
||||
};
|
||||
}
|
||||
|
||||
if (customAccent) {
|
||||
colors = { ...colors, primary: customAccent, secondary: customAccent };
|
||||
colors = {
|
||||
...colors,
|
||||
primary: customAccent,
|
||||
secondary: customAccent,
|
||||
};
|
||||
}
|
||||
|
||||
colors = {
|
||||
...colors,
|
||||
surface2: getElevationColor(colors, 0.08),
|
||||
overlay3: overlay(3, colors.surface),
|
||||
rippleColor: Color(colors.primary).alpha(0.12).toString(),
|
||||
surfaceReader: Color(colors.surface).alpha(0.9).toString(),
|
||||
};
|
||||
|
||||
return colors;
|
||||
}, [appTheme?.id, isAmoledBlack, customAccent]);
|
||||
|
||||
|
||||
@@ -25,12 +25,7 @@ const BottomNavigator = () => {
|
||||
|
||||
return (
|
||||
<Tab.Navigator
|
||||
barStyle={{
|
||||
backgroundColor: Color(theme.surface)
|
||||
.mix(Color(theme.primary), 0.08)
|
||||
.rgb()
|
||||
.string(),
|
||||
}}
|
||||
barStyle={{ backgroundColor: theme.surface2 }}
|
||||
theme={{ colors: theme }}
|
||||
activeColor={theme.onSecondaryContainer}
|
||||
shifting={!showLabelsInNav}
|
||||
|
||||
@@ -9,7 +9,7 @@ import TrackerSettings from '../screens/settings/SettingsTrackerScreen';
|
||||
import ReaderSettings from '../screens/settings/SettingsReaderScreen/SettingsReaderScreen';
|
||||
import BackupSettings from '../screens/settings/SettingsBackupScreen';
|
||||
import AdvancedSettings from '../screens/settings/SettingsAdvancedScreen';
|
||||
import GeneralSettings from '../screens/settings/SettingsGeneralScreen';
|
||||
import GeneralSettings from '../screens/settings/SettingsGeneralScreen/SettingsGeneralScreen';
|
||||
import DownloadQueue from '../screens/more/DownloadQueueScreen';
|
||||
import Downloads from '../screens/more/DownloadsScreen';
|
||||
import AppearanceSettings from '../screens/settings/SettingsAppearanceScreen';
|
||||
|
||||
@@ -13,9 +13,6 @@ export const useSettingsV2 = () =>
|
||||
export const useBrowseSettings = () =>
|
||||
useAppSelector((state: RootState) => state.settingsReducerV2.browse) || {};
|
||||
|
||||
export const useAppearanceSettings = () =>
|
||||
useAppSelector((state: RootState) => state.settingsReducerV2.appearance);
|
||||
|
||||
export const useReaderSettings = () =>
|
||||
useAppSelector((state: RootState) => state.settingsReducer.reader);
|
||||
|
||||
@@ -23,9 +20,6 @@ export const useReaderSettings = () =>
|
||||
export const useLibrarySettings = () =>
|
||||
useAppSelector((state: RootState) => state.settingsReducerV2.library);
|
||||
|
||||
export const useUpdateSettings = () =>
|
||||
useAppSelector((state: RootState) => state.settingsReducerV2.updates);
|
||||
|
||||
export const useDownloadQueue = () =>
|
||||
useAppSelector((state: RootState) => state.downloadsReducer.downloadQueue);
|
||||
|
||||
|
||||
@@ -39,7 +39,6 @@ import {
|
||||
} from '../../database/queries/ChapterQueries';
|
||||
import { deleteUpdateFromDb } from '../../database/queries/UpdateQueries';
|
||||
import {
|
||||
SAVE_SCROLL_POSITION,
|
||||
SET_CHAPTER_LIST_PREF,
|
||||
SET_LAST_READ,
|
||||
} from '../preferences/preference.types';
|
||||
@@ -47,16 +46,6 @@ import { showToast } from '../../hooks/showToast';
|
||||
|
||||
import * as Notifications from 'expo-notifications';
|
||||
|
||||
Notifications.setNotificationHandler({
|
||||
handleNotification: async () => {
|
||||
return {
|
||||
shouldShowAlert: true,
|
||||
shouldPlaySound: true,
|
||||
shouldSetBadge: true,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
import BackgroundService from 'react-native-background-actions';
|
||||
import { SET_DOWNLOAD_QUEUE } from '../downloads/donwloads.types';
|
||||
import { updateNovel } from '../../services/updates/LibraryUpdateQueries';
|
||||
@@ -205,19 +194,6 @@ export const markChapterReadAction = (chapterId, novelId) => async dispatch => {
|
||||
type: SET_LAST_READ,
|
||||
payload: { novelId, chapterId: nextChapter.chapterId },
|
||||
});
|
||||
|
||||
/**
|
||||
* Reset progress on marked read
|
||||
*/
|
||||
dispatch({
|
||||
type: SAVE_SCROLL_POSITION,
|
||||
payload: {
|
||||
position: 0,
|
||||
percentage: 0,
|
||||
chapterId,
|
||||
novelId,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const markPreviousChaptersReadAction =
|
||||
|
||||
@@ -63,17 +63,14 @@ export const initialState = {
|
||||
fullScreenMode: true,
|
||||
swipeGestures: false,
|
||||
showScrollPercentage: true,
|
||||
useWebViewForChapter: false,
|
||||
wvUseNewSwipes: false,
|
||||
wvShowSwipeMargins: true,
|
||||
wvUseVolumeButtons: false,
|
||||
useVolumeButtons: false,
|
||||
scrollAmount: 200,
|
||||
showBatteryAndTime: false,
|
||||
autoScroll: false,
|
||||
autoScrollInterval: 10,
|
||||
autoScrollOffset: null,
|
||||
verticalSeekbar: true,
|
||||
removeExtraParagraphSpacing: false,
|
||||
useChapterDrawerSwipeNavigation: true,
|
||||
|
||||
reader: {
|
||||
theme: '#292832',
|
||||
@@ -84,6 +81,7 @@ export const initialState = {
|
||||
fontFamily: '',
|
||||
lineHeight: 1.5,
|
||||
customCSS: '',
|
||||
customJS: '',
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -1,8 +1,34 @@
|
||||
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
||||
import AllSources from '../../sources/sources.json';
|
||||
|
||||
import { translations } from 'i18n-js';
|
||||
import { localization } from '../../../strings/translations';
|
||||
import { Source } from '../../sources/types';
|
||||
|
||||
const languages = {
|
||||
'en': 'English',
|
||||
'es': 'Spanish',
|
||||
'tr': 'Turkish',
|
||||
'ru': 'Russian',
|
||||
'ar': 'Arabic',
|
||||
'uk': 'Ukrainian',
|
||||
'pt': 'Portuguese',
|
||||
'pt-BR': 'Portuguese',
|
||||
'de': 'German',
|
||||
'it': 'Italian',
|
||||
'zh-CN': 'Chinese',
|
||||
'zh-TW': 'Chinese',
|
||||
'vi': 'Vietnamese',
|
||||
'ja': 'Japanese',
|
||||
};
|
||||
// Hope you can do something to synchronize translation system.
|
||||
// Also take care of some case like vi-VN: Vietnamese not vi
|
||||
export const defaultLanguage =
|
||||
localization in translations || localization.split('-')[0] in translations
|
||||
? languages[localization] || languages[localization.split('-')[0]]
|
||||
: 'English';
|
||||
// That's why this code is so long :(
|
||||
|
||||
interface SourcesState {
|
||||
allSources: Source[];
|
||||
searchResults: Source[];
|
||||
@@ -16,7 +42,7 @@ const initialState: SourcesState = {
|
||||
searchResults: [],
|
||||
pinnedSourceIds: [],
|
||||
lastUsed: null,
|
||||
languageFilters: ['English'],
|
||||
languageFilters: [defaultLanguage],
|
||||
};
|
||||
|
||||
export const sourcesSlice = createSlice({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useCallback, useRef } from 'react';
|
||||
import React, { useCallback, useEffect, useRef } from 'react';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
|
||||
import { FAB, Portal } from 'react-native-paper';
|
||||
@@ -8,7 +8,7 @@ import NovelCover from '@components/NovelCover';
|
||||
import Bottomsheet from '@gorhom/bottom-sheet';
|
||||
import FilterBottomSheet from './components/FilterBottomSheet';
|
||||
|
||||
import { useCategorySettings, useSearch } from '../../hooks';
|
||||
import { useCategorySettings, usePreviousRouteName, useSearch } from '@hooks';
|
||||
import { useTheme } from '@hooks/useTheme';
|
||||
import { useBrowseSource, useSearchSource } from './useBrowseSource';
|
||||
|
||||
@@ -35,6 +35,7 @@ interface BrowseSourceScreenProps {
|
||||
const BrowseSourceScreen: React.FC<BrowseSourceScreenProps> = ({ route }) => {
|
||||
const theme = useTheme();
|
||||
const { navigate, goBack } = useNavigation();
|
||||
const previousScreen = usePreviousRouteName();
|
||||
|
||||
const {
|
||||
sourceId,
|
||||
@@ -52,6 +53,7 @@ const BrowseSourceScreen: React.FC<BrowseSourceScreenProps> = ({ route }) => {
|
||||
filterValues,
|
||||
setFilters,
|
||||
clearFilters,
|
||||
refetchNovels,
|
||||
} = useBrowseSource(sourceId, showLatestNovels);
|
||||
|
||||
const { defaultCategoryId = 1 } = useCategorySettings();
|
||||
@@ -74,6 +76,12 @@ const BrowseSourceScreen: React.FC<BrowseSourceScreenProps> = ({ route }) => {
|
||||
clearSearchResults();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (previousScreen === 'WebviewScreen') {
|
||||
refetchNovels();
|
||||
}
|
||||
}, [previousScreen]);
|
||||
|
||||
const handleOpenWebView = async () => {
|
||||
navigate('WebviewScreen', {
|
||||
sourceId,
|
||||
@@ -94,10 +102,8 @@ const BrowseSourceScreen: React.FC<BrowseSourceScreenProps> = ({ route }) => {
|
||||
navigate(
|
||||
'Novel' as never,
|
||||
{
|
||||
novelName: item.novelName,
|
||||
novelCover: item.novelCover,
|
||||
novelUrl: item.novelUrl,
|
||||
sourceId,
|
||||
...item,
|
||||
sourceId: sourceId,
|
||||
} as never,
|
||||
),
|
||||
[sourceId],
|
||||
@@ -123,7 +129,6 @@ const BrowseSourceScreen: React.FC<BrowseSourceScreenProps> = ({ route }) => {
|
||||
) : errorMessage || novelList.length === 0 ? (
|
||||
<ErrorScreenV2
|
||||
error={errorMessage || getString('sourceScreen.noResultsFound')}
|
||||
theme={theme}
|
||||
/>
|
||||
) : (
|
||||
<NovelList
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import React, { Ref, useState } from 'react';
|
||||
import { Pressable, StyleSheet, Text, View } from 'react-native';
|
||||
import color from 'color';
|
||||
|
||||
import BottomSheet from '../../../components/BottomSheet/BottomSheet';
|
||||
import BottomSheetType, { BottomSheetView } from '@gorhom/bottom-sheet';
|
||||
@@ -13,10 +12,8 @@ import {
|
||||
} from '../../../sources/types/filterTypes';
|
||||
import { FlatList } from 'react-native-gesture-handler';
|
||||
import { Button, IconButtonV2 } from '@components/index';
|
||||
import { ButtonVariation } from '@components/Button/Button';
|
||||
import { dividerColor } from '../../../theme/colors';
|
||||
import { Checkbox } from '@components/Checkbox/Checkbox';
|
||||
import { defaultTo } from 'lodash';
|
||||
import { defaultTo } from 'lodash-es';
|
||||
import { Picker } from '@react-native-picker/picker';
|
||||
import useBoolean from '@hooks/useBoolean';
|
||||
import { overlay } from 'react-native-paper';
|
||||
@@ -44,7 +41,7 @@ const FilterItem: React.FC<FilterItemProps> = ({
|
||||
if (filter.inputType === FilterInputs.Picker) {
|
||||
return (
|
||||
<View style={styles.pickerContainer}>
|
||||
<Text style={[styles.pickerLabel, { color: theme.textColorSecondary }]}>
|
||||
<Text style={[styles.pickerLabel, { color: theme.onSurfaceVariant }]}>
|
||||
{filter.label}
|
||||
</Text>
|
||||
<Picker
|
||||
@@ -77,11 +74,9 @@ const FilterItem: React.FC<FilterItemProps> = ({
|
||||
<Pressable
|
||||
style={styles.checkboxHeader}
|
||||
onPress={toggleCard}
|
||||
android_ripple={{ color: color(theme.primary).alpha(0.12).string() }}
|
||||
android_ripple={{ color: theme.rippleColor }}
|
||||
>
|
||||
<Text
|
||||
style={[styles.filterLabel, { color: theme.textColorSecondary }]}
|
||||
>
|
||||
<Text style={[styles.filterLabel, { color: theme.onSurfaceVariant }]}>
|
||||
{filter.label}
|
||||
</Text>
|
||||
<IconButtonV2
|
||||
@@ -149,28 +144,23 @@ const FilterBottomSheet: React.FC<BottomSheetProps> = ({
|
||||
]}
|
||||
>
|
||||
<BottomSheetView
|
||||
style={[
|
||||
styles.buttonContainer,
|
||||
{ borderBottomColor: dividerColor(theme.isDark) },
|
||||
]}
|
||||
style={[styles.buttonContainer, { borderBottomColor: theme.outline }]}
|
||||
>
|
||||
<Button
|
||||
title={'Reset'}
|
||||
variation={ButtonVariation.CLEAR}
|
||||
onPress={() => {
|
||||
setSelectedFilters(undefined);
|
||||
clearFilters();
|
||||
}}
|
||||
theme={theme}
|
||||
/>
|
||||
<Button
|
||||
title={'Filter'}
|
||||
textColor={theme.textColorPrimary}
|
||||
textColor={theme.onSurface}
|
||||
onPress={() => {
|
||||
setFilters(selectedFilters);
|
||||
filterSheetRef?.current?.collapse();
|
||||
}}
|
||||
theme={theme}
|
||||
mode="contained"
|
||||
/>
|
||||
</BottomSheetView>
|
||||
<FlatList
|
||||
|
||||
@@ -11,17 +11,15 @@ export const useBrowseSource = (
|
||||
const [novels, setNovels] = useState<SourceNovelItem[]>([]);
|
||||
const [error, setError] = useState<string>();
|
||||
|
||||
const [totalPages, setTotalPages] = useState(1);
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [filterValues, setFilterValues] = useState<SourceFilter[]>();
|
||||
const [selectedFilters, setSelectedFilters] = useState<
|
||||
SelectedFilter | undefined
|
||||
>();
|
||||
const [hasNextPage, setHasNextPage] = useState(true);
|
||||
|
||||
const isScreenMounted = useRef(true);
|
||||
|
||||
const hasNextPage = currentPage <= totalPages;
|
||||
|
||||
const fetchNovels = useCallback(
|
||||
async (page: number, filters?: SelectedFilter) => {
|
||||
if (isScreenMounted.current === true) {
|
||||
@@ -34,7 +32,9 @@ export const useBrowseSource = (
|
||||
setNovels(prevState =>
|
||||
page === 1 ? res.novels : [...prevState, ...res.novels],
|
||||
);
|
||||
setTotalPages(res.totalPages);
|
||||
if (!res.novels.length) {
|
||||
setHasNextPage(false);
|
||||
}
|
||||
setFilterValues(source.filters);
|
||||
} catch (err: unknown) {
|
||||
setError(`${err}`);
|
||||
@@ -54,6 +54,11 @@ export const useBrowseSource = (
|
||||
fetchNovels(currentPage, selectedFilters);
|
||||
}, [fetchNovels, currentPage]);
|
||||
|
||||
const refetchNovels = () => {
|
||||
setCurrentPage(1);
|
||||
fetchNovels(1);
|
||||
};
|
||||
|
||||
/**
|
||||
* On screen unmount
|
||||
*/
|
||||
@@ -81,6 +86,7 @@ export const useBrowseSource = (
|
||||
filterValues,
|
||||
setFilters,
|
||||
clearFilters,
|
||||
refetchNovels,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ import { getString } from '@strings/translations';
|
||||
|
||||
import { Category } from '../../database/types';
|
||||
import CategoryCard from './components/CategoryCard';
|
||||
import { orderBy } from 'lodash';
|
||||
import { orderBy } from 'lodash-es';
|
||||
import CategorySkeletonLoading from './components/CategorySkeletonLoading';
|
||||
|
||||
const CategoriesScreen = () => {
|
||||
|
||||
@@ -2,7 +2,6 @@ import React, { useState } from 'react';
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
import { Modal, overlay, Portal, TextInput } from 'react-native-paper';
|
||||
|
||||
import { ButtonVariation } from '@components/Button/Button';
|
||||
import { Button } from '@components/index';
|
||||
|
||||
import { Category } from '../../../database/types';
|
||||
@@ -44,7 +43,7 @@ const AddCategoryModal: React.FC<AddCategoryModalProps> = ({
|
||||
{ backgroundColor: overlay(2, theme.surface) },
|
||||
]}
|
||||
>
|
||||
<Text style={[styles.modalTitle, { color: theme.textColorPrimary }]}>
|
||||
<Text style={[styles.modalTitle, { color: theme.onSurface }]}>
|
||||
{getString(
|
||||
isEditMode
|
||||
? 'categories.editCategories'
|
||||
@@ -57,14 +56,12 @@ const AddCategoryModal: React.FC<AddCategoryModalProps> = ({
|
||||
placeholder={getString('common.name')}
|
||||
onChangeText={setCategoryName}
|
||||
mode="outlined"
|
||||
underlineColor={theme.textColorHint}
|
||||
underlineColor={theme.outline}
|
||||
theme={{ colors: { ...theme } }}
|
||||
/>
|
||||
<View style={styles.btnContainer}>
|
||||
<Button
|
||||
title={getString(isEditMode ? 'common.ok' : 'common.add')}
|
||||
theme={theme}
|
||||
variation={ButtonVariation.CLEAR}
|
||||
onPress={async () => {
|
||||
if (await isCategoryNameDuplicate(categoryName)) {
|
||||
showToast(getString('categories.duplicateError'));
|
||||
@@ -80,12 +77,7 @@ const AddCategoryModal: React.FC<AddCategoryModalProps> = ({
|
||||
closeModal();
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
title={getString('common.cancel')}
|
||||
theme={theme}
|
||||
variation={ButtonVariation.CLEAR}
|
||||
onPress={closeModal}
|
||||
/>
|
||||
<Button title={getString('common.cancel')} onPress={closeModal} />
|
||||
</View>
|
||||
</Modal>
|
||||
</Portal>
|
||||
|
||||
@@ -2,13 +2,13 @@ import React, { memo } from 'react';
|
||||
import { StyleSheet, View } from 'react-native';
|
||||
import { createShimmerPlaceholder } from 'react-native-shimmer-placeholder';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import { MD3ThemeType } from '@theme/types';
|
||||
import { ThemeColors } from '@theme/types';
|
||||
import getLoadingColors from '@utils/getLoadingColors';
|
||||
|
||||
interface Props {
|
||||
width: number;
|
||||
height: number;
|
||||
theme: MD3ThemeType;
|
||||
theme: ThemeColors;
|
||||
}
|
||||
|
||||
const CategorySkeletonLoading: React.FC<Props> = ({ height, width, theme }) => {
|
||||
|
||||
@@ -2,7 +2,6 @@ import React from 'react';
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
import { Modal, Portal } from 'react-native-paper';
|
||||
|
||||
import { ButtonVariation } from '@components/Button/Button';
|
||||
import { Button } from '@components/index';
|
||||
|
||||
import { Category } from '../../../database/types';
|
||||
@@ -11,7 +10,6 @@ import { useTheme } from '@hooks/useTheme';
|
||||
|
||||
import { getString } from '@strings/translations';
|
||||
import { resetCategoryIdsToDefault } from '../../../database/queries/NovelQueriesV2';
|
||||
import { getDialogBackground } from '../../../theme/colors';
|
||||
|
||||
interface DeleteCategoryModalProps {
|
||||
category: Category;
|
||||
@@ -35,21 +33,19 @@ const DeleteCategoryModal: React.FC<DeleteCategoryModalProps> = ({
|
||||
onDismiss={closeModal}
|
||||
contentContainerStyle={[
|
||||
styles.modalContainer,
|
||||
{ backgroundColor: getDialogBackground(theme) },
|
||||
{ backgroundColor: theme.overlay3 },
|
||||
]}
|
||||
>
|
||||
<Text style={[styles.modalTitle, { color: theme.textColorPrimary }]}>
|
||||
<Text style={[styles.modalTitle, { color: theme.onSurface }]}>
|
||||
{getString('categories.deleteModal.header')}
|
||||
</Text>
|
||||
<Text style={[styles.modalDesc, { color: theme.textColorSecondary }]}>
|
||||
<Text style={[styles.modalDesc, { color: theme.onSurfaceVariant }]}>
|
||||
{getString('categories.deleteModal.desc')}
|
||||
{` "${category.name}"?`}
|
||||
</Text>
|
||||
<View style={styles.btnContainer}>
|
||||
<Button
|
||||
title={getString('common.ok')}
|
||||
theme={theme}
|
||||
variation={ButtonVariation.CLEAR}
|
||||
onPress={() => {
|
||||
deleteCategoryById(category.id);
|
||||
resetCategoryIdsToDefault(category.id);
|
||||
@@ -57,12 +53,7 @@ const DeleteCategoryModal: React.FC<DeleteCategoryModalProps> = ({
|
||||
onSuccess();
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
title={getString('common.cancel')}
|
||||
theme={theme}
|
||||
variation={ButtonVariation.CLEAR}
|
||||
onPress={closeModal}
|
||||
/>
|
||||
<Button title={getString('common.cancel')} onPress={closeModal} />
|
||||
</View>
|
||||
</Modal>
|
||||
</Portal>
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
import { Dimensions, Pressable, StyleSheet, Text, View } from 'react-native';
|
||||
import React, { useMemo } from 'react';
|
||||
import color from 'color';
|
||||
import FastImage from 'react-native-fast-image';
|
||||
|
||||
import { coverPlaceholderColor } from '../../../theme/colors';
|
||||
|
||||
import { SourceNovelItem } from '../../../sources/types';
|
||||
import { MD3ThemeType } from '../../../theme/types';
|
||||
import { ThemeColors } from '../../../theme/types';
|
||||
import { getString } from '@strings/translations';
|
||||
|
||||
interface Props {
|
||||
novel: SourceNovelItem;
|
||||
navigateToNovel: (novel: SourceNovelItem) => void;
|
||||
theme: MD3ThemeType;
|
||||
theme: ThemeColors;
|
||||
onLongPress?: () => void;
|
||||
inLibrary?: boolean;
|
||||
}
|
||||
@@ -37,7 +36,7 @@ const GlobalSearchNovelItem: React.FC<Props> = ({
|
||||
<View style={styles.novelItem}>
|
||||
<Pressable
|
||||
style={styles.pressable}
|
||||
android_ripple={{ color: color(theme.primary).alpha(0.12).string() }}
|
||||
android_ripple={{ color: theme.rippleColor }}
|
||||
onPress={() => navigateToNovel(novel)}
|
||||
onLongPress={onLongPress}
|
||||
>
|
||||
@@ -60,7 +59,7 @@ const GlobalSearchNovelItem: React.FC<Props> = ({
|
||||
) : null}
|
||||
<Text
|
||||
style={[
|
||||
{ color: theme.textColorPrimary, width: novelItemDimensions.width },
|
||||
{ color: theme.onSurface, width: novelItemDimensions.width },
|
||||
styles.novelName,
|
||||
]}
|
||||
numberOfLines={2}
|
||||
|
||||
@@ -66,13 +66,11 @@ const GlobalSearchResultsList: React.FC<GlobalSearchResultsListProps> = ({
|
||||
}
|
||||
>
|
||||
<View>
|
||||
<Text
|
||||
style={[styles.sourceName, { color: theme.textColorPrimary }]}
|
||||
>
|
||||
<Text style={[styles.sourceName, { color: theme.onSurface }]}>
|
||||
{item.source.sourceName}
|
||||
</Text>
|
||||
<Text
|
||||
style={[styles.language, { color: theme.textColorSecondary }]}
|
||||
style={[styles.language, { color: theme.onSurfaceVariant }]}
|
||||
>
|
||||
{item.source.lang}
|
||||
</Text>
|
||||
@@ -80,7 +78,7 @@ const GlobalSearchResultsList: React.FC<GlobalSearchResultsListProps> = ({
|
||||
<MaterialCommunityIcons
|
||||
name="arrow-right"
|
||||
size={24}
|
||||
color={theme.textColorPrimary}
|
||||
color={theme.onSurface}
|
||||
/>
|
||||
</Pressable>
|
||||
{item.isLoading ? (
|
||||
@@ -101,7 +99,7 @@ const GlobalSearchResultsList: React.FC<GlobalSearchResultsListProps> = ({
|
||||
<Text
|
||||
style={[
|
||||
styles.listEmpty,
|
||||
{ color: theme.textColorSecondary },
|
||||
{ color: theme.onSurfaceVariant },
|
||||
]}
|
||||
>
|
||||
{getString('sourceScreen.noResultsFound')}
|
||||
|
||||
@@ -72,7 +72,7 @@ const StatsScreen = () => {
|
||||
return (
|
||||
<>
|
||||
{Header}
|
||||
<ErrorScreenV2 theme={theme} />
|
||||
<ErrorScreenV2 error={error} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -84,7 +84,7 @@ const StatsScreen = () => {
|
||||
style={styles.screenCtn}
|
||||
contentContainerStyle={styles.contentCtn}
|
||||
>
|
||||
<Text style={[styles.header, { color: theme.textColorSecondary }]}>
|
||||
<Text style={[styles.header, { color: theme.onSurfaceVariant }]}>
|
||||
{getString('moreScreen.settingsScreen.generalSettings')}
|
||||
</Text>
|
||||
<Row style={styles.statsRow}>
|
||||
@@ -114,7 +114,7 @@ const StatsScreen = () => {
|
||||
<Row style={styles.statsRow}>
|
||||
<StatsCard label="Sources" value={stats.sourcesCount} />
|
||||
</Row>
|
||||
<Text style={[styles.header, { color: theme.textColorSecondary }]}>
|
||||
<Text style={[styles.header, { color: theme.onSurfaceVariant }]}>
|
||||
{getString('statsScreen.genreDistribution')}
|
||||
</Text>
|
||||
<Row style={[styles.statsRow, styles.genreRow]}>
|
||||
@@ -122,7 +122,7 @@ const StatsScreen = () => {
|
||||
<StatsCard key={item[0]} label={item[0]} value={item[1]} />
|
||||
))}
|
||||
</Row>
|
||||
<Text style={[styles.header, { color: theme.textColorSecondary }]}>
|
||||
<Text style={[styles.header, { color: theme.onSurfaceVariant }]}>
|
||||
{getString('statsScreen.statusDistribution')}
|
||||
</Text>
|
||||
<Row style={[styles.statsRow, styles.genreRow]}>
|
||||
@@ -159,7 +159,7 @@ export const StatsCard: React.FC<{ label: string; value?: number }> = ({
|
||||
]}
|
||||
>
|
||||
<Text style={[styles.statsVal, { color: theme.primary }]}>{value}</Text>
|
||||
<Text style={{ color: theme.textColorPrimary }}> {label}</Text>
|
||||
<Text style={{ color: theme.onSurface }}> {label}</Text>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -3,6 +3,7 @@ import React, { useCallback, useEffect, useMemo } from 'react';
|
||||
|
||||
import { EmptyView, SearchbarV2 } from '../../components';
|
||||
import {
|
||||
defaultLanguage,
|
||||
getSourcesAction,
|
||||
searchSourcesAction,
|
||||
setLastUsedSource,
|
||||
@@ -42,7 +43,7 @@ const BrowseScreen = () => {
|
||||
allSources,
|
||||
searchResults,
|
||||
pinnedSourceIds = [],
|
||||
languageFilters = ['English'],
|
||||
languageFilters = [defaultLanguage || 'English'], //defaultLang cant be null, but just for sure
|
||||
lastUsed,
|
||||
} = useSourcesReducer();
|
||||
|
||||
@@ -159,7 +160,7 @@ const BrowseScreen = () => {
|
||||
<Text
|
||||
style={[
|
||||
styles.sectionHeader,
|
||||
{ color: theme.textColorSecondary },
|
||||
{ color: theme.onSurfaceVariant },
|
||||
]}
|
||||
>
|
||||
{getString('browseScreen.discover')}
|
||||
@@ -174,7 +175,7 @@ const BrowseScreen = () => {
|
||||
<Text
|
||||
style={[
|
||||
styles.sectionHeader,
|
||||
{ color: theme.textColorSecondary },
|
||||
{ color: theme.onSurfaceVariant },
|
||||
]}
|
||||
>
|
||||
{header}
|
||||
|
||||
@@ -42,7 +42,7 @@ const SourceNovels = ({ navigation, route }) => {
|
||||
ListEmptyComponent={
|
||||
<Text
|
||||
style={{
|
||||
color: theme.textColorSecondary,
|
||||
color: theme.onSurfaceVariant,
|
||||
padding: 20,
|
||||
textAlign: 'center',
|
||||
}}
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
import React from 'react';
|
||||
import { StyleSheet, Text, View, Image, Pressable } from 'react-native';
|
||||
import color from 'color';
|
||||
|
||||
import { getString } from '../../../../../strings/translations';
|
||||
import { Button, IconButtonV2 } from '../../../../components';
|
||||
import { ButtonVariation } from '../../../../components/Button/Button';
|
||||
|
||||
import { Source } from '../../../../sources/types';
|
||||
import { coverPlaceholderColor } from '../../../../theme/colors';
|
||||
import { MD3ThemeType } from '../../../../theme/types';
|
||||
import { ThemeColors } from '../../../../theme/types';
|
||||
|
||||
interface Props {
|
||||
source: Source;
|
||||
isPinned: boolean;
|
||||
theme: MD3ThemeType;
|
||||
theme: ThemeColors;
|
||||
onTogglePinSource: (sourceId: number) => void;
|
||||
navigateToSource: (source: Source, showLatestNovels?: boolean) => void;
|
||||
}
|
||||
@@ -28,15 +26,13 @@ const SourceCard: React.FC<Props> = ({
|
||||
<Pressable
|
||||
style={styles.container}
|
||||
onPress={() => navigateToSource(source)}
|
||||
android_ripple={{ color: color(theme.primary).alpha(0.12).string() }}
|
||||
android_ripple={{ color: theme.rippleColor }}
|
||||
>
|
||||
<View style={styles.flexRow}>
|
||||
<Image source={{ uri: source.icon }} style={styles.icon} />
|
||||
<View style={styles.details}>
|
||||
<Text style={{ color: theme.textColorPrimary }}>
|
||||
{source.sourceName}
|
||||
</Text>
|
||||
<Text style={[{ color: theme.textColorSecondary }, styles.lang]}>
|
||||
<Text style={{ color: theme.onSurface }}>{source.sourceName}</Text>
|
||||
<Text style={[{ color: theme.onSurfaceVariant }, styles.lang]}>
|
||||
{source.lang}
|
||||
</Text>
|
||||
</View>
|
||||
@@ -44,15 +40,13 @@ const SourceCard: React.FC<Props> = ({
|
||||
<View style={styles.flexRow}>
|
||||
<Button
|
||||
title={getString('browseScreen.latest')}
|
||||
variation={ButtonVariation.CLEAR}
|
||||
textColor={theme.primary}
|
||||
onPress={() => navigateToSource(source, true)}
|
||||
theme={theme}
|
||||
/>
|
||||
<IconButtonV2
|
||||
name={isPinned ? 'pin' : 'pin-outline'}
|
||||
size={22}
|
||||
color={isPinned ? theme.primary : theme.textColorSecondary}
|
||||
color={isPinned ? theme.primary : theme.onSurfaceVariant}
|
||||
onPress={() => onTogglePinSource(source.sourceId)}
|
||||
theme={theme}
|
||||
/>
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import { getRippleColor } from '@theme/colors';
|
||||
import React from 'react';
|
||||
import { StyleSheet, Text, View, Image, Pressable } from 'react-native';
|
||||
import { getString } from '../../../../../strings/translations';
|
||||
import { Button } from '../../../../components';
|
||||
import { ButtonVariation } from '../../../../components/Button/Button';
|
||||
|
||||
import { MD3ThemeType } from '../../../../theme/types';
|
||||
import { ThemeColors } from '../../../../theme/types';
|
||||
|
||||
interface Props {
|
||||
theme: MD3ThemeType;
|
||||
theme: ThemeColors;
|
||||
}
|
||||
|
||||
const MalCard: React.FC<Props> = ({ theme }) => {
|
||||
@@ -19,7 +17,7 @@ const MalCard: React.FC<Props> = ({ theme }) => {
|
||||
<Pressable
|
||||
style={styles.container}
|
||||
onPress={() => navigate('BrowseMal' as never)}
|
||||
android_ripple={{ color: getRippleColor(theme.primary) }}
|
||||
android_ripple={{ color: theme.rippleColor }}
|
||||
>
|
||||
<View style={styles.flexRow}>
|
||||
<Image
|
||||
@@ -27,16 +25,14 @@ const MalCard: React.FC<Props> = ({ theme }) => {
|
||||
style={styles.icon}
|
||||
/>
|
||||
<View style={styles.details}>
|
||||
<Text style={{ color: theme.textColorPrimary }}>MyAnimeList</Text>
|
||||
<Text style={{ color: theme.onSurface }}>MyAnimeList</Text>
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.flexRow}>
|
||||
<Button
|
||||
title={getString('browse')}
|
||||
variation={ButtonVariation.CLEAR}
|
||||
textColor={theme.primary}
|
||||
onPress={() => navigate('BrowseMal' as never)}
|
||||
theme={theme}
|
||||
/>
|
||||
</View>
|
||||
</Pressable>
|
||||
|
||||
@@ -1,55 +1,47 @@
|
||||
import { getDialogBackground, getRippleColor } from '@theme/colors';
|
||||
import React from 'react';
|
||||
import { Pressable, StyleSheet, Text, View } from 'react-native';
|
||||
import FastImage from 'react-native-fast-image';
|
||||
|
||||
import { MD3ThemeType } from '../../../../theme/types';
|
||||
import { ThemeColors } from '../../../../theme/types';
|
||||
|
||||
interface Props {
|
||||
novel: { novelName: string; novelCover: string; score: string; info: string };
|
||||
onPress: () => void;
|
||||
theme: MD3ThemeType;
|
||||
theme: ThemeColors;
|
||||
}
|
||||
|
||||
const MalNovelCard: React.FC<Props> = ({ novel, onPress, theme }) => {
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
styles.container,
|
||||
{ backgroundColor: getDialogBackground(theme) },
|
||||
]}
|
||||
>
|
||||
<View style={[styles.container, { backgroundColor: theme.overlay3 }]}>
|
||||
<Pressable
|
||||
style={styles.pressable}
|
||||
onPress={onPress}
|
||||
android_ripple={{ color: getRippleColor(theme.primary) }}
|
||||
android_ripple={{ color: theme.rippleColor }}
|
||||
>
|
||||
<FastImage source={{ uri: novel.novelCover }} style={styles.cover} />
|
||||
<View style={styles.infoContainer}>
|
||||
<Text
|
||||
style={[styles.title, { color: theme.textColorPrimary }]}
|
||||
style={[styles.title, { color: theme.onSurface }]}
|
||||
numberOfLines={2}
|
||||
>
|
||||
{novel.novelName}
|
||||
</Text>
|
||||
<Text style={[styles.small, { color: theme.textColorPrimary }]}>
|
||||
<Text style={[styles.small, { color: theme.onSurface }]}>
|
||||
Score:{' '}
|
||||
<Text style={{ color: theme.textColorSecondary }}>
|
||||
{novel.score}
|
||||
</Text>
|
||||
<Text style={{ color: theme.onSurfaceVariant }}>{novel.score}</Text>
|
||||
</Text>
|
||||
{novel?.info?.[1] ? (
|
||||
<Text style={[styles.small, { color: theme.textColorPrimary }]}>
|
||||
<Text style={[styles.small, { color: theme.onSurface }]}>
|
||||
Type:{' '}
|
||||
<Text style={{ color: theme.textColorSecondary }}>
|
||||
<Text style={{ color: theme.onSurfaceVariant }}>
|
||||
{novel.info[1]}
|
||||
</Text>
|
||||
</Text>
|
||||
) : null}
|
||||
{novel?.info?.[2] ? (
|
||||
<Text style={[styles.small, { color: theme.textColorPrimary }]}>
|
||||
<Text style={[styles.small, { color: theme.onSurface }]}>
|
||||
Published:{' '}
|
||||
<Text style={{ color: theme.textColorSecondary }}>
|
||||
<Text style={{ color: theme.onSurfaceVariant }}>
|
||||
{novel.info[2]}
|
||||
</Text>
|
||||
</Text>
|
||||
|
||||
@@ -29,7 +29,7 @@ const GlobalSearchNovelCover = ({
|
||||
/>
|
||||
<Text
|
||||
numberOfLines={2}
|
||||
style={[styles.title, { color: theme.textColorPrimary }]}
|
||||
style={[styles.title, { color: theme.onSurface }]}
|
||||
>
|
||||
{novelName}
|
||||
</Text>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import React, { memo } from 'react';
|
||||
import { View, StyleSheet } from 'react-native';
|
||||
import { MD3ThemeType } from '@theme/types';
|
||||
import { ThemeColors } from '@theme/types';
|
||||
import LoadingNovel from './LoadingNovel';
|
||||
import getLoadingColors from '@utils/getLoadingColors';
|
||||
|
||||
interface Props {
|
||||
theme: MD3ThemeType;
|
||||
theme: ThemeColors;
|
||||
}
|
||||
|
||||
const GlobalSearchSkeletonLoading: React.FC<Props> = ({ theme }) => {
|
||||
|
||||
@@ -2,12 +2,12 @@ import React, { memo } from 'react';
|
||||
import { View, Dimensions, StyleSheet } from 'react-native';
|
||||
import { createShimmerPlaceholder } from 'react-native-shimmer-placeholder';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import { MD3ThemeType } from '@theme/types';
|
||||
import { getDialogBackground } from '@theme/colors';
|
||||
import { ThemeColors } from '@theme/types';
|
||||
|
||||
import getLoadingColors from '@utils/getLoadingColors';
|
||||
|
||||
interface Props {
|
||||
theme: MD3ThemeType;
|
||||
theme: ThemeColors;
|
||||
}
|
||||
|
||||
const MalLoading: React.FC<Props> = ({ theme }) => {
|
||||
@@ -53,7 +53,7 @@ const MalLoading: React.FC<Props> = ({ theme }) => {
|
||||
return <View style={styles.container}>{items.map(renderLoadingRect)}</View>;
|
||||
};
|
||||
|
||||
const createStyleSheet = (theme: MD3ThemeType) => {
|
||||
const createStyleSheet = (theme: ThemeColors) => {
|
||||
return StyleSheet.create({
|
||||
container: {
|
||||
position: 'relative',
|
||||
@@ -67,7 +67,7 @@ const createStyleSheet = (theme: MD3ThemeType) => {
|
||||
loadingContainer: {
|
||||
margin: 10,
|
||||
borderRadius: 8,
|
||||
backgroundColor: getDialogBackground(theme),
|
||||
backgroundColor: theme.overlay3,
|
||||
width: Dimensions.get('window').width - 20,
|
||||
overflow: 'hidden',
|
||||
flexDirection: 'row',
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import React, { memo, useMemo } from 'react';
|
||||
import { View, StyleSheet, useWindowDimensions } from 'react-native';
|
||||
import { MD3ThemeType } from '@theme/types';
|
||||
import { ThemeColors } from '@theme/types';
|
||||
import getLoadingColors from '@utils/getLoadingColors';
|
||||
import LoadingNovel from '@screens/browse/loadingAnimation/LoadingNovel';
|
||||
import { useLibrarySettings } from '@hooks/useSettings';
|
||||
import { useDeviceOrientation } from '../../../services/utils/helpers';
|
||||
import { DisplayModes } from '@screens/library/constants/constants';
|
||||
import { useDeviceOrientation } from '@hooks/useDeviceOrientation';
|
||||
|
||||
interface Props {
|
||||
theme: MD3ThemeType;
|
||||
theme: ThemeColors;
|
||||
}
|
||||
|
||||
const SourceScreenSkeletonLoading: React.FC<Props> = ({ theme }) => {
|
||||
|
||||
@@ -32,7 +32,7 @@ const GlobalSearch = ({ navigation }) => {
|
||||
);
|
||||
|
||||
const ListHeaderComponent = (
|
||||
<Text style={[{ color: theme.textColorSecondary }, styles.listHeader]}>
|
||||
<Text style={[{ color: theme.onSurfaceVariant }, styles.listHeader]}>
|
||||
Select a Source To Migrate From
|
||||
</Text>
|
||||
);
|
||||
|
||||
@@ -7,9 +7,8 @@ import GlobalSearchNovelCover from '../globalsearch/GlobalSearchNovelCover';
|
||||
|
||||
import { migrateNovel } from '../../../database/queries/NovelQueries';
|
||||
import { showToast } from '../../../hooks/showToast';
|
||||
import { getDialogBackground } from '@theme/colors';
|
||||
|
||||
import { Button } from '@components';
|
||||
import { ButtonVariation } from '@components/Button/Button';
|
||||
import { getString } from '@strings/translations';
|
||||
import { openNovel } from '@utils/handleNavigateParams';
|
||||
|
||||
@@ -61,7 +60,7 @@ const MigrationNovelList = ({ data, theme, library, navigation }) => {
|
||||
ListEmptyComponent={
|
||||
<Text
|
||||
style={{
|
||||
color: theme.textColorSecondary,
|
||||
color: theme.onSurfaceVariant,
|
||||
padding: 8,
|
||||
paddingVertical: 4,
|
||||
}}
|
||||
@@ -78,12 +77,12 @@ const MigrationNovelList = ({ data, theme, library, navigation }) => {
|
||||
padding: 24,
|
||||
margin: 20,
|
||||
borderRadius: 28,
|
||||
backgroundColor: getDialogBackground(theme),
|
||||
backgroundColor: theme.overlay3,
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
style={{
|
||||
color: theme.textColorPrimary,
|
||||
color: theme.onSurface,
|
||||
fontSize: 18,
|
||||
marginBottom: 16,
|
||||
}}
|
||||
@@ -97,15 +96,11 @@ const MigrationNovelList = ({ data, theme, library, navigation }) => {
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
variation={ButtonVariation.CLEAR}
|
||||
theme={theme}
|
||||
onPress={hideMigrateNovelDialog}
|
||||
title={getString('common.cancel')}
|
||||
/>
|
||||
<Button
|
||||
Button
|
||||
variation={ButtonVariation.CLEAR}
|
||||
theme={theme}
|
||||
onPress={async () => {
|
||||
hideMigrateNovelDialog();
|
||||
await migrateNovel(
|
||||
|
||||
@@ -101,8 +101,8 @@ const MigrationNovels = ({ navigation, route }) => {
|
||||
const renderItem = ({ item }) => (
|
||||
<>
|
||||
<View style={{ padding: 8, paddingVertical: 16 }}>
|
||||
<Text style={{ color: theme.textColorPrimary }}>{item.sourceName}</Text>
|
||||
<Text style={{ color: theme.textColorSecondary, fontSize: 12 }}>
|
||||
<Text style={{ color: theme.onSurface }}>{item.sourceName}</Text>
|
||||
<Text style={{ color: theme.onSurfaceVariant, fontSize: 12 }}>
|
||||
{item.lang}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
@@ -16,7 +16,7 @@ const MigrationSourceCard = ({ item, theme, noOfNovels, onPress }) => {
|
||||
<View style={styles.sourceDetailsContainer}>
|
||||
<Text
|
||||
style={{
|
||||
color: theme.textColorPrimary,
|
||||
color: theme.onSurface,
|
||||
fontSize: 14,
|
||||
}}
|
||||
>
|
||||
@@ -24,7 +24,7 @@ const MigrationSourceCard = ({ item, theme, noOfNovels, onPress }) => {
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
color: theme.textColorSecondary,
|
||||
color: theme.onSurfaceVariant,
|
||||
fontSize: 12,
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -112,13 +112,13 @@ const HistoryScreen = () => {
|
||||
{isLoading ? (
|
||||
<HistorySkeletonLoading theme={theme} />
|
||||
) : error ? (
|
||||
<ErrorScreenV2 error={error} theme={theme} />
|
||||
<ErrorScreenV2 error={error} />
|
||||
) : (
|
||||
<>
|
||||
<SectionList
|
||||
contentContainerStyle={styles.listContainer}
|
||||
sections={groupHistoryByDate(searchText ? searchResults : history)}
|
||||
keyExtractor={item => item.chapterId.toString()}
|
||||
keyExtractor={(item, index) => 'history' + index}
|
||||
renderSectionHeader={({ section: { date } }) => (
|
||||
<Text style={[styles.dateHeader, { color: theme.onSurface }]}>
|
||||
{dayjs(date).calendar()}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import React from 'react';
|
||||
import { StyleSheet } from 'react-native';
|
||||
import { Dialog, Portal } from 'react-native-paper';
|
||||
|
||||
import { Button } from '@components';
|
||||
import { getString } from '@strings/translations';
|
||||
|
||||
import { Button, Dialog, Portal } from 'react-native-paper';
|
||||
import { MD3ThemeType } from '../../../theme/types';
|
||||
import { ThemeColors } from '@theme/types';
|
||||
|
||||
interface ClearHistoryDialogProps {
|
||||
visible: boolean;
|
||||
theme: MD3ThemeType;
|
||||
theme: ThemeColors;
|
||||
onSubmit: () => void;
|
||||
onDismiss: () => void;
|
||||
}
|
||||
@@ -26,17 +26,17 @@ const ClearHistoryDialog: React.FC<ClearHistoryDialogProps> = ({
|
||||
|
||||
return (
|
||||
<Portal>
|
||||
<Dialog visible={visible} onDismiss={onDismiss} style={styles.container}>
|
||||
<Dialog.Title style={[styles.title, { color: theme.textColorPrimary }]}>
|
||||
<Dialog
|
||||
visible={visible}
|
||||
onDismiss={onDismiss}
|
||||
style={[styles.container, { backgroundColor: theme.overlay3 }]}
|
||||
>
|
||||
<Dialog.Title style={[styles.title, { color: theme.onSurface }]}>
|
||||
{getString('historyScreen.clearHistorWarning')}
|
||||
</Dialog.Title>
|
||||
<Dialog.Actions>
|
||||
<Button theme={{ colors: { ...theme } }} onPress={onDismiss}>
|
||||
{getString('common.cancel')}
|
||||
</Button>
|
||||
<Button theme={{ colors: { ...theme } }} onPress={handleOnSubmit}>
|
||||
{getString('common.ok')}
|
||||
</Button>
|
||||
<Button onPress={onDismiss}>{getString('common.cancel')}</Button>
|
||||
<Button onPress={handleOnSubmit}>{getString('common.ok')}</Button>
|
||||
</Dialog.Actions>
|
||||
</Dialog>
|
||||
</Portal>
|
||||
@@ -47,7 +47,8 @@ export default ClearHistoryDialog;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
borderRadius: 8,
|
||||
margin: 20,
|
||||
borderRadius: 28,
|
||||
},
|
||||
title: {
|
||||
letterSpacing: 0,
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { Pressable, StyleSheet, Text, View } from 'react-native';
|
||||
import color from 'color';
|
||||
|
||||
import dayjs from 'dayjs';
|
||||
import FastImage from 'react-native-fast-image';
|
||||
|
||||
import { IconButtonV2 } from '../../../../components';
|
||||
import { IconButtonV2 } from '@components';
|
||||
import { parseChapterNumber } from '@utils/parseChapterNumber';
|
||||
|
||||
import { parseChapterNumber } from '../../../../utils/parseChapterNumber';
|
||||
|
||||
import { History } from '../../../../database/types';
|
||||
import { MD3ThemeType } from '../../../../theme/types';
|
||||
import { coverPlaceholderColor } from '../../../../theme/colors';
|
||||
import { History } from '@database/types';
|
||||
import { ThemeColors } from '@theme/types';
|
||||
import { coverPlaceholderColor } from '@theme/colors';
|
||||
import {
|
||||
openChapterChapterTypes,
|
||||
openChapterNovelTypes,
|
||||
@@ -26,7 +24,7 @@ interface HistoryCardProps {
|
||||
) => void;
|
||||
handleRemoveFromHistory: (historyId: number) => void;
|
||||
handleNavigateToNovel: (novel: openNovelProps) => void;
|
||||
theme: MD3ThemeType;
|
||||
theme: ThemeColors;
|
||||
}
|
||||
|
||||
const HistoryCard: React.FC<HistoryCardProps> = ({
|
||||
@@ -61,7 +59,7 @@ const HistoryCard: React.FC<HistoryCardProps> = ({
|
||||
return (
|
||||
<Pressable
|
||||
style={styles.container}
|
||||
android_ripple={{ color: color(theme.primary).alpha(0.12).string() }}
|
||||
android_ripple={{ color: theme.rippleColor }}
|
||||
onPress={() =>
|
||||
handleNavigateToNovel({
|
||||
sourceId,
|
||||
@@ -81,7 +79,7 @@ const HistoryCard: React.FC<HistoryCardProps> = ({
|
||||
>
|
||||
{novelName}
|
||||
</Text>
|
||||
<Text style={{ color: theme.textColorSecondary }}>
|
||||
<Text style={{ color: theme.onSurfaceVariant }}>
|
||||
{chapterNoAndTime}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
@@ -2,11 +2,11 @@ import React, { memo } from 'react';
|
||||
import { StyleSheet, View } from 'react-native';
|
||||
import { createShimmerPlaceholder } from 'react-native-shimmer-placeholder';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import { MD3ThemeType } from '@theme/types';
|
||||
import { ThemeColors } from '@theme/types';
|
||||
import getLoadingColors from '@utils/getLoadingColors';
|
||||
|
||||
interface Props {
|
||||
theme: MD3ThemeType;
|
||||
theme: ThemeColors;
|
||||
}
|
||||
|
||||
const HistorySkeletonLoading: React.FC<Props> = ({ theme }) => {
|
||||
|
||||
@@ -29,8 +29,7 @@ import {
|
||||
import { unfollowNovel } from '../../database/queries/NovelQueries';
|
||||
import SetCategoryModal from '@screens/novel/components/SetCategoriesModal';
|
||||
import useBoolean from '@hooks/useBoolean';
|
||||
import { debounce, intersection } from 'lodash';
|
||||
import { ButtonVariation } from '@components/Button/Button';
|
||||
import { debounce, intersection } from 'lodash-es';
|
||||
import { useBackHandler } from '@hooks/useBackHandler';
|
||||
import { openChapter } from '@utils/handleNavigateParams';
|
||||
import useHistory from '@hooks/useHistory';
|
||||
@@ -120,7 +119,7 @@ const LibraryScreen = () => {
|
||||
)}
|
||||
inactiveColor={theme.secondary}
|
||||
activeColor={theme.primary}
|
||||
pressColor={color(theme.primary).alpha(0.12).rgb().string()}
|
||||
pressColor={theme.rippleColor}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -219,10 +218,7 @@ const LibraryScreen = () => {
|
||||
title={`${getString(
|
||||
'common.searchFor',
|
||||
)} "${searchText}" ${getString('common.globally')}`}
|
||||
theme={theme}
|
||||
variation={ButtonVariation.CLEAR}
|
||||
style={styles.globalSearchBtn}
|
||||
labelStyle={styles.globalSearchBtnLabel}
|
||||
onPress={() =>
|
||||
navigate(
|
||||
'GlobalSearchScreen' as never,
|
||||
@@ -328,9 +324,7 @@ const styles = StyleSheet.create({
|
||||
globalSearchBtn: {
|
||||
margin: 16,
|
||||
},
|
||||
globalSearchBtnLabel: {
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
|
||||
fab: {
|
||||
position: 'absolute',
|
||||
margin: 16,
|
||||
|
||||
@@ -2,14 +2,14 @@ import React from 'react';
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
|
||||
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||
import { MD3ThemeType } from '../../../theme/types';
|
||||
import { ThemeColors } from '../../../theme/types';
|
||||
|
||||
interface Props {
|
||||
label: string;
|
||||
icon?: string;
|
||||
backgroundColor?: string;
|
||||
textColor?: string;
|
||||
theme: MD3ThemeType;
|
||||
theme: ThemeColors;
|
||||
}
|
||||
|
||||
export const Banner: React.FC<Props> = ({
|
||||
|
||||
@@ -108,7 +108,7 @@ const ThirdRoute = () => {
|
||||
|
||||
return (
|
||||
<View style={{ flex: 1 }}>
|
||||
<Text style={[styles.sectionHeader, { color: theme.textColorSecondary }]}>
|
||||
<Text style={[styles.sectionHeader, { color: theme.onSurfaceVariant }]}>
|
||||
{getString('libraryScreen.bottomSheet.display.badges')}
|
||||
</Text>
|
||||
<Checkbox
|
||||
@@ -141,7 +141,7 @@ const ThirdRoute = () => {
|
||||
}
|
||||
theme={theme}
|
||||
/>
|
||||
<Text style={[styles.sectionHeader, { color: theme.textColorSecondary }]}>
|
||||
<Text style={[styles.sectionHeader, { color: theme.onSurfaceVariant }]}>
|
||||
{getString('libraryScreen.bottomSheet.display.displayMode')}
|
||||
</Text>
|
||||
<FlashList
|
||||
@@ -184,7 +184,7 @@ const LibraryBottomSheet: React.FC<LibraryBottomSheetProps> = ({
|
||||
renderLabel={({ route, color }) => (
|
||||
<Text style={{ color }}>{route.title}</Text>
|
||||
)}
|
||||
inactiveColor={theme.textColorSecondary}
|
||||
inactiveColor={theme.onSurfaceVariant}
|
||||
activeColor={theme.primary}
|
||||
pressColor={color(theme.primary).alpha(0.12).string()}
|
||||
/>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useState } from 'react';
|
||||
import { RefreshControl, View } from 'react-native';
|
||||
import { xor } from 'lodash';
|
||||
import { xor } from 'lodash-es';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
|
||||
import { EmptyView } from '@components/index';
|
||||
|
||||
@@ -40,31 +40,38 @@ export enum LibrarySortOrder {
|
||||
DateAdded_DESC = 'novelId DESC',
|
||||
LastRead_ASC = 'lastReadAt ASC',
|
||||
LastRead_DESC = 'lastReadAt DESC',
|
||||
LastUpdated_ASC = 'lastUpdatedAt ASC',
|
||||
LastUpdated_DESC = 'lastUpdatedAt DESC',
|
||||
}
|
||||
|
||||
export const librarySortOrderList = [
|
||||
{
|
||||
label: 'Alphabetically',
|
||||
label: getString('libraryScreen.bottomSheet.sortOrders.alphabetically'),
|
||||
ASC: LibrarySortOrder.Alphabetically_ASC,
|
||||
DESC: LibrarySortOrder.Alphabetically_DESC,
|
||||
},
|
||||
{
|
||||
label: 'Last Read',
|
||||
label: getString('libraryScreen.bottomSheet.sortOrders.lastRead'),
|
||||
ASC: LibrarySortOrder.LastRead_ASC,
|
||||
DESC: LibrarySortOrder.LastRead_DESC,
|
||||
},
|
||||
{
|
||||
label: 'Unread',
|
||||
label: getString('libraryScreen.bottomSheet.sortOrders.lastUpdated'),
|
||||
ASC: LibrarySortOrder.LastUpdated_ASC,
|
||||
DESC: LibrarySortOrder.LastUpdated_DESC,
|
||||
},
|
||||
{
|
||||
label: getString('libraryScreen.bottomSheet.sortOrders.unread'),
|
||||
ASC: LibrarySortOrder.Unread_ASC,
|
||||
DESC: LibrarySortOrder.Unread_DESC,
|
||||
},
|
||||
{
|
||||
label: 'Downloaded',
|
||||
label: getString('libraryScreen.bottomSheet.sortOrders.download'),
|
||||
ASC: LibrarySortOrder.Downloaded_ASC,
|
||||
DESC: LibrarySortOrder.Downloaded_DESC,
|
||||
},
|
||||
{
|
||||
label: 'Total chapters',
|
||||
label: getString('libraryScreen.bottomSheet.sortOrders.totalChapters'),
|
||||
ASC: LibrarySortOrder.TotalChapters_ASC,
|
||||
DESC: LibrarySortOrder.TotalChapters_DESC,
|
||||
},
|
||||
|
||||
@@ -46,7 +46,7 @@ const DownloadQueue = ({ navigation }) => {
|
||||
anchor={
|
||||
<MaterialAppbar.Action
|
||||
icon="dots-vertical"
|
||||
iconColor={theme.textColorPrimary}
|
||||
iconColor={theme.onSurface}
|
||||
onPress={openMenu}
|
||||
/>
|
||||
}
|
||||
@@ -61,7 +61,7 @@ const DownloadQueue = ({ navigation }) => {
|
||||
closeMenu();
|
||||
}}
|
||||
title="Cancel downloads"
|
||||
titleStyle={{ color: theme.textColorPrimary }}
|
||||
titleStyle={{ color: theme.onSurface }}
|
||||
/>
|
||||
</Menu>
|
||||
</Appbar>
|
||||
@@ -71,9 +71,7 @@ const DownloadQueue = ({ navigation }) => {
|
||||
data={downloadQueue}
|
||||
renderItem={({ item }) => (
|
||||
<View style={{ padding: 16 }}>
|
||||
<Text style={{ color: theme.textColorPrimary }}>
|
||||
{item.chapterName}
|
||||
</Text>
|
||||
<Text style={{ color: theme.onSurface }}>{item.chapterName}</Text>
|
||||
<ProgressBar
|
||||
indeterminate={BackgroundService.isRunning() ? true : false}
|
||||
progress={!BackgroundService.isRunning() && 0}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user