Compare commits
320 Commits
v122092671
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
61e0087894 | ||
|
1ec05d9913 | ||
|
859bd91bbb | ||
|
204b736c53 | ||
|
f24609c143 | ||
|
b94d7dc537 | ||
|
41910cc4cd | ||
|
db166ca9d4 | ||
|
db0d5a4a85 | ||
|
3bc0d7cf95 | ||
|
8f464d95fd | ||
|
5ccd6a3368 | ||
|
cdbded246e | ||
|
750c7758bd | ||
|
22f8b14ecd | ||
|
6e27d6d4e6 | ||
|
14ff4dbd05 | ||
|
390c2d0cf3 | ||
|
e58914ef58 | ||
|
a03f08fca1 | ||
|
8e9b87f00c | ||
|
f765224a86 | ||
|
14d2219eb8 | ||
|
137580ccf9 | ||
|
f101d22f54 | ||
|
68aedb7641 | ||
|
754d526b49 | ||
|
c458871569 | ||
056825aa0c | |||
16b19fc5ce | |||
4ad4a23ed8 | |||
d8c215eacc | |||
2b446ab22b | |||
a029d8a7dc | |||
4482234e1a | |||
b5de30f561 | |||
70ad5f322c | |||
d167092c83 | |||
c4f4bafe85 | |||
ed06b22a77 | |||
|
172362b533 | ||
|
ad72cb6f56 | ||
|
9057ee0052 | ||
|
50d0b44315 | ||
|
21b08ed384 | ||
|
993c4d2ee9 | ||
|
57a9d51027 | ||
|
673f0edb8b | ||
|
7f96798f13 | ||
|
6e5704a45b | ||
|
495591159f | ||
|
718fe7c5ee | ||
|
ecd23213f9 | ||
|
e6baed8cb4 | ||
|
c87abec0b9 | ||
|
0aba41d8bf | ||
|
2a2d1047b4 | ||
|
66ef1ccf32 | ||
|
677ede5bc7 | ||
|
996a7ed22c | ||
|
85208c4e5a | ||
|
5cfec50cba | ||
76ad71e1dc | |||
0277fb507c | |||
8d7d3174aa | |||
|
00eb3333fe | ||
|
629ca01d99 | ||
|
c2d8681ce8 | ||
|
08f79cb148 | ||
e21906e70d | |||
|
9d2cc32bc9 | ||
|
d9d057c8dc | ||
|
1f3fa0c4a6 | ||
|
dea3def385 | ||
|
f72ef2f5d4 | ||
|
f28cb759df | ||
|
b9d69c3e64 | ||
|
c2a1c9eaac | ||
|
bf37209a15 | ||
|
2c558fe6fd | ||
|
ad88011454 | ||
|
559c17bc1d | ||
|
ab9c46f0eb | ||
|
aa799d2ca8 | ||
|
177c978474 | ||
|
39b9991413 | ||
|
b303f110f1 | ||
|
f851941a6a | ||
|
a313552976 | ||
|
6ac97ed3fe | ||
|
d583b937b7 | ||
|
15b9a2d935 | ||
|
5a8ce15961 | ||
e1c64cef46 | |||
ee064f3cb4 | |||
3e46e2ff29 | |||
f28e702549 | |||
|
fc31a4399c | ||
|
9b23053b66 | ||
389a04d250 | |||
|
40e1d1478b | ||
|
2154ff3c33 | ||
2245565f95 | |||
014858f06b | |||
3f1f86a78e | |||
a549169a7c | |||
be7cae365a | |||
cef3b2e593 | |||
ae927ebc57 | |||
|
90532cf501 | ||
|
ab0678d61e | ||
|
a1b7d22d26 | ||
|
29eae4b1f6 | ||
|
f5bbc63481 | ||
ddc72d85b0 | |||
68bbf5b2d3 | |||
|
95e76a55da | ||
2b6659f4ec | |||
|
e0c118a73e | ||
|
4e61b2aed6 | ||
|
ba2758c0a3 | ||
|
c718b966a1 | ||
|
99438e142f | ||
|
4d8076c3cf | ||
|
db75c5b74a | ||
|
966a082147 | ||
|
cd20a5ec29 | ||
|
cc4c1c9201 | ||
|
ff021d572c | ||
|
89992967be | ||
|
3c68bde62b | ||
|
c38251f5b3 | ||
|
a01f6d2322 | ||
|
417a33eb25 | ||
|
2e7f7f23b3 | ||
|
e5e182761e | ||
|
a094d88799 | ||
e51915d1cd | |||
3a654f6ede | |||
5227751dca | |||
|
27eafe4ff4 | ||
|
8c83a9408b | ||
|
fe2410f719 | ||
|
a5e86bfb77 | ||
|
23be633798 | ||
|
813e0707d8 | ||
|
9ed9bf07fc | ||
|
47265c10d0 | ||
|
5cc633246a | ||
|
1f40385786 | ||
|
eb2876324a | ||
|
633b817d76 | ||
|
2cfaa9b285 | ||
|
f42ae97326 | ||
|
3b0028164b | ||
|
7420adeb5c | ||
|
316027ca3b | ||
|
9d58fba5c9 | ||
|
284c19ef89 | ||
|
7cfd17231a | ||
|
527830a5ae | ||
|
c4ed30f594 | ||
|
156c1681cf | ||
|
3593fbca78 | ||
|
430fc8e8cb | ||
|
4fce19bad4 | ||
|
49f5848e7b | ||
|
90452100a4 | ||
|
bf1196dd0f | ||
|
4316dc6516 | ||
|
9833a66a64 | ||
|
797bf06a9c | ||
|
d98b00533d | ||
|
bf8f7d8667 | ||
|
89c570f34f | ||
|
d6a562863a | ||
|
a02f06fe2e | ||
|
7b088d7bb4 | ||
|
477883ed39 | ||
|
748ed41096 | ||
|
86c50d4881 | ||
|
c4c92e6dd9 | ||
|
7f0ba193ec | ||
|
87ed5b0fa8 | ||
|
6947743ac0 | ||
|
07e3710d44 | ||
|
e68da7764f | ||
|
c3ff894027 | ||
|
f09f731d30 | ||
|
956c4341c7 | ||
|
7b68264dd7 | ||
|
cfcf030bf8 | ||
|
0e7d7a5835 | ||
|
0856ebb889 | ||
|
25bf68cf0c | ||
|
afc6f392c6 | ||
|
a0b5e2052b | ||
|
87d1ef2bce | ||
|
537a6d3a0b | ||
dbe97f564e | |||
|
3a3bf03114 | ||
c09a32e9ad | |||
b02a588dff | |||
|
a4527940b8 | ||
|
9e8a25ed3e | ||
|
8ea46e146b | ||
|
5ecf3c3f87 | ||
|
325f103417 | ||
|
ab4b1ae644 | ||
|
87ea44754e | ||
|
04dec50808 | ||
|
e36189e2e7 | ||
|
d6bdf510a4 | ||
|
a464e93370 | ||
4b63afe62a | |||
ac4c4b9441 | |||
|
16b10dc1b7 | ||
02d734eee8 | |||
c5cdfc0d53 | |||
6d610ed61a | |||
792950be7c | |||
|
af8969ce4a | ||
|
27c55e59a1 | ||
|
94a0747947 | ||
|
d862bfba4f | ||
|
b0d1d9c29a | ||
|
7b40a31979 | ||
|
823a8c3692 | ||
|
5494978db8 | ||
|
6076eb1cee | ||
|
131101d2ee | ||
|
62ad1f45ba | ||
|
402d18b889 | ||
|
e32699c93f | ||
|
059a237b99 | ||
|
d2bdbae6c8 | ||
|
510fcbe47e | ||
667e9c1a5d | |||
53b1d1f8b2 | |||
c25e8889a4 | |||
|
8b0bbe71c9 | ||
8bfe14c019 | |||
208babbce3 | |||
02098a7aa9 | |||
d0a982f385 | |||
1d1c121aab | |||
fe12819163 | |||
|
023a30c008 | ||
|
a2862a2587 | ||
|
054e936657 | ||
1d2e5069b8 | |||
a147646743 | |||
32e7fc0038 | |||
c15bf44032 | |||
0bcd55bd4e | |||
ebef0b3511 | |||
713ceb05bf | |||
dc8381b661 | |||
b5b820c64b | |||
f7055626d9 | |||
|
6ec3e96909 | ||
22da30eaa8 | |||
79fd115f5e | |||
8dc3d319cd | |||
27bb056397 | |||
f9ba13dc32 | |||
6f60ef4346 | |||
28b950f467 | |||
a9c7ec3dc1 | |||
920d4ac1ef | |||
0e96d313ec | |||
7211fdb1a3 | |||
|
381d6acc82 | ||
d311c2cdeb | |||
219cae5d74 | |||
2968aee309 | |||
6cb4b35c93 | |||
15ec0f2d26 | |||
4781e30da2 | |||
c8759cc035 | |||
cb4f2f02ef | |||
7517626ab7 | |||
41c951b659 | |||
|
ad279c6683 | ||
|
5f0817ddb7 | ||
|
7124cbcacd | ||
|
2a710a1a08 | ||
|
82ec2445a1 | ||
|
cabb6d494d | ||
|
5c12481813 | ||
|
b16f86dda1 | ||
|
2bc28db2cc | ||
|
bf1b680b4a | ||
e2afff0b8e | |||
a382fc89ea | |||
3f0a3903ae | |||
f46f98cef0 | |||
bf6f1a917e | |||
71c0a4d340 | |||
63c550ead3 | |||
|
d81fb79b4f | ||
|
144067d5b6 | ||
|
8106faa45c | ||
|
d9ef301e0f | ||
|
90b52232ab | ||
|
0f000ea359 | ||
|
fb8f81a4c8 | ||
|
a76b3dd2a9 | ||
|
91aed5a777 | ||
366b2e10f1 | |||
|
8823cc6c6c | ||
d2436bb976 | |||
ef994460c1 | |||
758708e18d | |||
c0381144d1 | |||
cda3ba6cb4 | |||
a4636cc0c8 | |||
60c24fc75a | |||
5853a19937 | |||
99f2c04bf6 |
109
.drone.yml
109
.drone.yml
@ -3,24 +3,38 @@ type: docker
|
|||||||
name: test
|
name: test
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: AnylyseBuildTest
|
- name: Lint
|
||||||
image: mingc/android-build-box:latest
|
|
||||||
failure: ignore
|
failure: ignore
|
||||||
|
image: mingc/android-build-box:latest
|
||||||
commands:
|
commands:
|
||||||
- echo "---------------------------------------------------------"
|
- echo "---------------------------------------------------------"
|
||||||
- echo "Analysing..."
|
- echo "Install linters..."
|
||||||
- ./gradlew sonarqube -Dsonar.projectKey=RFS2 -Dsonar.host.url=$SONAR_HOST_URL -Dsonar.login=$SONAR_LOGIN -PignoreGitVersion=true -P appLoginUrl="\"URL\"" -P appLoginUsername="\"LOGIN\"" -P appLoginPassword="\"PASS\""
|
- curl -sSLO https://github.com/pinterest/ktlint/releases/download/1.0.0/ktlint && chmod a+x ktlint && mv ktlint /usr/local/bin/
|
||||||
|
- curl -sSLO https://github.com/detekt/detekt/releases/download/v1.23.1/detekt-cli-1.23.1.zip && unzip detekt-cli-1.23.1.zip
|
||||||
- echo "---------------------------------------------------------"
|
- echo "---------------------------------------------------------"
|
||||||
- echo "Building..."
|
- echo "Linting..."
|
||||||
- ./gradlew :androidApp:build -PignoreGitVersion=true -P appLoginUrl="\"URL\"" -P appLoginUsername="\"LOGIN\"" -P appLoginPassword="\"PASS\"" -P pushCache=false
|
- ktlint 'shared/**/*.kt' 'androidApp/**/*.kt' '!shared/build' || true
|
||||||
- echo "---------------------------------------------------------"
|
- echo "---------------------------------------------------------"
|
||||||
- echo "Testing..."
|
- echo "Detecting..."
|
||||||
|
- ./detekt-cli-1.23.1/bin/detekt-cli --all-rules --excludes '**/shared/build/**/*.kt' || true
|
||||||
|
- echo "---------------------------------------------------------"
|
||||||
|
command_timeout: 1m
|
||||||
|
- name: BuildAndTest
|
||||||
|
image: mingc/android-build-box:latest
|
||||||
|
commands:
|
||||||
|
- echo "---------------------------------------------------------"
|
||||||
|
- echo "Configure gradle..."
|
||||||
|
- mkdir -p ~/.gradle && echo "org.gradle.daemon=false\nignoreGitVersion=true\nsystemProp.org.gradle.internal.http.connectionTimeout=180000\nsystemProp.org.gradle.internal.http.socketTimeout=180000" >> ~/.gradle/gradle.properties
|
||||||
|
- echo "---------------------------------------------------------"
|
||||||
|
- echo "Configure java..."
|
||||||
|
- . ~/.bash_profile
|
||||||
|
- jenv global 17.0
|
||||||
|
- java --version
|
||||||
|
- date
|
||||||
|
- echo "---------------------------------------------------------"
|
||||||
|
- echo "Building and testing..."
|
||||||
|
- ./gradlew build
|
||||||
- echo "---------------------------------------------------------"
|
- echo "---------------------------------------------------------"
|
||||||
environment:
|
|
||||||
SONAR_HOST_URL:
|
|
||||||
from_secret: sonarScannerHostUrl
|
|
||||||
SONAR_LOGIN:
|
|
||||||
from_secret: sonarScannerLogin
|
|
||||||
trigger:
|
trigger:
|
||||||
event:
|
event:
|
||||||
- push
|
- push
|
||||||
@ -32,23 +46,36 @@ type: docker
|
|||||||
name: Publish
|
name: Publish
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: createTag
|
- name: createTagAndChangelog
|
||||||
image: ubuntu:latest
|
image: ubuntu:latest
|
||||||
commands:
|
commands:
|
||||||
- apt-get update && apt-get install -y git
|
- apt-get update && apt-get install -y git
|
||||||
|
- git fetch --tags -p
|
||||||
|
- PREV=$(git describe --tags --abbrev=0)
|
||||||
- ./build.sh --publish --from-ci
|
- ./build.sh --publish --from-ci
|
||||||
- git remote add pushing https://$GITEA_USR:$GITEA_PASS@gitea.amine-louveau.fr/Louvorg/ReaderForSelfoss-multiplatform.git
|
- VER=$(git describe --tags --abbrev=0)
|
||||||
- git push pushing --tags
|
- CHANGELOG=$(git log $PREV..HEAD --pretty="- %s")
|
||||||
|
- echo "**$VER**\n\n$CHANGELOG\n\n--------------------------------------------------------------------\n\n$(cat CHANGELOG.md)" > CHANGELOG.md
|
||||||
|
- git add CHANGELOG.md
|
||||||
|
- git commit -m "Changelog for $VER [CI SKIP]"
|
||||||
environment:
|
environment:
|
||||||
GITEA_USR:
|
TZ: Europe/Paris
|
||||||
from_secret: giteaUsr
|
|
||||||
GITEA_PASS:
|
- name: git-push
|
||||||
from_secret: giteaPass
|
image: appleboy/drone-git-push
|
||||||
|
settings:
|
||||||
|
branch: master
|
||||||
|
remote:
|
||||||
|
from_secret: remoteUrl
|
||||||
|
followtags: true
|
||||||
|
ssh_key:
|
||||||
|
from_secret: privateKey
|
||||||
|
skip_verify: true
|
||||||
|
|
||||||
- name: scpFiles
|
- name: scpFiles
|
||||||
image: appleboy/drone-scp
|
image: appleboy/drone-scp
|
||||||
settings:
|
settings:
|
||||||
host: amine-louveau.fr
|
host: amine-bouabdallaoui.fr
|
||||||
username: ubuntu
|
username: ubuntu
|
||||||
key:
|
key:
|
||||||
from_secret: privateKey
|
from_secret: privateKey
|
||||||
@ -59,16 +86,13 @@ steps:
|
|||||||
- name: deploy
|
- name: deploy
|
||||||
image: appleboy/drone-ssh
|
image: appleboy/drone-ssh
|
||||||
settings:
|
settings:
|
||||||
host: amine-louveau.fr
|
host: amine-bouabdallaoui.fr
|
||||||
user: ubuntu
|
user: ubuntu
|
||||||
key:
|
key:
|
||||||
from_secret: privateKey
|
from_secret: privateKey
|
||||||
command_timeout: 2m
|
command_timeout: 2m
|
||||||
script:
|
script:
|
||||||
- cd /home/ubuntu
|
- cd /home/ubuntu && sudo rm -rf /var/www/amine/version.txt && sudo chown www-data:www-data ./version.txt && sudo mv version.txt /var/www/amine/
|
||||||
- sudo rm -rf /var/www/amine/version.txt
|
|
||||||
- sudo chown www-data:www-data ./version.txt
|
|
||||||
- sudo mv version.txt /var/www/amine/
|
|
||||||
|
|
||||||
trigger:
|
trigger:
|
||||||
event:
|
event:
|
||||||
@ -85,11 +109,18 @@ steps:
|
|||||||
- name: build
|
- name: build
|
||||||
image: mingc/android-build-box:latest
|
image: mingc/android-build-box:latest
|
||||||
commands:
|
commands:
|
||||||
|
- echo "---------------------------------------------------------"
|
||||||
|
- echo "Fetch tags..."
|
||||||
|
- git fetch --tags
|
||||||
|
- echo "---------------------------------------------------------"
|
||||||
|
- echo "Configure gradle..."
|
||||||
|
- mkdir -p ~/.gradle && echo "org.gradle.daemon=false\nignoreGitVersion=false\nsystemProp.org.gradle.internal.http.connectionTimeout=180000\nsystemProp.org.gradle.internal.http.socketTimeout=180000" >> ~/.gradle/gradle.properties
|
||||||
|
- echo "---------------------------------------------------------"
|
||||||
- echo "Generate APK"
|
- echo "Generate APK"
|
||||||
- ./gradlew :androidApp:assembleGithubConfigRelease -PignoreGitVersion=true -P appLoginUrl="\"URL\"" -P appLoginUsername="\"LOGIN\"" -P appLoginPassword="\"PASS\"" -P pushCache=false
|
- ./gradlew :androidApp:assembleGithubConfigRelease
|
||||||
- echo "---------------------------------------------------------"
|
- echo "---------------------------------------------------------"
|
||||||
- echo "Get Key"
|
- echo "Get Key"
|
||||||
- wget https://amine-louveau.fr/key
|
- wget https://amine-bouabdallaoui.fr/key
|
||||||
- echo "---------------------------------------------------------"
|
- echo "---------------------------------------------------------"
|
||||||
- echo "Zipalign"
|
- echo "Zipalign"
|
||||||
- $ANDROID_HOME/build-tools/31.0.0/zipalign -f -v 4 androidApp/build/outputs/apk/githubConfig/release/androidApp-githubConfig-release-unsigned.apk androidApp/build/outputs/apk/githubConfig/release/android-prod-released-ziped.apk
|
- $ANDROID_HOME/build-tools/31.0.0/zipalign -f -v 4 androidApp/build/outputs/apk/githubConfig/release/androidApp-githubConfig-release-unsigned.apk androidApp/build/outputs/apk/githubConfig/release/android-prod-released-ziped.apk
|
||||||
@ -100,6 +131,7 @@ steps:
|
|||||||
- echo "Verify"
|
- echo "Verify"
|
||||||
- $ANDROID_HOME/build-tools/31.0.0/apksigner verify signed.apk
|
- $ANDROID_HOME/build-tools/31.0.0/apksigner verify signed.apk
|
||||||
environment:
|
environment:
|
||||||
|
TZ: Europe/Paris
|
||||||
YOUR_KEYSTORE_PASSWORD:
|
YOUR_KEYSTORE_PASSWORD:
|
||||||
from_secret: keyPass
|
from_secret: keyPass
|
||||||
YOUR_KEY_ALIAS:
|
YOUR_KEY_ALIAS:
|
||||||
@ -110,8 +142,29 @@ steps:
|
|||||||
settings:
|
settings:
|
||||||
api_key:
|
api_key:
|
||||||
from_secret: giteaAPI
|
from_secret: giteaAPI
|
||||||
base_url: https://gitea.amine-louveau.fr
|
base_url: https://gitea.amine-bouabdallaoui.fr
|
||||||
files: signed.apk
|
files: signed.apk
|
||||||
|
|
||||||
|
- name: notify
|
||||||
|
image: drillster/drone-email
|
||||||
|
failure: ignore
|
||||||
|
settings:
|
||||||
|
host:
|
||||||
|
from_secret: smtpHOST
|
||||||
|
port:
|
||||||
|
from_secret: smtpPORT
|
||||||
|
username:
|
||||||
|
from_secret: smtpUSERNAME
|
||||||
|
password:
|
||||||
|
from_secret: smtpPASSWORD
|
||||||
|
from:
|
||||||
|
from_secret: smtpFROM
|
||||||
|
subject: Mapping file
|
||||||
|
recipients:
|
||||||
|
from_secret: smtpTO
|
||||||
|
recipients_only: true
|
||||||
|
skip_verify: true
|
||||||
|
attachment: androidApp/build/outputs/mapping/githubConfigRelease/mapping.txt
|
||||||
trigger:
|
trigger:
|
||||||
event:
|
event:
|
||||||
- tag
|
- tag
|
27
.github/CONTRIBUTING.md
vendored
27
.github/CONTRIBUTING.md
vendored
@ -10,7 +10,7 @@ Please read the guidelines before contributing, and follow them (or try to) when
|
|||||||
|
|
||||||
There are many ways to contribute to this project, you could [translate the app](https://crowdin.com/project/readerforselfoss), report bugs, request missing features, suggest enhancements and changes to existing ones. You also can improve the README with useful tips that could help the other users.
|
There are many ways to contribute to this project, you could [translate the app](https://crowdin.com/project/readerforselfoss), report bugs, request missing features, suggest enhancements and changes to existing ones. You also can improve the README with useful tips that could help the other users.
|
||||||
|
|
||||||
You can fork the repository, and [help me solve some issues](https://gitea.amine-louveau.fr/Louvorg/ReaderForSelfoss-multiplatform/issues?q=is%3Aissue+is%3Aopen+label%3A%22Up+For+Grabs%22) or [develop new things](https://gitea.amine-louveau.fr/Louvorg/ReaderForSelfoss-multiplatform/issues)
|
You can fork the repository, and [help me solve some issues](https://gitea.amine-bouabdallaoui.fr/Louvorg/ReaderForSelfoss-multiplatform/issues?q=is%3Aissue+is%3Aopen+label%3A%22Up+For+Grabs%22) or [develop new things](https://gitea.amine-bouabdallaoui.fr/Louvorg/ReaderForSelfoss-multiplatform/issues)
|
||||||
|
|
||||||
### What I can't help you with.
|
### What I can't help you with.
|
||||||
|
|
||||||
@ -46,28 +46,3 @@ Always check if the web version of your instance is working.
|
|||||||
I won't provide any selfoss instance url. If you want to help, but to not have one, you'll have to install one, and use it.
|
I won't provide any selfoss instance url. If you want to help, but to not have one, you'll have to install one, and use it.
|
||||||
|
|
||||||
All the details to need are [here](https://selfoss.aditu.de/).
|
All the details to need are [here](https://selfoss.aditu.de/).
|
||||||
|
|
||||||
# Build the project
|
|
||||||
|
|
||||||
You can directly import this project into IntellIJ/Android Studio.
|
|
||||||
|
|
||||||
You'll have to:
|
|
||||||
|
|
||||||
- Define some parameters either in `~/.gradle/gradle.properties` or as gradle parameters (see the examples)
|
|
||||||
|
|
||||||
- appLoginUrl, appLoginUsername and appLoginPassword: url, username and password of a selfoss instance. **These are only used for tests. They can be empty if you don't test API calls.**
|
|
||||||
|
|
||||||
### Examples:
|
|
||||||
#### Inside ~/.gradle/gradle.properties
|
|
||||||
|
|
||||||
```
|
|
||||||
appLoginUrl="URL" # It can be empty.
|
|
||||||
appLoginUsername="LOGIN" # It can be empty.
|
|
||||||
appLoginPassword="PASS" # It can be empty.
|
|
||||||
```
|
|
||||||
|
|
||||||
#### As gradle parameters
|
|
||||||
|
|
||||||
```
|
|
||||||
./gradlew .... -P appLoginUrl="URL" -P appLoginUsername="LOGIN" -P appLoginPassword="PASS"
|
|
||||||
```
|
|
||||||
|
281
CHANGELOG.md
281
CHANGELOG.md
@ -1,3 +1,284 @@
|
|||||||
|
**v124041081**
|
||||||
|
|
||||||
|
- chore: comment.
|
||||||
|
- fix: Last time fixing the parsing date hack before moving it to os version.
|
||||||
|
- Changelog for v124030731 [CI SKIP]
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
**v124030731**
|
||||||
|
|
||||||
|
- fix: Basic auth and password can have non whitspace characters. Fixes 142.
|
||||||
|
- Changelog for v124020451 [CI SKIP]
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
**v124020451**
|
||||||
|
|
||||||
|
- fix: Fixed handling of position in card adapter.
|
||||||
|
- Changelog for v124010301 [CI SKIP]
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
**v124010301**
|
||||||
|
|
||||||
|
- fix: This may fix the oom errors.
|
||||||
|
- Changelog for v124010191 [CI SKIP]
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
**v124010191**
|
||||||
|
|
||||||
|
- fix: moving listeners.
|
||||||
|
- chore: removed a useless log.
|
||||||
|
- Changelog for v124010032 [CI SKIP]
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
**v124010032**
|
||||||
|
|
||||||
|
- fix: Another date format thing.
|
||||||
|
- Changelog for v124010031 [CI SKIP]
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
**v124010031**
|
||||||
|
|
||||||
|
- fix: Checking if selfoss instance.
|
||||||
|
- fix: handle three characters lenght hexcode colors.
|
||||||
|
- Changelog for v123113311 [CI SKIP]
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
**v123113311**
|
||||||
|
|
||||||
|
- chore: Source tracker url in the menu.
|
||||||
|
- fix: Handle kodein proguard rules.
|
||||||
|
- Changelog for v123102961 [CI SKIP]
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
**v123102961**
|
||||||
|
|
||||||
|
- chore: domain changes.
|
||||||
|
- Changelog for v123102852 [CI SKIP]
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
**v123102852**
|
||||||
|
|
||||||
|
- chore: lint cleaning.
|
||||||
|
- Changelog for v123102841 [CI SKIP]
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
**v123102841**
|
||||||
|
|
||||||
|
- chore: cleaning ci steps and upgrading dependencies.
|
||||||
|
- feat: Self signed ssl support.
|
||||||
|
- Changelog for v123061811 [CI SKIP]
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
**v123061811**
|
||||||
|
|
||||||
|
- feat: Added confirmation dialog for disconnect item menu.
|
||||||
|
- Changelog for v123061651 [CI SKIP]
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
**v123061651**
|
||||||
|
|
||||||
|
- i18n: Translation update.
|
||||||
|
- i18n: Translation update.
|
||||||
|
- i18n: Translation update.
|
||||||
|
- fix: avoid trying to open invalid image urls.
|
||||||
|
- Changelog for v123051471 [CI SKIP]
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
**v123051471**
|
||||||
|
|
||||||
|
- fix: images could be null.
|
||||||
|
- fix: Check if color is not empty before parsing it.
|
||||||
|
- chore: Removed unused log.
|
||||||
|
- Changelog for v123051331 [CI SKIP]
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
**v123051331**
|
||||||
|
|
||||||
|
- fix: illegal input.
|
||||||
|
- Changelog for v123051321 [CI SKIP]
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
**v123051321**
|
||||||
|
|
||||||
|
- debug: Debug null context.
|
||||||
|
- Changelog for v123051301 [CI SKIP]
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
**v123051301**
|
||||||
|
|
||||||
|
- feat: Basic auth from url. Fixes #142 (#143)
|
||||||
|
- debug: Debug index out of bound exception.
|
||||||
|
- Changelog for v123051211 [CI SKIP]
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
**v123051211**
|
||||||
|
|
||||||
|
- fix: Sometimes url isn't even defined.
|
||||||
|
- Changelog for v123041021 [CI SKIP]
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
**v123041021**
|
||||||
|
|
||||||
|
- fix: 'Enable Core Library Desugaring to support older Android versions' (#138) from davidoskky/ReaderForSelfoss-multiplatform:desugaring into master
|
||||||
|
- Enable Core Library Desugaring to support older Android versions
|
||||||
|
- Changelog for v123030851 [CI SKIP]
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
**v123030851**
|
||||||
|
|
||||||
|
- chore: replace textDrawable library (#136)
|
||||||
|
- refactor: Remove slow login check. Closes #135.
|
||||||
|
- ci: send the mapping file after a release.
|
||||||
|
- Changelog for v123030751 [CI SKIP]
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
**v123030751**
|
||||||
|
|
||||||
|
- debug: added a lot to pinpoint the url issue.
|
||||||
|
- feat: Use /sources/stats in the home (#133)
|
||||||
|
- Changelog for v123030681 [CI SKIP]
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
**v123030681**
|
||||||
|
|
||||||
|
- fix: Unread and starred can be null.
|
||||||
|
- Fixed version number issue.
|
||||||
|
- Changelog for v123030621 [CI SKIP]
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
**v123030621**
|
||||||
|
|
||||||
|
- fix: url required issue.
|
||||||
|
- fix: Canvas reused issue.
|
||||||
|
- Changelog for v123020572 [CI SKIP]
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
**v123020572**
|
||||||
|
|
||||||
|
- fix: requirecontext issues ?
|
||||||
|
- debug: activity not found exception.
|
||||||
|
- Changelog for v123020571 [CI SKIP]
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
**v123020571**
|
||||||
|
|
||||||
|
- chore: remove errors logging.
|
||||||
|
- fix: quickfix for url param not provided for some sources.
|
||||||
|
- Update 'CHANGELOG.md'
|
||||||
|
- Changelog for v123020523 [CI SKIP]
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
**v123020523**
|
||||||
|
|
||||||
|
- fix: Git changelog.
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
**v123020491**
|
||||||
|
|
||||||
|
- fix: Fixed acra bug reporting.
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
**v123010301**
|
||||||
|
|
||||||
|
- Chore: acra config.
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
**v123010281**
|
||||||
|
|
||||||
|
- improvement: Improve right to left support (#130) Co-authored-by: davidoskky <davidoskky@hidden.hidden> Co-committed-by: davidoskky <davidoskky@hidden.hidden>
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
**v123010261**
|
||||||
|
|
||||||
|
- feat: Handle public instances (#126) Co-authored-by: davidoskky <davidoskky@hidden.hidden> Co-committed-by: davidoskky <davidoskky@hidden.hidden>
|
||||||
|
- ci: Pull request should trigger ci.
|
||||||
|
- fix: Complete the disconnection before redirecting to the login screen
|
||||||
|
- Complete the disconnection before redirecting to the login screen
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
**v123010241**
|
||||||
|
|
||||||
|
- Merge pull request 'feat: swipe down to close images' (#122) from davidoskky/ReaderForSelfoss-multiplatform:swipe_down into master
|
||||||
|
- Remove unnecessary definition
|
||||||
|
- Remove unused import
|
||||||
|
- Adjust the image closing animation
|
||||||
|
- Add a dark hue to the underlying article when swiping to close images
|
||||||
|
- Rename activity style to avoid interferences
|
||||||
|
- Adapt the style of the image activity to the rest of the application
|
||||||
|
- Resolve issues when swiping down to close images
|
||||||
|
- Close the image fragment only if the image has been dragged down
|
||||||
|
- Animate swipe down to close images
|
||||||
|
- Swipe down to close images
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
**v123010041**
|
||||||
|
|
||||||
|
- Merge pull request 'scroll-tag-filters' (#124) from scroll-tag-filters into master
|
||||||
|
- fix: added POST_NOTIFICATIONS to fix notifications issues.
|
||||||
|
- fix: scrollable filter sheet.
|
||||||
|
- enhancement: Ellipsize chips text.
|
||||||
|
- Cleaning.
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
**v122123641**
|
||||||
|
|
||||||
|
- feat: Disable the failing source in the filter sheet.
|
||||||
|
- feat: Display the source error in the sources list.
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
**v122123631**
|
||||||
|
|
||||||
|
- build: Added back maven repos (see https://gitlab.com/fdroid/fdroiddata/-/commit/1fb9d60dc58511abc2bb4eb321977922a0682c8b#note_1223925153)
|
||||||
|
- build: Added back maven repos (see https://gitlab.com/fdroid/fdroiddata/-/commit/1fb9d60dc58511abc2bb4eb321977922a0682c8b#note_1223925153)
|
||||||
|
- debug: trying to resolve `Canvas: trying to use a recycled bitmap`.
|
||||||
|
- fix: NPE may be caused by the binding or the title that was null.
|
||||||
|
- chore: Skip drone pipeline on changelog push.
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
**v122123621**
|
||||||
|
|
||||||
|
- fix: Automatic CHANGELOG generation.
|
||||||
|
- Merge pull request 'Sources Upsert' (#119) from sources-edit into master
|
||||||
|
- Source update screen.
|
||||||
|
- Sources menu.
|
||||||
|
- chore: Automatic CHANGELOG generation.
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
# V2/Multiplatform rewrite
|
# V2/Multiplatform rewrite
|
||||||
|
|
||||||
**v1**
|
**v1**
|
||||||
|
12
README.md
12
README.md
@ -1,4 +1,4 @@
|
|||||||
# ReaderForSelfoss-multiplatform [![Build Status](https://build.amine-louveau.fr/api/badges/Louvorg/ReaderForSelfoss-multiplatform/status.svg)](https://build.amine-louveau.fr/Louvorg/ReaderForSelfoss-multiplatform)
|
# ReaderForSelfoss-multiplatform [![Build Status](https://build.amine-bouabdallaoui.fr/api/badges/Louvorg/ReaderForSelfoss-multiplatform/status.svg)](https://build.amine-bouabdallaoui.fr/Louvorg/ReaderForSelfoss-multiplatform)
|
||||||
|
|
||||||
[![Crowdin](https://d322cqt584bo4o.cloudfront.net/readerforselfoss/localized.svg)](https://crowdin.com/project/readerforselfoss)
|
[![Crowdin](https://d322cqt584bo4o.cloudfront.net/readerforselfoss/localized.svg)](https://crowdin.com/project/readerforselfoss)
|
||||||
|
|
||||||
@ -22,15 +22,15 @@ If you are a user, you can still create new issues. I'll fix them when I can.
|
|||||||
|
|
||||||
1. **You'll have to have a Selfoss instance running.** You'll find everything you need to install it [here](https://selfoss.aditu.de/).
|
1. **You'll have to have a Selfoss instance running.** You'll find everything you need to install it [here](https://selfoss.aditu.de/).
|
||||||
|
|
||||||
2. Check the [Contribution guide](https://gitea.amine-louveau.fr/Louvorg/ReaderforSelfoss-multiplatform/src/branch/master/.github/CONTRIBUTING.md).
|
2. Check the [Contribution guide](https://gitea.amine-bouabdallaoui.fr/Louvorg/ReaderforSelfoss-multiplatform/src/branch/master/.github/CONTRIBUTING.md).
|
||||||
|
|
||||||
3. Build the project by following [these steps](https://gitea.amine-louveau.fr/Louvorg/ReaderforSelfoss-multiplatform/src/branch/master/.github/CONTRIBUTING.md#build-the-project) (you should have read them after the contribution guide)
|
3. Build the project by following [these steps](https://gitea.amine-bouabdallaoui.fr/Louvorg/ReaderforSelfoss-multiplatform/src/branch/master/.github/CONTRIBUTING.md#build-the-project) (you should have read them after the contribution guide)
|
||||||
|
|
||||||
## Useful links
|
## Useful links
|
||||||
|
|
||||||
- [Check what changed](https://gitea.amine-louveau.fr/Louvorg/ReaderforSelfoss-multiplatform/src/branch/master/CHANGELOG.md)
|
- [Check what changed](https://gitea.amine-bouabdallaoui.fr/Louvorg/ReaderforSelfoss-multiplatform/src/branch/master/CHANGELOG.md)
|
||||||
- [See what I'm doing](https://gitea.amine-louveau.fr/Louvorg/ReaderforSelfoss-multiplatform/projects/1)
|
- [See what I'm doing](https://gitea.amine-bouabdallaoui.fr/Louvorg/ReaderforSelfoss-multiplatform/projects/1)
|
||||||
- [Create an issue, or request a new feature](https://gitea.amine-louveau.fr/Louvorg/ReaderforSelfoss-multiplatform/issues)
|
- [Create an issue, or request a new feature](https://gitea.amine-bouabdallaoui.fr/Louvorg/ReaderforSelfoss-multiplatform/issues)
|
||||||
- [Help translation the app](https://crowdin.com/project/readerforselfoss)
|
- [Help translation the app](https://crowdin.com/project/readerforselfoss)
|
||||||
|
|
||||||
## Contributors (V1) (Alphabetical order) ❤️
|
## Contributors (V1) (Alphabetical order) ❤️
|
||||||
|
@ -1,19 +1,22 @@
|
|||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
|
|
||||||
val ignoreGitVersion: String by project
|
val ignoreGitVersion: String by project
|
||||||
|
val acraVersion = "5.9.7"
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("com.android.application")
|
id("com.android.application")
|
||||||
kotlin("android")
|
kotlin("android")
|
||||||
kotlin("kapt")
|
kotlin("kapt")
|
||||||
|
id("com.mikepenz.aboutlibraries.plugin")
|
||||||
|
id("org.jetbrains.kotlinx.kover")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Project.execWithOutput(cmd: String, ignore: Boolean = false): String {
|
fun Project.execWithOutput(cmd: String, ignore: Boolean = false): String {
|
||||||
var result: String = ByteArrayOutputStream().use { outputStream ->
|
val result: String = ByteArrayOutputStream().use { outputStream ->
|
||||||
project.exec {
|
project.exec {
|
||||||
commandLine = cmd.split(" ")
|
commandLine = cmd.split(" ")
|
||||||
standardOutput = outputStream
|
standardOutput = outputStream
|
||||||
isIgnoreExitValue = ignore ?: false
|
isIgnoreExitValue = ignore
|
||||||
}
|
}
|
||||||
outputStream.toString()
|
outputStream.toString()
|
||||||
}
|
}
|
||||||
@ -21,16 +24,15 @@ fun Project.execWithOutput(cmd: String, ignore: Boolean = false): String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun gitVersion(): String {
|
fun gitVersion(): String {
|
||||||
var process = ""
|
|
||||||
val maybeTagOfCurrentCommit = execWithOutput("git -C ../ describe --contains HEAD", true)
|
val maybeTagOfCurrentCommit = execWithOutput("git -C ../ describe --contains HEAD", true)
|
||||||
process = if (maybeTagOfCurrentCommit.isEmpty()) {
|
val process = if (maybeTagOfCurrentCommit.isEmpty()) {
|
||||||
println("No tag on current commit. Will take the latest one.")
|
println("No tag on current commit. Will take the latest one.")
|
||||||
execWithOutput("git -C ../ for-each-ref refs/tags --sort=-authordate --format='%(refname:short)' --count=1")
|
execWithOutput("git -C ../ for-each-ref refs/tags --sort=-refname --format='%(refname:short)' --count=1")
|
||||||
} else {
|
} else {
|
||||||
println("Tag found on current commit")
|
println("Tag found on current commit")
|
||||||
execWithOutput("git -C ../ describe --contains HEAD")
|
execWithOutput("git -C ../ describe --contains HEAD")
|
||||||
}
|
}
|
||||||
return process.replace("'", "").substring(1).replace("\\.", "").trim()
|
return process.replace("^0", "").replace("'", "").substring(1).replace("\\.", "").trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun versionCodeFromGit(): Int {
|
fun versionCodeFromGit(): Int {
|
||||||
@ -53,20 +55,24 @@ fun versionNameFromGit(): String {
|
|||||||
|
|
||||||
android {
|
android {
|
||||||
compileOptions {
|
compileOptions {
|
||||||
// Flag to enable support for the new language APIs
|
|
||||||
isCoreLibraryDesugaringEnabled = true
|
isCoreLibraryDesugaringEnabled = true
|
||||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
// Flag to enable support for the new language APIs
|
||||||
targetCompatibility = JavaVersion.VERSION_1_8
|
sourceCompatibility = JavaVersion.VERSION_17
|
||||||
|
targetCompatibility = JavaVersion.VERSION_17
|
||||||
}
|
}
|
||||||
compileSdk = 31
|
|
||||||
buildToolsVersion = "31.0.0"
|
// For Kotlin projects
|
||||||
|
kotlinOptions {
|
||||||
|
jvmTarget = "17"
|
||||||
|
}
|
||||||
|
compileSdk = 34
|
||||||
buildFeatures {
|
buildFeatures {
|
||||||
viewBinding = true
|
viewBinding = true
|
||||||
}
|
}
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId = "bou.amine.apps.readerforselfossv2.android"
|
applicationId = "bou.amine.apps.readerforselfossv2.android"
|
||||||
minSdk = 21
|
minSdk = 25
|
||||||
targetSdk = 31
|
targetSdk = 34
|
||||||
versionCode = versionCodeFromGit()
|
versionCode = versionCodeFromGit()
|
||||||
versionName = versionNameFromGit()
|
versionName = versionNameFromGit()
|
||||||
|
|
||||||
@ -79,6 +85,11 @@ android {
|
|||||||
// tests
|
// tests
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
|
packaging {
|
||||||
|
resources {
|
||||||
|
excludes += "/META-INF/{AL2.0,LGPL2.1}"
|
||||||
|
}
|
||||||
|
}
|
||||||
buildTypes {
|
buildTypes {
|
||||||
getByName("release") {
|
getByName("release") {
|
||||||
isMinifyEnabled = true
|
isMinifyEnabled = true
|
||||||
@ -86,9 +97,6 @@ android {
|
|||||||
proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
|
proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
|
||||||
}
|
}
|
||||||
getByName("debug") {
|
getByName("debug") {
|
||||||
buildConfigField("String", "LOGIN_URL", properties["appLoginUrl"] as String)
|
|
||||||
buildConfigField("String", "LOGIN_PASSWORD", properties["appLoginPassword"] as String)
|
|
||||||
buildConfigField("String", "LOGIN_USERNAME", properties["appLoginUsername"] as String)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
flavorDimensions.add("build")
|
flavorDimensions.add("build")
|
||||||
@ -98,82 +106,54 @@ android {
|
|||||||
dimension = "build"
|
dimension = "build"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
kotlinOptions {
|
|
||||||
jvmTarget = "1.8"
|
|
||||||
}
|
|
||||||
namespace = "bou.amine.apps.readerforselfossv2.android"
|
namespace = "bou.amine.apps.readerforselfossv2.android"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.3")
|
||||||
|
|
||||||
implementation(project(":shared"))
|
implementation(project(":shared"))
|
||||||
implementation("com.google.android.material:material:1.5.0")
|
implementation("com.google.android.material:material:1.9.0")
|
||||||
implementation("androidx.appcompat:appcompat:1.4.1")
|
implementation("androidx.appcompat:appcompat:1.6.1")
|
||||||
implementation("androidx.constraintlayout:constraintlayout:2.1.3")
|
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1")
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0")
|
|
||||||
|
|
||||||
implementation("androidx.preference:preference-ktx:1.1.1")
|
implementation("androidx.preference:preference-ktx:1.2.1")
|
||||||
|
|
||||||
// Testing
|
|
||||||
androidTestImplementation("androidx.test.espresso:espresso-core:3.4.0-alpha02")
|
|
||||||
androidTestImplementation("androidx.test:runner:1.3.1-alpha02")
|
|
||||||
// Espresso-contrib for DatePicker, RecyclerView, Drawer actions, Accessibility checks, CountingIdlingResource
|
|
||||||
androidTestImplementation("androidx.test.espresso:espresso-contrib:3.4.0-alpha02")
|
|
||||||
// Espresso-intents for validation and stubbing of Intents
|
|
||||||
androidTestImplementation("androidx.test.espresso:espresso-intents:3.4.0-alpha02")
|
|
||||||
implementation(fileTree(mapOf("include" to listOf("*.jar"), "dir" to "libs")))
|
implementation(fileTree(mapOf("include" to listOf("*.jar"), "dir" to "libs")))
|
||||||
|
|
||||||
// Android Support
|
// Android Support
|
||||||
implementation("androidx.appcompat:appcompat:1.4.1")
|
implementation("androidx.appcompat:appcompat:1.6.1")
|
||||||
implementation("com.google.android.material:material:1.5.0")
|
implementation("com.google.android.material:material:1.9.0")
|
||||||
implementation("androidx.recyclerview:recyclerview:1.3.0-alpha01")
|
implementation("androidx.recyclerview:recyclerview:1.3.1")
|
||||||
implementation("androidx.legacy:legacy-support-v4:1.0.0")
|
implementation("androidx.legacy:legacy-support-v4:1.0.0")
|
||||||
implementation("androidx.vectordrawable:vectordrawable:1.2.0-alpha02")
|
implementation("androidx.vectordrawable:vectordrawable:1.2.0-beta01")
|
||||||
implementation("androidx.browser:browser:1.4.0")
|
|
||||||
implementation("androidx.cardview:cardview:1.0.0")
|
implementation("androidx.cardview:cardview:1.0.0")
|
||||||
implementation("androidx.annotation:annotation:1.3.0")
|
implementation("androidx.annotation:annotation:1.7.0")
|
||||||
implementation("androidx.work:work-runtime-ktx:2.7.1")
|
implementation("androidx.work:work-runtime-ktx:2.8.1")
|
||||||
implementation("androidx.constraintlayout:constraintlayout:2.1.3")
|
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
|
||||||
implementation("org.jsoup:jsoup:1.14.3")
|
implementation("org.jsoup:jsoup:1.15.4")
|
||||||
|
|
||||||
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:1.1.5")
|
|
||||||
|
|
||||||
//multidex
|
//multidex
|
||||||
implementation("androidx.multidex:multidex:2.0.1")
|
implementation("androidx.multidex:multidex:2.0.1")
|
||||||
|
|
||||||
// About
|
// About
|
||||||
implementation("com.mikepenz:aboutlibraries-core:8.9.4")
|
implementation("com.mikepenz:aboutlibraries-core:10.5.1")
|
||||||
implementation("com.mikepenz:aboutlibraries:8.9.4")
|
implementation("com.mikepenz:aboutlibraries:10.5.1")
|
||||||
implementation("com.mikepenz:aboutlibraries-definitions:8.9.4")
|
|
||||||
|
|
||||||
// Async
|
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0")
|
|
||||||
|
|
||||||
// Retrofit + http logging + okhttp
|
|
||||||
implementation("com.squareup.retrofit2:retrofit:2.9.0")
|
|
||||||
implementation("com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.3")
|
|
||||||
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
|
|
||||||
implementation("com.burgstaller:okhttp-digest:2.5")
|
|
||||||
|
|
||||||
// Material-ish things
|
// Material-ish things
|
||||||
implementation("com.ashokvarma.android:bottom-navigation-bar:2.2.0")
|
implementation("com.ashokvarma.android:bottom-navigation-bar:2.2.0")
|
||||||
implementation("com.amulyakhare:com.amulyakhare.textdrawable:1.0.1")
|
|
||||||
|
|
||||||
// glide
|
// glide
|
||||||
kapt("com.github.bumptech.glide:compiler:4.11.0")
|
kapt("com.github.bumptech.glide:compiler:4.15.0")
|
||||||
implementation("com.github.bumptech.glide:okhttp3-integration:4.1.1")
|
implementation("com.github.bumptech.glide:okhttp3-integration:4.15.0")
|
||||||
|
|
||||||
// Drawer
|
|
||||||
implementation("com.mikepenz:materialdrawer:8.4.5")
|
|
||||||
|
|
||||||
// Themes
|
// Themes
|
||||||
implementation("com.52inc:scoops:1.0.0")
|
|
||||||
implementation("com.jaredrummler:colorpicker:1.1.0")
|
|
||||||
implementation("com.github.rubensousa:floatingtoolbar:1.5.1")
|
implementation("com.github.rubensousa:floatingtoolbar:1.5.1")
|
||||||
|
|
||||||
// Pager
|
// Pager
|
||||||
implementation("me.relex:circleindicator:2.1.6")
|
implementation("me.relex:circleindicator:2.1.6")
|
||||||
implementation("androidx.viewpager2:viewpager2:1.1.0-beta01")
|
implementation("androidx.viewpager2:viewpager2:1.1.0-beta02")
|
||||||
|
|
||||||
//Dependency Injection
|
//Dependency Injection
|
||||||
implementation("org.kodein.di:kodein-di:7.14.0")
|
implementation("org.kodein.di:kodein-di:7.14.0")
|
||||||
@ -189,16 +169,46 @@ dependencies {
|
|||||||
//PhotoView
|
//PhotoView
|
||||||
implementation("com.github.chrisbanes:PhotoView:2.3.0")
|
implementation("com.github.chrisbanes:PhotoView:2.3.0")
|
||||||
|
|
||||||
implementation("androidx.core:core-ktx:1.8.0")
|
implementation("androidx.core:core-ktx:1.12.0")
|
||||||
|
|
||||||
// implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.5.1")
|
|
||||||
// implementation("androidx.lifecycle:lifecycle-common-java8:2.5.1")
|
|
||||||
// implementation("androidx.lifecycle:lifecycle-runtime:2.5.1")
|
|
||||||
implementation("androidx.lifecycle:lifecycle-extensions:2.2.0")
|
implementation("androidx.lifecycle:lifecycle-extensions:2.2.0")
|
||||||
|
|
||||||
// Network information
|
// Network information
|
||||||
implementation("com.github.ln-12:multiplatform-connectivity-status:1.3.0")
|
implementation("com.github.ln-12:multiplatform-connectivity-status:1.3.0")
|
||||||
|
|
||||||
// SQLDELIGHT
|
// SQLDELIGHT
|
||||||
implementation("com.squareup.sqldelight:android-driver:1.5.3")
|
implementation("com.squareup.sqldelight:android-driver:1.5.4")
|
||||||
|
|
||||||
|
//test
|
||||||
|
testImplementation("junit:junit:4.13.2")
|
||||||
|
testImplementation("io.mockk:mockk:1.12.0")
|
||||||
|
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1")
|
||||||
|
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0")
|
||||||
|
|
||||||
|
implementation("ch.acra:acra-http:$acraVersion")
|
||||||
|
implementation("ch.acra:acra-toast:$acraVersion")
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType<Test> {
|
||||||
|
outputs.upToDateWhen { false }
|
||||||
|
useJUnit()
|
||||||
|
testLogging {
|
||||||
|
exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
|
||||||
|
events = setOf(
|
||||||
|
org.gradle.api.tasks.testing.logging.TestLogEvent.PASSED,
|
||||||
|
org.gradle.api.tasks.testing.logging.TestLogEvent.FAILED,
|
||||||
|
org.gradle.api.tasks.testing.logging.TestLogEvent.STANDARD_ERROR
|
||||||
|
)
|
||||||
|
showStandardStreams = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
aboutLibraries {
|
||||||
|
offlineMode = true
|
||||||
|
fetchRemoteLicense = false
|
||||||
|
fetchRemoteFunding = false
|
||||||
|
includePlatform = false
|
||||||
|
strictMode = com.mikepenz.aboutlibraries.plugin.StrictMode.FAIL
|
||||||
|
duplicationMode = com.mikepenz.aboutlibraries.plugin.DuplicateMode.MERGE
|
||||||
|
duplicationRule = com.mikepenz.aboutlibraries.plugin.DuplicateRule.GROUP
|
||||||
}
|
}
|
19
androidApp/proguard-rules.pro
vendored
19
androidApp/proguard-rules.pro
vendored
@ -30,15 +30,8 @@
|
|||||||
<fields>;
|
<fields>;
|
||||||
}
|
}
|
||||||
|
|
||||||
-dontwarn okio.**
|
|
||||||
-dontwarn retrofit2.Platform$Java8
|
|
||||||
-keep class retrofit.** { *; }
|
|
||||||
-keepclasseswithmembers class * {
|
|
||||||
@retrofit.http.* <methods>;
|
|
||||||
}
|
|
||||||
-keepattributes *Annotation*,Signature
|
-keepattributes *Annotation*,Signature
|
||||||
-keepattributes Exceptions
|
-keepattributes Exceptions
|
||||||
-dontwarn okio.**
|
|
||||||
-dontwarn javax.annotation.Nullable
|
-dontwarn javax.annotation.Nullable
|
||||||
-dontwarn javax.annotation.ParametersAreNonnullByDefault
|
-dontwarn javax.annotation.ParametersAreNonnullByDefault
|
||||||
|
|
||||||
@ -62,6 +55,7 @@
|
|||||||
# maybe remove later ?
|
# maybe remove later ?
|
||||||
-keep class * extends androidx.fragment.app.Fragment
|
-keep class * extends androidx.fragment.app.Fragment
|
||||||
|
|
||||||
|
-dontwarn org.slf4j.impl.StaticLoggerBinder
|
||||||
|
|
||||||
# Keep `Companion` object fields of serializable classes.
|
# Keep `Companion` object fields of serializable classes.
|
||||||
# This avoids serializer lookup through `getDeclaredClasses` as done for named companion objects.
|
# This avoids serializer lookup through `getDeclaredClasses` as done for named companion objects.
|
||||||
@ -90,3 +84,14 @@
|
|||||||
# @Serializable and @Polymorphic are used at runtime for polymorphic serialization.
|
# @Serializable and @Polymorphic are used at runtime for polymorphic serialization.
|
||||||
-keepattributes RuntimeVisibleAnnotations,AnnotationDefault
|
-keepattributes RuntimeVisibleAnnotations,AnnotationDefault
|
||||||
|
|
||||||
|
-dontwarn io.mockk.**
|
||||||
|
-keep class io.mockk.** { *; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Kodein
|
||||||
|
-keep, allowobfuscation, allowoptimization class org.kodein.type.TypeReference
|
||||||
|
-keep, allowobfuscation, allowoptimization class org.kodein.type.JVMAbstractTypeToken$Companion$WrappingTest
|
||||||
|
|
||||||
|
-keep, allowobfuscation, allowoptimization class * extends org.kodein.type.TypeReference
|
||||||
|
-keep, allowobfuscation, allowoptimization class * extends org.kodein.type.JVMAbstractTypeToken$Companion$WrappingTest
|
@ -2,6 +2,7 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
|
|
||||||
@ -15,7 +16,8 @@
|
|||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:networkSecurityConfig="@xml/network_security_config"
|
android:networkSecurityConfig="@xml/network_security_config"
|
||||||
android:theme="@style/NoBar"
|
android:theme="@style/NoBar"
|
||||||
android:dataExtractionRules="@xml/data_extraction_rules">
|
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||||
|
android:configChanges="uiMode">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:theme="@style/SplashTheme"
|
android:theme="@style/SplashTheme"
|
||||||
@ -51,7 +53,7 @@
|
|||||||
android:value=".HomeActivity" />
|
android:value=".HomeActivity" />
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".AddSourceActivity"
|
android:name=".UpsertSourceActivity"
|
||||||
android:parentActivityName=".SourcesActivity"
|
android:parentActivityName=".SourcesActivity"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
<meta-data
|
<meta-data
|
||||||
@ -68,7 +70,8 @@
|
|||||||
android:name=".ReaderActivity">
|
android:name=".ReaderActivity">
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".ImageActivity">
|
android:name=".ImageActivity"
|
||||||
|
android:theme="@style/Theme.AppCompat.ImageActivity">
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<meta-data android:name="android.webkit.WebView.MetricsOptOut"
|
<meta-data android:name="android.webkit.WebView.MetricsOptOut"
|
||||||
@ -78,8 +81,5 @@
|
|||||||
android:value="true" />
|
android:value="true" />
|
||||||
|
|
||||||
<meta-data android:name="android.max_aspect" android:value="2.1" />
|
<meta-data android:name="android.max_aspect" android:value="2.1" />
|
||||||
<meta-data
|
|
||||||
android:name="preloaded_fonts"
|
|
||||||
android:resource="@array/preloaded_fonts" />
|
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
@ -0,0 +1,9 @@
|
|||||||
|
package bou.amine.apps.readerforselfossv2.android
|
||||||
|
|
||||||
|
import org.acra.ACRA
|
||||||
|
import org.acra.ktx.sendSilentlyWithAcra
|
||||||
|
|
||||||
|
fun Throwable.sendSilentlyWithAcraWithName(name: String) {
|
||||||
|
ACRA.errorReporter.putCustomData("error_source", name)
|
||||||
|
this.sendSilentlyWithAcra()
|
||||||
|
}
|
@ -1,201 +0,0 @@
|
|||||||
package bou.amine.apps.readerforselfossv2.android
|
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.View
|
|
||||||
import android.widget.*
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
import bou.amine.apps.readerforselfossv2.android.databinding.ActivityAddSourceBinding
|
|
||||||
import bou.amine.apps.readerforselfossv2.android.themes.AppColors
|
|
||||||
import bou.amine.apps.readerforselfossv2.android.themes.Toppings
|
|
||||||
import bou.amine.apps.readerforselfossv2.android.utils.isBaseUrlInvalid
|
|
||||||
import bou.amine.apps.readerforselfossv2.model.NetworkUnavailableException
|
|
||||||
import bou.amine.apps.readerforselfossv2.repository.Repository
|
|
||||||
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
|
||||||
import com.ftinc.scoop.Scoop
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.kodein.di.DIAware
|
|
||||||
import org.kodein.di.android.closestDI
|
|
||||||
import org.kodein.di.instance
|
|
||||||
|
|
||||||
|
|
||||||
class AddSourceActivity : AppCompatActivity(), DIAware {
|
|
||||||
|
|
||||||
private var mSpoutsValue: String? = null
|
|
||||||
|
|
||||||
private lateinit var appColors: AppColors
|
|
||||||
private lateinit var binding: ActivityAddSourceBinding
|
|
||||||
|
|
||||||
override val di by closestDI()
|
|
||||||
private val repository : Repository by instance()
|
|
||||||
private val appSettingsService : AppSettingsService by instance()
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
appColors = AppColors(this@AddSourceActivity)
|
|
||||||
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
binding = ActivityAddSourceBinding.inflate(layoutInflater)
|
|
||||||
val view = binding.root
|
|
||||||
|
|
||||||
setContentView(view)
|
|
||||||
|
|
||||||
val scoop = Scoop.getInstance()
|
|
||||||
scoop.bind(this, Toppings.PRIMARY.value, binding.toolbar)
|
|
||||||
scoop.bindStatusBar(this, Toppings.PRIMARY_DARK.value)
|
|
||||||
|
|
||||||
val drawable = binding.nameInput.background
|
|
||||||
drawable.setTint(appColors.colorAccent)
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: clean
|
|
||||||
binding.nameInput.background = drawable
|
|
||||||
|
|
||||||
val drawable1 = binding.sourceUri.background
|
|
||||||
drawable1.setTint(appColors.colorAccent)
|
|
||||||
|
|
||||||
binding.sourceUri.background = drawable1
|
|
||||||
|
|
||||||
val drawable2 = binding.tags.background
|
|
||||||
drawable2.setTint(appColors.colorAccent)
|
|
||||||
|
|
||||||
binding.tags.background = drawable2
|
|
||||||
|
|
||||||
setSupportActionBar(binding.toolbar)
|
|
||||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
|
||||||
supportActionBar?.setDisplayShowHomeEnabled(true)
|
|
||||||
|
|
||||||
maybeGetDetailsFromIntentSharing(intent, binding.sourceUri, binding.nameInput)
|
|
||||||
|
|
||||||
binding.saveBtn.setTextColor(appColors.colorAccent)
|
|
||||||
|
|
||||||
binding.saveBtn.setOnClickListener {
|
|
||||||
handleSaveSource(
|
|
||||||
binding.tags,
|
|
||||||
binding.nameInput.text.toString(),
|
|
||||||
binding.sourceUri.text.toString()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResume() {
|
|
||||||
super.onResume()
|
|
||||||
|
|
||||||
val baseUrl = appSettingsService.getBaseUrl()
|
|
||||||
if (baseUrl.isEmpty() || baseUrl.isBaseUrlInvalid(this@AddSourceActivity)) {
|
|
||||||
mustLoginToAddSource()
|
|
||||||
} else {
|
|
||||||
handleSpoutsSpinner(binding.spoutsSpinner, binding.progress, binding.formContainer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleSpoutsSpinner(
|
|
||||||
spoutsSpinner: Spinner,
|
|
||||||
mProgress: ProgressBar,
|
|
||||||
formContainer: ConstraintLayout
|
|
||||||
) {
|
|
||||||
val spoutsKV = HashMap<String, String>()
|
|
||||||
spoutsSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
|
||||||
override fun onItemSelected(adapterView: AdapterView<*>, view: View?, i: Int, l: Long) {
|
|
||||||
if (view != null) {
|
|
||||||
val spoutName = (view as TextView).text.toString()
|
|
||||||
mSpoutsValue = spoutsKV[spoutName]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNothingSelected(adapterView: AdapterView<*>) {
|
|
||||||
mSpoutsValue = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun handleSpoutFailure(networkIssue: Boolean = false) {
|
|
||||||
Toast.makeText(
|
|
||||||
this@AddSourceActivity,
|
|
||||||
if (networkIssue) R.string.cant_get_spouts_no_network else R.string.cant_get_spouts,
|
|
||||||
Toast.LENGTH_SHORT
|
|
||||||
).show()
|
|
||||||
mProgress.visibility = View.GONE
|
|
||||||
}
|
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
|
||||||
try {
|
|
||||||
val items = repository.getSpouts()
|
|
||||||
if (items != null) {
|
|
||||||
val itemsStrings = items.map { it.value.name }
|
|
||||||
for ((key, value) in items) {
|
|
||||||
spoutsKV[value.name] = key
|
|
||||||
}
|
|
||||||
|
|
||||||
mProgress.visibility = View.GONE
|
|
||||||
formContainer.visibility = View.VISIBLE
|
|
||||||
|
|
||||||
val spinnerArrayAdapter =
|
|
||||||
ArrayAdapter(
|
|
||||||
this@AddSourceActivity,
|
|
||||||
android.R.layout.simple_spinner_item,
|
|
||||||
itemsStrings
|
|
||||||
)
|
|
||||||
spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
|
|
||||||
spoutsSpinner.adapter = spinnerArrayAdapter
|
|
||||||
} else {
|
|
||||||
handleSpoutFailure()
|
|
||||||
}
|
|
||||||
} catch (e: NetworkUnavailableException) {
|
|
||||||
handleSpoutFailure(networkIssue = true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun maybeGetDetailsFromIntentSharing(
|
|
||||||
intent: Intent,
|
|
||||||
sourceUri: EditText,
|
|
||||||
nameInput: EditText
|
|
||||||
) {
|
|
||||||
if (Intent.ACTION_SEND == intent.action && "text/plain" == intent.type) {
|
|
||||||
sourceUri.setText(intent.getStringExtra(Intent.EXTRA_TEXT))
|
|
||||||
nameInput.setText(intent.getStringExtra(Intent.EXTRA_TITLE))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun mustLoginToAddSource() {
|
|
||||||
Toast.makeText(this, getString(R.string.addStringNoUrl), Toast.LENGTH_SHORT).show()
|
|
||||||
val i = Intent(this, LoginActivity::class.java)
|
|
||||||
startActivity(i)
|
|
||||||
finish()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleSaveSource(tags: EditText, title: String, url: String) {
|
|
||||||
|
|
||||||
val sourceDetailsUnavailable =
|
|
||||||
title.isEmpty() || url.isEmpty() || mSpoutsValue == null || mSpoutsValue!!.isEmpty()
|
|
||||||
|
|
||||||
when {
|
|
||||||
sourceDetailsUnavailable -> {
|
|
||||||
Toast.makeText(this, R.string.form_not_complete, Toast.LENGTH_SHORT).show()
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
|
||||||
val successfullyAddedSource = repository.createSource(
|
|
||||||
title,
|
|
||||||
url,
|
|
||||||
mSpoutsValue!!,
|
|
||||||
tags.text.toString(),
|
|
||||||
"",
|
|
||||||
)
|
|
||||||
if (successfullyAddedSource) {
|
|
||||||
finish()
|
|
||||||
} else {
|
|
||||||
Toast.makeText(
|
|
||||||
this@AddSourceActivity,
|
|
||||||
R.string.cant_create_source,
|
|
||||||
Toast.LENGTH_SHORT
|
|
||||||
).show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,23 +1,18 @@
|
|||||||
package bou.amine.apps.readerforselfossv2.android
|
package bou.amine.apps.readerforselfossv2.android
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.Color
|
|
||||||
import android.graphics.drawable.Drawable
|
|
||||||
import android.graphics.drawable.GradientDrawable
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.ImageView
|
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.appcompat.app.ActionBarDrawerToggle
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.widget.SearchView
|
import androidx.appcompat.widget.SearchView
|
||||||
import androidx.core.view.doOnNextLayout
|
import androidx.core.view.doOnNextLayout
|
||||||
import androidx.drawerlayout.widget.DrawerLayout
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.recyclerview.widget.*
|
import androidx.recyclerview.widget.*
|
||||||
import androidx.work.Constraints
|
import androidx.work.Constraints
|
||||||
import androidx.work.ExistingPeriodicWorkPolicy
|
import androidx.work.ExistingPeriodicWorkPolicy
|
||||||
@ -28,50 +23,28 @@ import bou.amine.apps.readerforselfossv2.android.adapters.ItemListAdapter
|
|||||||
import bou.amine.apps.readerforselfossv2.android.adapters.ItemsAdapter
|
import bou.amine.apps.readerforselfossv2.android.adapters.ItemsAdapter
|
||||||
import bou.amine.apps.readerforselfossv2.android.background.LoadingWorker
|
import bou.amine.apps.readerforselfossv2.android.background.LoadingWorker
|
||||||
import bou.amine.apps.readerforselfossv2.android.databinding.ActivityHomeBinding
|
import bou.amine.apps.readerforselfossv2.android.databinding.ActivityHomeBinding
|
||||||
|
import bou.amine.apps.readerforselfossv2.android.fragments.FilterSheetFragment
|
||||||
import bou.amine.apps.readerforselfossv2.android.settings.SettingsActivity
|
import bou.amine.apps.readerforselfossv2.android.settings.SettingsActivity
|
||||||
import bou.amine.apps.readerforselfossv2.android.themes.AppColors
|
|
||||||
import bou.amine.apps.readerforselfossv2.android.themes.Toppings
|
|
||||||
import bou.amine.apps.readerforselfossv2.android.utils.bottombar.maybeShow
|
import bou.amine.apps.readerforselfossv2.android.utils.bottombar.maybeShow
|
||||||
import bou.amine.apps.readerforselfossv2.android.utils.bottombar.removeBadge
|
import bou.amine.apps.readerforselfossv2.android.utils.bottombar.removeBadge
|
||||||
import bou.amine.apps.readerforselfossv2.android.utils.customtabs.CustomTabActivityHelper
|
|
||||||
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
||||||
import bou.amine.apps.readerforselfossv2.repository.Repository
|
import bou.amine.apps.readerforselfossv2.repository.Repository
|
||||||
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
||||||
import bou.amine.apps.readerforselfossv2.utils.*
|
import bou.amine.apps.readerforselfossv2.utils.ItemType
|
||||||
import com.ashokvarma.bottomnavigation.BottomNavigationBar
|
import com.ashokvarma.bottomnavigation.BottomNavigationBar
|
||||||
import com.ashokvarma.bottomnavigation.BottomNavigationItem
|
import com.ashokvarma.bottomnavigation.BottomNavigationItem
|
||||||
import com.ashokvarma.bottomnavigation.TextBadgeItem
|
import com.ashokvarma.bottomnavigation.TextBadgeItem
|
||||||
import com.bumptech.glide.Glide
|
|
||||||
import com.bumptech.glide.request.RequestOptions
|
|
||||||
import com.ftinc.scoop.Scoop
|
|
||||||
import com.mikepenz.aboutlibraries.LibsBuilder
|
|
||||||
import com.mikepenz.materialdrawer.holder.BadgeStyle
|
|
||||||
import com.mikepenz.materialdrawer.holder.ColorHolder
|
|
||||||
import com.mikepenz.materialdrawer.holder.StringHolder
|
|
||||||
import com.mikepenz.materialdrawer.model.DividerDrawerItem
|
|
||||||
import com.mikepenz.materialdrawer.model.PrimaryDrawerItem
|
|
||||||
import com.mikepenz.materialdrawer.model.SecondaryDrawerItem
|
|
||||||
import com.mikepenz.materialdrawer.model.interfaces.*
|
|
||||||
import com.mikepenz.materialdrawer.util.AbstractDrawerImageLoader
|
|
||||||
import com.mikepenz.materialdrawer.util.DrawerImageLoader
|
|
||||||
import com.mikepenz.materialdrawer.util.addStickyFooterItem
|
|
||||||
import com.mikepenz.materialdrawer.util.updateBadge
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.kodein.di.DIAware
|
import org.kodein.di.DIAware
|
||||||
import org.kodein.di.android.closestDI
|
import org.kodein.di.android.closestDI
|
||||||
import org.kodein.di.instance
|
import org.kodein.di.instance
|
||||||
|
import java.security.MessageDigest
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
|
||||||
class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAware {
|
class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAware {
|
||||||
|
|
||||||
private val DRAWER_ID_TAGS = 100101L
|
|
||||||
private val DRAWER_ID_HIDDEN_TAGS = 101100L
|
|
||||||
private val DRAWER_ID_SOURCES = 100110L
|
|
||||||
private val DRAWER_ID_FILTERS = 100111L
|
|
||||||
|
|
||||||
private var items: ArrayList<SelfossModel.Item> = ArrayList()
|
private var items: ArrayList<SelfossModel.Item> = ArrayList()
|
||||||
|
|
||||||
private var elementsShown: ItemType = ItemType.UNREAD
|
private var elementsShown: ItemType = ItemType.UNREAD
|
||||||
@ -80,8 +53,6 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
private lateinit var tabNewBadge: TextBadgeItem
|
private lateinit var tabNewBadge: TextBadgeItem
|
||||||
private lateinit var tabArchiveBadge: TextBadgeItem
|
private lateinit var tabArchiveBadge: TextBadgeItem
|
||||||
private lateinit var tabStarredBadge: TextBadgeItem
|
private lateinit var tabStarredBadge: TextBadgeItem
|
||||||
private lateinit var customTabActivityHelper: CustomTabActivityHelper
|
|
||||||
private lateinit var appColors: AppColors
|
|
||||||
private var offset: Int = 0
|
private var offset: Int = 0
|
||||||
private var firstVisible: Int = 0
|
private var firstVisible: Int = 0
|
||||||
private lateinit var recyclerViewScrollListener: RecyclerView.OnScrollListener
|
private lateinit var recyclerViewScrollListener: RecyclerView.OnScrollListener
|
||||||
@ -91,9 +62,8 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
|
|
||||||
private var fromTabShortcut: Boolean = false
|
private var fromTabShortcut: Boolean = false
|
||||||
|
|
||||||
private lateinit var tagsBadge: Map<Long, Int>
|
private val settingsLauncher =
|
||||||
|
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||||
private val settingsLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
|
||||||
appSettingsService.refreshUserSettings()
|
appSettingsService.refreshUserSettings()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,18 +71,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
private val repository: Repository by instance()
|
private val repository: Repository by instance()
|
||||||
private val appSettingsService: AppSettingsService by instance()
|
private val appSettingsService: AppSettingsService by instance()
|
||||||
|
|
||||||
data class DrawerData(val tags: List<SelfossModel.Tag>?, val sources: List<SelfossModel.Source>?)
|
|
||||||
|
|
||||||
override fun onStart() {
|
|
||||||
super.onStart()
|
|
||||||
customTabActivityHelper.bindCustomTabsService(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
|
||||||
// Add appcolors to DI
|
|
||||||
appColors = AppColors(this@HomeActivity)
|
|
||||||
|
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
binding = ActivityHomeBinding.inflate(layoutInflater)
|
binding = ActivityHomeBinding.inflate(layoutInflater)
|
||||||
val view = binding.root
|
val view = binding.root
|
||||||
@ -126,71 +85,69 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
|
|
||||||
setContentView(view)
|
setContentView(view)
|
||||||
|
|
||||||
handleThemeBinding()
|
|
||||||
|
|
||||||
setSupportActionBar(binding.toolBar)
|
setSupportActionBar(binding.toolBar)
|
||||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
|
||||||
supportActionBar?.setHomeButtonEnabled(true)
|
|
||||||
val mDrawerToggle = ActionBarDrawerToggle(this, binding.drawerContainer, binding.toolBar, R.string.material_drawer_open, R.string.material_drawer_close)
|
|
||||||
binding.drawerContainer.addDrawerListener(mDrawerToggle)
|
|
||||||
mDrawerToggle.syncState()
|
|
||||||
|
|
||||||
customTabActivityHelper = CustomTabActivityHelper()
|
|
||||||
|
|
||||||
handleBottomBar()
|
handleBottomBar()
|
||||||
initDrawer()
|
|
||||||
|
|
||||||
handleSwipeRefreshLayout()
|
handleSwipeRefreshLayout()
|
||||||
|
|
||||||
getElementsAccordingToTab()
|
if (appSettingsService.isItemCachingEnabled()) {
|
||||||
|
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
repository.tryToCacheItemsAndGetNewOnes()
|
repository.tryToCacheItemsAndGetNewOnes()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun handleSwipeRefreshLayout() {
|
private fun handleSwipeRefreshLayout() {
|
||||||
binding.swipeRefreshLayout.setColorSchemeResources(
|
binding.swipeRefreshLayout.setColorSchemeResources(
|
||||||
R.color.refresh_progress_1,
|
R.color.refresh_progress_1,
|
||||||
R.color.refresh_progress_2,
|
R.color.refresh_progress_2,
|
||||||
R.color.refresh_progress_3
|
R.color.refresh_progress_3,
|
||||||
)
|
)
|
||||||
binding.swipeRefreshLayout.setOnRefreshListener {
|
binding.swipeRefreshLayout.setOnRefreshListener {
|
||||||
repository.offlineOverride = false
|
repository.offlineOverride = false
|
||||||
lastFetchDone = false
|
lastFetchDone = false
|
||||||
handleDrawerItems()
|
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
getElementsAccordingToTab()
|
getElementsAccordingToTab()
|
||||||
binding.swipeRefreshLayout.isRefreshing = false
|
binding.swipeRefreshLayout.isRefreshing = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val swipeDirs =
|
||||||
|
if (appSettingsService.getPublicAccess()) {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT
|
||||||
|
}
|
||||||
|
|
||||||
val simpleItemTouchCallback =
|
val simpleItemTouchCallback =
|
||||||
object : ItemTouchHelper.SimpleCallback(
|
object : ItemTouchHelper.SimpleCallback(
|
||||||
0,
|
0,
|
||||||
ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT
|
swipeDirs,
|
||||||
) {
|
) {
|
||||||
override fun getSwipeDirs(
|
override fun getSwipeDirs(
|
||||||
recyclerView: RecyclerView,
|
recyclerView: RecyclerView,
|
||||||
viewHolder: RecyclerView.ViewHolder
|
viewHolder: RecyclerView.ViewHolder,
|
||||||
): Int =
|
): Int =
|
||||||
if (elementsShown == ItemType.STARRED) {
|
if (elementsShown == ItemType.STARRED) {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
super.getSwipeDirs(
|
super.getSwipeDirs(
|
||||||
recyclerView,
|
recyclerView,
|
||||||
viewHolder
|
viewHolder,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onMove(
|
override fun onMove(
|
||||||
recyclerView: RecyclerView,
|
recyclerView: RecyclerView,
|
||||||
viewHolder: RecyclerView.ViewHolder,
|
viewHolder: RecyclerView.ViewHolder,
|
||||||
target: RecyclerView.ViewHolder
|
target: RecyclerView.ViewHolder,
|
||||||
): Boolean = false
|
): Boolean = false
|
||||||
|
|
||||||
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, swipeDir: Int) {
|
override fun onSwiped(
|
||||||
|
viewHolder: RecyclerView.ViewHolder,
|
||||||
|
swipeDir: Int,
|
||||||
|
) {
|
||||||
val position = viewHolder.bindingAdapterPosition
|
val position = viewHolder.bindingAdapterPosition
|
||||||
val i = items.elementAtOrNull(position)
|
val i = items.elementAtOrNull(position)
|
||||||
|
|
||||||
@ -199,18 +156,6 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
|
|
||||||
adapter.handleItemAtIndex(position)
|
adapter.handleItemAtIndex(position)
|
||||||
|
|
||||||
reloadBadgeContent()
|
|
||||||
|
|
||||||
val tagHashes = i.tags.map { it.longHash() }
|
|
||||||
tagsBadge = tagsBadge.map {
|
|
||||||
if (tagHashes.contains(it.key)) {
|
|
||||||
(it.key to (it.value - 1))
|
|
||||||
} else {
|
|
||||||
(it.key to it.value)
|
|
||||||
}
|
|
||||||
}.toMap()
|
|
||||||
reloadTagsBadges()
|
|
||||||
|
|
||||||
// Just load everythin
|
// Just load everythin
|
||||||
if (items.size <= 0) {
|
if (items.size <= 0) {
|
||||||
getElementsAccordingToTab()
|
getElementsAccordingToTab()
|
||||||
@ -219,7 +164,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
this@HomeActivity,
|
this@HomeActivity,
|
||||||
"Found null when swiping at positon $position.",
|
"Found null when swiping at positon $position.",
|
||||||
Toast.LENGTH_LONG
|
Toast.LENGTH_LONG,
|
||||||
).show()
|
).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -228,37 +173,71 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
ItemTouchHelper(simpleItemTouchCallback).attachToRecyclerView(binding.recyclerView)
|
ItemTouchHelper(simpleItemTouchCallback).attachToRecyclerView(binding.recyclerView)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleBottomBar() {
|
private fun updateBottomBarBadgeCount(
|
||||||
|
badge: TextBadgeItem,
|
||||||
|
count: Int,
|
||||||
|
) {
|
||||||
|
if (count > 0) {
|
||||||
|
badge
|
||||||
|
.setText(count.toString())
|
||||||
|
.maybeShow()
|
||||||
|
} else {
|
||||||
|
badge.removeBadge()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tabNewBadge = TextBadgeItem()
|
private fun handleBottomBar() {
|
||||||
|
tabNewBadge =
|
||||||
|
TextBadgeItem()
|
||||||
.setText("")
|
.setText("")
|
||||||
.setHideOnSelect(false).hide(false)
|
.setHideOnSelect(false).hide(false)
|
||||||
.setBackgroundColor(appColors.colorPrimary)
|
tabArchiveBadge =
|
||||||
tabArchiveBadge = TextBadgeItem()
|
TextBadgeItem()
|
||||||
.setText("")
|
.setText("")
|
||||||
.setHideOnSelect(false).hide(false)
|
.setHideOnSelect(false).hide(false)
|
||||||
.setBackgroundColor(appColors.colorPrimary)
|
tabStarredBadge =
|
||||||
tabStarredBadge = TextBadgeItem()
|
TextBadgeItem()
|
||||||
.setText("")
|
.setText("")
|
||||||
.setHideOnSelect(false).hide(false)
|
.setHideOnSelect(false).hide(false)
|
||||||
.setBackgroundColor(appColors.colorPrimary)
|
|
||||||
|
if (appSettingsService.isDisplayUnreadCountEnabled()) {
|
||||||
|
lifecycleScope.launch {
|
||||||
|
repository.badgeUnread.collect {
|
||||||
|
updateBottomBarBadgeCount(tabNewBadge, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (appSettingsService.isDisplayAllCountEnabled()) {
|
||||||
|
lifecycleScope.launch {
|
||||||
|
repository.badgeAll.collect {
|
||||||
|
updateBottomBarBadgeCount(tabArchiveBadge, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lifecycleScope.launch {
|
||||||
|
repository.badgeStarred.collect {
|
||||||
|
updateBottomBarBadgeCount(tabStarredBadge, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val tabNew =
|
val tabNew =
|
||||||
BottomNavigationItem(
|
BottomNavigationItem(
|
||||||
R.drawable.ic_tab_fiber_new_black_24dp,
|
R.drawable.ic_tab_fiber_new_black_24dp,
|
||||||
getString(R.string.tab_new)
|
getString(R.string.tab_new),
|
||||||
).setActiveColor(appColors.colorAccent)
|
)
|
||||||
.setBadgeItem(tabNewBadge)
|
.setBadgeItem(tabNewBadge)
|
||||||
val tabArchive =
|
val tabArchive =
|
||||||
BottomNavigationItem(
|
BottomNavigationItem(
|
||||||
R.drawable.ic_tab_archive_black_24dp,
|
R.drawable.ic_tab_archive_black_24dp,
|
||||||
getString(R.string.tab_read)
|
getString(R.string.tab_read),
|
||||||
).setActiveColor(appColors.colorAccentDark)
|
)
|
||||||
.setBadgeItem(tabArchiveBadge)
|
.setBadgeItem(tabArchiveBadge)
|
||||||
val tabStarred =
|
val tabStarred =
|
||||||
BottomNavigationItem(
|
BottomNavigationItem(
|
||||||
R.drawable.ic_tab_favorite_black_24dp,
|
R.drawable.ic_tab_favorite_black_24dp,
|
||||||
getString(R.string.tab_favs)
|
getString(R.string.tab_favs),
|
||||||
).setActiveColorResource(R.color.pink)
|
).setActiveColorResource(R.color.pink)
|
||||||
.setBadgeItem(tabStarredBadge)
|
.setBadgeItem(tabStarredBadge)
|
||||||
|
|
||||||
@ -269,7 +248,6 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
.setFirstSelectedPosition(0)
|
.setFirstSelectedPosition(0)
|
||||||
.initialise()
|
.initialise()
|
||||||
binding.bottomBar.setMode(BottomNavigationBar.MODE_SHIFTING)
|
binding.bottomBar.setMode(BottomNavigationBar.MODE_SHIFTING)
|
||||||
binding.bottomBar.setBackgroundStyle(BottomNavigationBar.BACKGROUND_STYLE_STATIC)
|
|
||||||
|
|
||||||
if (fromTabShortcut) {
|
if (fromTabShortcut) {
|
||||||
binding.bottomBar.selectTab(elementsShown.position - 1)
|
binding.bottomBar.selectTab(elementsShown.position - 1)
|
||||||
@ -279,12 +257,6 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
|
|
||||||
appColors = AppColors(this@HomeActivity)
|
|
||||||
|
|
||||||
handleDrawerItems()
|
|
||||||
|
|
||||||
handleThemeUpdate()
|
|
||||||
|
|
||||||
reloadLayoutManager()
|
reloadLayoutManager()
|
||||||
|
|
||||||
if (appSettingsService.isInfiniteLoadingEnabled()) {
|
if (appSettingsService.isInfiniteLoadingEnabled()) {
|
||||||
@ -295,6 +267,8 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
|
|
||||||
handleBottomBarActions()
|
handleBottomBarActions()
|
||||||
|
|
||||||
|
handleGDPRDialog(appSettingsService.settings.getBoolean("GDPR_shown", false))
|
||||||
|
|
||||||
handleRecurringTask()
|
handleRecurringTask()
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
@ -304,276 +278,21 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
getElementsAccordingToTab()
|
getElementsAccordingToTab()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStop() {
|
private fun handleGDPRDialog(GDPRShown: Boolean) {
|
||||||
super.onStop()
|
val messageDigest: MessageDigest = MessageDigest.getInstance("SHA-256")
|
||||||
customTabActivityHelper.unbindCustomTabsService(this)
|
messageDigest.update(appSettingsService.getBaseUrl().toByteArray())
|
||||||
|
if (!GDPRShown) {
|
||||||
|
val alertDialog = AlertDialog.Builder(this).create()
|
||||||
|
alertDialog.setTitle(getString(R.string.gdpr_dialog_title))
|
||||||
|
alertDialog.setMessage(getString(R.string.gdpr_dialog_message))
|
||||||
|
alertDialog.setButton(
|
||||||
|
AlertDialog.BUTTON_NEUTRAL,
|
||||||
|
"OK",
|
||||||
|
) { dialog, _ ->
|
||||||
|
appSettingsService.settings.putBoolean("GDPR_shown", true)
|
||||||
|
dialog.dismiss()
|
||||||
}
|
}
|
||||||
|
alertDialog.show()
|
||||||
private fun handleThemeBinding() {
|
|
||||||
val scoop = Scoop.getInstance()
|
|
||||||
scoop.bind(this, Toppings.PRIMARY.value, binding.toolBar)
|
|
||||||
scoop.bindStatusBar(this, Toppings.PRIMARY_DARK.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleThemeUpdate() {
|
|
||||||
|
|
||||||
val scoop = Scoop.getInstance()
|
|
||||||
scoop.update(Toppings.PRIMARY.value, appColors.colorPrimary)
|
|
||||||
|
|
||||||
scoop.update(Toppings.PRIMARY_DARK.value, appColors.colorPrimaryDark)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun initDrawer() {
|
|
||||||
DrawerImageLoader.init(object : AbstractDrawerImageLoader() {
|
|
||||||
override fun set(imageView: ImageView, uri: Uri, placeholder: Drawable, tag: String?) {
|
|
||||||
Glide.with(this@HomeActivity)
|
|
||||||
.asBitmap()
|
|
||||||
.load(uri)
|
|
||||||
.apply(RequestOptions()
|
|
||||||
.placeholder(R.mipmap.ic_launcher)
|
|
||||||
.fallback(R.mipmap.ic_launcher)
|
|
||||||
.fitCenter())
|
|
||||||
.into(imageView)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun cancel(imageView: ImageView) {
|
|
||||||
Glide.with(this@HomeActivity).clear(imageView)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
val drawerListener = object : DrawerLayout.DrawerListener {
|
|
||||||
override fun onDrawerSlide(drawerView: View, slideOffset: Float) {
|
|
||||||
// We do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDrawerOpened(drawerView: View) {
|
|
||||||
binding.bottomBar.hide()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDrawerClosed(drawerView: View) {
|
|
||||||
binding.bottomBar.show()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDrawerStateChanged(newState: Int) {
|
|
||||||
// We do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.drawerContainer.addDrawerListener(drawerListener)
|
|
||||||
|
|
||||||
// Sticky items
|
|
||||||
addStickyPrimaryItem(R.string.drawer_report_bug, R.drawable.ic_bug_report_black_24dp) { _, _, _ ->
|
|
||||||
val browserIntent =
|
|
||||||
Intent(Intent.ACTION_VIEW, Uri.parse(AppSettingsService.trackerUrl))
|
|
||||||
startActivity(browserIntent)
|
|
||||||
false
|
|
||||||
}
|
|
||||||
addStickyPrimaryItem(R.string.title_activity_settings, R.drawable.ic_settings_black_24dp) { _, _, _ ->
|
|
||||||
settingsLauncher.launch(Intent(this, SettingsActivity::class.java))
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun addStickyPrimaryItem(name: Int, icon: Int, clickListener: ((v: View?, item: IDrawerItem<*>, position: Int) -> Boolean)?) {
|
|
||||||
binding.mainDrawer.addStickyFooterItem(
|
|
||||||
PrimaryDrawerItem().apply {
|
|
||||||
nameRes = name
|
|
||||||
iconRes = icon
|
|
||||||
isIconTinted = true
|
|
||||||
onDrawerItemClickListener = clickListener
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleDrawerItems() {
|
|
||||||
tagsBadge = emptyMap()
|
|
||||||
binding.mainDrawer.itemAdapter.add(
|
|
||||||
PrimaryDrawerItem().apply {
|
|
||||||
nameRes = R.string.drawer_loading
|
|
||||||
isSelectable = false
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
|
||||||
val drawerData = DrawerData(repository.getDBTags().map { it.toView() },
|
|
||||||
repository.getDBSources().map { it.toView() })
|
|
||||||
runOnUiThread {
|
|
||||||
// Only refresh if there is no data in the DB, or if the `UpdateSources` setting is enabled
|
|
||||||
if (drawerData.sources?.isEmpty() == true || appSettingsService.isUpdateSourcesEnabled()) {
|
|
||||||
drawerApiCalls(drawerData)
|
|
||||||
} else {
|
|
||||||
handleDrawerData(drawerData, loadedFromCache = true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun drawerApiCalls(drawerData: DrawerData) {
|
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
|
||||||
val apiDrawerData = DrawerData(repository.getTags(), repository.getSources())
|
|
||||||
handleDrawerData(if (drawerData != apiDrawerData) apiDrawerData else drawerData)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleDrawerData(drawerData: DrawerData, loadedFromCache: Boolean = false) {
|
|
||||||
binding.mainDrawer.itemAdapter.clear()
|
|
||||||
|
|
||||||
// Filters title with clear action
|
|
||||||
secondaryItem(withDivider = false, R.string.drawer_item_filters, DRAWER_ID_FILTERS, R.string.drawer_action_clear) { _,_,_ ->
|
|
||||||
repository.sourceFilter = null
|
|
||||||
repository.tagFilter = null
|
|
||||||
binding.mainDrawer.setSelectionAtPosition(-1)
|
|
||||||
getElementsAccordingToTab()
|
|
||||||
fetchOnEmptyList()
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hidden tags
|
|
||||||
if (drawerData.tags != null && drawerData.tags.isNotEmpty() && appSettingsService.getHiddenTags().isNotEmpty()) {
|
|
||||||
secondaryItem(
|
|
||||||
withDivider = true,
|
|
||||||
R.string.drawer_item_hidden_tags,
|
|
||||||
DRAWER_ID_HIDDEN_TAGS
|
|
||||||
)
|
|
||||||
handleHiddenTags(drawerData.tags)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tags
|
|
||||||
secondaryItem(withDivider = true, R.string.drawer_item_tags, DRAWER_ID_TAGS)
|
|
||||||
if (drawerData.tags == null && !loadedFromCache) {
|
|
||||||
binding.mainDrawer.itemAdapter.add(
|
|
||||||
SecondaryDrawerItem()
|
|
||||||
.apply { nameRes = R.string.drawer_error_loading_tags; isSelectable = false }
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
handleTags(drawerData.tags!!)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sources
|
|
||||||
secondaryItem(withDivider = true, R.string.drawer_item_sources, DRAWER_ID_SOURCES, R.string.drawer_action_edit) { v, _, _ ->
|
|
||||||
startActivity(Intent(v!!.context, SourcesActivity::class.java))
|
|
||||||
false
|
|
||||||
}
|
|
||||||
if (drawerData.sources == null && !loadedFromCache) {
|
|
||||||
binding.mainDrawer.itemAdapter.add(
|
|
||||||
SecondaryDrawerItem().apply {
|
|
||||||
nameRes = R.string.drawer_error_loading_tags
|
|
||||||
isSelectable = false
|
|
||||||
}
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
handleSources(drawerData.sources!!)
|
|
||||||
}
|
|
||||||
|
|
||||||
// About action
|
|
||||||
binding.mainDrawer.itemAdapter.add(
|
|
||||||
DividerDrawerItem(),
|
|
||||||
PrimaryDrawerItem().apply {
|
|
||||||
nameRes = R.string.action_about
|
|
||||||
isSelectable = false
|
|
||||||
iconRes = R.drawable.ic_info_outline_white_24dp
|
|
||||||
isIconTinted = true
|
|
||||||
onDrawerItemClickListener = { _,_,_ ->
|
|
||||||
LibsBuilder()
|
|
||||||
.withAboutIconShown(true)
|
|
||||||
.withAboutVersionShown(true)
|
|
||||||
.start(this@HomeActivity)
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun secondaryItem(withDivider: Boolean, name: Int, id: Long, badgeId: Int? = null, clickListener: ((v: View?, item: IDrawerItem<*>, position: Int) -> Boolean)? = null) {
|
|
||||||
if (withDivider) {
|
|
||||||
binding.mainDrawer.itemAdapter.add(DividerDrawerItem())
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.mainDrawer.itemAdapter.add(
|
|
||||||
SecondaryDrawerItem().apply {
|
|
||||||
nameRes = name
|
|
||||||
identifier = id
|
|
||||||
isSelectable = false
|
|
||||||
if (badgeId != null) {
|
|
||||||
badgeRes = badgeId
|
|
||||||
}
|
|
||||||
onDrawerItemClickListener = clickListener
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createDrawerItem(it: SelfossModel.Tag) {
|
|
||||||
val gd = GradientDrawable()
|
|
||||||
val gdColor = try {
|
|
||||||
Color.parseColor(it.color)
|
|
||||||
} catch (e: IllegalArgumentException) {
|
|
||||||
appColors.colorPrimary
|
|
||||||
}
|
|
||||||
gd.setColor(gdColor)
|
|
||||||
gd.shape = GradientDrawable.RECTANGLE
|
|
||||||
gd.setSize(30, 30)
|
|
||||||
gd.cornerRadius = 30F
|
|
||||||
|
|
||||||
val drawerItem = PrimaryDrawerItem()
|
|
||||||
.apply {
|
|
||||||
nameText = it.tag.getHtmlDecoded()
|
|
||||||
identifier = it.tag.longHash()
|
|
||||||
iconDrawable = gd
|
|
||||||
badgeStyle = BadgeStyle().apply {
|
|
||||||
textColor = ColorHolder.fromColor(Color.WHITE)
|
|
||||||
color = ColorHolder.fromColor(appColors.colorAccent)
|
|
||||||
}
|
|
||||||
onDrawerItemClickListener = { _, _, _ ->
|
|
||||||
repository.tagFilter = it
|
|
||||||
repository.sourceFilter = null
|
|
||||||
getElementsAccordingToTab()
|
|
||||||
fetchOnEmptyList()
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (it.unread > 0) {
|
|
||||||
drawerItem.badgeText = it.unread.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.mainDrawer.itemAdapter.add(drawerItem)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleTags(tags: List<SelfossModel.Tag>) {
|
|
||||||
val filteredTags = tags
|
|
||||||
.filterNot { appSettingsService.getHiddenTags().contains(it.tag) }
|
|
||||||
.sortedBy { it.tag }
|
|
||||||
createTagItems(filteredTags)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleHiddenTags(tags: List<SelfossModel.Tag>) {
|
|
||||||
val filteredHiddenTags: List<SelfossModel.Tag> =
|
|
||||||
tags.filter { appSettingsService.getHiddenTags().contains(it.tag) }
|
|
||||||
createTagItems(filteredHiddenTags)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createTagItems(tags: List<SelfossModel.Tag>) {
|
|
||||||
tagsBadge = tags.associate {
|
|
||||||
createDrawerItem(it)
|
|
||||||
|
|
||||||
(it.tag.longHash() to it.unread)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleSources(sources: List<SelfossModel.Source>) {
|
|
||||||
for (source in sources) {
|
|
||||||
val item = PrimaryDrawerItem().apply {
|
|
||||||
nameText = source.title.getHtmlDecoded()
|
|
||||||
identifier = source.id.toLong()
|
|
||||||
iconUrl = source.getIcon(repository.baseUrl)
|
|
||||||
onDrawerItemClickListener = { _,_,_ ->
|
|
||||||
repository.sourceFilter = source
|
|
||||||
repository.tagFilter = null
|
|
||||||
getElementsAccordingToTab()
|
|
||||||
fetchOnEmptyList()
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
binding.mainDrawer.itemAdapter.add(item)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -585,17 +304,19 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
when (currentManager) {
|
when (currentManager) {
|
||||||
is StaggeredGridLayoutManager ->
|
is StaggeredGridLayoutManager ->
|
||||||
if (!appSettingsService.isCardViewEnabled()) {
|
if (!appSettingsService.isCardViewEnabled()) {
|
||||||
layoutManager = GridLayoutManager(
|
layoutManager =
|
||||||
|
GridLayoutManager(
|
||||||
this,
|
this,
|
||||||
calculateNoOfColumns()
|
calculateNoOfColumns(),
|
||||||
)
|
)
|
||||||
binding.recyclerView.layoutManager = layoutManager
|
binding.recyclerView.layoutManager = layoutManager
|
||||||
}
|
}
|
||||||
is GridLayoutManager ->
|
is GridLayoutManager ->
|
||||||
if (appSettingsService.isCardViewEnabled()) {
|
if (appSettingsService.isCardViewEnabled()) {
|
||||||
layoutManager = StaggeredGridLayoutManager(
|
layoutManager =
|
||||||
|
StaggeredGridLayoutManager(
|
||||||
calculateNoOfColumns(),
|
calculateNoOfColumns(),
|
||||||
StaggeredGridLayoutManager.VERTICAL
|
StaggeredGridLayoutManager.VERTICAL,
|
||||||
)
|
)
|
||||||
layoutManager.gapStrategy =
|
layoutManager.gapStrategy =
|
||||||
StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS
|
StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS
|
||||||
@ -604,15 +325,17 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
else ->
|
else ->
|
||||||
if (currentManager == null) {
|
if (currentManager == null) {
|
||||||
if (!appSettingsService.isCardViewEnabled()) {
|
if (!appSettingsService.isCardViewEnabled()) {
|
||||||
layoutManager = GridLayoutManager(
|
layoutManager =
|
||||||
|
GridLayoutManager(
|
||||||
this,
|
this,
|
||||||
calculateNoOfColumns()
|
calculateNoOfColumns(),
|
||||||
)
|
)
|
||||||
binding.recyclerView.layoutManager = layoutManager
|
binding.recyclerView.layoutManager = layoutManager
|
||||||
} else {
|
} else {
|
||||||
layoutManager = StaggeredGridLayoutManager(
|
layoutManager =
|
||||||
|
StaggeredGridLayoutManager(
|
||||||
calculateNoOfColumns(),
|
calculateNoOfColumns(),
|
||||||
StaggeredGridLayoutManager.VERTICAL
|
StaggeredGridLayoutManager.VERTICAL,
|
||||||
)
|
)
|
||||||
layoutManager.gapStrategy =
|
layoutManager.gapStrategy =
|
||||||
StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS
|
StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS
|
||||||
@ -623,11 +346,11 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun handleBottomBarActions() {
|
private fun handleBottomBarActions() {
|
||||||
binding.bottomBar.setTabSelectedListener(object : BottomNavigationBar.OnTabSelectedListener {
|
binding.bottomBar.setTabSelectedListener(
|
||||||
|
object : BottomNavigationBar.OnTabSelectedListener {
|
||||||
override fun onTabUnselected(position: Int) = Unit
|
override fun onTabUnselected(position: Int) = Unit
|
||||||
|
|
||||||
override fun onTabReselected(position: Int) {
|
override fun onTabReselected(position: Int) {
|
||||||
|
|
||||||
when (val layoutManager = binding.recyclerView.adapter) {
|
when (val layoutManager = binding.recyclerView.adapter) {
|
||||||
is StaggeredGridLayoutManager ->
|
is StaggeredGridLayoutManager ->
|
||||||
if (layoutManager.findFirstCompletelyVisibleItemPositions(null)[0] == 0) {
|
if (layoutManager.findFirstCompletelyVisibleItemPositions(null)[0] == 0) {
|
||||||
@ -655,19 +378,24 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
|
|
||||||
fetchOnEmptyList()
|
fetchOnEmptyList()
|
||||||
}
|
}
|
||||||
})
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun fetchOnEmptyList() {
|
fun fetchOnEmptyList() {
|
||||||
binding.recyclerView.doOnNextLayout {
|
binding.recyclerView.doOnNextLayout {
|
||||||
// TODO: do if last element (or is empty ?)
|
|
||||||
getElementsAccordingToTab(true)
|
getElementsAccordingToTab(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleInfiniteScroll() {
|
private fun handleInfiniteScroll() {
|
||||||
recyclerViewScrollListener = object : RecyclerView.OnScrollListener() {
|
recyclerViewScrollListener =
|
||||||
override fun onScrolled(localRecycler: RecyclerView, dx: Int, dy: Int) {
|
object : RecyclerView.OnScrollListener() {
|
||||||
|
override fun onScrolled(
|
||||||
|
localRecycler: RecyclerView,
|
||||||
|
dx: Int,
|
||||||
|
dy: Int,
|
||||||
|
) {
|
||||||
if (dy > 0) {
|
if (dy > 0) {
|
||||||
val lastVisibleItem = getLastVisibleItem()
|
val lastVisibleItem = getLastVisibleItem()
|
||||||
|
|
||||||
@ -684,8 +412,9 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
|
|
||||||
private fun getLastVisibleItem(): Int {
|
private fun getLastVisibleItem(): Int {
|
||||||
return when (val manager = binding.recyclerView.layoutManager) {
|
return when (val manager = binding.recyclerView.layoutManager) {
|
||||||
is StaggeredGridLayoutManager -> manager.findLastCompletelyVisibleItemPositions(
|
is StaggeredGridLayoutManager ->
|
||||||
null
|
manager.findLastCompletelyVisibleItemPositions(
|
||||||
|
null,
|
||||||
).last()
|
).last()
|
||||||
is GridLayoutManager -> manager.findLastCompletelyVisibleItemPosition()
|
is GridLayoutManager -> manager.findLastCompletelyVisibleItemPosition()
|
||||||
else -> 0
|
else -> 0
|
||||||
@ -699,10 +428,9 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
binding.emptyText.visibility = View.GONE
|
binding.emptyText.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getElementsAccordingToTab(
|
fun getElementsAccordingToTab(appendResults: Boolean = false) {
|
||||||
appendResults: Boolean = false
|
offset =
|
||||||
) {
|
if (appendResults && items.size > 0) {
|
||||||
offset = if (appendResults && items.size > 0) {
|
|
||||||
items.size - 1
|
items.size - 1
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
@ -712,11 +440,15 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
getItems(appendResults, elementsShown)
|
getItems(appendResults, elementsShown)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getItems(appendResults: Boolean, itemType: ItemType) {
|
private fun getItems(
|
||||||
|
appendResults: Boolean,
|
||||||
|
itemType: ItemType,
|
||||||
|
) {
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
binding.swipeRefreshLayout.isRefreshing = true
|
binding.swipeRefreshLayout.isRefreshing = true
|
||||||
repository.displayedItems = itemType
|
repository.displayedItems = itemType
|
||||||
items = if (appendResults) {
|
items =
|
||||||
|
if (appendResults) {
|
||||||
repository.getOlderItems()
|
repository.getOlderItems()
|
||||||
} else {
|
} else {
|
||||||
repository.getNewerItems()
|
repository.getNewerItems()
|
||||||
@ -729,7 +461,8 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
private fun handleListResult(appendResults: Boolean = false) {
|
private fun handleListResult(appendResults: Boolean = false) {
|
||||||
if (appendResults) {
|
if (appendResults) {
|
||||||
val oldManager = binding.recyclerView.layoutManager
|
val oldManager = binding.recyclerView.layoutManager
|
||||||
firstVisible = when (oldManager) {
|
firstVisible =
|
||||||
|
when (oldManager) {
|
||||||
is StaggeredGridLayoutManager ->
|
is StaggeredGridLayoutManager ->
|
||||||
oldManager.findFirstCompletelyVisibleItemPositions(null).last()
|
oldManager.findFirstCompletelyVisibleItemPositions(null).last()
|
||||||
is GridLayoutManager ->
|
is GridLayoutManager ->
|
||||||
@ -744,8 +477,6 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
ItemCardAdapter(
|
ItemCardAdapter(
|
||||||
this,
|
this,
|
||||||
items,
|
items,
|
||||||
customTabActivityHelper,
|
|
||||||
appColors,
|
|
||||||
) {
|
) {
|
||||||
updateItems(it)
|
updateItems(it)
|
||||||
}
|
}
|
||||||
@ -754,8 +485,6 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
ItemListAdapter(
|
ItemListAdapter(
|
||||||
this,
|
this,
|
||||||
items,
|
items,
|
||||||
customTabActivityHelper,
|
|
||||||
appColors,
|
|
||||||
) {
|
) {
|
||||||
updateItems(it)
|
updateItems(it)
|
||||||
}
|
}
|
||||||
@ -763,8 +492,8 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
binding.recyclerView.addItemDecoration(
|
binding.recyclerView.addItemDecoration(
|
||||||
DividerItemDecoration(
|
DividerItemDecoration(
|
||||||
this@HomeActivity,
|
this@HomeActivity,
|
||||||
DividerItemDecoration.VERTICAL
|
DividerItemDecoration.VERTICAL,
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
binding.recyclerView.adapter = recyclerAdapter
|
binding.recyclerView.adapter = recyclerAdapter
|
||||||
@ -778,36 +507,12 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
|
|
||||||
private fun reloadBadges() {
|
private fun reloadBadges() {
|
||||||
if (appSettingsService.isDisplayUnreadCountEnabled() || appSettingsService.isDisplayAllCountEnabled()) {
|
if (appSettingsService.isDisplayUnreadCountEnabled() || appSettingsService.isDisplayAllCountEnabled()) {
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
repository.reloadBadges()
|
repository.reloadBadges()
|
||||||
reloadBadgeContent()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun reloadBadgeContent() {
|
|
||||||
if (appSettingsService.isDisplayUnreadCountEnabled()) {
|
|
||||||
tabNewBadge
|
|
||||||
.setText(repository.badgeUnread.toString())
|
|
||||||
.maybeShow()
|
|
||||||
}
|
|
||||||
if (appSettingsService.isDisplayAllCountEnabled()) {
|
|
||||||
tabArchiveBadge
|
|
||||||
.setText(repository.badgeAll.toString())
|
|
||||||
.maybeShow()
|
|
||||||
tabStarredBadge
|
|
||||||
.setText(repository.badgeStarred.toString())
|
|
||||||
.maybeShow()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun reloadTagsBadges() {
|
|
||||||
tagsBadge.forEach {
|
|
||||||
binding.mainDrawer.updateBadge(it.key, StringHolder(it.value.toString()))
|
|
||||||
}
|
|
||||||
binding.mainDrawer.resetDrawerContent()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun calculateNoOfColumns(): Int {
|
private fun calculateNoOfColumns(): Int {
|
||||||
val displayMetrics = resources.displayMetrics
|
val displayMetrics = resources.displayMetrics
|
||||||
val dpWidth = displayMetrics.widthPixels / displayMetrics.density
|
val dpWidth = displayMetrics.widthPixels / displayMetrics.density
|
||||||
@ -833,6 +538,10 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||||
val inflater = menuInflater
|
val inflater = menuInflater
|
||||||
inflater.inflate(R.menu.home_menu, menu)
|
inflater.inflate(R.menu.home_menu, menu)
|
||||||
|
if (appSettingsService.getPublicAccess()) {
|
||||||
|
menu.removeItem(R.id.readAll)
|
||||||
|
menu.removeItem(R.id.action_sources)
|
||||||
|
}
|
||||||
|
|
||||||
val searchItem = menu.findItem(R.id.action_search)
|
val searchItem = menu.findItem(R.id.action_search)
|
||||||
val searchView = searchItem.getActionView() as SearchView
|
val searchView = searchItem.getActionView() as SearchView
|
||||||
@ -841,7 +550,11 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun needsConfirmation(titleRes: Int, messageRes: Int, doFn: () -> Unit) {
|
private fun needsConfirmation(
|
||||||
|
titleRes: Int,
|
||||||
|
messageRes: Int,
|
||||||
|
doFn: () -> Unit,
|
||||||
|
) {
|
||||||
AlertDialog.Builder(this@HomeActivity)
|
AlertDialog.Builder(this@HomeActivity)
|
||||||
.setMessage(messageRes)
|
.setMessage(messageRes)
|
||||||
.setTitle(titleRes)
|
.setTitle(titleRes)
|
||||||
@ -853,24 +566,33 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
|
R.id.issue_tracker -> {
|
||||||
|
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(AppSettingsService.trackerUrl))
|
||||||
|
startActivity(browserIntent)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
R.id.action_filter -> {
|
||||||
|
val filterSheetFragment = FilterSheetFragment()
|
||||||
|
filterSheetFragment.show(supportFragmentManager, FilterSheetFragment.TAG)
|
||||||
|
return true
|
||||||
|
}
|
||||||
R.id.refresh -> {
|
R.id.refresh -> {
|
||||||
needsConfirmation(R.string.menu_home_refresh, R.string.refresh_dialog_message) {
|
needsConfirmation(R.string.menu_home_refresh, R.string.refresh_dialog_message) {
|
||||||
Toast.makeText(this, R.string.refresh_in_progress, Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, R.string.refresh_in_progress, Toast.LENGTH_SHORT).show()
|
||||||
// TODO: Use Dispatchers.IO
|
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
val updatedRemote = repository.updateRemote()
|
val updatedRemote = repository.updateRemote()
|
||||||
if (updatedRemote) {
|
if (updatedRemote) {
|
||||||
// TODO: Send toast messages from the repository
|
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
this@HomeActivity,
|
this@HomeActivity,
|
||||||
R.string.refresh_success_response, Toast.LENGTH_LONG
|
R.string.refresh_success_response,
|
||||||
|
Toast.LENGTH_LONG,
|
||||||
)
|
)
|
||||||
.show()
|
.show()
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
this@HomeActivity,
|
this@HomeActivity,
|
||||||
R.string.refresh_failer_message,
|
R.string.refresh_failer_message,
|
||||||
Toast.LENGTH_SHORT
|
Toast.LENGTH_SHORT,
|
||||||
).show()
|
).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -888,18 +610,16 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
this@HomeActivity,
|
this@HomeActivity,
|
||||||
R.string.all_posts_read,
|
R.string.all_posts_read,
|
||||||
Toast.LENGTH_SHORT
|
Toast.LENGTH_SHORT,
|
||||||
).show()
|
).show()
|
||||||
tabNewBadge.removeBadge()
|
tabNewBadge.removeBadge()
|
||||||
|
|
||||||
handleDrawerItems()
|
|
||||||
|
|
||||||
getElementsAccordingToTab()
|
getElementsAccordingToTab()
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
this@HomeActivity,
|
this@HomeActivity,
|
||||||
R.string.all_posts_not_read,
|
R.string.all_posts_not_read,
|
||||||
Toast.LENGTH_SHORT
|
Toast.LENGTH_SHORT,
|
||||||
).show()
|
).show()
|
||||||
}
|
}
|
||||||
handleListResult()
|
handleListResult()
|
||||||
@ -910,10 +630,22 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
R.id.action_disconnect -> {
|
R.id.action_disconnect -> {
|
||||||
appSettingsService.clearAll()
|
needsConfirmation(R.string.confirm_disconnect_title, R.string.confirm_disconnect_description) {
|
||||||
|
runBlocking {
|
||||||
|
repository.logout()
|
||||||
|
}
|
||||||
val intent = Intent(this, LoginActivity::class.java)
|
val intent = Intent(this, LoginActivity::class.java)
|
||||||
this.startActivity(intent)
|
this.startActivity(intent)
|
||||||
this@HomeActivity.finish()
|
finish()
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
R.id.action_settings -> {
|
||||||
|
settingsLauncher.launch(Intent(this, SettingsActivity::class.java))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
R.id.action_sources -> {
|
||||||
|
startActivity(Intent(this, SourcesActivity::class.java))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
else -> return super.onOptionsItemSelected(item)
|
else -> return super.onOptionsItemSelected(item)
|
||||||
@ -922,10 +654,10 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
|
|
||||||
private fun maxItemNumber(): Int =
|
private fun maxItemNumber(): Int =
|
||||||
when (elementsShown) {
|
when (elementsShown) {
|
||||||
ItemType.UNREAD -> repository.badgeUnread
|
ItemType.UNREAD -> repository.badgeUnread.value
|
||||||
ItemType.ALL -> repository.badgeAll
|
ItemType.ALL -> repository.badgeAll.value
|
||||||
ItemType.STARRED -> repository.badgeStarred
|
ItemType.STARRED -> repository.badgeStarred.value
|
||||||
else -> repository.badgeUnread // if !elementsShown then unread are fetched.
|
else -> repository.badgeUnread.value // if !elementsShown then unread are fetched.
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateItems(adapterItems: ArrayList<SelfossModel.Item>) {
|
private fun updateItems(adapterItems: ArrayList<SelfossModel.Item>) {
|
||||||
@ -934,7 +666,8 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
|
|
||||||
private fun handleRecurringTask() {
|
private fun handleRecurringTask() {
|
||||||
if (appSettingsService.isPeriodicRefreshEnabled()) {
|
if (appSettingsService.isPeriodicRefreshEnabled()) {
|
||||||
val myConstraints = Constraints.Builder()
|
val myConstraints =
|
||||||
|
Constraints.Builder()
|
||||||
.setRequiresBatteryNotLow(true)
|
.setRequiresBatteryNotLow(true)
|
||||||
.setRequiresCharging(appSettingsService.isRefreshWhenChargingOnlyEnabled())
|
.setRequiresCharging(appSettingsService.isRefreshWhenChargingOnlyEnabled())
|
||||||
.setRequiresStorageNotLow(true)
|
.setRequiresStorageNotLow(true)
|
||||||
@ -946,8 +679,9 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
.addTag("selfoss-loading")
|
.addTag("selfoss-loading")
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
WorkManager.getInstance(baseContext).enqueueUniquePeriodicWork("selfoss-loading", ExistingPeriodicWorkPolicy.KEEP, backgroundWork)
|
WorkManager.getInstance(
|
||||||
|
baseContext,
|
||||||
|
).enqueueUniquePeriodicWork("selfoss-loading", ExistingPeriodicWorkPolicy.KEEP, backgroundWork)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ package bou.amine.apps.readerforselfossv2.android
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.constraintlayout.motion.widget.MotionLayout
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||||
@ -23,7 +24,6 @@ class ImageActivity : AppCompatActivity() {
|
|||||||
setContentView(view)
|
setContentView(view)
|
||||||
|
|
||||||
setSupportActionBar(binding.toolBar)
|
setSupportActionBar(binding.toolBar)
|
||||||
supportActionBar?.setDisplayShowTitleEnabled(false)
|
|
||||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||||
|
|
||||||
allImages = intent.getStringArrayListExtra("allImages") as ArrayList<String>
|
allImages = intent.getStringArrayListExtra("allImages") as ArrayList<String>
|
||||||
@ -31,12 +31,52 @@ class ImageActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
binding.pager.adapter = ScreenSlidePagerAdapter(this)
|
binding.pager.adapter = ScreenSlidePagerAdapter(this)
|
||||||
binding.pager.setCurrentItem(position, false)
|
binding.pager.setCurrentItem(position, false)
|
||||||
|
|
||||||
|
val transitionListener =
|
||||||
|
object : MotionLayout.TransitionListener {
|
||||||
|
override fun onTransitionStarted(
|
||||||
|
motionLayout: MotionLayout?,
|
||||||
|
startId: Int,
|
||||||
|
endId: Int,
|
||||||
|
) {
|
||||||
|
// Nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onTransitionChange(
|
||||||
|
motionLayout: MotionLayout?,
|
||||||
|
startId: Int,
|
||||||
|
endId: Int,
|
||||||
|
progress: Float,
|
||||||
|
) {
|
||||||
|
// Nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onTransitionCompleted(
|
||||||
|
motionLayout: MotionLayout?,
|
||||||
|
currentId: Int,
|
||||||
|
) {
|
||||||
|
if (motionLayout?.currentState == binding.root.endState) {
|
||||||
|
onBackPressedDispatcher.onBackPressed()
|
||||||
|
overridePendingTransition(0, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onTransitionTrigger(
|
||||||
|
motionLayout: MotionLayout?,
|
||||||
|
triggerId: Int,
|
||||||
|
positive: Boolean,
|
||||||
|
progress: Float,
|
||||||
|
) {
|
||||||
|
// Nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
binding.root.setTransitionListener(transitionListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
android.R.id.home -> {
|
android.R.id.home -> {
|
||||||
onBackPressed()
|
onBackPressedDispatcher.onBackPressed()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -45,7 +85,6 @@ class ImageActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private inner class ScreenSlidePagerAdapter(fa: FragmentActivity) : FragmentStateAdapter(fa) {
|
private inner class ScreenSlidePagerAdapter(fa: FragmentActivity) : FragmentStateAdapter(fa) {
|
||||||
|
|
||||||
override fun getItemCount(): Int = allImages.size
|
override fun getItemCount(): Int = allImages.size
|
||||||
|
|
||||||
override fun createFragment(position: Int): Fragment = ImageFragment.newInstance(allImages[position])
|
override fun createFragment(position: Int): Fragment = ImageFragment.newInstance(allImages[position])
|
||||||
|
@ -2,7 +2,9 @@ package bou.amine.apps.readerforselfossv2.android
|
|||||||
|
|
||||||
import android.animation.Animator
|
import android.animation.Animator
|
||||||
import android.animation.AnimatorListenerAdapter
|
import android.animation.AnimatorListenerAdapter
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
@ -10,10 +12,11 @@ import android.view.MenuItem
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.inputmethod.EditorInfo
|
import android.view.inputmethod.EditorInfo
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
import bou.amine.apps.readerforselfossv2.android.databinding.ActivityLoginBinding
|
import bou.amine.apps.readerforselfossv2.android.databinding.ActivityLoginBinding
|
||||||
import bou.amine.apps.readerforselfossv2.android.themes.AppColors
|
|
||||||
import bou.amine.apps.readerforselfossv2.android.utils.isBaseUrlInvalid
|
import bou.amine.apps.readerforselfossv2.android.utils.isBaseUrlInvalid
|
||||||
import bou.amine.apps.readerforselfossv2.repository.Repository
|
import bou.amine.apps.readerforselfossv2.repository.Repository
|
||||||
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
||||||
@ -21,16 +24,15 @@ import com.mikepenz.aboutlibraries.LibsBuilder
|
|||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import org.acra.ACRA
|
||||||
import org.kodein.di.DIAware
|
import org.kodein.di.DIAware
|
||||||
import org.kodein.di.android.closestDI
|
import org.kodein.di.android.closestDI
|
||||||
import org.kodein.di.instance
|
import org.kodein.di.instance
|
||||||
|
|
||||||
class LoginActivity : AppCompatActivity(), DIAware {
|
class LoginActivity : AppCompatActivity(), DIAware {
|
||||||
|
|
||||||
private var inValidCount: Int = 0
|
private var inValidCount: Int = 0
|
||||||
private var isWithLogin = false
|
private var isWithLogin = false
|
||||||
|
|
||||||
private lateinit var appColors: AppColors
|
|
||||||
private lateinit var binding: ActivityLoginBinding
|
private lateinit var binding: ActivityLoginBinding
|
||||||
|
|
||||||
override val di by closestDI()
|
override val di by closestDI()
|
||||||
@ -38,9 +40,10 @@ class LoginActivity : AppCompatActivity(), DIAware {
|
|||||||
private val appSettingsService: AppSettingsService by instance()
|
private val appSettingsService: AppSettingsService by instance()
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
appColors = AppColors(this@LoginActivity)
|
|
||||||
|
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
handleTheme()
|
||||||
|
|
||||||
binding = ActivityLoginBinding.inflate(layoutInflater)
|
binding = ActivityLoginBinding.inflate(layoutInflater)
|
||||||
val view = binding.root
|
val view = binding.root
|
||||||
|
|
||||||
@ -51,14 +54,19 @@ class LoginActivity : AppCompatActivity(), DIAware {
|
|||||||
handleBaseUrlFail()
|
handleBaseUrlFail()
|
||||||
|
|
||||||
if (appSettingsService.getBaseUrl().isNotEmpty()) {
|
if (appSettingsService.getBaseUrl().isNotEmpty()) {
|
||||||
|
showProgress(true)
|
||||||
goToMain()
|
goToMain()
|
||||||
}
|
}
|
||||||
|
|
||||||
handleActions()
|
handleActions()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleActions() {
|
@SuppressLint("WrongConstant") // Constant is fetched from the settings
|
||||||
|
private fun handleTheme() {
|
||||||
|
AppCompatDelegate.setDefaultNightMode(appSettingsService.getCurrentTheme())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleActions() {
|
||||||
binding.passwordView.setOnEditorActionListener(
|
binding.passwordView.setOnEditorActionListener(
|
||||||
TextView.OnEditorActionListener { _, id, _ ->
|
TextView.OnEditorActionListener { _, id, _ ->
|
||||||
if (id == R.id.loginView || id == EditorInfo.IME_NULL) {
|
if (id == R.id.loginView || id == EditorInfo.IME_NULL) {
|
||||||
@ -66,7 +74,7 @@ class LoginActivity : AppCompatActivity(), DIAware {
|
|||||||
return@OnEditorActionListener true
|
return@OnEditorActionListener true
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
binding.signInButton.setOnClickListener { attemptLogin() }
|
binding.signInButton.setOnClickListener { attemptLogin() }
|
||||||
@ -87,19 +95,23 @@ class LoginActivity : AppCompatActivity(), DIAware {
|
|||||||
alertDialog.setMessage(getString(R.string.base_url_error))
|
alertDialog.setMessage(getString(R.string.base_url_error))
|
||||||
alertDialog.setButton(
|
alertDialog.setButton(
|
||||||
AlertDialog.BUTTON_NEUTRAL,
|
AlertDialog.BUTTON_NEUTRAL,
|
||||||
"OK"
|
"OK",
|
||||||
) { dialog, _ -> dialog.dismiss() }
|
) { dialog, _ -> dialog.dismiss() }
|
||||||
alertDialog.show()
|
alertDialog.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun goToMain() {
|
private fun goToMain() {
|
||||||
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
|
repository.updateApiInformation()
|
||||||
|
ACRA.errorReporter.putCustomData("SELFOSS_API_VERSION", appSettingsService.getApiVersion().toString())
|
||||||
|
}
|
||||||
val intent = Intent(this, HomeActivity::class.java)
|
val intent = Intent(this, HomeActivity::class.java)
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
finish()
|
finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun preferenceError(t: Throwable) {
|
private fun preferenceError() {
|
||||||
appSettingsService.resetLoginInformation()
|
appSettingsService.resetLoginInformation()
|
||||||
|
|
||||||
binding.urlView.error = getString(R.string.wrong_infos)
|
binding.urlView.error = getString(R.string.wrong_infos)
|
||||||
@ -108,7 +120,6 @@ class LoginActivity : AppCompatActivity(), DIAware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun attemptLogin() {
|
private fun attemptLogin() {
|
||||||
|
|
||||||
// Reset errors.
|
// Reset errors.
|
||||||
binding.urlView.error = null
|
binding.urlView.error = null
|
||||||
binding.loginView.error = null
|
binding.loginView.error = null
|
||||||
@ -119,13 +130,72 @@ class LoginActivity : AppCompatActivity(), DIAware {
|
|||||||
val login = binding.loginView.text.toString().trim()
|
val login = binding.loginView.text.toString().trim()
|
||||||
val password = binding.passwordView.text.toString().trim()
|
val password = binding.passwordView.text.toString().trim()
|
||||||
|
|
||||||
var cancel = false
|
failInvalidUrl(url)
|
||||||
var focusView: View? = null
|
failLoginDetails(password, login)
|
||||||
|
|
||||||
if (url.isBaseUrlInvalid(this@LoginActivity)) {
|
showProgress(true)
|
||||||
binding.urlView.error = getString(R.string.login_url_problem)
|
|
||||||
focusView = binding.urlView
|
appSettingsService.updateSelfSigned(binding.selfSigned.isChecked)
|
||||||
|
|
||||||
|
repository.refreshLoginInformation(url, login, password)
|
||||||
|
|
||||||
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
|
try {
|
||||||
|
repository.updateApiInformation()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
if (e.message?.startsWith("No transformation found") == true) {
|
||||||
|
Toast.makeText(
|
||||||
|
applicationContext,
|
||||||
|
R.string.application_selfoss_only,
|
||||||
|
Toast.LENGTH_LONG,
|
||||||
|
).show()
|
||||||
|
preferenceError()
|
||||||
|
showProgress(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val result = repository.login()
|
||||||
|
if (result) {
|
||||||
|
val errorFetching = repository.checkIfFetchFails()
|
||||||
|
if (!errorFetching) {
|
||||||
|
goToMain()
|
||||||
|
} else {
|
||||||
|
preferenceError()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
preferenceError()
|
||||||
|
}
|
||||||
|
showProgress(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun failLoginDetails(
|
||||||
|
password: String,
|
||||||
|
login: String,
|
||||||
|
) {
|
||||||
|
var lastFocusedView: View? = null
|
||||||
|
var cancel = false
|
||||||
|
if (isWithLogin) {
|
||||||
|
if (TextUtils.isEmpty(password)) {
|
||||||
|
binding.passwordView.error = getString(R.string.error_invalid_password)
|
||||||
|
lastFocusedView = binding.passwordView
|
||||||
cancel = true
|
cancel = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TextUtils.isEmpty(login)) {
|
||||||
|
binding.loginView.error = getString(R.string.error_field_required)
|
||||||
|
lastFocusedView = binding.loginView
|
||||||
|
cancel = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
maybeCancelAndFocusView(cancel, lastFocusedView)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun failInvalidUrl(url: String) {
|
||||||
|
val focusView = binding.urlView
|
||||||
|
var cancel = false
|
||||||
|
if (url.isBaseUrlInvalid()) {
|
||||||
|
cancel = true
|
||||||
|
binding.urlView.error = getString(R.string.login_url_problem)
|
||||||
inValidCount++
|
inValidCount++
|
||||||
if (inValidCount == 3) {
|
if (inValidCount == 3) {
|
||||||
val alertDialog = AlertDialog.Builder(this).create()
|
val alertDialog = AlertDialog.Builder(this).create()
|
||||||
@ -133,46 +203,21 @@ class LoginActivity : AppCompatActivity(), DIAware {
|
|||||||
alertDialog.setMessage(getString(R.string.text_wrong_url))
|
alertDialog.setMessage(getString(R.string.text_wrong_url))
|
||||||
alertDialog.setButton(
|
alertDialog.setButton(
|
||||||
AlertDialog.BUTTON_NEUTRAL,
|
AlertDialog.BUTTON_NEUTRAL,
|
||||||
"OK"
|
"OK",
|
||||||
) { dialog, _ -> dialog.dismiss() }
|
) { dialog, _ -> dialog.dismiss() }
|
||||||
alertDialog.show()
|
alertDialog.show()
|
||||||
inValidCount = 0
|
inValidCount = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
maybeCancelAndFocusView(cancel, focusView)
|
||||||
if (isWithLogin) {
|
|
||||||
if (TextUtils.isEmpty(password)) {
|
|
||||||
binding.passwordView.error = getString(R.string.error_invalid_password)
|
|
||||||
focusView = binding.passwordView
|
|
||||||
cancel = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TextUtils.isEmpty(login)) {
|
|
||||||
binding.loginView.error = getString(R.string.error_field_required)
|
|
||||||
focusView = binding.loginView
|
|
||||||
cancel = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun maybeCancelAndFocusView(
|
||||||
|
cancel: Boolean,
|
||||||
|
focusView: View?,
|
||||||
|
) {
|
||||||
if (cancel) {
|
if (cancel) {
|
||||||
focusView?.requestFocus()
|
focusView?.requestFocus()
|
||||||
} else {
|
|
||||||
showProgress(true)
|
|
||||||
|
|
||||||
repository.refreshLoginInformation(url, login, password)
|
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
|
||||||
val result = repository.login()
|
|
||||||
if (result) {
|
|
||||||
repository.updateApiVersion()
|
|
||||||
goToMain()
|
|
||||||
} else {
|
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
|
||||||
preferenceError(Exception("Not success"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
showProgress(false)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,12 +229,13 @@ class LoginActivity : AppCompatActivity(), DIAware {
|
|||||||
.animate()
|
.animate()
|
||||||
.setDuration(shortAnimTime.toLong())
|
.setDuration(shortAnimTime.toLong())
|
||||||
.alpha(
|
.alpha(
|
||||||
if (show) 0F else 1F
|
if (show) 0F else 1F,
|
||||||
).setListener(object : AnimatorListenerAdapter() {
|
).setListener(
|
||||||
|
object : AnimatorListenerAdapter() {
|
||||||
override fun onAnimationEnd(animation: Animator) {
|
override fun onAnimationEnd(animation: Animator) {
|
||||||
binding.loginForm.visibility = if (show) View.GONE else View.VISIBLE
|
binding.loginForm.visibility = if (show) View.GONE else View.VISIBLE
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
binding.loginProgress.visibility = if (show) View.VISIBLE else View.GONE
|
binding.loginProgress.visibility = if (show) View.VISIBLE else View.GONE
|
||||||
@ -197,12 +243,13 @@ class LoginActivity : AppCompatActivity(), DIAware {
|
|||||||
.animate()
|
.animate()
|
||||||
.setDuration(shortAnimTime.toLong())
|
.setDuration(shortAnimTime.toLong())
|
||||||
.alpha(
|
.alpha(
|
||||||
if (show) 1F else 0F
|
if (show) 1F else 0F,
|
||||||
).setListener(object : AnimatorListenerAdapter() {
|
).setListener(
|
||||||
|
object : AnimatorListenerAdapter() {
|
||||||
override fun onAnimationEnd(animation: Animator) {
|
override fun onAnimationEnd(animation: Animator) {
|
||||||
binding.loginProgress.visibility = if (show) View.VISIBLE else View.GONE
|
binding.loginProgress.visibility = if (show) View.VISIBLE else View.GONE
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,10 +260,17 @@ class LoginActivity : AppCompatActivity(), DIAware {
|
|||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
return when (item.itemId) {
|
return when (item.itemId) {
|
||||||
|
R.id.issue_tracker -> {
|
||||||
|
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(AppSettingsService.trackerUrl))
|
||||||
|
startActivity(browserIntent)
|
||||||
|
return true
|
||||||
|
}
|
||||||
R.id.about -> {
|
R.id.about -> {
|
||||||
LibsBuilder()
|
LibsBuilder()
|
||||||
.withAboutIconShown(true)
|
.withAboutIconShown(true)
|
||||||
.withAboutVersionShown(true)
|
.withAboutVersionShown(true)
|
||||||
|
.withAboutSpecial2("Bug reports").withAboutSpecial2Description(AppSettingsService.trackerUrl)
|
||||||
|
.withAboutSpecial1("Project Page").withAboutSpecial1Description(AppSettingsService.sourceUrl)
|
||||||
.start(this)
|
.start(this)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ import bou.amine.apps.readerforselfossv2.android.databinding.ActivityMainBinding
|
|||||||
class MainActivity : AppCompatActivity() {
|
class MainActivity : AppCompatActivity() {
|
||||||
private lateinit var binding: ActivityMainBinding
|
private lateinit var binding: ActivityMainBinding
|
||||||
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
binding = ActivityMainBinding.inflate(layoutInflater)
|
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||||
|
@ -3,42 +3,49 @@ package bou.amine.apps.readerforselfossv2.android
|
|||||||
import android.app.NotificationChannel
|
import android.app.NotificationChannel
|
||||||
import android.app.NotificationManager
|
import android.app.NotificationManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.drawable.Drawable
|
|
||||||
import android.net.Uri
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.widget.ImageView
|
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.lifecycle.DefaultLifecycleObserver
|
import androidx.lifecycle.DefaultLifecycleObserver
|
||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import androidx.lifecycle.ProcessLifecycleOwner
|
import androidx.lifecycle.ProcessLifecycleOwner
|
||||||
import androidx.multidex.MultiDexApplication
|
import androidx.multidex.MultiDexApplication
|
||||||
import androidx.preference.PreferenceManager
|
|
||||||
import bou.amine.apps.readerforselfossv2.DI.networkModule
|
import bou.amine.apps.readerforselfossv2.DI.networkModule
|
||||||
import bou.amine.apps.readerforselfossv2.android.viewmodel.AppViewModel
|
import bou.amine.apps.readerforselfossv2.android.viewmodel.AppViewModel
|
||||||
import bou.amine.apps.readerforselfossv2.dao.DriverFactory
|
import bou.amine.apps.readerforselfossv2.dao.DriverFactory
|
||||||
import bou.amine.apps.readerforselfossv2.dao.ReaderForSelfossDB
|
import bou.amine.apps.readerforselfossv2.dao.ReaderForSelfossDB
|
||||||
import bou.amine.apps.readerforselfossv2.repository.Repository
|
import bou.amine.apps.readerforselfossv2.repository.Repository
|
||||||
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
||||||
import com.bumptech.glide.Glide
|
|
||||||
import com.bumptech.glide.request.RequestOptions
|
|
||||||
import com.ftinc.scoop.Scoop
|
|
||||||
import com.github.ln_12.library.ConnectivityStatus
|
import com.github.ln_12.library.ConnectivityStatus
|
||||||
import com.mikepenz.materialdrawer.util.AbstractDrawerImageLoader
|
|
||||||
import com.mikepenz.materialdrawer.util.DrawerImageLoader
|
|
||||||
import io.github.aakira.napier.DebugAntilog
|
import io.github.aakira.napier.DebugAntilog
|
||||||
import io.github.aakira.napier.Napier
|
import io.github.aakira.napier.Napier
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import org.acra.ACRA
|
||||||
|
import org.acra.ReportField
|
||||||
|
import org.acra.config.httpSender
|
||||||
|
import org.acra.config.toast
|
||||||
|
import org.acra.data.StringFormat
|
||||||
|
import org.acra.ktx.initAcra
|
||||||
|
import org.acra.sender.HttpSender
|
||||||
import org.kodein.di.*
|
import org.kodein.di.*
|
||||||
|
|
||||||
class MyApp : MultiDexApplication(), DIAware {
|
class MyApp : MultiDexApplication(), DIAware {
|
||||||
|
|
||||||
override val di by DI.lazy {
|
override val di by DI.lazy {
|
||||||
|
bind<AppSettingsService>() with singleton { AppSettingsService(ACRA.isACRASenderServiceProcess()) }
|
||||||
import(networkModule)
|
import(networkModule)
|
||||||
bind<DriverFactory>() with singleton { DriverFactory(applicationContext) }
|
bind<DriverFactory>() with singleton { DriverFactory(applicationContext) }
|
||||||
bind<ReaderForSelfossDB>() with singleton { ReaderForSelfossDB(driverFactory.createDriver()) }
|
bind<ReaderForSelfossDB>() with singleton { ReaderForSelfossDB(driverFactory.createDriver()) }
|
||||||
bind<Repository>() with singleton { Repository(instance(), instance(), connectivityStatus, instance()) }
|
bind<Repository>() with
|
||||||
|
singleton {
|
||||||
|
Repository(
|
||||||
|
instance(),
|
||||||
|
instance(),
|
||||||
|
isConnectionAvailable,
|
||||||
|
instance(),
|
||||||
|
)
|
||||||
|
}
|
||||||
bind<ConnectivityStatus>() with singleton { ConnectivityStatus(applicationContext) }
|
bind<ConnectivityStatus>() with singleton { ConnectivityStatus(applicationContext) }
|
||||||
bind<AppViewModel>() with singleton { AppViewModel(repository = instance()) }
|
bind<AppViewModel>() with singleton { AppViewModel(repository = instance()) }
|
||||||
}
|
}
|
||||||
@ -48,23 +55,29 @@ class MyApp : MultiDexApplication(), DIAware {
|
|||||||
private val connectivityStatus: ConnectivityStatus by instance()
|
private val connectivityStatus: ConnectivityStatus by instance()
|
||||||
private val driverFactory: DriverFactory by instance()
|
private val driverFactory: DriverFactory by instance()
|
||||||
|
|
||||||
|
// TODO: handle with the "previous" way
|
||||||
|
private val isConnectionAvailable: MutableStateFlow<Boolean> = MutableStateFlow(true)
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
Napier.base(DebugAntilog())
|
Napier.base(DebugAntilog())
|
||||||
|
|
||||||
initDrawerImageLoader()
|
if (!ACRA.isACRASenderServiceProcess()) {
|
||||||
|
|
||||||
initTheme()
|
|
||||||
|
|
||||||
tryToHandleBug()
|
tryToHandleBug()
|
||||||
|
|
||||||
handleNotificationChannels()
|
handleNotificationChannels()
|
||||||
|
|
||||||
ProcessLifecycleOwner.get().lifecycle.addObserver(AppLifeCycleObserver(connectivityStatus, repository))
|
ProcessLifecycleOwner.get().lifecycle.addObserver(
|
||||||
|
AppLifeCycleObserver(
|
||||||
|
connectivityStatus,
|
||||||
|
repository,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
viewModel.networkAvailableProvider.collect { networkAvailable ->
|
viewModel.networkAvailableProvider.collect { networkAvailable ->
|
||||||
val toastMessage = if (networkAvailable) {
|
val toastMessage =
|
||||||
|
if (networkAvailable) {
|
||||||
repository.handleDBActions()
|
repository.handleDBActions()
|
||||||
R.string.network_connectivity_retrieved
|
R.string.network_connectivity_retrieved
|
||||||
} else {
|
} else {
|
||||||
@ -74,11 +87,57 @@ class MyApp : MultiDexApplication(), DIAware {
|
|||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
toastMessage,
|
toastMessage,
|
||||||
Toast.LENGTH_SHORT
|
Toast.LENGTH_SHORT,
|
||||||
).show()
|
).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
repository.migrate(driverFactory)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun attachBaseContext(base: Context?) {
|
||||||
|
super.attachBaseContext(base)
|
||||||
|
|
||||||
|
initAcra {
|
||||||
|
reportFormat = StringFormat.JSON
|
||||||
|
reportContent =
|
||||||
|
listOf(
|
||||||
|
ReportField.REPORT_ID,
|
||||||
|
ReportField.INSTALLATION_ID,
|
||||||
|
ReportField.APP_VERSION_CODE,
|
||||||
|
ReportField.APP_VERSION_NAME,
|
||||||
|
ReportField.BUILD,
|
||||||
|
ReportField.ANDROID_VERSION,
|
||||||
|
ReportField.BRAND,
|
||||||
|
ReportField.PHONE_MODEL,
|
||||||
|
ReportField.AVAILABLE_MEM_SIZE,
|
||||||
|
ReportField.TOTAL_MEM_SIZE,
|
||||||
|
ReportField.STACK_TRACE,
|
||||||
|
ReportField.APPLICATION_LOG,
|
||||||
|
ReportField.LOGCAT,
|
||||||
|
ReportField.INITIAL_CONFIGURATION,
|
||||||
|
ReportField.CRASH_CONFIGURATION,
|
||||||
|
ReportField.IS_SILENT,
|
||||||
|
ReportField.USER_APP_START_DATE,
|
||||||
|
ReportField.USER_COMMENT,
|
||||||
|
ReportField.USER_CRASH_DATE,
|
||||||
|
ReportField.USER_EMAIL,
|
||||||
|
ReportField.CUSTOM_DATA,
|
||||||
|
)
|
||||||
|
toast {
|
||||||
|
// required
|
||||||
|
text = getString(R.string.crash_toast_text)
|
||||||
|
length = Toast.LENGTH_SHORT
|
||||||
|
}
|
||||||
|
httpSender {
|
||||||
|
uri =
|
||||||
|
"https://bugs.amine-bouabdallaoui.fr/report" // best guess, you may need to adjust this
|
||||||
|
basicAuthLogin = "qMEscjj89Gwt6cPR"
|
||||||
|
basicAuthPassword = "Yo58QFlGzFaWlBzP"
|
||||||
|
httpMethod = HttpSender.Method.POST
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleNotificationChannels() {
|
private fun handleNotificationChannels() {
|
||||||
@ -91,56 +150,38 @@ class MyApp : MultiDexApplication(), DIAware {
|
|||||||
|
|
||||||
val newItemsChannelname = getString(R.string.new_items_channel_sync)
|
val newItemsChannelname = getString(R.string.new_items_channel_sync)
|
||||||
val newItemsChannelimportance = NotificationManager.IMPORTANCE_DEFAULT
|
val newItemsChannelimportance = NotificationManager.IMPORTANCE_DEFAULT
|
||||||
val newItemsChannelmChannel = NotificationChannel(AppSettingsService.newItemsChannelId, newItemsChannelname, newItemsChannelimportance)
|
val newItemsChannelmChannel =
|
||||||
|
NotificationChannel(
|
||||||
|
AppSettingsService.newItemsChannelId,
|
||||||
|
newItemsChannelname,
|
||||||
|
newItemsChannelimportance,
|
||||||
|
)
|
||||||
|
|
||||||
notificationManager.createNotificationChannel(mChannel)
|
notificationManager.createNotificationChannel(mChannel)
|
||||||
notificationManager.createNotificationChannel(newItemsChannelmChannel)
|
notificationManager.createNotificationChannel(newItemsChannelmChannel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initDrawerImageLoader() {
|
|
||||||
DrawerImageLoader.init(object : AbstractDrawerImageLoader() {
|
|
||||||
override fun set(imageView: ImageView, uri: Uri, placeholder: Drawable, tag: String?) {
|
|
||||||
Glide.with(imageView.context)
|
|
||||||
.load(uri.toString())
|
|
||||||
.apply(RequestOptions.fitCenterTransform().placeholder(placeholder))
|
|
||||||
.into(imageView)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun cancel(imageView: ImageView) {
|
|
||||||
Glide.with(imageView.context).clear(imageView)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun placeholder(ctx: Context, tag: String?): Drawable {
|
|
||||||
return baseContext.resources.getDrawable(R.mipmap.ic_launcher)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun initTheme() {
|
|
||||||
Scoop.waffleCone()
|
|
||||||
.addFlavor(getString(R.string.default_theme), R.style.NoBar, true)
|
|
||||||
.addFlavor(getString(R.string.default_dark_theme), R.style.NoBarDark, false)
|
|
||||||
.setSharedPreferences(PreferenceManager.getDefaultSharedPreferences(this))
|
|
||||||
.initialize()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun tryToHandleBug() {
|
private fun tryToHandleBug() {
|
||||||
val oldHandler = Thread.getDefaultUncaughtExceptionHandler()
|
val oldHandler = Thread.getDefaultUncaughtExceptionHandler()
|
||||||
|
|
||||||
Thread.setDefaultUncaughtExceptionHandler { thread, e ->
|
Thread.setDefaultUncaughtExceptionHandler { thread, e ->
|
||||||
if (e is java.lang.NoClassDefFoundError && e.stackTrace.asList().any {
|
if (e is NoClassDefFoundError &&
|
||||||
|
e.stackTrace.asList().any {
|
||||||
it.toString().contains("android.view.ViewDebug")
|
it.toString().contains("android.view.ViewDebug")
|
||||||
}) {
|
}
|
||||||
Unit
|
) {
|
||||||
|
// Nothing
|
||||||
} else {
|
} else {
|
||||||
oldHandler.uncaughtException(thread, e)
|
oldHandler.uncaughtException(thread, e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AppLifeCycleObserver(val connectivityStatus: ConnectivityStatus, val repository: Repository) : DefaultLifecycleObserver {
|
class AppLifeCycleObserver(
|
||||||
|
val connectivityStatus: ConnectivityStatus,
|
||||||
|
val repository: Repository,
|
||||||
|
) : DefaultLifecycleObserver {
|
||||||
override fun onResume(owner: LifecycleOwner) {
|
override fun onResume(owner: LifecycleOwner) {
|
||||||
super.onResume(owner)
|
super.onResume(owner)
|
||||||
repository.connectionMonitored = true
|
repository.connectionMonitored = true
|
||||||
|
@ -12,12 +12,9 @@ import androidx.viewpager2.adapter.FragmentStateAdapter
|
|||||||
import androidx.viewpager2.widget.ViewPager2
|
import androidx.viewpager2.widget.ViewPager2
|
||||||
import bou.amine.apps.readerforselfossv2.android.databinding.ActivityReaderBinding
|
import bou.amine.apps.readerforselfossv2.android.databinding.ActivityReaderBinding
|
||||||
import bou.amine.apps.readerforselfossv2.android.fragments.ArticleFragment
|
import bou.amine.apps.readerforselfossv2.android.fragments.ArticleFragment
|
||||||
import bou.amine.apps.readerforselfossv2.android.themes.AppColors
|
|
||||||
import bou.amine.apps.readerforselfossv2.android.themes.Toppings
|
|
||||||
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
||||||
import bou.amine.apps.readerforselfossv2.repository.Repository
|
import bou.amine.apps.readerforselfossv2.repository.Repository
|
||||||
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
||||||
import com.ftinc.scoop.Scoop
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -26,23 +23,23 @@ import org.kodein.di.android.closestDI
|
|||||||
import org.kodein.di.instance
|
import org.kodein.di.instance
|
||||||
|
|
||||||
class ReaderActivity : AppCompatActivity(), DIAware {
|
class ReaderActivity : AppCompatActivity(), DIAware {
|
||||||
|
|
||||||
private var currentItem: Int = 0
|
private var currentItem: Int = 0
|
||||||
private lateinit var appColors: AppColors
|
|
||||||
|
|
||||||
private lateinit var toolbarMenu: Menu
|
private lateinit var toolbarMenu: Menu
|
||||||
|
|
||||||
private lateinit var binding: ActivityReaderBinding
|
private lateinit var binding: ActivityReaderBinding
|
||||||
|
|
||||||
|
private var allItems: ArrayList<SelfossModel.Item> = ArrayList()
|
||||||
|
|
||||||
override val di by closestDI()
|
override val di by closestDI()
|
||||||
private val repository: Repository by instance()
|
private val repository: Repository by instance()
|
||||||
private val appSettingsService: AppSettingsService by instance()
|
private val appSettingsService: AppSettingsService by instance()
|
||||||
|
|
||||||
private fun showMenuItem(willAddToFavorite: Boolean) {
|
private fun showMenuItem(willAddToFavorite: Boolean) {
|
||||||
if (willAddToFavorite) {
|
if (willAddToFavorite) {
|
||||||
toolbarMenu.findItem(R.id.star).icon.setTint(Color.WHITE)
|
toolbarMenu.findItem(R.id.star).icon?.setTint(Color.WHITE)
|
||||||
} else {
|
} else {
|
||||||
toolbarMenu.findItem(R.id.star).icon.setTint(Color.RED)
|
toolbarMenu.findItem(R.id.star).icon?.setTint(Color.RED)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,27 +53,28 @@ class ReaderActivity : AppCompatActivity(), DIAware {
|
|||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
appColors = AppColors(this)
|
|
||||||
binding = ActivityReaderBinding.inflate(layoutInflater)
|
binding = ActivityReaderBinding.inflate(layoutInflater)
|
||||||
val view = binding.root
|
val view = binding.root
|
||||||
|
|
||||||
setContentView(view)
|
setContentView(view)
|
||||||
|
|
||||||
val scoop = Scoop.getInstance()
|
|
||||||
scoop.bind(this, Toppings.PRIMARY.value, binding.toolBar)
|
|
||||||
scoop.bindStatusBar(this, Toppings.PRIMARY_DARK.value)
|
|
||||||
|
|
||||||
setSupportActionBar(binding.toolBar)
|
setSupportActionBar(binding.toolBar)
|
||||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||||
supportActionBar?.setDisplayShowHomeEnabled(true)
|
supportActionBar?.setDisplayShowHomeEnabled(true)
|
||||||
|
|
||||||
if (allItems.isEmpty()) {
|
currentItem = intent.getIntExtra("currentItem", 0)
|
||||||
|
|
||||||
|
allItems = repository.getReaderItems()
|
||||||
|
|
||||||
|
if (allItems.isEmpty() || currentItem > allItems.size) {
|
||||||
finish()
|
finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
currentItem = intent.getIntExtra("currentItem", 0)
|
try {
|
||||||
|
|
||||||
readItem(allItems[currentItem])
|
readItem(allItems[currentItem])
|
||||||
|
} catch (e: IndexOutOfBoundsException) {
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
binding.pager.adapter = ScreenSlidePagerAdapter(this)
|
binding.pager.adapter = ScreenSlidePagerAdapter(this)
|
||||||
binding.pager.setCurrentItem(currentItem, false)
|
binding.pager.setCurrentItem(currentItem, false)
|
||||||
@ -89,7 +87,7 @@ class ReaderActivity : AppCompatActivity(), DIAware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun readItem(item: SelfossModel.Item) {
|
private fun readItem(item: SelfossModel.Item) {
|
||||||
if (appSettingsService.isMarkOnScrollEnabled()) {
|
if (appSettingsService.isMarkOnScrollEnabled() && !appSettingsService.getPublicAccess()) {
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
repository.markAsRead(item)
|
repository.markAsRead(item)
|
||||||
}
|
}
|
||||||
@ -103,15 +101,15 @@ class ReaderActivity : AppCompatActivity(), DIAware {
|
|||||||
|
|
||||||
private inner class ScreenSlidePagerAdapter(fa: FragmentActivity) :
|
private inner class ScreenSlidePagerAdapter(fa: FragmentActivity) :
|
||||||
FragmentStateAdapter(fa) {
|
FragmentStateAdapter(fa) {
|
||||||
|
|
||||||
override fun getItemCount(): Int = allItems.size
|
override fun getItemCount(): Int = allItems.size
|
||||||
|
|
||||||
override fun createFragment(position: Int): Fragment =
|
override fun createFragment(position: Int): Fragment = ArticleFragment.newInstance(allItems[position])
|
||||||
ArticleFragment.newInstance(allItems[position])
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
|
override fun onKeyDown(
|
||||||
|
keyCode: Int,
|
||||||
|
event: KeyEvent?,
|
||||||
|
): Boolean {
|
||||||
return when (keyCode) {
|
return when (keyCode) {
|
||||||
KeyEvent.KEYCODE_VOLUME_DOWN -> {
|
KeyEvent.KEYCODE_VOLUME_DOWN -> {
|
||||||
val currentFragment =
|
val currentFragment =
|
||||||
@ -142,16 +140,19 @@ class ReaderActivity : AppCompatActivity(), DIAware {
|
|||||||
inflater.inflate(R.menu.reader_menu, menu)
|
inflater.inflate(R.menu.reader_menu, menu)
|
||||||
toolbarMenu = menu
|
toolbarMenu = menu
|
||||||
|
|
||||||
|
alignmentMenu()
|
||||||
|
|
||||||
|
if (appSettingsService.getPublicAccess()) {
|
||||||
|
menu.removeItem(R.id.star)
|
||||||
|
} else {
|
||||||
if (allItems.isNotEmpty() && allItems[currentItem].starred) {
|
if (allItems.isNotEmpty() && allItems[currentItem].starred) {
|
||||||
canRemoveFromFavorite()
|
canRemoveFromFavorite()
|
||||||
} else {
|
} else {
|
||||||
canFavorite()
|
canFavorite()
|
||||||
}
|
}
|
||||||
alignmentMenu()
|
|
||||||
|
|
||||||
binding.pager.registerOnPageChangeCallback(
|
binding.pager.registerOnPageChangeCallback(
|
||||||
object : ViewPager2.OnPageChangeCallback() {
|
object : ViewPager2.OnPageChangeCallback() {
|
||||||
|
|
||||||
override fun onPageSelected(position: Int) {
|
override fun onPageSelected(position: Int) {
|
||||||
super.onPageSelected(position)
|
super.onPageSelected(position)
|
||||||
|
|
||||||
@ -162,8 +163,9 @@ class ReaderActivity : AppCompatActivity(), DIAware {
|
|||||||
}
|
}
|
||||||
readItem(allItems[position])
|
readItem(allItems[position])
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -182,20 +184,18 @@ class ReaderActivity : AppCompatActivity(), DIAware {
|
|||||||
|
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
android.R.id.home -> {
|
android.R.id.home -> {
|
||||||
onBackPressed()
|
onBackPressedDispatcher.onBackPressed()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
R.id.star -> {
|
R.id.star -> {
|
||||||
if (allItems[binding.pager.currentItem].starred) {
|
if (allItems[binding.pager.currentItem].starred) {
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
repository.unstarr(allItems[binding.pager.currentItem])
|
repository.unstarr(allItems[binding.pager.currentItem])
|
||||||
// TODO: Handle failure
|
|
||||||
}
|
}
|
||||||
afterUnsave()
|
afterUnsave()
|
||||||
} else {
|
} else {
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
repository.starr(allItems[binding.pager.currentItem])
|
repository.starr(allItems[binding.pager.currentItem])
|
||||||
// TODO: Handle failure
|
|
||||||
}
|
}
|
||||||
afterSave()
|
afterSave()
|
||||||
}
|
}
|
||||||
@ -223,8 +223,4 @@ class ReaderActivity : AppCompatActivity(), DIAware {
|
|||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
overridePendingTransition(0, 0)
|
overridePendingTransition(0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
var allItems: ArrayList<SelfossModel.Item> = ArrayList()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -8,11 +8,8 @@ import androidx.appcompat.app.AppCompatActivity
|
|||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import bou.amine.apps.readerforselfossv2.android.adapters.SourcesListAdapter
|
import bou.amine.apps.readerforselfossv2.android.adapters.SourcesListAdapter
|
||||||
import bou.amine.apps.readerforselfossv2.android.databinding.ActivitySourcesBinding
|
import bou.amine.apps.readerforselfossv2.android.databinding.ActivitySourcesBinding
|
||||||
import bou.amine.apps.readerforselfossv2.android.themes.AppColors
|
|
||||||
import bou.amine.apps.readerforselfossv2.android.themes.Toppings
|
|
||||||
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
||||||
import bou.amine.apps.readerforselfossv2.repository.Repository
|
import bou.amine.apps.readerforselfossv2.repository.Repository
|
||||||
import com.ftinc.scoop.Scoop
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -21,22 +18,15 @@ import org.kodein.di.android.closestDI
|
|||||||
import org.kodein.di.instance
|
import org.kodein.di.instance
|
||||||
|
|
||||||
class SourcesActivity : AppCompatActivity(), DIAware {
|
class SourcesActivity : AppCompatActivity(), DIAware {
|
||||||
|
|
||||||
private lateinit var appColors: AppColors
|
|
||||||
private lateinit var binding: ActivitySourcesBinding
|
private lateinit var binding: ActivitySourcesBinding
|
||||||
|
|
||||||
override val di by closestDI()
|
override val di by closestDI()
|
||||||
private val repository: Repository by instance()
|
private val repository: Repository by instance()
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
appColors = AppColors(this@SourcesActivity)
|
|
||||||
binding = ActivitySourcesBinding.inflate(layoutInflater)
|
binding = ActivitySourcesBinding.inflate(layoutInflater)
|
||||||
val view = binding.root
|
val view = binding.root
|
||||||
|
|
||||||
val scoop = Scoop.getInstance()
|
|
||||||
scoop.bind(this, Toppings.PRIMARY.value, binding.toolbar)
|
|
||||||
scoop.bindStatusBar(this, Toppings.PRIMARY_DARK.value)
|
|
||||||
|
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
setContentView(view)
|
setContentView(view)
|
||||||
@ -45,8 +35,8 @@ class SourcesActivity : AppCompatActivity(), DIAware {
|
|||||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||||
supportActionBar?.setDisplayShowHomeEnabled(true)
|
supportActionBar?.setDisplayShowHomeEnabled(true)
|
||||||
|
|
||||||
binding.fab.rippleColor = appColors.colorAccentDark
|
binding.fab.rippleColor = resources.getColor(R.color.colorAccentDark)
|
||||||
binding.fab.backgroundTintList = ColorStateList.valueOf(appColors.colorAccent)
|
binding.fab.backgroundTintList = ColorStateList.valueOf(resources.getColor(R.color.colorAccent))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStop() {
|
override fun onStop() {
|
||||||
@ -58,38 +48,33 @@ class SourcesActivity : AppCompatActivity(), DIAware {
|
|||||||
super.onResume()
|
super.onResume()
|
||||||
val mLayoutManager = LinearLayoutManager(this)
|
val mLayoutManager = LinearLayoutManager(this)
|
||||||
|
|
||||||
var items: ArrayList<SelfossModel.Source>
|
var items: ArrayList<SelfossModel.SourceDetail>
|
||||||
|
|
||||||
binding.recyclerView.setHasFixedSize(true)
|
binding.recyclerView.setHasFixedSize(true)
|
||||||
binding.recyclerView.layoutManager = mLayoutManager
|
binding.recyclerView.layoutManager = mLayoutManager
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
val response = repository.getSources()
|
val response = repository.getSourcesDetails()
|
||||||
if (response != null) {
|
if (response.isNotEmpty()) {
|
||||||
items = response
|
items = response
|
||||||
val mAdapter = SourcesListAdapter(
|
val mAdapter =
|
||||||
this@SourcesActivity, items
|
SourcesListAdapter(
|
||||||
|
this@SourcesActivity,
|
||||||
|
items,
|
||||||
)
|
)
|
||||||
binding.recyclerView.adapter = mAdapter
|
binding.recyclerView.adapter = mAdapter
|
||||||
mAdapter.notifyDataSetChanged()
|
mAdapter.notifyDataSetChanged()
|
||||||
if (items.isEmpty()) {
|
|
||||||
Toast.makeText(
|
|
||||||
this@SourcesActivity,
|
|
||||||
R.string.nothing_here,
|
|
||||||
Toast.LENGTH_SHORT
|
|
||||||
).show()
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
this@SourcesActivity,
|
this@SourcesActivity,
|
||||||
R.string.cant_get_sources,
|
R.string.cant_get_sources,
|
||||||
Toast.LENGTH_SHORT
|
Toast.LENGTH_SHORT,
|
||||||
).show()
|
).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.fab.setOnClickListener {
|
binding.fab.setOnClickListener {
|
||||||
startActivity(Intent(this@SourcesActivity, AddSourceActivity::class.java))
|
startActivity(Intent(this@SourcesActivity, UpsertSourceActivity::class.java))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,210 @@
|
|||||||
|
package bou.amine.apps.readerforselfossv2.android
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.AdapterView
|
||||||
|
import android.widget.ArrayAdapter
|
||||||
|
import android.widget.TextView
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import bou.amine.apps.readerforselfossv2.android.databinding.ActivityUpsertSourceBinding
|
||||||
|
import bou.amine.apps.readerforselfossv2.android.utils.isBaseUrlInvalid
|
||||||
|
import bou.amine.apps.readerforselfossv2.model.NetworkUnavailableException
|
||||||
|
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
||||||
|
import bou.amine.apps.readerforselfossv2.repository.Repository
|
||||||
|
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import org.kodein.di.DIAware
|
||||||
|
import org.kodein.di.android.closestDI
|
||||||
|
import org.kodein.di.instance
|
||||||
|
|
||||||
|
class UpsertSourceActivity : AppCompatActivity(), DIAware {
|
||||||
|
private var existingSource: SelfossModel.SourceDetail? = null
|
||||||
|
private var mSpoutsValue: String? = null
|
||||||
|
|
||||||
|
private lateinit var binding: ActivityUpsertSourceBinding
|
||||||
|
|
||||||
|
override val di by closestDI()
|
||||||
|
private val repository: Repository by instance()
|
||||||
|
private val appSettingsService: AppSettingsService by instance()
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
binding = ActivityUpsertSourceBinding.inflate(layoutInflater)
|
||||||
|
val view = binding.root
|
||||||
|
|
||||||
|
existingSource = repository.getSelectedSource()
|
||||||
|
if (existingSource != null) {
|
||||||
|
binding.formContainer.visibility = View.GONE
|
||||||
|
binding.progress.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
val title = if (existingSource == null) R.string.add_source else R.string.update_source
|
||||||
|
|
||||||
|
supportFragmentManager.addOnBackStackChangedListener {
|
||||||
|
if (supportFragmentManager.backStackEntryCount == 0) {
|
||||||
|
setTitle(title)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setContentView(view)
|
||||||
|
|
||||||
|
setSupportActionBar(binding.toolbar)
|
||||||
|
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||||
|
supportActionBar?.setDisplayShowHomeEnabled(true)
|
||||||
|
supportActionBar?.title = resources.getString(title)
|
||||||
|
|
||||||
|
maybeGetDetailsFromIntentSharing(intent)
|
||||||
|
|
||||||
|
binding.saveBtn.setOnClickListener {
|
||||||
|
handleSaveSource()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initFields(items: Map<String, SelfossModel.Spout>) {
|
||||||
|
binding.nameInput.setText(existingSource!!.title)
|
||||||
|
binding.tags.setText(existingSource!!.tags?.joinToString(", "))
|
||||||
|
binding.sourceUri.setText(existingSource!!.params?.url)
|
||||||
|
binding.spoutsSpinner.setSelection(items.keys.indexOf(existingSource!!.spout))
|
||||||
|
binding.progress.visibility = View.GONE
|
||||||
|
binding.formContainer.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
|
||||||
|
val baseUrl = appSettingsService.getBaseUrl()
|
||||||
|
if (baseUrl.isEmpty() || baseUrl.isBaseUrlInvalid()) {
|
||||||
|
mustLoginToAddSource()
|
||||||
|
} else {
|
||||||
|
handleSpoutsSpinner()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleSpoutsSpinner() {
|
||||||
|
val spoutsKV = HashMap<String, String>()
|
||||||
|
binding.spoutsSpinner.onItemSelectedListener =
|
||||||
|
object : AdapterView.OnItemSelectedListener {
|
||||||
|
override fun onItemSelected(
|
||||||
|
adapterView: AdapterView<*>,
|
||||||
|
view: View?,
|
||||||
|
i: Int,
|
||||||
|
l: Long,
|
||||||
|
) {
|
||||||
|
if (view != null) {
|
||||||
|
val spoutName = (view as TextView).text.toString()
|
||||||
|
mSpoutsValue = spoutsKV[spoutName]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNothingSelected(adapterView: AdapterView<*>) {
|
||||||
|
mSpoutsValue = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun handleSpoutFailure(networkIssue: Boolean = false) {
|
||||||
|
Toast.makeText(
|
||||||
|
this@UpsertSourceActivity,
|
||||||
|
if (networkIssue) R.string.cant_get_spouts_no_network else R.string.cant_get_spouts,
|
||||||
|
Toast.LENGTH_SHORT,
|
||||||
|
).show()
|
||||||
|
binding.progress.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
|
try {
|
||||||
|
val items = repository.getSpouts()
|
||||||
|
if (items.isNotEmpty()) {
|
||||||
|
val itemsStrings = items.map { it.value.name }
|
||||||
|
for ((key, value) in items) {
|
||||||
|
spoutsKV[value.name] = key
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.progress.visibility = View.GONE
|
||||||
|
binding.formContainer.visibility = View.VISIBLE
|
||||||
|
|
||||||
|
val spinnerArrayAdapter =
|
||||||
|
ArrayAdapter(
|
||||||
|
this@UpsertSourceActivity,
|
||||||
|
android.R.layout.simple_spinner_item,
|
||||||
|
itemsStrings,
|
||||||
|
)
|
||||||
|
spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
|
||||||
|
binding.spoutsSpinner.adapter = spinnerArrayAdapter
|
||||||
|
|
||||||
|
if (existingSource != null) {
|
||||||
|
initFields(items)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
handleSpoutFailure()
|
||||||
|
}
|
||||||
|
} catch (e: NetworkUnavailableException) {
|
||||||
|
handleSpoutFailure(networkIssue = true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun maybeGetDetailsFromIntentSharing(intent: Intent) {
|
||||||
|
if (Intent.ACTION_SEND == intent.action && "text/plain" == intent.type) {
|
||||||
|
binding.sourceUri.setText(intent.getStringExtra(Intent.EXTRA_TEXT))
|
||||||
|
binding.nameInput.setText(intent.getStringExtra(Intent.EXTRA_TITLE))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun mustLoginToAddSource() {
|
||||||
|
Toast.makeText(this, getString(R.string.addStringNoUrl), Toast.LENGTH_SHORT).show()
|
||||||
|
val i = Intent(this, LoginActivity::class.java)
|
||||||
|
startActivity(i)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleSaveSource() {
|
||||||
|
val url = binding.sourceUri.text.toString()
|
||||||
|
|
||||||
|
val sourceDetailsUnavailable =
|
||||||
|
title.isEmpty() || url.isEmpty() || mSpoutsValue == null || mSpoutsValue!!.isEmpty()
|
||||||
|
|
||||||
|
when {
|
||||||
|
sourceDetailsUnavailable -> {
|
||||||
|
Toast.makeText(this, R.string.form_not_complete, Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
|
val successfullyAddedSource =
|
||||||
|
if (existingSource != null) {
|
||||||
|
repository.updateSource(
|
||||||
|
existingSource!!.id,
|
||||||
|
binding.nameInput.text.toString(),
|
||||||
|
url,
|
||||||
|
mSpoutsValue!!,
|
||||||
|
binding.tags.text.toString(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
repository.createSource(
|
||||||
|
binding.nameInput.text.toString(),
|
||||||
|
url,
|
||||||
|
mSpoutsValue!!,
|
||||||
|
binding.tags.text.toString(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (successfullyAddedSource) {
|
||||||
|
finish()
|
||||||
|
} else {
|
||||||
|
Toast.makeText(
|
||||||
|
this@UpsertSourceActivity,
|
||||||
|
R.string.cant_create_source,
|
||||||
|
Toast.LENGTH_SHORT,
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
repository.unsetSelectedSource()
|
||||||
|
}
|
||||||
|
}
|
@ -9,20 +9,19 @@ import android.widget.ImageView.ScaleType
|
|||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import bou.amine.apps.readerforselfossv2.android.R
|
import bou.amine.apps.readerforselfossv2.android.R
|
||||||
import bou.amine.apps.readerforselfossv2.android.databinding.CardItemBinding
|
import bou.amine.apps.readerforselfossv2.android.databinding.CardItemBinding
|
||||||
import bou.amine.apps.readerforselfossv2.android.model.toTextDrawableString
|
import bou.amine.apps.readerforselfossv2.android.sendSilentlyWithAcraWithName
|
||||||
import bou.amine.apps.readerforselfossv2.android.themes.AppColors
|
import bou.amine.apps.readerforselfossv2.android.utils.LinkOnTouchListener
|
||||||
import bou.amine.apps.readerforselfossv2.android.utils.*
|
|
||||||
import bou.amine.apps.readerforselfossv2.android.utils.customtabs.CustomTabActivityHelper
|
|
||||||
import bou.amine.apps.readerforselfossv2.android.utils.glide.bitmapCenterCrop
|
import bou.amine.apps.readerforselfossv2.android.utils.glide.bitmapCenterCrop
|
||||||
import bou.amine.apps.readerforselfossv2.android.utils.glide.circularBitmapDrawable
|
import bou.amine.apps.readerforselfossv2.android.utils.glide.circularDrawable
|
||||||
|
import bou.amine.apps.readerforselfossv2.android.utils.openInBrowserAsNewTask
|
||||||
|
import bou.amine.apps.readerforselfossv2.android.utils.openItemUrl
|
||||||
|
import bou.amine.apps.readerforselfossv2.android.utils.shareLink
|
||||||
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
||||||
import bou.amine.apps.readerforselfossv2.repository.Repository
|
import bou.amine.apps.readerforselfossv2.repository.Repository
|
||||||
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
||||||
import bou.amine.apps.readerforselfossv2.utils.getHtmlDecoded
|
import bou.amine.apps.readerforselfossv2.utils.getHtmlDecoded
|
||||||
import bou.amine.apps.readerforselfossv2.utils.getIcon
|
import bou.amine.apps.readerforselfossv2.utils.getIcon
|
||||||
import bou.amine.apps.readerforselfossv2.utils.getThumbnail
|
import bou.amine.apps.readerforselfossv2.utils.getThumbnail
|
||||||
import com.amulyakhare.textdrawable.TextDrawable
|
|
||||||
import com.amulyakhare.textdrawable.util.ColorGenerator
|
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@ -34,12 +33,10 @@ import org.kodein.di.instance
|
|||||||
class ItemCardAdapter(
|
class ItemCardAdapter(
|
||||||
override val app: Activity,
|
override val app: Activity,
|
||||||
override var items: ArrayList<SelfossModel.Item>,
|
override var items: ArrayList<SelfossModel.Item>,
|
||||||
private val helper: CustomTabActivityHelper,
|
override val updateItems: (ArrayList<SelfossModel.Item>) -> Unit,
|
||||||
override val appColors: AppColors,
|
|
||||||
override val updateItems: (ArrayList<SelfossModel.Item>) -> Unit
|
|
||||||
) : ItemsAdapter<ItemCardAdapter.ViewHolder>() {
|
) : ItemsAdapter<ItemCardAdapter.ViewHolder>() {
|
||||||
|
private lateinit var binding: CardItemBinding
|
||||||
private val c: Context = app.baseContext
|
private val c: Context = app.baseContext
|
||||||
private val generator: ColorGenerator = ColorGenerator.MATERIAL
|
|
||||||
private val imageMaxHeight: Int =
|
private val imageMaxHeight: Int =
|
||||||
c.resources.getDimension(R.dimen.card_image_max_height).toInt()
|
c.resources.getDimension(R.dimen.card_image_max_height).toInt()
|
||||||
|
|
||||||
@ -47,23 +44,79 @@ class ItemCardAdapter(
|
|||||||
override val repository: Repository by instance()
|
override val repository: Repository by instance()
|
||||||
override val appSettingsService: AppSettingsService by instance()
|
override val appSettingsService: AppSettingsService by instance()
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
override fun onCreateViewHolder(
|
||||||
val binding = CardItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
parent: ViewGroup,
|
||||||
|
viewType: Int,
|
||||||
|
): ViewHolder {
|
||||||
|
binding = CardItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||||
return ViewHolder(binding)
|
return ViewHolder(binding)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
private fun handleClickListeners(position: Int) {
|
||||||
|
binding.favButton.setOnClickListener {
|
||||||
|
val item = items[position]
|
||||||
|
if (item.starred) {
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
repository.unstarr(item)
|
||||||
|
}
|
||||||
|
binding.favButton.isSelected = false
|
||||||
|
} else {
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
repository.starr(item)
|
||||||
|
}
|
||||||
|
binding.favButton.isSelected = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.shareBtn.setOnClickListener {
|
||||||
|
val item = items[position]
|
||||||
|
c.shareLink(item.getLinkDecoded(), item.title.getHtmlDecoded())
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.browserBtn.setOnClickListener {
|
||||||
|
c.openInBrowserAsNewTask(items[position])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleLinkOpening(position: Int) {
|
||||||
|
binding.root.setOnClickListener {
|
||||||
|
repository.setReaderItems(items)
|
||||||
|
c.openItemUrl(
|
||||||
|
position,
|
||||||
|
items[position].getLinkDecoded(),
|
||||||
|
appSettingsService.isArticleViewerEnabled(),
|
||||||
|
app,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(
|
||||||
|
holder: ViewHolder,
|
||||||
|
position: Int,
|
||||||
|
) {
|
||||||
with(holder) {
|
with(holder) {
|
||||||
val itm = items[position]
|
val itm = items[holder.bindingAdapterPosition]
|
||||||
|
|
||||||
|
handleClickListeners(holder.bindingAdapterPosition)
|
||||||
|
handleLinkOpening(holder.bindingAdapterPosition)
|
||||||
|
|
||||||
binding.favButton.isSelected = itm.starred
|
binding.favButton.isSelected = itm.starred
|
||||||
|
if (appSettingsService.getPublicAccess()) {
|
||||||
|
binding.favButton.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
binding.title.text = itm.title.getHtmlDecoded()
|
binding.title.text = itm.title.getHtmlDecoded()
|
||||||
|
|
||||||
binding.title.setOnTouchListener(LinkOnTouchListener())
|
binding.title.setOnTouchListener(LinkOnTouchListener())
|
||||||
|
|
||||||
binding.title.setLinkTextColor(appColors.colorAccent)
|
binding.title.setLinkTextColor(c.resources.getColor(R.color.colorAccent))
|
||||||
|
|
||||||
binding.sourceTitleAndDate.text = itm.sourceAndDateText(repository.dateUtils)
|
binding.sourceTitleAndDate.text = try {
|
||||||
|
itm.sourceAuthorAndDate()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.sendSilentlyWithAcraWithName("ItemCardAdapter parse date")
|
||||||
|
itm.sourceAuthorOnly()
|
||||||
|
}
|
||||||
|
|
||||||
if (!appSettingsService.isFullHeightCardsEnabled()) {
|
if (!appSettingsService.isFullHeightCardsEnabled()) {
|
||||||
binding.itemImage.maxHeight = imageMaxHeight
|
binding.itemImage.maxHeight = imageMaxHeight
|
||||||
@ -80,16 +133,9 @@ class ItemCardAdapter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (itm.getIcon(repository.baseUrl).isEmpty()) {
|
if (itm.getIcon(repository.baseUrl).isEmpty()) {
|
||||||
val color = generator.getColor(itm.title.getHtmlDecoded())
|
binding.sourceImage.setBackgroundAndText(itm.sourcetitle.getHtmlDecoded())
|
||||||
|
|
||||||
val drawable =
|
|
||||||
TextDrawable
|
|
||||||
.builder()
|
|
||||||
.round()
|
|
||||||
.build(itm.title.getHtmlDecoded().toTextDrawableString(), color)
|
|
||||||
binding.sourceImage.setImageDrawable(drawable)
|
|
||||||
} else {
|
} else {
|
||||||
c.circularBitmapDrawable(itm.getIcon(repository.baseUrl), binding.sourceImage)
|
c.circularDrawable(itm.getIcon(repository.baseUrl), binding.sourceImage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -98,58 +144,5 @@ class ItemCardAdapter(
|
|||||||
return items.size
|
return items.size
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class ViewHolder(val binding: CardItemBinding) : RecyclerView.ViewHolder(binding.root) {
|
inner class ViewHolder(val binding: CardItemBinding) : RecyclerView.ViewHolder(binding.root)
|
||||||
init {
|
|
||||||
handleClickListeners()
|
|
||||||
handleCustomTabActions()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleClickListeners() {
|
|
||||||
|
|
||||||
binding.favButton.setOnClickListener {
|
|
||||||
val item = items[bindingAdapterPosition]
|
|
||||||
if (item.starred) {
|
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
|
||||||
repository.unstarr(item)
|
|
||||||
// TODO: Handle failure
|
|
||||||
}
|
|
||||||
item.starred = false
|
|
||||||
binding.favButton.isSelected = false
|
|
||||||
} else {
|
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
|
||||||
repository.starr(item)
|
|
||||||
// TODO: Handle failure
|
|
||||||
}
|
|
||||||
item.starred = true
|
|
||||||
binding.favButton.isSelected = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.shareBtn.setOnClickListener {
|
|
||||||
val item = items[bindingAdapterPosition]
|
|
||||||
c.shareLink(item.getLinkDecoded(), item.title.getHtmlDecoded())
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.browserBtn.setOnClickListener {
|
|
||||||
c.openInBrowserAsNewTask(items[bindingAdapterPosition])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleCustomTabActions() {
|
|
||||||
val customTabsIntent = c.buildCustomTabsIntent()
|
|
||||||
helper.bindCustomTabsService(app)
|
|
||||||
|
|
||||||
binding.root.setOnClickListener {
|
|
||||||
c.openItemUrl(
|
|
||||||
items,
|
|
||||||
bindingAdapterPosition,
|
|
||||||
items[bindingAdapterPosition].getLinkDecoded(),
|
|
||||||
customTabsIntent,
|
|
||||||
appSettingsService.isInternalBrowserEnabled(),
|
|
||||||
appSettingsService.isArticleViewerEnabled(),
|
|
||||||
app
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -5,14 +5,11 @@ import android.content.Context
|
|||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import bou.amine.apps.readerforselfossv2.android.R
|
||||||
import bou.amine.apps.readerforselfossv2.android.databinding.ListItemBinding
|
import bou.amine.apps.readerforselfossv2.android.databinding.ListItemBinding
|
||||||
import bou.amine.apps.readerforselfossv2.android.model.toTextDrawableString
|
import bou.amine.apps.readerforselfossv2.android.sendSilentlyWithAcraWithName
|
||||||
import bou.amine.apps.readerforselfossv2.android.themes.AppColors
|
|
||||||
import bou.amine.apps.readerforselfossv2.android.utils.LinkOnTouchListener
|
import bou.amine.apps.readerforselfossv2.android.utils.LinkOnTouchListener
|
||||||
import bou.amine.apps.readerforselfossv2.android.utils.buildCustomTabsIntent
|
import bou.amine.apps.readerforselfossv2.android.utils.glide.circularDrawable
|
||||||
import bou.amine.apps.readerforselfossv2.android.utils.customtabs.CustomTabActivityHelper
|
|
||||||
import bou.amine.apps.readerforselfossv2.android.utils.glide.bitmapCenterCrop
|
|
||||||
import bou.amine.apps.readerforselfossv2.android.utils.glide.circularBitmapDrawable
|
|
||||||
import bou.amine.apps.readerforselfossv2.android.utils.openItemUrl
|
import bou.amine.apps.readerforselfossv2.android.utils.openItemUrl
|
||||||
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
||||||
import bou.amine.apps.readerforselfossv2.repository.Repository
|
import bou.amine.apps.readerforselfossv2.repository.Repository
|
||||||
@ -20,8 +17,6 @@ import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
|||||||
import bou.amine.apps.readerforselfossv2.utils.getHtmlDecoded
|
import bou.amine.apps.readerforselfossv2.utils.getHtmlDecoded
|
||||||
import bou.amine.apps.readerforselfossv2.utils.getIcon
|
import bou.amine.apps.readerforselfossv2.utils.getIcon
|
||||||
import bou.amine.apps.readerforselfossv2.utils.getThumbnail
|
import bou.amine.apps.readerforselfossv2.utils.getThumbnail
|
||||||
import com.amulyakhare.textdrawable.TextDrawable
|
|
||||||
import com.amulyakhare.textdrawable.util.ColorGenerator
|
|
||||||
import org.kodein.di.DI
|
import org.kodein.di.DI
|
||||||
import org.kodein.di.android.closestDI
|
import org.kodein.di.android.closestDI
|
||||||
import org.kodein.di.instance
|
import org.kodein.di.instance
|
||||||
@ -29,78 +24,66 @@ import org.kodein.di.instance
|
|||||||
class ItemListAdapter(
|
class ItemListAdapter(
|
||||||
override val app: Activity,
|
override val app: Activity,
|
||||||
override var items: ArrayList<SelfossModel.Item>,
|
override var items: ArrayList<SelfossModel.Item>,
|
||||||
private val helper: CustomTabActivityHelper,
|
override val updateItems: (ArrayList<SelfossModel.Item>) -> Unit,
|
||||||
override val appColors: AppColors,
|
|
||||||
override val updateItems: (ArrayList<SelfossModel.Item>) -> Unit
|
|
||||||
) : ItemsAdapter<ItemListAdapter.ViewHolder>() {
|
) : ItemsAdapter<ItemListAdapter.ViewHolder>() {
|
||||||
private val generator: ColorGenerator = ColorGenerator.MATERIAL
|
private lateinit var binding: ListItemBinding
|
||||||
private val c: Context = app.baseContext
|
private val c: Context = app.baseContext
|
||||||
|
|
||||||
override val di: DI by closestDI(app)
|
override val di: DI by closestDI(app)
|
||||||
override val repository: Repository by instance()
|
override val repository: Repository by instance()
|
||||||
override val appSettingsService: AppSettingsService by instance()
|
override val appSettingsService: AppSettingsService by instance()
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
override fun onCreateViewHolder(
|
||||||
val binding = ListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
parent: ViewGroup,
|
||||||
|
viewType: Int,
|
||||||
|
): ViewHolder {
|
||||||
|
binding = ListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||||
return ViewHolder(binding)
|
return ViewHolder(binding)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
override fun onBindViewHolder(
|
||||||
|
holder: ViewHolder,
|
||||||
|
position: Int,
|
||||||
|
) {
|
||||||
with(holder) {
|
with(holder) {
|
||||||
val itm = items[position]
|
val itm = items[holder.bindingAdapterPosition]
|
||||||
|
|
||||||
|
binding.root.setOnClickListener {
|
||||||
|
repository.setReaderItems(items)
|
||||||
|
c.openItemUrl(
|
||||||
|
holder.bindingAdapterPosition,
|
||||||
|
items[holder.bindingAdapterPosition].getLinkDecoded(),
|
||||||
|
appSettingsService.isArticleViewerEnabled(),
|
||||||
|
app,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
binding.title.text = itm.title.getHtmlDecoded()
|
binding.title.text = itm.title.getHtmlDecoded()
|
||||||
|
|
||||||
binding.title.setOnTouchListener(LinkOnTouchListener())
|
binding.title.setOnTouchListener(LinkOnTouchListener())
|
||||||
|
|
||||||
binding.title.setLinkTextColor(appColors.colorAccent)
|
binding.title.setLinkTextColor(c.resources.getColor(R.color.colorAccent))
|
||||||
|
|
||||||
binding.sourceTitleAndDate.text = itm.sourceAndDateText(repository.dateUtils)
|
binding.sourceTitleAndDate.text = try {
|
||||||
|
itm.sourceAuthorAndDate()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.sendSilentlyWithAcraWithName("ItemListAdapter parse date")
|
||||||
|
itm.sourceAuthorOnly()
|
||||||
|
}
|
||||||
|
|
||||||
if (itm.getThumbnail(repository.baseUrl).isEmpty()) {
|
if (itm.getThumbnail(repository.baseUrl).isEmpty()) {
|
||||||
|
|
||||||
if (itm.getIcon(repository.baseUrl).isEmpty()) {
|
if (itm.getIcon(repository.baseUrl).isEmpty()) {
|
||||||
val color = generator.getColor(itm.title.getHtmlDecoded())
|
binding.itemImage.setBackgroundAndText(itm.sourcetitle.getHtmlDecoded())
|
||||||
|
|
||||||
val drawable =
|
|
||||||
TextDrawable
|
|
||||||
.builder()
|
|
||||||
.round()
|
|
||||||
.build(itm.title.getHtmlDecoded().toTextDrawableString(), color)
|
|
||||||
|
|
||||||
binding.itemImage.setImageDrawable(drawable)
|
|
||||||
} else {
|
} else {
|
||||||
c.circularBitmapDrawable(itm.getIcon(repository.baseUrl), binding.itemImage)
|
c.circularDrawable(itm.getIcon(repository.baseUrl), binding.itemImage)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
c.bitmapCenterCrop(itm.getThumbnail(repository.baseUrl), binding.itemImage)
|
c.circularDrawable(itm.getThumbnail(repository.baseUrl), binding.itemImage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemCount(): Int = items.size
|
override fun getItemCount(): Int = items.size
|
||||||
|
|
||||||
inner class ViewHolder(val binding: ListItemBinding) : RecyclerView.ViewHolder(binding.root) {
|
inner class ViewHolder(val binding: ListItemBinding) : RecyclerView.ViewHolder(binding.root)
|
||||||
|
|
||||||
init {
|
|
||||||
handleCustomTabActions()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleCustomTabActions() {
|
|
||||||
val customTabsIntent = c.buildCustomTabsIntent()
|
|
||||||
helper.bindCustomTabsService(app)
|
|
||||||
|
|
||||||
binding.root.setOnClickListener {
|
|
||||||
c.openItemUrl(
|
|
||||||
items,
|
|
||||||
bindingAdapterPosition,
|
|
||||||
items[bindingAdapterPosition].getLinkDecoded(),
|
|
||||||
customTabsIntent,
|
|
||||||
appSettingsService.isInternalBrowserEnabled(),
|
|
||||||
appSettingsService.isArticleViewerEnabled(),
|
|
||||||
app
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ import android.graphics.Color
|
|||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import bou.amine.apps.readerforselfossv2.android.R
|
import bou.amine.apps.readerforselfossv2.android.R
|
||||||
import bou.amine.apps.readerforselfossv2.android.themes.AppColors
|
|
||||||
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
||||||
import bou.amine.apps.readerforselfossv2.repository.Repository
|
import bou.amine.apps.readerforselfossv2.repository.Repository
|
||||||
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
||||||
@ -21,7 +20,6 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
|
|||||||
abstract val repository: Repository
|
abstract val repository: Repository
|
||||||
abstract val appSettingsService: AppSettingsService
|
abstract val appSettingsService: AppSettingsService
|
||||||
abstract val app: Activity
|
abstract val app: Activity
|
||||||
abstract val appColors: AppColors
|
|
||||||
abstract val updateItems: (ArrayList<SelfossModel.Item>) -> Unit
|
abstract val updateItems: (ArrayList<SelfossModel.Item>) -> Unit
|
||||||
|
|
||||||
fun updateAllItems(items: ArrayList<SelfossModel.Item>) {
|
fun updateAllItems(items: ArrayList<SelfossModel.Item>) {
|
||||||
@ -30,17 +28,19 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
|
|||||||
updateItems(this.items)
|
updateItems(this.items)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun unmarkSnackbar(i: SelfossModel.Item, position: Int) {
|
private fun unmarkSnackbar(
|
||||||
val s = Snackbar
|
item: SelfossModel.Item,
|
||||||
|
position: Int,
|
||||||
|
) {
|
||||||
|
val s =
|
||||||
|
Snackbar
|
||||||
.make(
|
.make(
|
||||||
app.findViewById(R.id.coordLayout),
|
app.findViewById(R.id.coordLayout),
|
||||||
R.string.marked_as_read,
|
R.string.marked_as_read,
|
||||||
Snackbar.LENGTH_LONG
|
Snackbar.LENGTH_LONG,
|
||||||
)
|
)
|
||||||
.setAction(R.string.undo_string) {
|
.setAction(R.string.undo_string) {
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
unreadItemAtIndex(item, position, false)
|
||||||
unreadItemAtIndex(position, false)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val view = s.view
|
val view = s.view
|
||||||
@ -49,15 +49,19 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
|
|||||||
s.show()
|
s.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun markSnackbar(position: Int) {
|
private fun markSnackbar(
|
||||||
val s = Snackbar
|
item: SelfossModel.Item,
|
||||||
|
position: Int,
|
||||||
|
) {
|
||||||
|
val s =
|
||||||
|
Snackbar
|
||||||
.make(
|
.make(
|
||||||
app.findViewById(R.id.coordLayout),
|
app.findViewById(R.id.coordLayout),
|
||||||
R.string.marked_as_unread,
|
R.string.marked_as_unread,
|
||||||
Snackbar.LENGTH_LONG
|
Snackbar.LENGTH_LONG,
|
||||||
)
|
)
|
||||||
.setAction(R.string.undo_string) {
|
.setAction(R.string.undo_string) {
|
||||||
readItemAtIndex(position)
|
readItemAtIndex(item, position, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
val view = s.view
|
val view = s.view
|
||||||
@ -68,45 +72,54 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
|
|||||||
|
|
||||||
fun handleItemAtIndex(position: Int) {
|
fun handleItemAtIndex(position: Int) {
|
||||||
if (items[position].unread) {
|
if (items[position].unread) {
|
||||||
readItemAtIndex(position)
|
readItemAtIndex(items[position], position)
|
||||||
} else {
|
} else {
|
||||||
unreadItemAtIndex(position)
|
unreadItemAtIndex(items[position], position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun readItemAtIndex(position: Int, showSnackbar: Boolean = true) {
|
private fun readItemAtIndex(
|
||||||
val i = items[position]
|
item: SelfossModel.Item,
|
||||||
|
position: Int,
|
||||||
|
showSnackbar: Boolean = true,
|
||||||
|
) {
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
repository.markAsRead(i)
|
repository.markAsRead(item)
|
||||||
}
|
}
|
||||||
if (repository.displayedItems == ItemType.UNREAD) {
|
if (repository.displayedItems == ItemType.UNREAD) {
|
||||||
items.remove(i)
|
items.remove(item)
|
||||||
notifyItemRemoved(position)
|
notifyItemRemoved(position)
|
||||||
|
notifyItemRangeChanged(position, itemCount)
|
||||||
updateItems(items)
|
updateItems(items)
|
||||||
} else {
|
} else {
|
||||||
notifyItemChanged(position)
|
notifyItemChanged(position)
|
||||||
}
|
}
|
||||||
if (showSnackbar) {
|
if (showSnackbar) {
|
||||||
unmarkSnackbar(i, position)
|
unmarkSnackbar(item, position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun unreadItemAtIndex(position: Int, showSnackbar: Boolean = true) {
|
private fun unreadItemAtIndex(
|
||||||
|
item: SelfossModel.Item,
|
||||||
|
position: Int,
|
||||||
|
showSnackbar: Boolean = true,
|
||||||
|
) {
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
repository.unmarkAsRead(items[position])
|
repository.unmarkAsRead(item)
|
||||||
|
|
||||||
}
|
}
|
||||||
notifyItemChanged(position)
|
notifyItemChanged(position)
|
||||||
if (showSnackbar) {
|
if (showSnackbar) {
|
||||||
markSnackbar(position)
|
markSnackbar(item, position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addItemAtIndex(item: SelfossModel.Item, position: Int) {
|
fun addItemAtIndex(
|
||||||
|
item: SelfossModel.Item,
|
||||||
|
position: Int,
|
||||||
|
) {
|
||||||
items.add(position, item)
|
items.add(position, item)
|
||||||
notifyItemInserted(position)
|
notifyItemInserted(position)
|
||||||
updateItems(items)
|
updateItems(items)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addItemsAtEnd(newItems: List<SelfossModel.Item>) {
|
fun addItemsAtEnd(newItems: List<SelfossModel.Item>) {
|
||||||
@ -114,6 +127,5 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
|
|||||||
items.addAll(newItems)
|
items.addAll(newItems)
|
||||||
notifyItemRangeInserted(oldSize, newItems.size)
|
notifyItemRangeInserted(oldSize, newItems.size)
|
||||||
updateItems(items)
|
updateItems(items)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,22 +2,22 @@ package bou.amine.apps.readerforselfossv2.android.adapters
|
|||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.Button
|
import android.widget.Button
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import bou.amine.apps.readerforselfossv2.android.R
|
import bou.amine.apps.readerforselfossv2.android.R
|
||||||
|
import bou.amine.apps.readerforselfossv2.android.UpsertSourceActivity
|
||||||
import bou.amine.apps.readerforselfossv2.android.databinding.SourceListItemBinding
|
import bou.amine.apps.readerforselfossv2.android.databinding.SourceListItemBinding
|
||||||
import bou.amine.apps.readerforselfossv2.android.model.toTextDrawableString
|
import bou.amine.apps.readerforselfossv2.android.utils.glide.circularDrawable
|
||||||
import bou.amine.apps.readerforselfossv2.android.utils.glide.circularBitmapDrawable
|
|
||||||
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
||||||
import bou.amine.apps.readerforselfossv2.repository.Repository
|
import bou.amine.apps.readerforselfossv2.repository.Repository
|
||||||
import bou.amine.apps.readerforselfossv2.utils.getHtmlDecoded
|
import bou.amine.apps.readerforselfossv2.utils.getHtmlDecoded
|
||||||
import bou.amine.apps.readerforselfossv2.utils.getIcon
|
import bou.amine.apps.readerforselfossv2.utils.getIcon
|
||||||
import com.amulyakhare.textdrawable.TextDrawable
|
|
||||||
import com.amulyakhare.textdrawable.util.ColorGenerator
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -28,68 +28,76 @@ import org.kodein.di.instance
|
|||||||
|
|
||||||
class SourcesListAdapter(
|
class SourcesListAdapter(
|
||||||
private val app: Activity,
|
private val app: Activity,
|
||||||
private val items: ArrayList<SelfossModel.Source>
|
private val items: ArrayList<SelfossModel.SourceDetail>,
|
||||||
) : RecyclerView.Adapter<SourcesListAdapter.ViewHolder>(), DIAware {
|
) : RecyclerView.Adapter<SourcesListAdapter.ViewHolder>(), DIAware {
|
||||||
private val c: Context = app.baseContext
|
private val c: Context = app.baseContext
|
||||||
private val generator: ColorGenerator = ColorGenerator.MATERIAL
|
|
||||||
private lateinit var binding: SourceListItemBinding
|
private lateinit var binding: SourceListItemBinding
|
||||||
|
|
||||||
override val di: DI by closestDI(app)
|
override val di: DI by closestDI(app)
|
||||||
private val repository: Repository by instance()
|
private val repository: Repository by instance()
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
override fun onCreateViewHolder(
|
||||||
|
parent: ViewGroup,
|
||||||
|
viewType: Int,
|
||||||
|
): ViewHolder {
|
||||||
binding = SourceListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
binding = SourceListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||||
return ViewHolder(binding.root)
|
return ViewHolder(binding.root)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
override fun onBindViewHolder(
|
||||||
|
holder: ViewHolder,
|
||||||
|
position: Int,
|
||||||
|
) {
|
||||||
val itm = items[position]
|
val itm = items[position]
|
||||||
|
|
||||||
if (itm.getIcon(repository.baseUrl).isEmpty()) {
|
val deleteBtn: Button = holder.mView.findViewById(R.id.deleteBtn)
|
||||||
val color = generator.getColor(itm.title.getHtmlDecoded())
|
|
||||||
|
|
||||||
val drawable =
|
deleteBtn.setOnClickListener {
|
||||||
TextDrawable
|
val (id, title) = items[position]
|
||||||
.builder()
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
.round()
|
val successfullyDeletedSource = repository.deleteSource(id, title)
|
||||||
.build(itm.title.getHtmlDecoded().toTextDrawableString(), color)
|
if (successfullyDeletedSource) {
|
||||||
binding.itemImage.setImageDrawable(drawable)
|
items.removeAt(position)
|
||||||
|
notifyItemRemoved(position)
|
||||||
|
notifyItemRangeChanged(position, itemCount)
|
||||||
} else {
|
} else {
|
||||||
c.circularBitmapDrawable(itm.getIcon(repository.baseUrl), binding.itemImage)
|
Toast.makeText(
|
||||||
|
app,
|
||||||
|
R.string.can_delete_source,
|
||||||
|
Toast.LENGTH_SHORT,
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
holder.mView.setOnClickListener {
|
||||||
|
val source = items[position]
|
||||||
|
|
||||||
|
repository.setSelectedSource(source)
|
||||||
|
app.startActivity(Intent(app, UpsertSourceActivity::class.java))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (itm.getIcon(repository.baseUrl).isEmpty()) {
|
||||||
|
binding.itemImage.setBackgroundAndText(itm.title.getHtmlDecoded())
|
||||||
|
} else {
|
||||||
|
c.circularDrawable(itm.getIcon(repository.baseUrl), binding.itemImage)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!itm.error.isNullOrBlank()) {
|
||||||
|
binding.errorText.visibility = View.VISIBLE
|
||||||
|
binding.errorText.text = itm.error
|
||||||
|
} else {
|
||||||
|
binding.errorText.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.sourceTitle.text = itm.title.getHtmlDecoded()
|
binding.sourceTitle.text = itm.title.getHtmlDecoded()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getItemId(position: Int) = position.toLong()
|
||||||
|
|
||||||
|
override fun getItemViewType(position: Int) = position
|
||||||
|
|
||||||
override fun getItemCount(): Int = items.size
|
override fun getItemCount(): Int = items.size
|
||||||
|
|
||||||
inner class ViewHolder(internal val mView: ConstraintLayout) : RecyclerView.ViewHolder(mView) {
|
inner class ViewHolder(val mView: ConstraintLayout) : RecyclerView.ViewHolder(mView)
|
||||||
|
|
||||||
init {
|
|
||||||
handleClickListeners()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleClickListeners() {
|
|
||||||
|
|
||||||
val deleteBtn: Button = mView.findViewById(R.id.deleteBtn)
|
|
||||||
|
|
||||||
deleteBtn.setOnClickListener {
|
|
||||||
val (id) = items[adapterPosition]
|
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
|
||||||
val successfullyDeletedSource = repository.deleteSource(id)
|
|
||||||
if (successfullyDeletedSource) {
|
|
||||||
items.removeAt(adapterPosition)
|
|
||||||
notifyItemRemoved(adapterPosition)
|
|
||||||
notifyItemRangeChanged(adapterPosition, itemCount)
|
|
||||||
} else {
|
|
||||||
Toast.makeText(
|
|
||||||
app,
|
|
||||||
R.string.can_delete_source,
|
|
||||||
Toast.LENGTH_SHORT
|
|
||||||
).show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,35 +0,0 @@
|
|||||||
package bou.amine.apps.readerforselfossv2.android.api.mercury
|
|
||||||
|
|
||||||
import com.google.gson.GsonBuilder
|
|
||||||
import okhttp3.OkHttpClient
|
|
||||||
import okhttp3.logging.HttpLoggingInterceptor
|
|
||||||
import retrofit2.Call
|
|
||||||
import retrofit2.Retrofit
|
|
||||||
import retrofit2.converter.gson.GsonConverterFactory
|
|
||||||
|
|
||||||
class MercuryApi() {
|
|
||||||
private val service: MercuryService
|
|
||||||
|
|
||||||
init {
|
|
||||||
|
|
||||||
val interceptor = HttpLoggingInterceptor()
|
|
||||||
interceptor.level = HttpLoggingInterceptor.Level.NONE
|
|
||||||
val client = OkHttpClient.Builder().addInterceptor(interceptor).build()
|
|
||||||
|
|
||||||
val gson = GsonBuilder()
|
|
||||||
.setLenient()
|
|
||||||
.create()
|
|
||||||
val retrofit =
|
|
||||||
Retrofit
|
|
||||||
.Builder()
|
|
||||||
.baseUrl("https://www.amine-louveau.fr")
|
|
||||||
.client(client)
|
|
||||||
.addConverterFactory(GsonConverterFactory.create(gson))
|
|
||||||
.build()
|
|
||||||
service = retrofit.create(MercuryService::class.java)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun parseUrl(url: String): Call<ParsedContent> {
|
|
||||||
return service.parseUrl(url)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,59 +0,0 @@
|
|||||||
package bou.amine.apps.readerforselfossv2.android.api.mercury
|
|
||||||
|
|
||||||
import android.os.Parcel
|
|
||||||
import android.os.Parcelable
|
|
||||||
import com.google.gson.annotations.SerializedName
|
|
||||||
|
|
||||||
class ParsedContent(
|
|
||||||
@SerializedName("title") val title: String,
|
|
||||||
@SerializedName("content") val content: String?,
|
|
||||||
@SerializedName("date_published") val date_published: String,
|
|
||||||
@SerializedName("lead_image_url") val lead_image_url: String?,
|
|
||||||
@SerializedName("dek") val dek: String,
|
|
||||||
@SerializedName("url") val url: String,
|
|
||||||
@SerializedName("domain") val domain: String,
|
|
||||||
@SerializedName("excerpt") val excerpt: String,
|
|
||||||
@SerializedName("total_pages") val total_pages: Int,
|
|
||||||
@SerializedName("rendered_pages") val rendered_pages: Int,
|
|
||||||
@SerializedName("next_page_url") val next_page_url: String
|
|
||||||
) : Parcelable {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
@JvmField
|
|
||||||
val CREATOR: Parcelable.Creator<ParsedContent> =
|
|
||||||
object : Parcelable.Creator<ParsedContent> {
|
|
||||||
override fun createFromParcel(source: Parcel): ParsedContent = ParsedContent(source)
|
|
||||||
override fun newArray(size: Int): Array<ParsedContent?> = arrayOfNulls(size)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(source: Parcel) : this(
|
|
||||||
title = source.readString().orEmpty(),
|
|
||||||
content = source.readString(),
|
|
||||||
date_published = source.readString().orEmpty(),
|
|
||||||
lead_image_url = source.readString(),
|
|
||||||
dek = source.readString().orEmpty(),
|
|
||||||
url = source.readString().orEmpty(),
|
|
||||||
domain = source.readString().orEmpty(),
|
|
||||||
excerpt = source.readString().orEmpty(),
|
|
||||||
total_pages = source.readInt(),
|
|
||||||
rendered_pages = source.readInt(),
|
|
||||||
next_page_url = source.readString().orEmpty()
|
|
||||||
)
|
|
||||||
|
|
||||||
override fun describeContents() = 0
|
|
||||||
|
|
||||||
override fun writeToParcel(dest: Parcel, flags: Int) {
|
|
||||||
dest.writeString(title)
|
|
||||||
dest.writeString(content)
|
|
||||||
dest.writeString(date_published)
|
|
||||||
dest.writeString(lead_image_url)
|
|
||||||
dest.writeString(dek)
|
|
||||||
dest.writeString(url)
|
|
||||||
dest.writeString(domain)
|
|
||||||
dest.writeString(excerpt)
|
|
||||||
dest.writeInt(total_pages)
|
|
||||||
dest.writeInt(rendered_pages)
|
|
||||||
dest.writeString(next_page_url)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
package bou.amine.apps.readerforselfossv2.android.api.mercury
|
|
||||||
|
|
||||||
import retrofit2.Call
|
|
||||||
import retrofit2.http.GET
|
|
||||||
import retrofit2.http.Query
|
|
||||||
|
|
||||||
interface MercuryService {
|
|
||||||
@GET("parser.php")
|
|
||||||
fun parseUrl(@Query("link") link: String): Call<ParsedContent>
|
|
||||||
}
|
|
@ -26,15 +26,15 @@ import org.kodein.di.instance
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.concurrent.schedule
|
import kotlin.concurrent.schedule
|
||||||
|
|
||||||
class LoadingWorker(val context: Context, params: WorkerParameters) : Worker(context, params), DIAware {
|
class LoadingWorker(val context: Context, params: WorkerParameters) :
|
||||||
|
Worker(context, params),
|
||||||
|
DIAware {
|
||||||
override val di by lazy { (applicationContext as MyApp).di }
|
override val di by lazy { (applicationContext as MyApp).di }
|
||||||
private val repository: Repository by instance()
|
private val repository: Repository by instance()
|
||||||
private val appSettingsService: AppSettingsService by instance()
|
private val appSettingsService: AppSettingsService by instance()
|
||||||
|
|
||||||
override fun doWork(): Result {
|
override fun doWork(): Result {
|
||||||
if (appSettingsService.isPeriodicRefreshEnabled() && isNetworkAccessible(context)) {
|
if (appSettingsService.isPeriodicRefreshEnabled() && isNetworkAccessible(context)) {
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
val notificationManager =
|
val notificationManager =
|
||||||
applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||||
@ -52,11 +52,13 @@ override fun doWork(): Result {
|
|||||||
|
|
||||||
repository.handleDBActions()
|
repository.handleDBActions()
|
||||||
|
|
||||||
|
val apiItems = repository.tryToCacheItemsAndGetNewOnes()
|
||||||
if (appSettingsService.isNotifyNewItemsEnabled()) {
|
if (appSettingsService.isNotifyNewItemsEnabled()) {
|
||||||
launch {
|
launch {
|
||||||
handleNewItemsNotification(repository.tryToCacheItemsAndGetNewOnes(), notificationManager)
|
handleNewItemsNotification(apiItems, notificationManager)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
apiItems.map { it.preloadImages(context) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Result.success()
|
return Result.success()
|
||||||
@ -64,33 +66,37 @@ override fun doWork(): Result {
|
|||||||
|
|
||||||
private fun handleNewItemsNotification(
|
private fun handleNewItemsNotification(
|
||||||
newItems: List<SelfossModel.Item>?,
|
newItems: List<SelfossModel.Item>?,
|
||||||
notificationManager: NotificationManager
|
notificationManager: NotificationManager,
|
||||||
) {
|
) {
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
val apiItems = newItems.orEmpty()
|
val apiItems = newItems.orEmpty()
|
||||||
|
|
||||||
|
|
||||||
val newSize = apiItems.filter { it.unread }.size
|
val newSize = apiItems.filter { it.unread }.size
|
||||||
if (newSize > 0) {
|
if (newSize > 0) {
|
||||||
|
val intent =
|
||||||
val intent = Intent(context, MainActivity::class.java).apply {
|
Intent(context, MainActivity::class.java).apply {
|
||||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||||
}
|
}
|
||||||
val pflags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
val pflags =
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
PendingIntent.FLAG_IMMUTABLE
|
PendingIntent.FLAG_IMMUTABLE
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
val pendingIntent: PendingIntent = PendingIntent.getActivity(context, 0, intent, pflags)
|
val pendingIntent: PendingIntent =
|
||||||
|
PendingIntent.getActivity(context, 0, intent, pflags)
|
||||||
|
|
||||||
val newItemsNotification =
|
val newItemsNotification =
|
||||||
NotificationCompat.Builder(applicationContext, AppSettingsService.newItemsChannelId)
|
NotificationCompat.Builder(
|
||||||
|
applicationContext,
|
||||||
|
AppSettingsService.newItemsChannelId,
|
||||||
|
)
|
||||||
.setContentTitle(context.getString(R.string.new_items_notification_title))
|
.setContentTitle(context.getString(R.string.new_items_notification_title))
|
||||||
.setContentText(
|
.setContentText(
|
||||||
context.getString(
|
context.getString(
|
||||||
R.string.new_items_notification_text,
|
R.string.new_items_notification_text,
|
||||||
newSize
|
newSize,
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
.setPriority(PRIORITY_DEFAULT)
|
.setPriority(PRIORITY_DEFAULT)
|
||||||
.setChannelId(AppSettingsService.newItemsChannelId)
|
.setChannelId(AppSettingsService.newItemsChannelId)
|
||||||
@ -102,7 +108,6 @@ override fun doWork(): Result {
|
|||||||
notificationManager.notify(2, newItemsNotification.build())
|
notificationManager.notify(2, newItemsNotification.build())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
apiItems.map { it.preloadImages(context) }
|
|
||||||
Timer("", false).schedule(4000) {
|
Timer("", false).schedule(4000) {
|
||||||
notificationManager.cancel(1)
|
notificationManager.cancel(1)
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package bou.amine.apps.readerforselfossv2.android.fragments
|
package bou.amine.apps.readerforselfossv2.android.fragments
|
||||||
|
|
||||||
|
import android.content.ActivityNotFoundException
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.res.ColorStateList
|
import android.content.res.ColorStateList
|
||||||
import android.content.res.TypedArray
|
import android.content.res.TypedArray
|
||||||
@ -8,6 +9,7 @@ import android.graphics.Typeface
|
|||||||
import android.graphics.drawable.ColorDrawable
|
import android.graphics.drawable.ColorDrawable
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.util.TypedValue
|
||||||
import android.view.*
|
import android.view.*
|
||||||
import android.webkit.WebResourceResponse
|
import android.webkit.WebResourceResponse
|
||||||
import android.webkit.WebSettings
|
import android.webkit.WebSettings
|
||||||
@ -15,27 +17,23 @@ import android.webkit.WebView
|
|||||||
import android.webkit.WebViewClient
|
import android.webkit.WebViewClient
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.browser.customtabs.CustomTabsIntent
|
|
||||||
import androidx.core.content.res.ResourcesCompat
|
|
||||||
import androidx.core.widget.NestedScrollView
|
import androidx.core.widget.NestedScrollView
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import bou.amine.apps.readerforselfossv2.android.ImageActivity
|
import bou.amine.apps.readerforselfossv2.android.ImageActivity
|
||||||
import bou.amine.apps.readerforselfossv2.android.R
|
import bou.amine.apps.readerforselfossv2.android.R
|
||||||
import bou.amine.apps.readerforselfossv2.android.api.mercury.MercuryApi
|
|
||||||
import bou.amine.apps.readerforselfossv2.android.api.mercury.ParsedContent
|
|
||||||
import bou.amine.apps.readerforselfossv2.android.databinding.FragmentArticleBinding
|
import bou.amine.apps.readerforselfossv2.android.databinding.FragmentArticleBinding
|
||||||
import bou.amine.apps.readerforselfossv2.android.model.ParecelableItem
|
import bou.amine.apps.readerforselfossv2.android.model.ParecelableItem
|
||||||
import bou.amine.apps.readerforselfossv2.android.model.toModel
|
import bou.amine.apps.readerforselfossv2.android.model.toModel
|
||||||
import bou.amine.apps.readerforselfossv2.android.model.toParcelable
|
import bou.amine.apps.readerforselfossv2.android.model.toParcelable
|
||||||
import bou.amine.apps.readerforselfossv2.android.themes.AppColors
|
import bou.amine.apps.readerforselfossv2.android.sendSilentlyWithAcraWithName
|
||||||
import bou.amine.apps.readerforselfossv2.android.utils.buildCustomTabsIntent
|
|
||||||
import bou.amine.apps.readerforselfossv2.android.utils.customtabs.CustomTabActivityHelper
|
|
||||||
import bou.amine.apps.readerforselfossv2.android.utils.glide.getBitmapInputStream
|
import bou.amine.apps.readerforselfossv2.android.utils.glide.getBitmapInputStream
|
||||||
|
import bou.amine.apps.readerforselfossv2.android.utils.isUrlValid
|
||||||
import bou.amine.apps.readerforselfossv2.android.utils.openInBrowserAsNewTask
|
import bou.amine.apps.readerforselfossv2.android.utils.openInBrowserAsNewTask
|
||||||
import bou.amine.apps.readerforselfossv2.android.utils.openItemUrlInternalBrowser
|
|
||||||
import bou.amine.apps.readerforselfossv2.android.utils.shareLink
|
import bou.amine.apps.readerforselfossv2.android.utils.shareLink
|
||||||
|
import bou.amine.apps.readerforselfossv2.model.MercuryModel
|
||||||
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
||||||
import bou.amine.apps.readerforselfossv2.repository.Repository
|
import bou.amine.apps.readerforselfossv2.repository.Repository
|
||||||
|
import bou.amine.apps.readerforselfossv2.rest.MercuryApi
|
||||||
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
||||||
import bou.amine.apps.readerforselfossv2.utils.getHtmlDecoded
|
import bou.amine.apps.readerforselfossv2.utils.getHtmlDecoded
|
||||||
import bou.amine.apps.readerforselfossv2.utils.getImages
|
import bou.amine.apps.readerforselfossv2.utils.getImages
|
||||||
@ -53,18 +51,16 @@ import org.kodein.di.DI
|
|||||||
import org.kodein.di.DIAware
|
import org.kodein.di.DIAware
|
||||||
import org.kodein.di.android.x.closestDI
|
import org.kodein.di.android.x.closestDI
|
||||||
import org.kodein.di.instance
|
import org.kodein.di.instance
|
||||||
import retrofit2.Call
|
|
||||||
import retrofit2.Callback
|
|
||||||
import retrofit2.Response
|
|
||||||
import java.net.MalformedURLException
|
import java.net.MalformedURLException
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.ExecutionException
|
import java.util.concurrent.ExecutionException
|
||||||
|
|
||||||
|
private const val IMAGE_JPG = "image/jpg"
|
||||||
|
|
||||||
class ArticleFragment : Fragment(), DIAware {
|
class ArticleFragment : Fragment(), DIAware {
|
||||||
private var fontSize: Int = 16
|
private var fontSize: Int = 16
|
||||||
private lateinit var item: SelfossModel.Item
|
private lateinit var item: SelfossModel.Item
|
||||||
private var mCustomTabActivityHelper: CustomTabActivityHelper? = null
|
|
||||||
private lateinit var url: String
|
private lateinit var url: String
|
||||||
private lateinit var contentText: String
|
private lateinit var contentText: String
|
||||||
private lateinit var contentSource: String
|
private lateinit var contentSource: String
|
||||||
@ -72,10 +68,8 @@ class ArticleFragment : Fragment(), DIAware {
|
|||||||
private lateinit var contentTitle: String
|
private lateinit var contentTitle: String
|
||||||
private lateinit var allImages: ArrayList<String>
|
private lateinit var allImages: ArrayList<String>
|
||||||
private lateinit var fab: FloatingActionButton
|
private lateinit var fab: FloatingActionButton
|
||||||
private lateinit var appColors: AppColors
|
|
||||||
private lateinit var textAlignment: String
|
private lateinit var textAlignment: String
|
||||||
private var _binding: FragmentArticleBinding? = null
|
private lateinit var binding: FragmentArticleBinding
|
||||||
private val binding get() = _binding!!
|
|
||||||
|
|
||||||
override val di: DI by closestDI()
|
override val di: DI by closestDI()
|
||||||
private val repository: Repository by instance()
|
private val repository: Repository by instance()
|
||||||
@ -86,16 +80,9 @@ class ArticleFragment : Fragment(), DIAware {
|
|||||||
private var font = ""
|
private var font = ""
|
||||||
private var staticBar = false
|
private var staticBar = false
|
||||||
|
|
||||||
override fun onStop() {
|
private val mercuryApi: MercuryApi by instance()
|
||||||
super.onStop()
|
|
||||||
if (mCustomTabActivityHelper != null) {
|
|
||||||
mCustomTabActivityHelper!!.unbindCustomTabsService(activity)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
appColors = AppColors(requireActivity())
|
|
||||||
|
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
val pi: ParecelableItem = requireArguments().getParcelable(ARG_ITEMS)!!
|
val pi: ParecelableItem = requireArguments().getParcelable(ARG_ITEMS)!!
|
||||||
@ -106,88 +93,36 @@ class ArticleFragment : Fragment(), DIAware {
|
|||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?,
|
||||||
): View {
|
): View {
|
||||||
try {
|
try {
|
||||||
_binding = FragmentArticleBinding.inflate(inflater, container, false)
|
binding = FragmentArticleBinding.inflate(inflater, container, false)
|
||||||
|
|
||||||
url = item.getLinkDecoded()
|
url = item.getLinkDecoded()
|
||||||
contentText = item.content
|
contentText = item.content
|
||||||
contentTitle = item.title.getHtmlDecoded()
|
contentTitle = item.title.getHtmlDecoded()
|
||||||
contentImage = item.getThumbnail(repository.baseUrl)
|
contentImage = item.getThumbnail(repository.baseUrl)
|
||||||
contentSource = item.sourceAndDateText(repository.dateUtils)
|
contentSource = try {
|
||||||
|
item.sourceAuthorAndDate()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.sendSilentlyWithAcraWithName("Article Fragment parse date")
|
||||||
|
item.sourceAuthorOnly()
|
||||||
|
}
|
||||||
allImages = item.getImages()
|
allImages = item.getImages()
|
||||||
|
|
||||||
fontSize = appSettingsService.getFontSize()
|
fontSize = appSettingsService.getFontSize()
|
||||||
staticBar = appSettingsService.isStaticBarEnabled()
|
staticBar = appSettingsService.isStaticBarEnabled()
|
||||||
font = appSettingsService.getFont()
|
font = appSettingsService.getFont()
|
||||||
|
|
||||||
if (font.isNotEmpty()) {
|
|
||||||
resId = requireContext().resources.getIdentifier(font, "font", requireContext().packageName)
|
|
||||||
typeface = try {
|
|
||||||
ResourcesCompat.getFont(requireContext(), resId)!!
|
|
||||||
} catch (e: java.lang.Exception) {
|
|
||||||
// Just to be sure
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
refreshAlignment()
|
refreshAlignment()
|
||||||
|
|
||||||
fab = binding.fab
|
fab = binding.fab
|
||||||
|
|
||||||
fab.backgroundTintList = ColorStateList.valueOf(appColors.colorAccent)
|
fab.backgroundTintList = ColorStateList.valueOf(resources.getColor(R.color.colorAccent))
|
||||||
|
|
||||||
fab.rippleColor = appColors.colorAccentDark
|
fab.rippleColor = resources.getColor(R.color.colorAccentDark)
|
||||||
|
|
||||||
val floatingToolbar: FloatingToolbar = binding.floatingToolbar
|
val floatingToolbar: FloatingToolbar = handleFloatingToolbar()
|
||||||
floatingToolbar.attachFab(fab)
|
|
||||||
|
|
||||||
floatingToolbar.background = ColorDrawable(appColors.colorAccent)
|
|
||||||
|
|
||||||
val customTabsIntent = requireActivity().buildCustomTabsIntent()
|
|
||||||
mCustomTabActivityHelper = CustomTabActivityHelper()
|
|
||||||
mCustomTabActivityHelper!!.bindCustomTabsService(activity)
|
|
||||||
|
|
||||||
|
|
||||||
floatingToolbar.setClickListener(
|
|
||||||
object : FloatingToolbar.ItemClickListener {
|
|
||||||
override fun onItemClick(item: MenuItem) {
|
|
||||||
when (item.itemId) {
|
|
||||||
R.id.more_action -> getContentFromMercury(customTabsIntent)
|
|
||||||
R.id.share_action -> requireActivity().shareLink(url, contentTitle)
|
|
||||||
R.id.open_action -> requireActivity().openInBrowserAsNewTask(this@ArticleFragment.item)
|
|
||||||
R.id.unread_action -> if (context != null) {
|
|
||||||
if (this@ArticleFragment.item.unread) {
|
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
|
||||||
repository.markAsRead(this@ArticleFragment.item)
|
|
||||||
}
|
|
||||||
this@ArticleFragment.item.unread = false
|
|
||||||
Toast.makeText(
|
|
||||||
context,
|
|
||||||
R.string.marked_as_read,
|
|
||||||
Toast.LENGTH_LONG
|
|
||||||
).show()
|
|
||||||
} else {
|
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
|
||||||
repository.unmarkAsRead(this@ArticleFragment.item)
|
|
||||||
}
|
|
||||||
this@ArticleFragment.item.unread = true
|
|
||||||
Toast.makeText(
|
|
||||||
context,
|
|
||||||
R.string.marked_as_unread,
|
|
||||||
Toast.LENGTH_LONG
|
|
||||||
).show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> Unit
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onItemLongClick(item: MenuItem?) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
if (staticBar) {
|
if (staticBar) {
|
||||||
fab.hide()
|
fab.hide()
|
||||||
@ -199,8 +134,47 @@ class ArticleFragment : Fragment(), DIAware {
|
|||||||
binding.source.typeface = typeface
|
binding.source.typeface = typeface
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleContent()
|
||||||
|
|
||||||
|
binding.nestedScrollView.setOnScrollChangeListener(
|
||||||
|
NestedScrollView.OnScrollChangeListener { _, _, scrollY, _, oldScrollY ->
|
||||||
|
if (scrollY > oldScrollY) {
|
||||||
|
floatingToolbar.hide()
|
||||||
|
fab.hide()
|
||||||
|
} else {
|
||||||
|
if (staticBar) {
|
||||||
|
floatingToolbar.show()
|
||||||
|
} else {
|
||||||
|
if (floatingToolbar.isShowing) floatingToolbar.hide() else fab.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
} catch (e: InflateException) {
|
||||||
|
e.sendSilentlyWithAcraWithName("webview not available")
|
||||||
|
if (context != null) {
|
||||||
|
AlertDialog.Builder(requireContext())
|
||||||
|
.setMessage(requireContext().getString(R.string.webview_dialog_issue_message))
|
||||||
|
.setTitle(requireContext().getString(R.string.webview_dialog_issue_title))
|
||||||
|
.setPositiveButton(
|
||||||
|
android.R.string.ok,
|
||||||
|
) { _, _ ->
|
||||||
|
appSettingsService.disableArticleViewer()
|
||||||
|
requireActivity().finish()
|
||||||
|
}
|
||||||
|
.create()
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleContent() {
|
||||||
if (contentText.isEmptyOrNullOrNullString()) {
|
if (contentText.isEmptyOrNullOrNullString()) {
|
||||||
getContentFromMercury(customTabsIntent)
|
if (repository.isNetworkAvailable()) {
|
||||||
|
getContentFromMercury()
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
binding.titleView.text = contentTitle
|
binding.titleView.text = contentTitle
|
||||||
if (typeface != null) {
|
if (typeface != null) {
|
||||||
@ -221,198 +195,223 @@ class ArticleFragment : Fragment(), DIAware {
|
|||||||
binding.imageView.visibility = View.GONE
|
binding.imageView.visibility = View.GONE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
binding.nestedScrollView.setOnScrollChangeListener(
|
private fun handleFloatingToolbar(): FloatingToolbar {
|
||||||
NestedScrollView.OnScrollChangeListener { _, _, scrollY, _, oldScrollY ->
|
val floatingToolbar: FloatingToolbar = binding.floatingToolbar
|
||||||
if (scrollY > oldScrollY) {
|
if (appSettingsService.getPublicAccess()) {
|
||||||
floatingToolbar.hide()
|
floatingToolbar.setMenu(R.menu.reader_toolbar_no_read)
|
||||||
fab.hide()
|
}
|
||||||
|
floatingToolbar.attachFab(fab)
|
||||||
|
|
||||||
|
floatingToolbar.background = ColorDrawable(resources.getColor(R.color.colorAccent))
|
||||||
|
|
||||||
|
floatingToolbar.setClickListener(
|
||||||
|
object : FloatingToolbar.ItemClickListener {
|
||||||
|
override fun onItemClick(item: MenuItem) {
|
||||||
|
when (item.itemId) {
|
||||||
|
R.id.share_action -> requireActivity().shareLink(url, contentTitle)
|
||||||
|
R.id.open_action -> requireActivity().openInBrowserAsNewTask(this@ArticleFragment.item)
|
||||||
|
R.id.unread_action ->
|
||||||
|
if (context != null) {
|
||||||
|
if (this@ArticleFragment.item.unread) {
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
repository.markAsRead(this@ArticleFragment.item)
|
||||||
|
}
|
||||||
|
this@ArticleFragment.item.unread = false
|
||||||
|
Toast.makeText(
|
||||||
|
context,
|
||||||
|
R.string.marked_as_read,
|
||||||
|
Toast.LENGTH_LONG,
|
||||||
|
).show()
|
||||||
} else {
|
} else {
|
||||||
if (staticBar) {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
floatingToolbar.show()
|
repository.unmarkAsRead(this@ArticleFragment.item)
|
||||||
} else {
|
}
|
||||||
if (floatingToolbar.isShowing) floatingToolbar.hide() else fab.show()
|
this@ArticleFragment.item.unread = true
|
||||||
|
Toast.makeText(
|
||||||
|
context,
|
||||||
|
R.string.marked_as_unread,
|
||||||
|
Toast.LENGTH_LONG,
|
||||||
|
).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else -> Unit
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onItemLongClick(item: MenuItem?) {
|
||||||
|
// We do nothing
|
||||||
|
}
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
return floatingToolbar
|
||||||
} catch (e: InflateException) {
|
|
||||||
AlertDialog.Builder(requireContext())
|
|
||||||
.setMessage(requireContext().getString(R.string.webview_dialog_issue_message))
|
|
||||||
.setTitle(requireContext().getString(R.string.webview_dialog_issue_title))
|
|
||||||
.setPositiveButton(android.R.string.ok
|
|
||||||
) { _, _ ->
|
|
||||||
appSettingsService.disableArticleViewer()
|
|
||||||
requireActivity().finish()
|
|
||||||
}
|
|
||||||
.create()
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
|
|
||||||
return binding.root
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroyView() {
|
|
||||||
super.onDestroyView()
|
|
||||||
_binding = null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun refreshAlignment() {
|
private fun refreshAlignment() {
|
||||||
textAlignment = when (appSettingsService.getActiveAllignment()) {
|
textAlignment =
|
||||||
|
when (appSettingsService.getActiveAllignment()) {
|
||||||
1 -> "justify"
|
1 -> "justify"
|
||||||
2 -> "left"
|
2 -> "left"
|
||||||
else -> "justify"
|
else -> "justify"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getContentFromMercury(customTabsIntent: CustomTabsIntent) {
|
private fun getContentFromMercury() {
|
||||||
if (repository.isNetworkAvailable()) {
|
|
||||||
binding.progressBar.visibility = View.VISIBLE
|
binding.progressBar.visibility = View.VISIBLE
|
||||||
val parser = MercuryApi()
|
|
||||||
|
|
||||||
parser.parseUrl(url).enqueue(
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
object : Callback<ParsedContent> {
|
|
||||||
override fun onResponse(
|
|
||||||
call: Call<ParsedContent>,
|
|
||||||
response: Response<ParsedContent>
|
|
||||||
) {
|
|
||||||
// TODO: clean all the following after finding the mercury content issue
|
|
||||||
try {
|
try {
|
||||||
if (response.body() != null && response.body()!!.content != null && !response.body()!!.content.isNullOrEmpty()) {
|
val response = mercuryApi.query(url)
|
||||||
try {
|
if (response.success && response.data != null) {
|
||||||
binding.titleView.text = response.body()!!.title
|
handleMercuryData(response.data!!)
|
||||||
|
} else {
|
||||||
|
openInBrowserAfterFailing()
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
openInBrowserAfterFailing()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleMercuryData(data: MercuryModel.ParsedContent) {
|
||||||
|
if (data.error == true || data.failed == true) {
|
||||||
|
openInBrowserAfterFailing()
|
||||||
|
} else {
|
||||||
|
binding.titleView.text = data.title.orEmpty()
|
||||||
if (typeface != null) {
|
if (typeface != null) {
|
||||||
binding.titleView.typeface = typeface
|
binding.titleView.typeface = typeface
|
||||||
}
|
}
|
||||||
try {
|
URL(data.url)
|
||||||
// Note: Mercury may return relative urls... If it does the url val will not be changed.
|
url = data.url!!
|
||||||
URL(response.body()!!.url)
|
|
||||||
url = response.body()!!.url
|
|
||||||
} catch (e: MalformedURLException) {
|
|
||||||
// Mercury returned a relative url. We do nothing.
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
contentText = data.content.orEmpty()
|
||||||
contentText = response.body()!!.content.orEmpty()
|
|
||||||
htmlToWebview()
|
htmlToWebview()
|
||||||
} catch (e: Exception) {
|
|
||||||
|
handleLeadImage(data?.lead_image_url)
|
||||||
|
|
||||||
|
binding.nestedScrollView.scrollTo(0, 0)
|
||||||
|
binding.progressBar.visibility = View.GONE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
private fun handleLeadImage(lead_image_url: String?) {
|
||||||
if (response.body()!!.lead_image_url != null && !response.body()!!.lead_image_url.isNullOrEmpty() && context != null) {
|
if (!lead_image_url.isNullOrEmpty() && context != null) {
|
||||||
binding.imageView.visibility = View.VISIBLE
|
binding.imageView.visibility = View.VISIBLE
|
||||||
try {
|
|
||||||
Glide
|
Glide
|
||||||
.with(requireContext())
|
.with(requireContext())
|
||||||
.asBitmap()
|
.asBitmap()
|
||||||
.load(
|
.load(
|
||||||
response.body()!!.lead_image_url.orEmpty()
|
lead_image_url,
|
||||||
)
|
)
|
||||||
.apply(RequestOptions.fitCenterTransform())
|
.apply(RequestOptions.fitCenterTransform())
|
||||||
.into(binding.imageView)
|
.into(binding.imageView)
|
||||||
} catch (e: Exception) {
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
binding.imageView.visibility = View.GONE
|
binding.imageView.visibility = View.GONE
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
|
||||||
if (context != null) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun handleImageLoading() {
|
||||||
|
binding.webcontent.webViewClient =
|
||||||
|
object : WebViewClient() {
|
||||||
|
@Deprecated("Deprecated in Java")
|
||||||
|
override fun shouldOverrideUrlLoading(
|
||||||
|
view: WebView?,
|
||||||
|
url: String,
|
||||||
|
): Boolean {
|
||||||
|
return if (context != null && url.isUrlValid() && binding.webcontent.hitTestResult.type != WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE) {
|
||||||
try {
|
try {
|
||||||
binding.nestedScrollView.scrollTo(0, 0)
|
|
||||||
|
|
||||||
binding.progressBar.visibility = View.GONE
|
|
||||||
} catch (e: Exception) {
|
|
||||||
if (context != null) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
openInBrowserAfterFailing(customTabsIntent)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
if (context != null) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
if (context != null) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onFailure(
|
|
||||||
call: Call<ParsedContent>,
|
|
||||||
t: Throwable
|
|
||||||
) = openInBrowserAfterFailing(customTabsIntent)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun htmlToWebview() {
|
|
||||||
val stringColor = String.format("#%06X", 0xFFFFFF and appColors.colorAccent)
|
|
||||||
|
|
||||||
val attrs: IntArray = intArrayOf(android.R.attr.fontFamily)
|
|
||||||
val a: TypedArray = requireContext().obtainStyledAttributes(resId, attrs)
|
|
||||||
|
|
||||||
|
|
||||||
binding.webcontent.settings.standardFontFamily = a.getString(0)
|
|
||||||
binding.webcontent.visibility = View.VISIBLE
|
|
||||||
|
|
||||||
// TODO: Set the color strings programmatically
|
|
||||||
val (stringTextColor, stringBackgroundColor) = if (appColors.isDarkTheme) {
|
|
||||||
Pair("#FFFFFF", "#303030")
|
|
||||||
} else {
|
|
||||||
Pair("#212121", "#FAFAFA")
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.webcontent.settings.useWideViewPort = true
|
|
||||||
binding.webcontent.settings.loadWithOverviewMode = true
|
|
||||||
binding.webcontent.settings.javaScriptEnabled = false
|
|
||||||
|
|
||||||
binding.webcontent.webViewClient = object : WebViewClient() {
|
|
||||||
override fun shouldOverrideUrlLoading(view: WebView?, url : String): Boolean {
|
|
||||||
if (binding.webcontent.hitTestResult.type != WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE) {
|
|
||||||
requireContext().startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url)))
|
requireContext().startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url)))
|
||||||
|
} catch (e: ActivityNotFoundException) {
|
||||||
|
e.sendSilentlyWithAcraWithName("activityNotFound > $url")
|
||||||
|
}
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
}
|
}
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun shouldInterceptRequest(view: WebView?, url: String): WebResourceResponse? {
|
@Deprecated("Deprecated in Java")
|
||||||
|
override fun shouldInterceptRequest(
|
||||||
|
view: WebView,
|
||||||
|
url: String,
|
||||||
|
): WebResourceResponse? {
|
||||||
val glideOptions = RequestOptions.diskCacheStrategyOf(DiskCacheStrategy.ALL)
|
val glideOptions = RequestOptions.diskCacheStrategyOf(DiskCacheStrategy.ALL)
|
||||||
if (url.lowercase(Locale.US).contains(".jpg") || url.lowercase(Locale.US).contains(".jpeg")) {
|
if (url.lowercase(Locale.US).contains(".jpg") ||
|
||||||
|
url.lowercase(Locale.US)
|
||||||
|
.contains(".jpeg")
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
val image = Glide.with(view).asBitmap().apply(glideOptions).load(url).submit().get()
|
val image =
|
||||||
return WebResourceResponse("image/jpg", "UTF-8", getBitmapInputStream(image, Bitmap.CompressFormat.JPEG))
|
Glide.with(view).asBitmap().apply(glideOptions).load(url).submit().get()
|
||||||
}catch ( e : ExecutionException) {}
|
return WebResourceResponse(
|
||||||
|
IMAGE_JPG,
|
||||||
|
"UTF-8",
|
||||||
|
getBitmapInputStream(image, Bitmap.CompressFormat.JPEG),
|
||||||
|
)
|
||||||
|
} catch (e: ExecutionException) {
|
||||||
|
// Do nothing
|
||||||
}
|
}
|
||||||
else if (url.lowercase(Locale.US).contains(".png")) {
|
} else if (url.lowercase(Locale.US).contains(".png")) {
|
||||||
try {
|
try {
|
||||||
val image = Glide.with(view).asBitmap().apply(glideOptions).load(url).submit().get()
|
val image =
|
||||||
return WebResourceResponse("image/jpg", "UTF-8", getBitmapInputStream(image, Bitmap.CompressFormat.PNG))
|
Glide.with(view).asBitmap().apply(glideOptions).load(url).submit().get()
|
||||||
}catch ( e : ExecutionException) {}
|
return WebResourceResponse(
|
||||||
|
IMAGE_JPG,
|
||||||
|
"UTF-8",
|
||||||
|
getBitmapInputStream(image, Bitmap.CompressFormat.PNG),
|
||||||
|
)
|
||||||
|
} catch (e: ExecutionException) {
|
||||||
|
// Do nothing
|
||||||
}
|
}
|
||||||
else if (url.lowercase(Locale.US).contains(".webp")) {
|
} else if (url.lowercase(Locale.US).contains(".webp")) {
|
||||||
try {
|
try {
|
||||||
val image = Glide.with(view).asBitmap().apply(glideOptions).load(url).submit().get()
|
val image =
|
||||||
return WebResourceResponse("image/jpg", "UTF-8", getBitmapInputStream(image, Bitmap.CompressFormat.WEBP))
|
Glide.with(view).asBitmap().apply(glideOptions).load(url).submit().get()
|
||||||
}catch ( e : ExecutionException) {}
|
return WebResourceResponse(
|
||||||
|
IMAGE_JPG,
|
||||||
|
"UTF-8",
|
||||||
|
getBitmapInputStream(image, Bitmap.CompressFormat.WEBP),
|
||||||
|
)
|
||||||
|
} catch (e: ExecutionException) {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.shouldInterceptRequest(view, url)
|
return super.shouldInterceptRequest(view, url)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val gestureDetector = GestureDetector(activity, object : GestureDetector.SimpleOnGestureListener() {
|
private fun htmlToWebview() {
|
||||||
override fun onSingleTapUp(e: MotionEvent?): Boolean {
|
if (context != null) {
|
||||||
|
val attrs: IntArray = intArrayOf(android.R.attr.fontFamily)
|
||||||
|
val a: TypedArray = requireContext().obtainStyledAttributes(resId, attrs)
|
||||||
|
|
||||||
|
binding.webcontent.settings.standardFontFamily = a.getString(0)
|
||||||
|
binding.webcontent.visibility = View.VISIBLE
|
||||||
|
|
||||||
|
val colorOnSurface = TypedValue()
|
||||||
|
requireContext().theme.resolveAttribute(R.attr.colorOnSurface, colorOnSurface, true)
|
||||||
|
|
||||||
|
val colorSurface = TypedValue()
|
||||||
|
requireContext().theme.resolveAttribute(R.attr.colorSurface, colorSurface, true)
|
||||||
|
|
||||||
|
binding.webcontent.settings.useWideViewPort = true
|
||||||
|
binding.webcontent.settings.loadWithOverviewMode = true
|
||||||
|
binding.webcontent.settings.javaScriptEnabled = false
|
||||||
|
|
||||||
|
handleImageLoading()
|
||||||
|
|
||||||
|
val gestureDetector =
|
||||||
|
GestureDetector(
|
||||||
|
activity,
|
||||||
|
object : GestureDetector.SimpleOnGestureListener() {
|
||||||
|
override fun onSingleTapUp(e: MotionEvent): Boolean {
|
||||||
return performClick()
|
return performClick()
|
||||||
}
|
}
|
||||||
})
|
},
|
||||||
|
)
|
||||||
|
|
||||||
binding.webcontent.setOnTouchListener { _, event -> gestureDetector.onTouchEvent(event) }
|
binding.webcontent.setOnTouchListener { _, event -> gestureDetector.onTouchEvent(event) }
|
||||||
|
|
||||||
@ -425,16 +424,25 @@ class ArticleFragment : Fragment(), DIAware {
|
|||||||
val itemUrl = URL(url)
|
val itemUrl = URL(url)
|
||||||
baseUrl = itemUrl.protocol + "://" + itemUrl.host
|
baseUrl = itemUrl.protocol + "://" + itemUrl.host
|
||||||
} catch (e: MalformedURLException) {
|
} catch (e: MalformedURLException) {
|
||||||
|
e.sendSilentlyWithAcraWithName("htmlToWebview > $url")
|
||||||
}
|
}
|
||||||
|
|
||||||
val fontName = when (font) {
|
val fontName =
|
||||||
|
when (font) {
|
||||||
getString(R.string.open_sans_font_id) -> "Open Sans"
|
getString(R.string.open_sans_font_id) -> "Open Sans"
|
||||||
getString(R.string.roboto_font_id) -> "Roboto"
|
getString(R.string.roboto_font_id) -> "Roboto"
|
||||||
|
getString(R.string.source_code_pro_font_id) -> "Source Code Pro"
|
||||||
else -> ""
|
else -> ""
|
||||||
}
|
}
|
||||||
|
|
||||||
val fontLinkAndStyle = if (font.isNotEmpty()) {
|
val fontLinkAndStyle =
|
||||||
"""<link href="https://fonts.googleapis.com/css?family=${fontName.replace(" ", "+")}" rel="stylesheet">
|
if (font.isNotEmpty()) {
|
||||||
|
"""<link href="https://fonts.googleapis.com/css?family=${
|
||||||
|
fontName.replace(
|
||||||
|
" ",
|
||||||
|
"+",
|
||||||
|
)
|
||||||
|
}" rel="stylesheet">
|
||||||
|<style>
|
|<style>
|
||||||
| * {
|
| * {
|
||||||
| font-family: '$fontName';
|
| font-family: '$fontName';
|
||||||
@ -458,10 +466,15 @@ class ArticleFragment : Fragment(), DIAware {
|
|||||||
| max-width: 100%;
|
| max-width: 100%;
|
||||||
| }
|
| }
|
||||||
| a {
|
| a {
|
||||||
| color: $stringColor !important;
|
| color: ${
|
||||||
|
String.format(
|
||||||
|
"#%06X",
|
||||||
|
0xFFFFFF and resources.getColor(R.color.colorAccent),
|
||||||
|
)
|
||||||
|
} !important;
|
||||||
| }
|
| }
|
||||||
| *:not(a) {
|
| *:not(a) {
|
||||||
| color: $stringTextColor;
|
| color: ${String.format("#%06X", 0xFFFFFF and colorOnSurface.data)};
|
||||||
| }
|
| }
|
||||||
| * {
|
| * {
|
||||||
| font-size: ${fontSize}px;
|
| font-size: ${fontSize}px;
|
||||||
@ -469,11 +482,26 @@ class ArticleFragment : Fragment(), DIAware {
|
|||||||
| word-break: break-word;
|
| word-break: break-word;
|
||||||
| overflow:hidden;
|
| overflow:hidden;
|
||||||
| line-height: 1.5em;
|
| line-height: 1.5em;
|
||||||
| background-color: $stringBackgroundColor;
|
| background-color: ${
|
||||||
|
String.format(
|
||||||
|
"#%06X",
|
||||||
|
0xFFFFFF and colorSurface.data,
|
||||||
|
)
|
||||||
|
};
|
||||||
| }
|
| }
|
||||||
| body, html {
|
| body, html {
|
||||||
| background-color: $stringBackgroundColor !important;
|
| background-color: ${
|
||||||
| border-color: $stringBackgroundColor !important;
|
String.format(
|
||||||
|
"#%06X",
|
||||||
|
0xFFFFFF and colorSurface.data,
|
||||||
|
)
|
||||||
|
} !important;
|
||||||
|
| border-color: ${
|
||||||
|
String.format(
|
||||||
|
"#%06X",
|
||||||
|
0xFFFFFF and colorSurface.data,
|
||||||
|
)
|
||||||
|
} !important;
|
||||||
| padding: 0 !important;
|
| padding: 0 !important;
|
||||||
| margin: 0 !important;
|
| margin: 0 !important;
|
||||||
| }
|
| }
|
||||||
@ -483,19 +511,26 @@ class ArticleFragment : Fragment(), DIAware {
|
|||||||
| pre, code {
|
| pre, code {
|
||||||
| white-space: pre-wrap;
|
| white-space: pre-wrap;
|
||||||
| width:100%;
|
| width:100%;
|
||||||
| background-color: $stringBackgroundColor;
|
| background-color: ${
|
||||||
|
String.format(
|
||||||
|
"#%06X",
|
||||||
|
0xFFFFFF and colorSurface.data,
|
||||||
|
)
|
||||||
|
};
|
||||||
| }
|
| }
|
||||||
| </style>
|
| </style>
|
||||||
| $fontLinkAndStyle
|
| $fontLinkAndStyle
|
||||||
|</head>
|
|</head>
|
||||||
|<body>
|
|<body>
|
||||||
| $contentText
|
| $contentText
|
||||||
|</body>""".trimMargin(),
|
|</body>
|
||||||
|
""".trimMargin(),
|
||||||
"text/html",
|
"text/html",
|
||||||
"utf-8",
|
"utf-8",
|
||||||
null
|
null,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun scrollDown() {
|
fun scrollDown() {
|
||||||
val height = binding.nestedScrollView.measuredHeight
|
val height = binding.nestedScrollView.measuredHeight
|
||||||
@ -507,21 +542,19 @@ class ArticleFragment : Fragment(), DIAware {
|
|||||||
binding.nestedScrollView.smoothScrollBy(0, -height / 2)
|
binding.nestedScrollView.smoothScrollBy(0, -height / 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun openInBrowserAfterFailing(customTabsIntent: CustomTabsIntent) {
|
private fun openInBrowserAfterFailing() {
|
||||||
binding.progressBar.visibility = View.GONE
|
binding.progressBar.visibility = View.GONE
|
||||||
requireActivity().openItemUrlInternalBrowser(
|
if (context != null) {
|
||||||
url,
|
requireContext().openInBrowserAsNewTask(this@ArticleFragment.item)
|
||||||
customTabsIntent,
|
} else {
|
||||||
requireActivity()
|
Exception("openInBrowserAfterFailing context is null").sendSilentlyWithAcraWithName("openInBrowserAfterFailing > $context")
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val ARG_ITEMS = "items"
|
private const val ARG_ITEMS = "items"
|
||||||
|
|
||||||
fun newInstance(
|
fun newInstance(item: SelfossModel.Item): ArticleFragment {
|
||||||
item: SelfossModel.Item
|
|
||||||
): ArticleFragment {
|
|
||||||
val fragment = ArticleFragment()
|
val fragment = ArticleFragment()
|
||||||
val args = Bundle()
|
val args = Bundle()
|
||||||
args.putParcelable(ARG_ITEMS, item.toParcelable())
|
args.putParcelable(ARG_ITEMS, item.toParcelable())
|
||||||
@ -531,9 +564,11 @@ class ArticleFragment : Fragment(), DIAware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun performClick(): Boolean {
|
fun performClick(): Boolean {
|
||||||
if (binding.webcontent.hitTestResult.type == WebView.HitTestResult.IMAGE_TYPE ||
|
if (allImages != null && (
|
||||||
binding.webcontent.hitTestResult.type == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE) {
|
binding.webcontent.hitTestResult.type == WebView.HitTestResult.IMAGE_TYPE ||
|
||||||
|
binding.webcontent.hitTestResult.type == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE
|
||||||
|
)
|
||||||
|
) {
|
||||||
val position: Int = allImages.indexOf(binding.webcontent.hitTestResult.extra)
|
val position: Int = allImages.indexOf(binding.webcontent.hitTestResult.extra)
|
||||||
|
|
||||||
val intent = Intent(activity, ImageActivity::class.java)
|
val intent = Intent(activity, ImageActivity::class.java)
|
||||||
@ -544,6 +579,4 @@ class ArticleFragment : Fragment(), DIAware {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,195 @@
|
|||||||
|
package bou.amine.apps.readerforselfossv2.android.fragments
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.graphics.drawable.GradientDrawable
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.text.TextUtils
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.View.GONE
|
||||||
|
import android.view.View.VISIBLE
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import bou.amine.apps.readerforselfossv2.android.HomeActivity
|
||||||
|
import bou.amine.apps.readerforselfossv2.android.R
|
||||||
|
import bou.amine.apps.readerforselfossv2.android.databinding.FilterFragmentBinding
|
||||||
|
import bou.amine.apps.readerforselfossv2.android.sendSilentlyWithAcraWithName
|
||||||
|
import bou.amine.apps.readerforselfossv2.repository.Repository
|
||||||
|
import bou.amine.apps.readerforselfossv2.utils.getColorHexCode
|
||||||
|
import bou.amine.apps.readerforselfossv2.utils.getHtmlDecoded
|
||||||
|
import bou.amine.apps.readerforselfossv2.utils.getIcon
|
||||||
|
import com.bumptech.glide.Glide
|
||||||
|
import com.bumptech.glide.request.target.ViewTarget
|
||||||
|
import com.bumptech.glide.request.transition.Transition
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
|
import com.google.android.material.chip.Chip
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import org.kodein.di.DI
|
||||||
|
import org.kodein.di.DIAware
|
||||||
|
import org.kodein.di.android.x.closestDI
|
||||||
|
import org.kodein.di.instance
|
||||||
|
|
||||||
|
class FilterSheetFragment : BottomSheetDialogFragment(), DIAware {
|
||||||
|
private lateinit var binding: FilterFragmentBinding
|
||||||
|
override val di: DI by closestDI()
|
||||||
|
private val repository: Repository by instance()
|
||||||
|
|
||||||
|
private var selectedChip: Chip? = null
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?,
|
||||||
|
): View {
|
||||||
|
binding =
|
||||||
|
FilterFragmentBinding.inflate(
|
||||||
|
inflater,
|
||||||
|
container,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
|
||||||
|
val context: Context? = context
|
||||||
|
|
||||||
|
if (context == null) {
|
||||||
|
dismiss()
|
||||||
|
Exception("FilterSheetFragment context is null").sendSilentlyWithAcraWithName("FilterSheetFragment > onCreateView")
|
||||||
|
} else {
|
||||||
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
|
handleTagChips(context)
|
||||||
|
handleSourceChips(context)
|
||||||
|
|
||||||
|
binding.progressBar2.visibility = GONE
|
||||||
|
binding.filterView.visibility = VISIBLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.floatingActionButton2.setOnClickListener {
|
||||||
|
(activity as HomeActivity).getElementsAccordingToTab()
|
||||||
|
(activity as HomeActivity).fetchOnEmptyList()
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun handleSourceChips(context: Context) {
|
||||||
|
val sourceGroup = binding.sourcesGroup
|
||||||
|
|
||||||
|
repository.getSourcesDetailsOrStats().forEachIndexed { _, source ->
|
||||||
|
val c = Chip(context)
|
||||||
|
c.ellipsize = TextUtils.TruncateAt.END
|
||||||
|
|
||||||
|
Glide.with(context)
|
||||||
|
.load(source.getIcon(repository.baseUrl))
|
||||||
|
.into(
|
||||||
|
object : ViewTarget<Chip?, Drawable?>(c) {
|
||||||
|
override fun onResourceReady(
|
||||||
|
resource: Drawable,
|
||||||
|
transition: Transition<in Drawable?>?,
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
c.chipIcon = resource
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.sendSilentlyWithAcraWithName("sources > onResourceReady")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
c.text = source.title.getHtmlDecoded()
|
||||||
|
|
||||||
|
c.setOnCloseIconClickListener {
|
||||||
|
(it as Chip).isCloseIconVisible = false
|
||||||
|
selectedChip = null
|
||||||
|
repository.setSourceFilter(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.setOnClickListener {
|
||||||
|
if (selectedChip != null) {
|
||||||
|
selectedChip!!.isCloseIconVisible = false
|
||||||
|
}
|
||||||
|
(it as Chip).isCloseIconVisible = true
|
||||||
|
selectedChip = it
|
||||||
|
repository.setSourceFilter(source)
|
||||||
|
|
||||||
|
repository.setTagFilter(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (repository.sourceFilter.value?.equals(source) == true) {
|
||||||
|
c.isCloseIconVisible = true
|
||||||
|
selectedChip = c
|
||||||
|
}
|
||||||
|
|
||||||
|
c.isEnabled = source.error.isNullOrBlank()
|
||||||
|
|
||||||
|
if (!source.error.isNullOrBlank() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
c.tooltipText = source.error
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceGroup.addView(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun handleTagChips(context: Context) {
|
||||||
|
val tagGroup = binding.tagsGroup
|
||||||
|
|
||||||
|
val tags = repository.getTags()
|
||||||
|
|
||||||
|
tags.forEachIndexed { _, tag ->
|
||||||
|
val c = Chip(context)
|
||||||
|
c.ellipsize = TextUtils.TruncateAt.END
|
||||||
|
c.text = tag.tag
|
||||||
|
|
||||||
|
if (tag.color.isNotEmpty()) {
|
||||||
|
try {
|
||||||
|
val gd = GradientDrawable()
|
||||||
|
val gdColor =
|
||||||
|
try {
|
||||||
|
Color.parseColor(tag.getColorHexCode())
|
||||||
|
} catch (e: IllegalArgumentException) {
|
||||||
|
e.sendSilentlyWithAcraWithName("color issue " + tag.color + " / " + tag.getColorHexCode())
|
||||||
|
resources.getColor(R.color.colorPrimary)
|
||||||
|
}
|
||||||
|
gd.setColor(gdColor)
|
||||||
|
gd.shape = GradientDrawable.RECTANGLE
|
||||||
|
gd.setSize(30, 30)
|
||||||
|
gd.cornerRadius = 30F
|
||||||
|
c.chipIcon = gd
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.sendSilentlyWithAcraWithName("tags > GradientDrawable")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c.setOnCloseIconClickListener {
|
||||||
|
(it as Chip).isCloseIconVisible = false
|
||||||
|
selectedChip = null
|
||||||
|
repository.setTagFilter(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.setOnClickListener {
|
||||||
|
if (selectedChip != null) {
|
||||||
|
selectedChip!!.isCloseIconVisible = false
|
||||||
|
}
|
||||||
|
(it as Chip).isCloseIconVisible = true
|
||||||
|
selectedChip = it
|
||||||
|
repository.setTagFilter(tag)
|
||||||
|
|
||||||
|
repository.setSourceFilter(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (repository.tagFilter.value?.equals(tag) == true) {
|
||||||
|
c.isCloseIconVisible = true
|
||||||
|
selectedChip = c
|
||||||
|
}
|
||||||
|
|
||||||
|
tagGroup.addView(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TAG = "FilterModalBottomSheet"
|
||||||
|
}
|
||||||
|
}
|
@ -11,7 +11,6 @@ import com.bumptech.glide.load.engine.DiskCacheStrategy
|
|||||||
import com.bumptech.glide.request.RequestOptions
|
import com.bumptech.glide.request.RequestOptions
|
||||||
|
|
||||||
class ImageFragment : Fragment() {
|
class ImageFragment : Fragment() {
|
||||||
|
|
||||||
private lateinit var imageUrl: String
|
private lateinit var imageUrl: String
|
||||||
private val glideOptions = RequestOptions.diskCacheStrategyOf(DiskCacheStrategy.ALL)
|
private val glideOptions = RequestOptions.diskCacheStrategyOf(DiskCacheStrategy.ALL)
|
||||||
private var _binding: FragmentImageBinding? = null
|
private var _binding: FragmentImageBinding? = null
|
||||||
@ -23,12 +22,16 @@ class ImageFragment : Fragment() {
|
|||||||
imageUrl = requireArguments().getString("imageUrl")!!
|
imageUrl = requireArguments().getString("imageUrl")!!
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?,
|
||||||
|
): View? {
|
||||||
_binding = FragmentImageBinding.inflate(inflater, container, false)
|
_binding = FragmentImageBinding.inflate(inflater, container, false)
|
||||||
val view = binding?.root
|
val view = binding?.root
|
||||||
|
|
||||||
binding!!.photoView.visibility = View.VISIBLE
|
binding!!.photoView.visibility = View.VISIBLE
|
||||||
Glide.with(activity)
|
Glide.with(requireActivity())
|
||||||
.asBitmap()
|
.asBitmap()
|
||||||
.apply(glideOptions)
|
.apply(glideOptions)
|
||||||
.load(imageUrl)
|
.load(imageUrl)
|
||||||
@ -45,9 +48,7 @@ class ImageFragment : Fragment() {
|
|||||||
companion object {
|
companion object {
|
||||||
private const val ARG_IMAGE = "imageUrl"
|
private const val ARG_IMAGE = "imageUrl"
|
||||||
|
|
||||||
fun newInstance(
|
fun newInstance(imageUrl: String): ImageFragment {
|
||||||
imageUrl : String
|
|
||||||
): ImageFragment {
|
|
||||||
val fragment = ImageFragment()
|
val fragment = ImageFragment()
|
||||||
val args = Bundle()
|
val args = Bundle()
|
||||||
args.putString(ARG_IMAGE, imageUrl)
|
args.putString(ARG_IMAGE, imageUrl)
|
||||||
|
@ -2,6 +2,7 @@ package bou.amine.apps.readerforselfossv2.android.model
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.webkit.URLUtil
|
import android.webkit.URLUtil
|
||||||
|
import bou.amine.apps.readerforselfossv2.android.sendSilentlyWithAcraWithName
|
||||||
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
||||||
import bou.amine.apps.readerforselfossv2.utils.getImages
|
import bou.amine.apps.readerforselfossv2.utils.getImages
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
@ -13,7 +14,6 @@ fun SelfossModel.Item.preloadImages(context: Context) : Boolean {
|
|||||||
|
|
||||||
val glideOptions = RequestOptions.diskCacheStrategyOf(DiskCacheStrategy.ALL).timeout(10000)
|
val glideOptions = RequestOptions.diskCacheStrategyOf(DiskCacheStrategy.ALL).timeout(10000)
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for (url in imageUrls) {
|
for (url in imageUrls) {
|
||||||
if (URLUtil.isValidUrl(url)) {
|
if (URLUtil.isValidUrl(url)) {
|
||||||
@ -23,6 +23,7 @@ fun SelfossModel.Item.preloadImages(context: Context) : Boolean {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e: Error) {
|
} catch (e: Error) {
|
||||||
|
e.sendSilentlyWithAcraWithName("preloadImages")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,7 +36,7 @@ fun String.toTextDrawableString(): String {
|
|||||||
try {
|
try {
|
||||||
textDrawable.append(s[0])
|
textDrawable.append(s[0])
|
||||||
} catch (e: StringIndexOutOfBoundsException) {
|
} catch (e: StringIndexOutOfBoundsException) {
|
||||||
// We do nothing
|
e.sendSilentlyWithAcraWithName("toTextDrawableString")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return textDrawable.toString()
|
return textDrawable.toString()
|
||||||
|
@ -3,7 +3,6 @@ package bou.amine.apps.readerforselfossv2.android.model
|
|||||||
import android.os.Parcel
|
import android.os.Parcel
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
||||||
import com.google.gson.annotations.SerializedName
|
|
||||||
|
|
||||||
fun SelfossModel.Item.toParcelable(): ParecelableItem =
|
fun SelfossModel.Item.toParcelable(): ParecelableItem =
|
||||||
ParecelableItem(
|
ParecelableItem(
|
||||||
@ -17,8 +16,10 @@ fun SelfossModel.Item.toParcelable() : ParecelableItem =
|
|||||||
this.icon,
|
this.icon,
|
||||||
this.link,
|
this.link,
|
||||||
this.sourcetitle,
|
this.sourcetitle,
|
||||||
this.tags.joinToString(",")
|
this.tags.joinToString(","),
|
||||||
|
this.author,
|
||||||
)
|
)
|
||||||
|
|
||||||
fun ParecelableItem.toModel(): SelfossModel.Item =
|
fun ParecelableItem.toModel(): SelfossModel.Item =
|
||||||
SelfossModel.Item(
|
SelfossModel.Item(
|
||||||
this.id,
|
this.id,
|
||||||
@ -31,26 +32,30 @@ fun ParecelableItem.toModel() : SelfossModel.Item =
|
|||||||
this.icon,
|
this.icon,
|
||||||
this.link,
|
this.link,
|
||||||
this.sourcetitle,
|
this.sourcetitle,
|
||||||
this.tags.split(",")
|
this.tags.split(","),
|
||||||
|
this.author,
|
||||||
)
|
)
|
||||||
data class ParecelableItem(
|
|
||||||
@SerializedName("id") val id: Int,
|
|
||||||
@SerializedName("datetime") val datetime: String,
|
|
||||||
@SerializedName("title") val title: String,
|
|
||||||
@SerializedName("content") val content: String,
|
|
||||||
@SerializedName("unread") var unread: Boolean,
|
|
||||||
@SerializedName("starred") var starred: Boolean,
|
|
||||||
@SerializedName("thumbnail") val thumbnail: String?,
|
|
||||||
@SerializedName("icon") val icon: String?,
|
|
||||||
@SerializedName("link") val link: String,
|
|
||||||
@SerializedName("sourcetitle") val sourcetitle: String,
|
|
||||||
@SerializedName("tags") val tags: String
|
|
||||||
) : Parcelable {
|
|
||||||
|
|
||||||
|
data class ParecelableItem(
|
||||||
|
val id: Int,
|
||||||
|
val datetime: String,
|
||||||
|
val title: String,
|
||||||
|
val content: String,
|
||||||
|
var unread: Boolean,
|
||||||
|
var starred: Boolean,
|
||||||
|
val thumbnail: String?,
|
||||||
|
val icon: String?,
|
||||||
|
val link: String,
|
||||||
|
val sourcetitle: String,
|
||||||
|
val tags: String,
|
||||||
|
val author: String?,
|
||||||
|
) : Parcelable {
|
||||||
companion object {
|
companion object {
|
||||||
@JvmField
|
@JvmField
|
||||||
val CREATOR: Parcelable.Creator<ParecelableItem> = object : Parcelable.Creator<ParecelableItem> {
|
val CREATOR: Parcelable.Creator<ParecelableItem> =
|
||||||
|
object : Parcelable.Creator<ParecelableItem> {
|
||||||
override fun createFromParcel(source: Parcel): ParecelableItem = ParecelableItem(source)
|
override fun createFromParcel(source: Parcel): ParecelableItem = ParecelableItem(source)
|
||||||
|
|
||||||
override fun newArray(size: Int): Array<ParecelableItem?> = arrayOfNulls(size)
|
override fun newArray(size: Int): Array<ParecelableItem?> = arrayOfNulls(size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -66,12 +71,16 @@ data class ParecelableItem(
|
|||||||
icon = source.readString(),
|
icon = source.readString(),
|
||||||
link = source.readString().orEmpty(),
|
link = source.readString().orEmpty(),
|
||||||
sourcetitle = source.readString().orEmpty(),
|
sourcetitle = source.readString().orEmpty(),
|
||||||
tags = source.readString().orEmpty()
|
tags = source.readString().orEmpty(),
|
||||||
|
author = source.readString().orEmpty(),
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun describeContents() = 0
|
override fun describeContents() = 0
|
||||||
|
|
||||||
override fun writeToParcel(dest: Parcel, flags: Int) {
|
override fun writeToParcel(
|
||||||
|
dest: Parcel,
|
||||||
|
flags: Int,
|
||||||
|
) {
|
||||||
dest.writeInt(id)
|
dest.writeInt(id)
|
||||||
dest.writeString(datetime)
|
dest.writeString(datetime)
|
||||||
dest.writeString(title)
|
dest.writeString(title)
|
||||||
@ -83,5 +92,6 @@ data class ParecelableItem(
|
|||||||
dest.writeString(link)
|
dest.writeString(link)
|
||||||
dest.writeString(sourcetitle)
|
dest.writeString(sourcetitle)
|
||||||
dest.writeString(tags)
|
dest.writeString(tags)
|
||||||
|
dest.writeString(author)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -7,39 +7,33 @@ import android.text.Editable
|
|||||||
import android.text.InputFilter
|
import android.text.InputFilter
|
||||||
import android.text.InputType
|
import android.text.InputType
|
||||||
import android.text.TextWatcher
|
import android.text.TextWatcher
|
||||||
import android.view.Menu
|
|
||||||
import android.view.MenuInflater
|
|
||||||
import android.view.MenuItem
|
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
import androidx.core.widget.addTextChangedListener
|
import androidx.core.widget.addTextChangedListener
|
||||||
import androidx.preference.EditTextPreference
|
import androidx.preference.EditTextPreference
|
||||||
import androidx.preference.Preference
|
import androidx.preference.Preference
|
||||||
import androidx.preference.PreferenceFragmentCompat
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
import androidx.preference.PreferenceManager
|
|
||||||
import bou.amine.apps.readerforselfossv2.android.R
|
import bou.amine.apps.readerforselfossv2.android.R
|
||||||
import bou.amine.apps.readerforselfossv2.android.databinding.ActivitySettingsBinding
|
import bou.amine.apps.readerforselfossv2.android.databinding.ActivitySettingsBinding
|
||||||
import bou.amine.apps.readerforselfossv2.android.themes.AppColors
|
import bou.amine.apps.readerforselfossv2.android.sendSilentlyWithAcraWithName
|
||||||
import bou.amine.apps.readerforselfossv2.android.themes.Toppings
|
|
||||||
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
||||||
import com.ftinc.scoop.Scoop
|
import com.mikepenz.aboutlibraries.LibsBuilder
|
||||||
|
import org.kodein.di.DIAware
|
||||||
|
import org.kodein.di.android.closestDI
|
||||||
|
|
||||||
private const val TITLE_TAG = "settingsActivityTitle"
|
private const val TITLE_TAG = "settingsActivityTitle"
|
||||||
|
|
||||||
class SettingsActivity : AppCompatActivity(),
|
class SettingsActivity :
|
||||||
PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
|
AppCompatActivity(),
|
||||||
|
PreferenceFragmentCompat.OnPreferenceStartFragmentCallback,
|
||||||
|
DIAware {
|
||||||
|
override val di by closestDI()
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean("dark_theme", false)) {
|
|
||||||
setTheme(R.style.NoBarDark)
|
|
||||||
}
|
|
||||||
val binding = ActivitySettingsBinding.inflate(layoutInflater)
|
val binding = ActivitySettingsBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
val scoop = Scoop.getInstance()
|
|
||||||
scoop.bind(this, Toppings.PRIMARY.value, binding.toolbar)
|
|
||||||
scoop.bindStatusBar(this, Toppings.PRIMARY_DARK.value)
|
|
||||||
|
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
if (savedInstanceState == null) {
|
if (savedInstanceState == null) {
|
||||||
supportFragmentManager
|
supportFragmentManager
|
||||||
@ -80,13 +74,14 @@ class SettingsActivity : AppCompatActivity(),
|
|||||||
|
|
||||||
override fun onPreferenceStartFragment(
|
override fun onPreferenceStartFragment(
|
||||||
caller: PreferenceFragmentCompat,
|
caller: PreferenceFragmentCompat,
|
||||||
pref: Preference
|
pref: Preference,
|
||||||
): Boolean {
|
): Boolean {
|
||||||
// Instantiate the new Fragment
|
// Instantiate the new Fragment
|
||||||
val args = pref.extras
|
val args = pref.extras
|
||||||
val fragment = supportFragmentManager.fragmentFactory.instantiate(
|
val fragment =
|
||||||
|
supportFragmentManager.fragmentFactory.instantiate(
|
||||||
classLoader,
|
classLoader,
|
||||||
pref.fragment
|
pref.fragment.toString(),
|
||||||
).apply {
|
).apply {
|
||||||
arguments = args
|
arguments = args
|
||||||
setTargetFragment(caller, 0)
|
setTargetFragment(caller, 0)
|
||||||
@ -102,88 +97,134 @@ class SettingsActivity : AppCompatActivity(),
|
|||||||
}
|
}
|
||||||
|
|
||||||
class MainPreferenceFragment : PreferenceFragmentCompat() {
|
class MainPreferenceFragment : PreferenceFragmentCompat() {
|
||||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
override fun onCreatePreferences(
|
||||||
|
savedInstanceState: Bundle?,
|
||||||
|
rootKey: String?,
|
||||||
|
) {
|
||||||
setPreferencesFromResource(R.xml.pref_main, rootKey)
|
setPreferencesFromResource(R.xml.pref_main, rootKey)
|
||||||
|
|
||||||
|
preferenceManager.findPreference<Preference>("currentMode")?.onPreferenceChangeListener =
|
||||||
|
Preference.OnPreferenceChangeListener { _, newValue ->
|
||||||
|
AppCompatDelegate.setDefaultNightMode(newValue.toString().toInt()) // ListPreference Only takes string-arrays ¯\_(ツ)_/¯
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
preferenceManager.findPreference<Preference>("action_about")?.onPreferenceClickListener =
|
||||||
|
Preference.OnPreferenceClickListener { _ ->
|
||||||
|
context?.let {
|
||||||
|
LibsBuilder()
|
||||||
|
.withAboutIconShown(true)
|
||||||
|
.withAboutVersionShown(true)
|
||||||
|
.start(it)
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class GeneralPreferenceFragment : PreferenceFragmentCompat() {
|
class GeneralPreferenceFragment : PreferenceFragmentCompat() {
|
||||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
override fun onCreatePreferences(
|
||||||
|
savedInstanceState: Bundle?,
|
||||||
|
rootKey: String?,
|
||||||
|
) {
|
||||||
setPreferencesFromResource(R.xml.pref_general, rootKey)
|
setPreferencesFromResource(R.xml.pref_general, rootKey)
|
||||||
|
|
||||||
val editTextPreference = preferenceManager.findPreference<EditTextPreference>("prefer_api_items_number")
|
val editTextPreference = preferenceManager.findPreference<EditTextPreference>("prefer_api_items_number")
|
||||||
editTextPreference?.setOnBindEditTextListener { editText ->
|
editTextPreference?.setOnBindEditTextListener { editText ->
|
||||||
editText.inputType = InputType.TYPE_CLASS_NUMBER
|
editText.inputType = InputType.TYPE_CLASS_NUMBER
|
||||||
editText.filters = arrayOf(
|
editText.filters =
|
||||||
|
arrayOf(
|
||||||
InputFilter { source, _, _, dest, _, _ ->
|
InputFilter { source, _, _, dest, _, _ ->
|
||||||
try {
|
try {
|
||||||
val input: Int = (dest.toString() + source.toString()).toInt()
|
val input: Int = (dest.toString() + source.toString()).toInt()
|
||||||
if (input in 1..200) return@InputFilter null
|
if (input in 1..200) return@InputFilter null
|
||||||
} catch (nfe: NumberFormatException) {
|
} catch (nfe: NumberFormatException) {
|
||||||
|
nfe.sendSilentlyWithAcraWithName("GeneralPreferenceFragment")
|
||||||
Toast.makeText(activity, R.string.items_number_should_be_number, Toast.LENGTH_LONG).show()
|
Toast.makeText(activity, R.string.items_number_should_be_number, Toast.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
""
|
""
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ArticleViewerPreferenceFragment : PreferenceFragmentCompat() {
|
class ArticleViewerPreferenceFragment : PreferenceFragmentCompat() {
|
||||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
override fun onCreatePreferences(
|
||||||
|
savedInstanceState: Bundle?,
|
||||||
|
rootKey: String?,
|
||||||
|
) {
|
||||||
setPreferencesFromResource(R.xml.pref_viewer, rootKey)
|
setPreferencesFromResource(R.xml.pref_viewer, rootKey)
|
||||||
|
|
||||||
val fontSize = preferenceManager.findPreference<EditTextPreference>("reader_font_size")
|
val fontSize = preferenceManager.findPreference<EditTextPreference>("reader_font_size")
|
||||||
fontSize?.setOnBindEditTextListener { editText ->
|
fontSize?.setOnBindEditTextListener { editText ->
|
||||||
editText.inputType = InputType.TYPE_CLASS_NUMBER
|
editText.inputType = InputType.TYPE_CLASS_NUMBER
|
||||||
editText.addTextChangedListener { object : TextWatcher {
|
editText.addTextChangedListener {
|
||||||
override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
|
object : TextWatcher {
|
||||||
override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
|
override fun beforeTextChanged(
|
||||||
|
charSequence: CharSequence,
|
||||||
|
i: Int,
|
||||||
|
i1: Int,
|
||||||
|
i2: Int,
|
||||||
|
) {
|
||||||
|
// We do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onTextChanged(
|
||||||
|
charSequence: CharSequence,
|
||||||
|
i: Int,
|
||||||
|
i1: Int,
|
||||||
|
i2: Int,
|
||||||
|
) {
|
||||||
|
// We do nothing
|
||||||
|
}
|
||||||
|
|
||||||
override fun afterTextChanged(editable: Editable) {
|
override fun afterTextChanged(editable: Editable) {
|
||||||
try {
|
try {
|
||||||
editText.textSize = editable.toString().toInt().toFloat()
|
editText.textSize = editable.toString().toInt().toFloat()
|
||||||
} catch (e: NumberFormatException) {
|
} catch (e: NumberFormatException) {
|
||||||
|
e.sendSilentlyWithAcraWithName("ArticleViewerPreferenceFragment > afterTextChanged")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} }
|
}
|
||||||
editText.filters = arrayOf(
|
}
|
||||||
|
editText.filters =
|
||||||
|
arrayOf(
|
||||||
InputFilter { source, _, _, dest, _, _ ->
|
InputFilter { source, _, _, dest, _, _ ->
|
||||||
try {
|
try {
|
||||||
val input = (dest.toString() + source.toString()).toInt()
|
val input = (dest.toString() + source.toString()).toInt()
|
||||||
if (input > 0) return@InputFilter null
|
if (input > 0) return@InputFilter null
|
||||||
} catch (nfe: NumberFormatException) {
|
} catch (nfe: NumberFormatException) {
|
||||||
|
nfe.sendSilentlyWithAcraWithName("ArticleViewerPreferenceFragment > filters")
|
||||||
}
|
}
|
||||||
""
|
""
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class OfflinePreferenceFragment : PreferenceFragmentCompat() {
|
class OfflinePreferenceFragment : PreferenceFragmentCompat() {
|
||||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
override fun onCreatePreferences(
|
||||||
|
savedInstanceState: Bundle?,
|
||||||
|
rootKey: String?,
|
||||||
|
) {
|
||||||
setPreferencesFromResource(R.xml.pref_offline, rootKey)
|
setPreferencesFromResource(R.xml.pref_offline, rootKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ThemePreferenceFragment : PreferenceFragmentCompat() {
|
class ThemePreferenceFragment : PreferenceFragmentCompat() {
|
||||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
override fun onCreatePreferences(
|
||||||
|
savedInstanceState: Bundle?,
|
||||||
|
rootKey: String?,
|
||||||
|
) {
|
||||||
setPreferencesFromResource(R.xml.pref_theme, rootKey)
|
setPreferencesFromResource(R.xml.pref_theme, rootKey)
|
||||||
setHasOptionsMenu(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
preferenceManager.findPreference<Preference>("currentMode")?.onPreferenceChangeListener =
|
||||||
super.onCreateOptionsMenu(menu, inflater)
|
Preference.OnPreferenceChangeListener { _, newValue ->
|
||||||
inflater.inflate(R.menu.settings_theme, menu)
|
AppCompatDelegate.setDefaultNightMode(newValue.toString().toInt()) // ListPreference Only takes string-arrays ¯\_(ツ)_/¯
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
|
||||||
val id = item.itemId
|
|
||||||
if (id == R.id.clear) {
|
|
||||||
AppColors.resetColors()
|
|
||||||
requireActivity().recreate()
|
|
||||||
}
|
|
||||||
return super.onOptionsItemSelected(item)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,20 +234,26 @@ class SettingsActivity : AppCompatActivity(),
|
|||||||
startActivity(browserIntent)
|
startActivity(browserIntent)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
override fun onCreatePreferences(
|
||||||
|
savedInstanceState: Bundle?,
|
||||||
|
rootKey: String?,
|
||||||
|
) {
|
||||||
setPreferencesFromResource(R.xml.pref_links, rootKey)
|
setPreferencesFromResource(R.xml.pref_links, rootKey)
|
||||||
|
|
||||||
preferenceManager.findPreference<Preference>("trackerLink")?.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
preferenceManager.findPreference<Preference>("trackerLink")?.onPreferenceClickListener =
|
||||||
|
Preference.OnPreferenceClickListener {
|
||||||
openUrl(Uri.parse(AppSettingsService.trackerUrl))
|
openUrl(Uri.parse(AppSettingsService.trackerUrl))
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
preferenceManager.findPreference<Preference>("sourceLink")?.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
preferenceManager.findPreference<Preference>("sourceLink")?.onPreferenceClickListener =
|
||||||
|
Preference.OnPreferenceClickListener {
|
||||||
openUrl(Uri.parse(AppSettingsService.sourceUrl))
|
openUrl(Uri.parse(AppSettingsService.sourceUrl))
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
preferenceManager.findPreference<Preference>("translation")?.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
preferenceManager.findPreference<Preference>("translation")?.onPreferenceClickListener =
|
||||||
|
Preference.OnPreferenceClickListener {
|
||||||
openUrl(Uri.parse(AppSettingsService.translationUrl))
|
openUrl(Uri.parse(AppSettingsService.translationUrl))
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
@ -214,7 +261,10 @@ class SettingsActivity : AppCompatActivity(),
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ExperimentalPreferenceFragment : PreferenceFragmentCompat() {
|
class ExperimentalPreferenceFragment : PreferenceFragmentCompat() {
|
||||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
override fun onCreatePreferences(
|
||||||
|
savedInstanceState: Bundle?,
|
||||||
|
rootKey: String?,
|
||||||
|
) {
|
||||||
setPreferencesFromResource(R.xml.pref_experimental, rootKey)
|
setPreferencesFromResource(R.xml.pref_experimental, rootKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,72 +0,0 @@
|
|||||||
package bou.amine.apps.readerforselfossv2.android.themes
|
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import androidx.annotation.ColorInt
|
|
||||||
import bou.amine.apps.readerforselfossv2.android.R
|
|
||||||
import com.russhwolf.settings.Settings
|
|
||||||
|
|
||||||
class AppColors(a: Activity) {
|
|
||||||
|
|
||||||
@ColorInt val colorPrimary: Int
|
|
||||||
@ColorInt val colorPrimaryDark: Int
|
|
||||||
@ColorInt val colorAccent: Int
|
|
||||||
@ColorInt val colorAccentDark: Int
|
|
||||||
@ColorInt val colorBackground: Int
|
|
||||||
@ColorInt val textColor: Int
|
|
||||||
val isDarkTheme: Boolean
|
|
||||||
|
|
||||||
init {
|
|
||||||
val settings = Settings()
|
|
||||||
|
|
||||||
colorPrimary =
|
|
||||||
settings.getInt(
|
|
||||||
"color_primary",
|
|
||||||
a.resources.getColor(R.color.colorPrimary)
|
|
||||||
)
|
|
||||||
colorPrimaryDark =
|
|
||||||
settings.getInt(
|
|
||||||
"color_primary_dark",
|
|
||||||
a.resources.getColor(R.color.colorPrimaryDark)
|
|
||||||
)
|
|
||||||
colorAccent =
|
|
||||||
settings.getInt(
|
|
||||||
"color_accent",
|
|
||||||
a.resources.getColor(R.color.colorAccent)
|
|
||||||
)
|
|
||||||
colorAccentDark =
|
|
||||||
settings.getInt(
|
|
||||||
"color_accent_dark",
|
|
||||||
a.resources.getColor(R.color.colorAccentDark)
|
|
||||||
)
|
|
||||||
isDarkTheme =
|
|
||||||
settings.getBoolean(
|
|
||||||
"dark_theme",
|
|
||||||
false
|
|
||||||
)
|
|
||||||
|
|
||||||
colorBackground = if (isDarkTheme) {
|
|
||||||
a.setTheme(R.style.NoBarDark)
|
|
||||||
a.resources.getColor(R.color.darkBackground)
|
|
||||||
} else {
|
|
||||||
a.setTheme(R.style.NoBar)
|
|
||||||
a.resources.getColor(R.color.grey_50)
|
|
||||||
}
|
|
||||||
|
|
||||||
textColor = if (isDarkTheme) {
|
|
||||||
a.resources.getColor(R.color.white)
|
|
||||||
} else {
|
|
||||||
a.resources.getColor(R.color.grey_900)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun resetColors() {
|
|
||||||
val settings = Settings()
|
|
||||||
settings.remove("color_primary")
|
|
||||||
settings.remove("color_primary_dark")
|
|
||||||
settings.remove("color_accent")
|
|
||||||
settings.remove("color_accent_dark")
|
|
||||||
settings.remove("dark_theme")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
package bou.amine.apps.readerforselfossv2.android.themes
|
|
||||||
|
|
||||||
enum class Toppings(val value: Int) {
|
|
||||||
PRIMARY(1),
|
|
||||||
PRIMARY_DARK(2),
|
|
||||||
ACCENT(3),
|
|
||||||
ACCENT_DARK(4)
|
|
||||||
}
|
|
@ -5,7 +5,10 @@ import android.content.Intent
|
|||||||
import bou.amine.apps.readerforselfossv2.android.R
|
import bou.amine.apps.readerforselfossv2.android.R
|
||||||
import bou.amine.apps.readerforselfossv2.utils.toStringUriWithHttp
|
import bou.amine.apps.readerforselfossv2.utils.toStringUriWithHttp
|
||||||
|
|
||||||
fun Context.shareLink(itemUrl: String, itemTitle: String) {
|
fun Context.shareLink(
|
||||||
|
itemUrl: String,
|
||||||
|
itemTitle: String,
|
||||||
|
) {
|
||||||
val sendIntent = Intent()
|
val sendIntent = Intent()
|
||||||
sendIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
sendIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
sendIntent.action = Intent.ACTION_SEND
|
sendIntent.action = Intent.ACTION_SEND
|
||||||
@ -15,7 +18,7 @@ fun Context.shareLink(itemUrl: String, itemTitle: String) {
|
|||||||
startActivity(
|
startActivity(
|
||||||
Intent.createChooser(
|
Intent.createChooser(
|
||||||
sendIntent,
|
sendIntent,
|
||||||
getString(R.string.share)
|
getString(R.string.share),
|
||||||
).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
|
||||||
)
|
)
|
||||||
}
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
package bou.amine.apps.readerforselfossv2.android.utils
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.drawable.GradientDrawable
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.RelativeLayout
|
||||||
|
import android.widget.TextView
|
||||||
|
import bou.amine.apps.readerforselfossv2.android.R
|
||||||
|
import bou.amine.apps.readerforselfossv2.android.model.toTextDrawableString
|
||||||
|
import com.google.android.material.imageview.ShapeableImageView
|
||||||
|
import kotlin.math.abs
|
||||||
|
|
||||||
|
class CircleImageView
|
||||||
|
@JvmOverloads
|
||||||
|
constructor(
|
||||||
|
context: Context,
|
||||||
|
attrs: AttributeSet? = null,
|
||||||
|
defStyleAttr: Int = 0,
|
||||||
|
) : RelativeLayout(context, attrs, defStyleAttr) {
|
||||||
|
val view: View
|
||||||
|
val imageView: ShapeableImageView
|
||||||
|
val textView: TextView
|
||||||
|
|
||||||
|
private val colorScheme =
|
||||||
|
listOf(
|
||||||
|
-0x1a8c8d,
|
||||||
|
-0xf9d6e,
|
||||||
|
-0x459738,
|
||||||
|
-0x6a8a33,
|
||||||
|
-0x867935,
|
||||||
|
-0x9b4a0a,
|
||||||
|
-0xb03c09,
|
||||||
|
-0xb22f1f,
|
||||||
|
-0xb24954,
|
||||||
|
-0x7e387c,
|
||||||
|
-0x512a7f,
|
||||||
|
-0x759b,
|
||||||
|
-0x2b1ea9,
|
||||||
|
-0x2ab1,
|
||||||
|
-0x48b3,
|
||||||
|
-0x5e7781,
|
||||||
|
-0x6f5b52,
|
||||||
|
)
|
||||||
|
|
||||||
|
init {
|
||||||
|
view = LayoutInflater.from(context).inflate(R.layout.circle_image_view, this, true)
|
||||||
|
imageView = view.findViewById(R.id.circleImage)
|
||||||
|
textView = view.findViewById(R.id.circleText)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setBackgroundAndText(text: String) {
|
||||||
|
val circleDrawable = GradientDrawable()
|
||||||
|
val color = colorFromIdentifier(text)
|
||||||
|
circleDrawable.setColor(color)
|
||||||
|
imageView.setImageDrawable(circleDrawable)
|
||||||
|
|
||||||
|
textView.text = text.toTextDrawableString()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun colorFromIdentifier(key: String): Int {
|
||||||
|
return colorScheme[abs(key.hashCode()) % colorScheme.size]
|
||||||
|
}
|
||||||
|
}
|
@ -1,13 +1,9 @@
|
|||||||
package bou.amine.apps.readerforselfossv2.android.utils
|
package bou.amine.apps.readerforselfossv2.android.utils
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.app.PendingIntent
|
|
||||||
import android.content.ActivityNotFoundException
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.BitmapFactory
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
|
||||||
import android.text.Spannable
|
import android.text.Spannable
|
||||||
import android.text.style.ClickableSpan
|
import android.text.style.ClickableSpan
|
||||||
import android.util.Patterns
|
import android.util.Patterns
|
||||||
@ -15,155 +11,41 @@ import android.view.MotionEvent
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.browser.customtabs.CustomTabsIntent
|
|
||||||
import bou.amine.apps.readerforselfossv2.android.R
|
import bou.amine.apps.readerforselfossv2.android.R
|
||||||
import bou.amine.apps.readerforselfossv2.android.ReaderActivity
|
import bou.amine.apps.readerforselfossv2.android.ReaderActivity
|
||||||
import bou.amine.apps.readerforselfossv2.android.utils.customtabs.CustomTabActivityHelper
|
|
||||||
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
||||||
import bou.amine.apps.readerforselfossv2.utils.toStringUriWithHttp
|
import bou.amine.apps.readerforselfossv2.utils.toStringUriWithHttp
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||||
|
|
||||||
fun Context.buildCustomTabsIntent(): CustomTabsIntent {
|
|
||||||
|
|
||||||
val actionIntent = Intent(Intent.ACTION_SEND)
|
|
||||||
actionIntent.type = "text/plain"
|
|
||||||
val pflags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
||||||
PendingIntent.FLAG_IMMUTABLE
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
val createPendingShareIntent: PendingIntent = PendingIntent.getActivity(
|
|
||||||
this,
|
|
||||||
0,
|
|
||||||
actionIntent,
|
|
||||||
pflags
|
|
||||||
)
|
|
||||||
|
|
||||||
val intentBuilder = CustomTabsIntent.Builder()
|
|
||||||
|
|
||||||
// TODO: change to primary when it's possible to customize custom tabs title color
|
|
||||||
//intentBuilder.setToolbarColor(c.getResources().getColor(R.color.colorPrimary));
|
|
||||||
intentBuilder.setToolbarColor(resources.getColor(R.color.colorAccentDark))
|
|
||||||
intentBuilder.setShowTitle(true)
|
|
||||||
|
|
||||||
|
|
||||||
intentBuilder.setStartAnimations(
|
|
||||||
this,
|
|
||||||
R.anim.slide_in_right,
|
|
||||||
R.anim.slide_out_left
|
|
||||||
)
|
|
||||||
intentBuilder.setExitAnimations(
|
|
||||||
this,
|
|
||||||
android.R.anim.slide_in_left,
|
|
||||||
android.R.anim.slide_out_right
|
|
||||||
)
|
|
||||||
|
|
||||||
val closeicon = BitmapFactory.decodeResource(resources, R.drawable.ic_close_white_24dp)
|
|
||||||
intentBuilder.setCloseButtonIcon(closeicon)
|
|
||||||
|
|
||||||
val shareLabel = this.getString(R.string.label_share)
|
|
||||||
val icon = BitmapFactory.decodeResource(
|
|
||||||
resources,
|
|
||||||
R.drawable.ic_share_white_24dp
|
|
||||||
)
|
|
||||||
intentBuilder.setActionButton(icon, shareLabel, createPendingShareIntent)
|
|
||||||
|
|
||||||
return intentBuilder.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Context.openItemUrlInternally(
|
|
||||||
allItems: ArrayList<SelfossModel.Item>,
|
|
||||||
currentItem: Int,
|
|
||||||
linkDecoded: String,
|
|
||||||
customTabsIntent: CustomTabsIntent,
|
|
||||||
articleViewer: Boolean,
|
|
||||||
app: Activity
|
|
||||||
) {
|
|
||||||
if (articleViewer) {
|
|
||||||
ReaderActivity.allItems = allItems
|
|
||||||
val intent = Intent(this, ReaderActivity::class.java)
|
|
||||||
intent.putExtra("currentItem", currentItem)
|
|
||||||
app.startActivity(intent)
|
|
||||||
} else {
|
|
||||||
this.openItemUrlInternalBrowser(
|
|
||||||
linkDecoded,
|
|
||||||
customTabsIntent,
|
|
||||||
app)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Context.openItemUrlInternalBrowser(
|
|
||||||
linkDecoded: String,
|
|
||||||
customTabsIntent: CustomTabsIntent,
|
|
||||||
app: Activity
|
|
||||||
) {
|
|
||||||
try {
|
|
||||||
CustomTabActivityHelper.openCustomTab(
|
|
||||||
app,
|
|
||||||
customTabsIntent,
|
|
||||||
Uri.parse(linkDecoded)
|
|
||||||
) { _, uri ->
|
|
||||||
val intent = Intent(Intent.ACTION_VIEW, uri)
|
|
||||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
|
||||||
startActivity(intent)
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
openInBrowser(linkDecoded, app)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Context.openItemUrl(
|
fun Context.openItemUrl(
|
||||||
allItems: ArrayList<SelfossModel.Item>,
|
|
||||||
currentItem: Int,
|
currentItem: Int,
|
||||||
linkDecoded: String,
|
linkDecoded: String,
|
||||||
customTabsIntent: CustomTabsIntent,
|
|
||||||
internalBrowser: Boolean,
|
|
||||||
articleViewer: Boolean,
|
articleViewer: Boolean,
|
||||||
app: Activity
|
app: Activity,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
if (!linkDecoded.isUrlValid()) {
|
if (!linkDecoded.isUrlValid()) {
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
this,
|
this,
|
||||||
this.getString(R.string.cant_open_invalid_url),
|
this.getString(R.string.cant_open_invalid_url),
|
||||||
Toast.LENGTH_LONG
|
Toast.LENGTH_LONG,
|
||||||
).show()
|
).show()
|
||||||
} else {
|
} else {
|
||||||
if (!internalBrowser) {
|
if (articleViewer) {
|
||||||
openInBrowser(linkDecoded, app)
|
val intent = Intent(this, ReaderActivity::class.java)
|
||||||
} else if (articleViewer) {
|
intent.putExtra("currentItem", currentItem)
|
||||||
this.openItemUrlInternally(
|
|
||||||
allItems,
|
|
||||||
currentItem,
|
|
||||||
linkDecoded,
|
|
||||||
customTabsIntent,
|
|
||||||
articleViewer,
|
|
||||||
app
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
this.openItemUrlInternalBrowser(
|
|
||||||
linkDecoded,
|
|
||||||
customTabsIntent,
|
|
||||||
app
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun openInBrowser(linkDecoded: String, app: Activity) {
|
|
||||||
val intent = Intent(Intent.ACTION_VIEW)
|
|
||||||
intent.data = Uri.parse(linkDecoded)
|
|
||||||
try {
|
|
||||||
app.startActivity(intent)
|
app.startActivity(intent)
|
||||||
} catch (e: ActivityNotFoundException) {
|
} else {
|
||||||
Toast.makeText(app.baseContext, e.message, Toast.LENGTH_LONG).show()
|
val intent = Intent(Intent.ACTION_VIEW)
|
||||||
|
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
|
intent.data = Uri.parse(linkDecoded.toStringUriWithHttp())
|
||||||
|
startActivity(intent)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun String.isUrlValid(): Boolean =
|
fun String.isUrlValid(): Boolean = this.toHttpUrlOrNull() != null && Patterns.WEB_URL.matcher(this).matches()
|
||||||
this.toHttpUrlOrNull() != null && Patterns.WEB_URL.matcher(this).matches()
|
|
||||||
|
|
||||||
fun String.isBaseUrlInvalid(ctx: Context): Boolean {
|
fun String.isBaseUrlInvalid(): Boolean {
|
||||||
val baseUrl = this.toHttpUrlOrNull()
|
val baseUrl = this.toHttpUrlOrNull()
|
||||||
var existsAndEndsWithSlash = false
|
var existsAndEndsWithSlash = false
|
||||||
if (baseUrl != null) {
|
if (baseUrl != null) {
|
||||||
@ -182,7 +64,10 @@ fun Context.openInBrowserAsNewTask(i: SelfossModel.Item) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class LinkOnTouchListener : View.OnTouchListener {
|
class LinkOnTouchListener : View.OnTouchListener {
|
||||||
override fun onTouch(v: View?, event: MotionEvent?): Boolean {
|
override fun onTouch(
|
||||||
|
v: View?,
|
||||||
|
event: MotionEvent?,
|
||||||
|
): Boolean {
|
||||||
var ret = false
|
var ret = false
|
||||||
val widget: TextView = v as TextView
|
val widget: TextView = v as TextView
|
||||||
val text: CharSequence = widget.text
|
val text: CharSequence = widget.text
|
||||||
@ -191,7 +76,8 @@ class LinkOnTouchListener: View.OnTouchListener {
|
|||||||
val action = event!!.action
|
val action = event!!.action
|
||||||
|
|
||||||
if (action == MotionEvent.ACTION_UP ||
|
if (action == MotionEvent.ACTION_UP ||
|
||||||
action == MotionEvent.ACTION_DOWN) {
|
action == MotionEvent.ACTION_DOWN
|
||||||
|
) {
|
||||||
var x: Float = event.x
|
var x: Float = event.x
|
||||||
var y: Float = event.y
|
var y: Float = event.y
|
||||||
|
|
||||||
|
@ -8,5 +8,4 @@ fun TextBadgeItem.removeBadge(): TextBadgeItem {
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
fun TextBadgeItem.maybeShow(): TextBadgeItem =
|
fun TextBadgeItem.maybeShow(): TextBadgeItem = if (this.isHidden) this.show() else this
|
||||||
if (this.isHidden) this.show() else this
|
|
||||||
|
@ -1,153 +0,0 @@
|
|||||||
package bou.amine.apps.readerforselfossv2.android.utils.customtabs;
|
|
||||||
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import androidx.browser.customtabs.CustomTabsClient;
|
|
||||||
import androidx.browser.customtabs.CustomTabsIntent;
|
|
||||||
import androidx.browser.customtabs.CustomTabsServiceConnection;
|
|
||||||
import androidx.browser.customtabs.CustomTabsSession;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is a helper class to manage the connection to the Custom Tabs Service.
|
|
||||||
*/
|
|
||||||
public class CustomTabActivityHelper implements ServiceConnectionCallback {
|
|
||||||
private CustomTabsSession mCustomTabsSession;
|
|
||||||
private CustomTabsClient mClient;
|
|
||||||
private CustomTabsServiceConnection mConnection;
|
|
||||||
private ConnectionCallback mConnectionCallback;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Opens the URL on a Custom Tab if possible. Otherwise fallsback to opening it on a WebView.
|
|
||||||
*
|
|
||||||
* @param activity The host activity.
|
|
||||||
* @param customTabsIntent a CustomTabsIntent to be used if Custom Tabs is available.
|
|
||||||
* @param uri the Uri to be opened.
|
|
||||||
* @param fallback a CustomTabFallback to be used if Custom Tabs is not available.
|
|
||||||
*/
|
|
||||||
public static void openCustomTab(Activity activity,
|
|
||||||
CustomTabsIntent customTabsIntent,
|
|
||||||
Uri uri,
|
|
||||||
CustomTabFallback fallback) {
|
|
||||||
String packageName = CustomTabsHelper.getPackageNameToUse(activity);
|
|
||||||
|
|
||||||
//If we cant find a package name, it means theres no browser that supports
|
|
||||||
//Chrome Custom Tabs installed. So, we fallback to the webview
|
|
||||||
if (packageName == null) {
|
|
||||||
if (fallback != null) {
|
|
||||||
fallback.openUri(activity, uri);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
customTabsIntent.intent.setPackage(packageName);
|
|
||||||
customTabsIntent.launchUrl(activity, uri);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unbinds the Activity from the Custom Tabs Service.
|
|
||||||
*
|
|
||||||
* @param activity the activity that is connected to the service.
|
|
||||||
*/
|
|
||||||
public void unbindCustomTabsService(Activity activity) {
|
|
||||||
if (mConnection == null) return;
|
|
||||||
activity.unbindService(mConnection);
|
|
||||||
mClient = null;
|
|
||||||
mCustomTabsSession = null;
|
|
||||||
mConnection = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates or retrieves an exiting CustomTabsSession.
|
|
||||||
*
|
|
||||||
* @return a CustomTabsSession.
|
|
||||||
*/
|
|
||||||
public CustomTabsSession getSession() {
|
|
||||||
if (mClient == null) {
|
|
||||||
mCustomTabsSession = null;
|
|
||||||
} else if (mCustomTabsSession == null) {
|
|
||||||
mCustomTabsSession = mClient.newSession(null);
|
|
||||||
}
|
|
||||||
return mCustomTabsSession;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a Callback to be called when connected or disconnected from the Custom Tabs Service.
|
|
||||||
*
|
|
||||||
* @param connectionCallback
|
|
||||||
*/
|
|
||||||
public void setConnectionCallback(ConnectionCallback connectionCallback) {
|
|
||||||
this.mConnectionCallback = connectionCallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Binds the Activity to the Custom Tabs Service.
|
|
||||||
*
|
|
||||||
* @param activity the activity to be binded to the service.
|
|
||||||
*/
|
|
||||||
public void bindCustomTabsService(Activity activity) {
|
|
||||||
if (mClient != null) return;
|
|
||||||
|
|
||||||
String packageName = CustomTabsHelper.getPackageNameToUse(activity);
|
|
||||||
if (packageName == null) return;
|
|
||||||
|
|
||||||
mConnection = new ServiceConnection(this);
|
|
||||||
CustomTabsClient.bindCustomTabsService(activity, packageName, mConnection);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true if call to mayLaunchUrl was accepted.
|
|
||||||
* @see {@link CustomTabsSession#mayLaunchUrl(Uri, Bundle, List)}.
|
|
||||||
*/
|
|
||||||
public boolean mayLaunchUrl(Uri uri, Bundle extras, List<Bundle> otherLikelyBundles) {
|
|
||||||
if (mClient == null) return false;
|
|
||||||
|
|
||||||
CustomTabsSession session = getSession();
|
|
||||||
return session != null && session.mayLaunchUrl(uri, extras, otherLikelyBundles);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onServiceConnected(CustomTabsClient client) {
|
|
||||||
mClient = client;
|
|
||||||
mClient.warmup(0L);
|
|
||||||
if (mConnectionCallback != null) mConnectionCallback.onCustomTabsConnected();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onServiceDisconnected() {
|
|
||||||
mClient = null;
|
|
||||||
mCustomTabsSession = null;
|
|
||||||
if (mConnectionCallback != null) mConnectionCallback.onCustomTabsDisconnected();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A Callback for when the service is connected or disconnected. Use those callbacks to
|
|
||||||
* handle UI changes when the service is connected or disconnected.
|
|
||||||
*/
|
|
||||||
public interface ConnectionCallback {
|
|
||||||
/**
|
|
||||||
* Called when the service is connected.
|
|
||||||
*/
|
|
||||||
void onCustomTabsConnected();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the service is disconnected.
|
|
||||||
*/
|
|
||||||
void onCustomTabsDisconnected();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* To be used as a fallback to open the Uri when Custom Tabs is not available.
|
|
||||||
*/
|
|
||||||
public interface CustomTabFallback {
|
|
||||||
/**
|
|
||||||
* @param activity The Activity that wants to open the Uri.
|
|
||||||
* @param uri The uri to be opened by the fallback.
|
|
||||||
*/
|
|
||||||
void openUri(Activity activity, Uri uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,129 +0,0 @@
|
|||||||
package bou.amine.apps.readerforselfossv2.android.utils.customtabs;
|
|
||||||
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.content.pm.ResolveInfo;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.util.Log;
|
|
||||||
import androidx.browser.customtabs.CustomTabsService;
|
|
||||||
import bou.amine.apps.readerforselfossv2.android.utils.customtabs.helpers.KeepAliveService;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@SuppressWarnings("ALL")
|
|
||||||
class CustomTabsHelper {
|
|
||||||
private static final String TAG = "CustomTabsHelper";
|
|
||||||
private static final String STABLE_PACKAGE = "com.android.chrome";
|
|
||||||
private static final String BETA_PACKAGE = "com.chrome.beta";
|
|
||||||
private static final String DEV_PACKAGE = "com.chrome.dev";
|
|
||||||
private static final String LOCAL_PACKAGE = "com.google.android.apps.chrome";
|
|
||||||
private static final String EXTRA_CUSTOM_TABS_KEEP_ALIVE =
|
|
||||||
"android.support.customtabs.extra.KEEP_ALIVE";
|
|
||||||
|
|
||||||
private static String sPackageNameToUse;
|
|
||||||
|
|
||||||
private CustomTabsHelper() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addKeepAliveExtra(Context context, Intent intent) {
|
|
||||||
Intent keepAliveIntent = new Intent().setClassName(
|
|
||||||
context.getPackageName(), KeepAliveService.class.getCanonicalName());
|
|
||||||
intent.putExtra(EXTRA_CUSTOM_TABS_KEEP_ALIVE, keepAliveIntent);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Goes through all apps that handle VIEW intents and have a warmup service. Picks
|
|
||||||
* the one chosen by the user if there is one, otherwise makes a best effort to return a
|
|
||||||
* valid package name.
|
|
||||||
* <p>
|
|
||||||
* This is <strong>not</strong> threadsafe.
|
|
||||||
*
|
|
||||||
* @param context {@link Context} to use for accessing {@link PackageManager}.
|
|
||||||
* @return The package name recommended to use for connecting to custom tabs related components.
|
|
||||||
*/
|
|
||||||
public static String getPackageNameToUse(Context context) {
|
|
||||||
if (sPackageNameToUse != null) return sPackageNameToUse;
|
|
||||||
|
|
||||||
PackageManager pm = context.getPackageManager();
|
|
||||||
// Get default VIEW intent handler.
|
|
||||||
Intent activityIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.example.com"));
|
|
||||||
ResolveInfo defaultViewHandlerInfo = pm.resolveActivity(activityIntent, 0);
|
|
||||||
String defaultViewHandlerPackageName = null;
|
|
||||||
if (defaultViewHandlerInfo != null) {
|
|
||||||
defaultViewHandlerPackageName = defaultViewHandlerInfo.activityInfo.packageName;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get all apps that can handle VIEW intents.
|
|
||||||
List<ResolveInfo> resolvedActivityList = pm.queryIntentActivities(activityIntent, 0);
|
|
||||||
List<String> packagesSupportingCustomTabs = new ArrayList<>();
|
|
||||||
for (ResolveInfo info : resolvedActivityList) {
|
|
||||||
Intent serviceIntent = new Intent();
|
|
||||||
serviceIntent.setAction(CustomTabsService.ACTION_CUSTOM_TABS_CONNECTION);
|
|
||||||
serviceIntent.setPackage(info.activityInfo.packageName);
|
|
||||||
if (pm.resolveService(serviceIntent, 0) != null) {
|
|
||||||
packagesSupportingCustomTabs.add(info.activityInfo.packageName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now packagesSupportingCustomTabs contains all apps that can handle both VIEW intents
|
|
||||||
// and service calls.
|
|
||||||
if (packagesSupportingCustomTabs.isEmpty()) {
|
|
||||||
sPackageNameToUse = null;
|
|
||||||
} else if (packagesSupportingCustomTabs.size() == 1) {
|
|
||||||
sPackageNameToUse = packagesSupportingCustomTabs.get(0);
|
|
||||||
} else if (!TextUtils.isEmpty(defaultViewHandlerPackageName)
|
|
||||||
&& !hasSpecializedHandlerIntents(context, activityIntent)
|
|
||||||
&& packagesSupportingCustomTabs.contains(defaultViewHandlerPackageName)) {
|
|
||||||
sPackageNameToUse = defaultViewHandlerPackageName;
|
|
||||||
} else if (packagesSupportingCustomTabs.contains(STABLE_PACKAGE)) {
|
|
||||||
sPackageNameToUse = STABLE_PACKAGE;
|
|
||||||
} else if (packagesSupportingCustomTabs.contains(BETA_PACKAGE)) {
|
|
||||||
sPackageNameToUse = BETA_PACKAGE;
|
|
||||||
} else if (packagesSupportingCustomTabs.contains(DEV_PACKAGE)) {
|
|
||||||
sPackageNameToUse = DEV_PACKAGE;
|
|
||||||
} else if (packagesSupportingCustomTabs.contains(LOCAL_PACKAGE)) {
|
|
||||||
sPackageNameToUse = LOCAL_PACKAGE;
|
|
||||||
}
|
|
||||||
return sPackageNameToUse;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to check whether there is a specialized handler for a given intent.
|
|
||||||
*
|
|
||||||
* @param intent The intent to check with.
|
|
||||||
* @return Whether there is a specialized handler for the given intent.
|
|
||||||
*/
|
|
||||||
private static boolean hasSpecializedHandlerIntents(Context context, Intent intent) {
|
|
||||||
try {
|
|
||||||
PackageManager pm = context.getPackageManager();
|
|
||||||
List<ResolveInfo> handlers = pm.queryIntentActivities(
|
|
||||||
intent,
|
|
||||||
PackageManager.GET_RESOLVED_FILTER);
|
|
||||||
if (handlers == null || handlers.isEmpty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for (ResolveInfo resolveInfo : handlers) {
|
|
||||||
IntentFilter filter = resolveInfo.filter;
|
|
||||||
if (filter == null) continue;
|
|
||||||
if (filter.countDataAuthorities() == 0 || filter.countDataPaths() == 0) continue;
|
|
||||||
if (resolveInfo.activityInfo == null) continue;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} catch (RuntimeException e) {
|
|
||||||
Log.e(TAG, "Runtime exception while getting specialized handlers");
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return All possible chrome package names that provide custom tabs feature.
|
|
||||||
*/
|
|
||||||
public static String[] getPackages() {
|
|
||||||
return new String[]{"", STABLE_PACKAGE, BETA_PACKAGE, DEV_PACKAGE, LOCAL_PACKAGE};
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
package bou.amine.apps.readerforselfossv2.android.utils.customtabs;
|
|
||||||
|
|
||||||
|
|
||||||
import android.content.ComponentName;
|
|
||||||
import androidx.browser.customtabs.CustomTabsClient;
|
|
||||||
import androidx.browser.customtabs.CustomTabsServiceConnection;
|
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation for the CustomTabsServiceConnection that avoids leaking the
|
|
||||||
* ServiceConnectionCallback
|
|
||||||
*/
|
|
||||||
public class ServiceConnection extends CustomTabsServiceConnection {
|
|
||||||
// A weak reference to the ServiceConnectionCallback to avoid leaking it.
|
|
||||||
private WeakReference<ServiceConnectionCallback> mConnectionCallback;
|
|
||||||
|
|
||||||
public ServiceConnection(ServiceConnectionCallback connectionCallback) {
|
|
||||||
mConnectionCallback = new WeakReference<>(connectionCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCustomTabsServiceConnected(ComponentName name, CustomTabsClient client) {
|
|
||||||
ServiceConnectionCallback connectionCallback = mConnectionCallback.get();
|
|
||||||
if (connectionCallback != null) connectionCallback.onServiceConnected(client);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onServiceDisconnected(ComponentName name) {
|
|
||||||
ServiceConnectionCallback connectionCallback = mConnectionCallback.get();
|
|
||||||
if (connectionCallback != null) connectionCallback.onServiceDisconnected();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
package bou.amine.apps.readerforselfossv2.android.utils.customtabs;
|
|
||||||
|
|
||||||
|
|
||||||
import androidx.browser.customtabs.CustomTabsClient;
|
|
||||||
|
|
||||||
|
|
||||||
public interface ServiceConnectionCallback {
|
|
||||||
/**
|
|
||||||
* Called when the service is connected.
|
|
||||||
*
|
|
||||||
* @param client a CustomTabsClient
|
|
||||||
*/
|
|
||||||
void onServiceConnected(CustomTabsClient client);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the service is disconnected.
|
|
||||||
*/
|
|
||||||
void onServiceDisconnected();
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
package bou.amine.apps.readerforselfossv2.android.utils.customtabs.helpers;
|
|
||||||
|
|
||||||
import android.app.Service;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Binder;
|
|
||||||
import android.os.IBinder;
|
|
||||||
|
|
||||||
public class KeepAliveService extends Service {
|
|
||||||
private static final Binder sBinder = new Binder();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IBinder onBind(Intent intent) {
|
|
||||||
return sBinder;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
/* From https://github.com/mikepenz/MaterialDrawer/blob/develop/app/src/main/java/com/mikepenz/materialdrawer/app/drawerItems/CustomBaseViewHolder.java */
|
|
||||||
package bou.amine.apps.readerforselfossv2.android.utils.drawer
|
|
||||||
|
|
||||||
import android.view.View
|
|
||||||
import android.widget.ImageView
|
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import bou.amine.apps.readerforselfossv2.android.R
|
|
||||||
|
|
||||||
open class CustomBaseViewHolder(var view: View) : RecyclerView.ViewHolder(view) {
|
|
||||||
var icon: ImageView = view.findViewById(R.id.material_drawer_icon)
|
|
||||||
var name: TextView = view.findViewById(R.id.material_drawer_name)
|
|
||||||
var description: TextView = view.findViewById(R.id.material_drawer_description)
|
|
||||||
}
|
|
@ -3,38 +3,37 @@ package bou.amine.apps.readerforselfossv2.android.utils.glide
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory
|
import bou.amine.apps.readerforselfossv2.android.utils.CircleImageView
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
import com.bumptech.glide.request.RequestOptions
|
import com.bumptech.glide.request.RequestOptions
|
||||||
import com.bumptech.glide.request.target.BitmapImageViewTarget
|
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
|
||||||
fun Context.bitmapCenterCrop(url: String, iv: ImageView) =
|
fun Context.bitmapCenterCrop(
|
||||||
Glide.with(this)
|
url: String,
|
||||||
|
iv: ImageView,
|
||||||
|
) = Glide.with(this)
|
||||||
.asBitmap()
|
.asBitmap()
|
||||||
.load(url)
|
.load(url)
|
||||||
.apply(RequestOptions.centerCropTransform())
|
.apply(RequestOptions.centerCropTransform())
|
||||||
.into(iv)
|
.into(iv)
|
||||||
|
|
||||||
fun Context.circularBitmapDrawable(url: String, iv: ImageView) =
|
fun Context.circularDrawable(
|
||||||
Glide.with(this)
|
url: String,
|
||||||
.asBitmap()
|
view: CircleImageView,
|
||||||
.load(url)
|
) {
|
||||||
.apply(RequestOptions.centerCropTransform())
|
view.textView.text = ""
|
||||||
.into(object : BitmapImageViewTarget(iv) {
|
|
||||||
override fun setResource(resource: Bitmap?) {
|
|
||||||
val circularBitmapDrawable = RoundedBitmapDrawableFactory.create(
|
|
||||||
resources,
|
|
||||||
resource
|
|
||||||
)
|
|
||||||
circularBitmapDrawable.isCircular = true
|
|
||||||
iv.setImageDrawable(circularBitmapDrawable)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
fun getBitmapInputStream(bitmap:Bitmap,compressFormat: Bitmap.CompressFormat): InputStream {
|
Glide.with(this)
|
||||||
|
.load(url)
|
||||||
|
.into(view.imageView)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getBitmapInputStream(
|
||||||
|
bitmap: Bitmap,
|
||||||
|
compressFormat: Bitmap.CompressFormat,
|
||||||
|
): InputStream {
|
||||||
val byteArrayOutputStream = ByteArrayOutputStream()
|
val byteArrayOutputStream = ByteArrayOutputStream()
|
||||||
bitmap.compress(compressFormat, 80, byteArrayOutputStream)
|
bitmap.compress(compressFormat, 80, byteArrayOutputStream)
|
||||||
val bitmapData: ByteArray = byteArrayOutputStream.toByteArray()
|
val bitmapData: ByteArray = byteArrayOutputStream.toByteArray()
|
||||||
|
@ -19,7 +19,8 @@ class AppViewModel(private val repository: Repository) : ViewModel() {
|
|||||||
if (isConnected && !wasConnected && repository.connectionMonitored) {
|
if (isConnected && !wasConnected && repository.connectionMonitored) {
|
||||||
_networkAvailableProvider.emit(true)
|
_networkAvailableProvider.emit(true)
|
||||||
wasConnected = true
|
wasConnected = true
|
||||||
} else if (!isConnected && wasConnected && repository.connectionMonitored){
|
} else if (!isConnected && wasConnected && repository.connectionMonitored)
|
||||||
|
{
|
||||||
_networkAvailableProvider.emit(false)
|
_networkAvailableProvider.emit(false)
|
||||||
wasConnected = false
|
wasConnected = false
|
||||||
}
|
}
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!-- Copyright 2015 Google Inc. All Rights Reserved.
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<translate android:fromXDelta="100%p" android:toXDelta="0"
|
|
||||||
android:duration="@android:integer/config_mediumAnimTime"/>
|
|
||||||
</set>
|
|
@ -1,16 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!-- Copyright 2015 Google Inc. All Rights Reserved.
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<translate android:fromXDelta="0" android:toXDelta="-100%p"
|
|
||||||
android:duration="@android:integer/config_mediumAnimTime"/>
|
|
||||||
</set>
|
|
@ -1,8 +1,11 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<item
|
<item>
|
||||||
android:drawable="@color/ic_launcher_background"/>
|
<shape android:shape="rectangle" >
|
||||||
|
<solid android:color="?attr/colorSurface" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
|
||||||
<item>
|
<item>
|
||||||
<bitmap
|
<bitmap
|
||||||
|
5
androidApp/src/main/res/drawable/checkerboard.xml
Normal file
5
androidApp/src/main/res/drawable/checkerboard.xml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<bitmap
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:dither="true"
|
||||||
|
android:src="@drawable/checktile"
|
||||||
|
android:tileMode="repeat"/>
|
BIN
androidApp/src/main/res/drawable/checktile.png
Normal file
BIN
androidApp/src/main/res/drawable/checktile.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 235 B |
@ -0,0 +1,5 @@
|
|||||||
|
<vector android:height="24dp" android:tint="#000000"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M20,8h-2.81c-0.45,-0.78 -1.07,-1.45 -1.82,-1.96L17,4.41 15.59,3l-2.17,2.17C12.96,5.06 12.49,5 12,5c-0.49,0 -0.96,0.06 -1.41,0.17L8.41,3 7,4.41l1.62,1.63C7.88,6.55 7.26,7.22 6.81,8L4,8v2h2.09c-0.05,0.33 -0.09,0.66 -0.09,1v1L4,12v2h2v1c0,0.34 0.04,0.67 0.09,1L4,16v2h2.81c1.04,1.79 2.97,3 5.19,3s4.15,-1.21 5.19,-3L20,18v-2h-2.09c0.05,-0.33 0.09,-0.66 0.09,-1v-1h2v-2h-2v-1c0,-0.34 -0.04,-0.67 -0.09,-1L20,10L20,8zM14,16h-4v-2h4v2zM14,12h-4v-2h4v2z"/>
|
||||||
|
</vector>
|
@ -0,0 +1,5 @@
|
|||||||
|
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M4.25,5.61C6.27,8.2 10,13 10,13v6c0,0.55 0.45,1 1,1h2c0.55,0 1,-0.45 1,-1v-6c0,0 3.72,-4.8 5.74,-7.39C20.25,4.95 19.78,4 18.95,4H5.04C4.21,4 3.74,4.95 4.25,5.61z"/>
|
||||||
|
</vector>
|
@ -1,9 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:viewportWidth="24.0"
|
|
||||||
android:viewportHeight="24.0">
|
|
||||||
<path
|
|
||||||
android:fillColor="#FF000000"
|
|
||||||
android:pathData="M20,8h-2.81c-0.45,-0.78 -1.07,-1.45 -1.82,-1.96L17,4.41 15.59,3l-2.17,2.17C12.96,5.06 12.49,5 12,5c-0.49,0 -0.96,0.06 -1.41,0.17L8.41,3 7,4.41l1.62,1.63C7.88,6.55 7.26,7.22 6.81,8L4,8v2h2.09c-0.05,0.33 -0.09,0.66 -0.09,1v1L4,12v2h2v1c0,0.34 0.04,0.67 0.09,1L4,16v2h2.81c1.04,1.79 2.97,3 5.19,3s4.15,-1.21 5.19,-3L20,18v-2h-2.09c0.05,-0.33 0.09,-0.66 0.09,-1v-1h2v-2h-2v-1c0,-0.34 -0.04,-0.67 -0.09,-1L20,10L20,8zM14,16h-4v-2h4v2zM14,12h-4v-2h4v2z"/>
|
|
||||||
</vector>
|
|
@ -1,9 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:viewportWidth="24.0"
|
|
||||||
android:viewportHeight="24.0">
|
|
||||||
<path
|
|
||||||
android:fillColor="#FFFFFFFF"
|
|
||||||
android:pathData="M13,12h7v1.5h-7zM13,9.5h7L20,11h-7zM13,14.5h7L20,16h-7zM21,4L3,4c-1.1,0 -2,0.9 -2,2v13c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2L23,6c0,-1.1 -0.9,-2 -2,-2zM21,19h-9L12,6h9v13z"/>
|
|
||||||
</vector>
|
|
@ -1,5 +0,0 @@
|
|||||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
|
||||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
|
||||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<path android:fillColor="#FF000000" android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
|
|
||||||
</vector>
|
|
@ -1,5 +0,0 @@
|
|||||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
|
||||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
|
||||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<path android:fillColor="#FF000000" android:pathData="M13,3c-4.97,0 -9,4.03 -9,9L1,12l3.89,3.89 0.07,0.14L9,12L6,12c0,-3.87 3.13,-7 7,-7s7,3.13 7,7 -3.13,7 -7,7c-1.93,0 -3.68,-0.79 -4.94,-2.06l-1.42,1.42C8.27,19.99 10.51,21 13,21c4.97,0 9,-4.03 9,-9s-4.03,-9 -9,-9zM12,8v5l4.28,2.54 0.72,-1.21 -3.5,-2.08L13.5,8L12,8z"/>
|
|
||||||
</vector>
|
|
@ -1,5 +0,0 @@
|
|||||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
|
||||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
|
||||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<path android:fillColor="#FF000000" android:pathData="M17.65,6.35C16.2,4.9 14.21,4 12,4c-4.42,0 -7.99,3.58 -7.99,8s3.57,8 7.99,8c3.73,0 6.84,-2.55 7.73,-6h-2.08c-0.82,2.33 -3.04,4 -5.65,4 -3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6c1.66,0 3.14,0.69 4.22,1.78L13,11h7V4l-2.35,2.35z"/>
|
|
||||||
</vector>
|
|
@ -1,7 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<font-family xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
app:fontProviderAuthority="com.google.android.gms.fonts"
|
|
||||||
app:fontProviderPackage="com.google.android.gms"
|
|
||||||
app:fontProviderQuery="Open Sans"
|
|
||||||
app:fontProviderCerts="@array/com_google_android_gms_fonts_certs">
|
|
||||||
</font-family>
|
|
@ -1,7 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<font-family xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
app:fontProviderAuthority="com.google.android.gms.fonts"
|
|
||||||
app:fontProviderPackage="com.google.android.gms"
|
|
||||||
app:fontProviderQuery="Roboto"
|
|
||||||
app:fontProviderCerts="@array/com_google_android_gms_fonts_certs">
|
|
||||||
</font-family>
|
|
@ -1,13 +1,12 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.drawerlayout.widget.DrawerLayout
|
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/drawerContainer"
|
android:id="@+id/drawerContainer"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context="bou.amine.apps.readerforselfossv2.android.HomeActivity"
|
|
||||||
android:fitsSystemWindows="true"
|
android:fitsSystemWindows="true"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
tools:context="bou.amine.apps.readerforselfossv2.android.HomeActivity">
|
||||||
|
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
android:id="@+id/coordLayout"
|
android:id="@+id/coordLayout"
|
||||||
@ -32,8 +31,10 @@
|
|||||||
android:id="@+id/toolBar"
|
android:id="@+id/toolBar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
app:theme="@style/ToolBarStyle"
|
android:theme="@style/ToolBarStyle"
|
||||||
app:popupTheme="?attr/toolbarPopupTheme" />
|
app:popupTheme="?attr/toolbarPopupTheme"
|
||||||
|
|
||||||
|
/>
|
||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
@ -45,19 +46,19 @@
|
|||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical"
|
android:background="?android:attr/windowBackground"
|
||||||
android:background="?android:attr/windowBackground">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/emptyText"
|
android:id="@+id/emptyText"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
android:gravity="center_horizontal"
|
android:gravity="center_horizontal"
|
||||||
android:paddingTop="100dp"
|
android:paddingTop="100dp"
|
||||||
android:text="@string/nothing_here"
|
android:text="@string/nothing_here"
|
||||||
android:textAlignment="center"
|
android:textAlignment="center"
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Headline"
|
android:textAppearance="@style/TextAppearance.AppCompat.Headline"
|
||||||
android:background="@android:color/transparent"
|
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
@ -77,17 +78,13 @@
|
|||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
||||||
<com.ashokvarma.bottomnavigation.BottomNavigationBar
|
<com.ashokvarma.bottomnavigation.BottomNavigationBar
|
||||||
android:layout_gravity="bottom"
|
|
||||||
android:id="@+id/bottomBar"
|
android:id="@+id/bottomBar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="60dp"/>
|
android:layout_height="60dp"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
app:bnbActiveColor="@color/colorAccent"
|
||||||
|
app:bnbBackgroundColor="?attr/bottomBarBackground" />
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
||||||
<com.mikepenz.materialdrawer.widget.MaterialDrawerSliderView
|
|
||||||
android:id="@+id/mainDrawer"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_gravity="start"
|
|
||||||
android:fitsSystemWindows="true" />
|
|
||||||
</androidx.drawerlayout.widget.DrawerLayout>
|
</androidx.drawerlayout.widget.DrawerLayout>
|
@ -1,33 +1,40 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.motion.widget.MotionLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:id="@+id/container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent"
|
||||||
|
app:layoutDescription="@xml/image_close_scene">
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:id="@+id/appBarLayout"
|
android:id="@+id/appBarLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content">
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
|
||||||
|
|
||||||
<androidx.appcompat.widget.Toolbar
|
<androidx.appcompat.widget.Toolbar android:theme="@style/ToolBarStyle"
|
||||||
android:id="@+id/toolBar"
|
android:id="@+id/toolBar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
app:popupTheme="?attr/toolbarPopupTheme"
|
|
||||||
app:theme="@style/ToolBarStyle" />
|
/>
|
||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
|
<androidx.core.widget.NestedScrollView
|
||||||
|
android:id="@+id/scrollView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:fillViewport="true"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/appBarLayout">
|
||||||
|
|
||||||
<androidx.viewpager2.widget.ViewPager2
|
<androidx.viewpager2.widget.ViewPager2
|
||||||
android:id="@+id/pager"
|
android:id="@+id/pager"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="match_parent"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
app:layout_constraintTop_toBottomOf="@+id/appBarLayout" />
|
</androidx.core.widget.NestedScrollView>
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
</androidx.constraintlayout.motion.widget.MotionLayout>
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:gravity="center_horizontal"
|
android:gravity="center_horizontal"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
tools:context="bou.amine.apps.readerforselfossv2.android.LoginActivity">
|
tools:context="bou.amine.apps.readerforselfossv2.android.LoginActivity">
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
@ -14,18 +15,16 @@
|
|||||||
android:id="@+id/toolbar"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
app:theme="@style/ToolBarStyle"
|
android:theme="@style/ToolBarStyle"
|
||||||
app:popupTheme="?attr/toolbarPopupTheme" />
|
app:popupTheme="?attr/toolbarPopupTheme" />
|
||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
android:padding="@dimen/activity_horizontal_margin">
|
||||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
|
||||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
|
||||||
android:paddingTop="@dimen/activity_vertical_margin">
|
|
||||||
<!-- Login progress -->
|
<!-- Login progress -->
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
android:id="@+id/loginProgress"
|
android:id="@+id/loginProgress"
|
||||||
@ -35,12 +34,8 @@
|
|||||||
android:layout_marginBottom="8dp"
|
android:layout_marginBottom="8dp"
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
<ScrollView
|
|
||||||
android:id="@+id/loginForm"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
android:id="@+id/loginForm"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
@ -53,14 +48,22 @@
|
|||||||
android:imeOptions="actionUnspecified"
|
android:imeOptions="actionUnspecified"
|
||||||
android:importantForAutofill="no"
|
android:importantForAutofill="no"
|
||||||
android:inputType="textUri"
|
android:inputType="textUri"
|
||||||
android:maxLines="1" />
|
android:maxLines="1"
|
||||||
|
android:minHeight="48dp" />
|
||||||
|
|
||||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||||
android:text="@string/withLoginSwitch"
|
android:id="@+id/selfSigned"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/disable_ssl"
|
||||||
|
android:textAlignment="viewStart" />
|
||||||
|
|
||||||
|
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||||
android:id="@+id/withLogin"
|
android:id="@+id/withLogin"
|
||||||
android:layout_weight="1"/>
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/withLoginSwitch"
|
||||||
|
android:textAlignment="viewStart" />
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
android:id="@+id/loginView"
|
android:id="@+id/loginView"
|
||||||
@ -70,6 +73,7 @@
|
|||||||
android:hint="@string/prompt_login"
|
android:hint="@string/prompt_login"
|
||||||
android:inputType="text"
|
android:inputType="text"
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
|
android:minHeight="48dp"
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
@ -80,6 +84,7 @@
|
|||||||
android:hint="@string/prompt_password"
|
android:hint="@string/prompt_password"
|
||||||
android:inputType="textPassword"
|
android:inputType="textPassword"
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
|
android:minHeight="48dp"
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
@ -93,7 +98,6 @@
|
|||||||
android:textStyle="bold" />
|
android:textStyle="bold" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</ScrollView>
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
@ -17,8 +17,10 @@
|
|||||||
android:id="@+id/toolBar"
|
android:id="@+id/toolBar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
android:theme="@style/ToolBarStyle"
|
||||||
app:popupTheme="?attr/toolbarPopupTheme"
|
app:popupTheme="?attr/toolbarPopupTheme"
|
||||||
app:theme="@style/ToolBarStyle" />
|
|
||||||
|
/>
|
||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:id="@+id/layout"
|
android:id="@+id/layout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
@ -8,11 +9,11 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
<androidx.appcompat.widget.Toolbar
|
<androidx.appcompat.widget.Toolbar app:popupTheme="?attr/toolbarPopupTheme" android:theme="@style/ToolBarStyle"
|
||||||
android:id="@+id/toolbar"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
android:theme="@style/ToolBarStyle" />
|
/>
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
|
@ -10,12 +10,12 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
<androidx.appcompat.widget.Toolbar
|
<androidx.appcompat.widget.Toolbar app:popupTheme="?attr/toolbarPopupTheme" android:theme="@style/ToolBarStyle"
|
||||||
android:id="@+id/toolbar"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
app:theme="@style/ToolBarStyle"
|
|
||||||
app:popupTheme="?attr/toolbarPopupTheme" />
|
/>
|
||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
@ -24,7 +24,8 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:scrollbars="vertical"
|
android:scrollbars="vertical"
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||||
|
tools:listitem="@layout/source_list_item">
|
||||||
</androidx.recyclerview.widget.RecyclerView>
|
</androidx.recyclerview.widget.RecyclerView>
|
||||||
|
|
||||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context="bou.amine.apps.readerforselfossv2.android.AddSourceActivity">
|
tools:context="bou.amine.apps.readerforselfossv2.android.UpsertSourceActivity">
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
@ -14,120 +14,86 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
<androidx.appcompat.widget.Toolbar
|
<androidx.appcompat.widget.Toolbar app:popupTheme="?attr/toolbarPopupTheme" android:theme="@style/ToolBarStyle"
|
||||||
android:id="@+id/toolbar"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize" />
|
||||||
app:theme="@style/ToolBarStyle"
|
|
||||||
app:popupTheme="?attr/toolbarPopupTheme" />
|
|
||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
|
||||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
|
||||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
|
||||||
android:paddingTop="@dimen/activity_vertical_margin"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
android:id="@+id/formContainer"
|
android:id="@+id/formContainer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:padding="16dp"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
app:layout_constraintHorizontal_bias="1.0"
|
app:layout_constraintHorizontal_bias="1.0"
|
||||||
app:layout_constraintVertical_bias="0.0">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:text="@string/add_source"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:id="@+id/textView2"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Large"
|
|
||||||
android:textAlignment="center"
|
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
|
||||||
android:layout_marginRight="16dp"
|
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
android:layout_marginLeft="16dp"
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
android:gravity="center_horizontal" />
|
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:ems="10"
|
|
||||||
android:id="@+id/nameInput"
|
android:id="@+id/nameInput"
|
||||||
android:layout_marginTop="32dp"
|
android:layout_width="match_parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/textView2"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
android:minHeight="48dp"
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
android:layout_marginTop="16dp"
|
||||||
android:inputType="text"
|
android:autofillHints="false"
|
||||||
android:hint="@string/add_source_hint_name"
|
android:hint="@string/add_source_hint_name"
|
||||||
android:textColorHint="?android:textColorPrimary"
|
|
||||||
android:autofillHints="false" />
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:inputType="textUri"
|
|
||||||
android:ems="10"
|
|
||||||
android:id="@+id/sourceUri"
|
|
||||||
android:hint="@string/add_source_hint_url"
|
|
||||||
android:textColorHint="?android:textColorPrimary"
|
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/nameInput"
|
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
|
||||||
android:autofillHints="false" />
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:ems="10"
|
|
||||||
android:id="@+id/tags"
|
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/sourceUri"
|
|
||||||
android:hint="@string/add_source_hint_tags"
|
|
||||||
android:textColorHint="?android:textColorPrimary"
|
|
||||||
android:inputType="text"
|
android:inputType="text"
|
||||||
android:autofillHints="false" />
|
android:textColorHint="?android:textColorPrimary"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/sourceUri"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minHeight="48dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:autofillHints="false"
|
||||||
|
android:hint="@string/add_source_hint_url"
|
||||||
|
android:inputType="textUri"
|
||||||
|
android:textColorHint="?android:textColorPrimary"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/nameInput" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/tags"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minHeight="48dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:autofillHints="false"
|
||||||
|
android:hint="@string/add_source_hint_tags"
|
||||||
|
android:inputType="text"
|
||||||
|
android:textColorHint="?android:textColorPrimary"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/sourceUri" />
|
||||||
|
|
||||||
<Spinner
|
<Spinner
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:id="@+id/spoutsSpinner"
|
android:id="@+id/spoutsSpinner"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minHeight="48dp"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/tags"
|
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
android:layout_height="40dp"
|
app:layout_constraintTop_toBottomOf="@+id/tags" />
|
||||||
android:theme="@style/App.Spinner"/>
|
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:text="@string/add_source_save"
|
android:id="@+id/saveBtn"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:id="@+id/saveBtn"
|
|
||||||
android:elevation="5dp"
|
|
||||||
android:textColor="?attr/colorAccent"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
|
||||||
android:layout_marginRight="16dp"
|
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
|
||||||
android:layout_marginLeft="16dp"
|
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/spoutsSpinner"
|
android:elevation="5dp"
|
||||||
|
android:text="@string/add_source_save"
|
||||||
|
android:textColor="?android:textColorPrimary"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
android:layout_marginBottom="16dp"
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
app:layout_constraintVertical_bias="0.0"/>
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/spoutsSpinner" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
@ -136,8 +102,6 @@
|
|||||||
style="?android:attr/progressBarStyleLarge"
|
style="?android:attr/progressBarStyleLarge"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:visibility="visible"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
@ -1,23 +1,18 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.cardview.widget.CardView
|
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/card"
|
android:id="@+id/card"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginLeft="8dp"
|
android:layout_margin="8dp"
|
||||||
android:layout_marginRight="8dp"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
android:layout_marginTop="8dp"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintHorizontal_bias="0.62"
|
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
card_view:cardElevation="2dp"
|
card_view:cardElevation="2dp"
|
||||||
card_view:cardUseCompatPadding="true"
|
card_view:cardUseCompatPadding="true"
|
||||||
card_view:layout_constraintBottom_toBottomOf="parent"
|
card_view:layout_constraintBottom_toBottomOf="parent">
|
||||||
app:cardBackgroundColor="?cardBackgroundColor">
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@ -29,8 +24,8 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:cropToPadding="true"
|
android:cropToPadding="true"
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:srcCompat="@drawable/background_splash"
|
app:srcCompat="@drawable/background_splash"
|
||||||
card_view:layout_constraintBottom_toTopOf="@+id/constraintLayout" />
|
card_view:layout_constraintBottom_toTopOf="@+id/constraintLayout" />
|
||||||
@ -40,18 +35,17 @@
|
|||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/itemImage">
|
app:layout_constraintTop_toBottomOf="@+id/itemImage">
|
||||||
|
|
||||||
<ImageView
|
<bou.amine.apps.readerforselfossv2.android.utils.CircleImageView
|
||||||
android:id="@+id/sourceImage"
|
android:id="@+id/sourceImage"
|
||||||
android:layout_width="40dp"
|
android:layout_width="40dp"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
android:layout_marginLeft="8dp"
|
|
||||||
android:layout_marginStart="8dp"
|
android:layout_marginStart="8dp"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:srcCompat="@drawable/background_splash" />
|
app:srcCompat="@drawable/background_splash" />
|
||||||
|
|
||||||
@ -59,70 +53,58 @@
|
|||||||
android:id="@+id/title"
|
android:id="@+id/title"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginEnd="8dp"
|
android:layout_margin="8dp"
|
||||||
android:layout_marginLeft="8dp"
|
|
||||||
android:layout_marginRight="8dp"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:gravity="start"
|
|
||||||
android:textAlignment="viewStart"
|
android:textAlignment="viewStart"
|
||||||
android:textStyle="bold"
|
|
||||||
android:textColor="?android:textColorPrimary"
|
android:textColor="?android:textColorPrimary"
|
||||||
app:layout_constraintHorizontal_bias="0.0"
|
android:textStyle="bold"
|
||||||
app:layout_constraintLeft_toRightOf="@+id/sourceImage"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
app:layout_constraintStart_toEndOf="@+id/sourceImage"
|
||||||
app:layout_constraintTop_toTopOf="@+id/sourceImage"
|
app:layout_constraintTop_toTopOf="@+id/sourceImage"
|
||||||
tools:text="Titre" />
|
tools:text="Titre" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/sourceTitleAndDate"
|
android:id="@+id/sourceTitleAndDate"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:gravity="start"
|
|
||||||
android:textAlignment="viewStart"
|
android:textAlignment="viewStart"
|
||||||
android:textSize="14sp"
|
|
||||||
android:textColor="?android:textColorPrimary"
|
android:textColor="?android:textColorPrimary"
|
||||||
app:layout_constraintLeft_toLeftOf="@+id/title"
|
android:textSize="14sp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="@+id/title"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/title"
|
app:layout_constraintTop_toBottomOf="@+id/title"
|
||||||
tools:text="Google Actualité Il y a 5h" />
|
tools:text="Google Actualité Il y a 5h" />
|
||||||
|
|
||||||
<RelativeLayout
|
<LinearLayout
|
||||||
android:layout_width="0dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/sourceTitleAndDate">
|
app:layout_constraintTop_toBottomOf="@+id/sourceTitleAndDate">
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/favButton"
|
android:id="@+id/browserBtn"
|
||||||
android:layout_width="35dp"
|
android:layout_width="35dp"
|
||||||
android:layout_height="35dp"
|
android:layout_height="35dp"
|
||||||
android:layout_alignParentEnd="true"
|
|
||||||
android:layout_alignParentRight="true"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:layout_marginRight="8dp"
|
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:background="@android:color/transparent"
|
android:background="@android:color/transparent"
|
||||||
|
android:contentDescription="@string/reader_action_open"
|
||||||
android:elevation="5dp"
|
android:elevation="5dp"
|
||||||
android:padding="4dp"
|
android:padding="4dp"
|
||||||
android:scaleType="centerCrop"
|
android:scaleType="centerCrop"
|
||||||
app:srcCompat="@drawable/ic_menu_heart_60dp"
|
app:srcCompat="@drawable/ic_open_in_browser_black_24dp"
|
||||||
app:tint="@color/ic_menu_heart_color" />
|
app:tint="?android:attr/textColorPrimary" />
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/shareBtn"
|
android:id="@+id/shareBtn"
|
||||||
android:layout_width="35dp"
|
android:layout_width="35dp"
|
||||||
android:layout_height="35dp"
|
android:layout_height="35dp"
|
||||||
android:layout_centerVertical="true"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
android:layout_marginRight="16dp"
|
|
||||||
android:layout_toLeftOf="@+id/favButton"
|
|
||||||
android:layout_toStartOf="@+id/favButton"
|
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:background="@android:color/transparent"
|
android:background="@android:color/transparent"
|
||||||
|
android:contentDescription="@string/share"
|
||||||
android:elevation="5dp"
|
android:elevation="5dp"
|
||||||
android:padding="4dp"
|
android:padding="4dp"
|
||||||
android:scaleType="centerCrop"
|
android:scaleType="centerCrop"
|
||||||
@ -130,23 +112,21 @@
|
|||||||
app:tint="?android:attr/textColorPrimary" />
|
app:tint="?android:attr/textColorPrimary" />
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/browserBtn"
|
android:id="@+id/favButton"
|
||||||
android:layout_width="35dp"
|
android:layout_width="35dp"
|
||||||
android:layout_height="35dp"
|
android:layout_height="35dp"
|
||||||
android:layout_centerVertical="true"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
android:layout_marginRight="16dp"
|
|
||||||
android:layout_toLeftOf="@+id/shareBtn"
|
|
||||||
android:layout_toStartOf="@+id/shareBtn"
|
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:background="@android:color/transparent"
|
android:background="@android:color/transparent"
|
||||||
|
android:contentDescription="@string/add_to_favs_reader"
|
||||||
android:elevation="5dp"
|
android:elevation="5dp"
|
||||||
android:padding="4dp"
|
android:padding="4dp"
|
||||||
android:scaleType="centerCrop"
|
android:scaleType="centerCrop"
|
||||||
app:srcCompat="@drawable/ic_open_in_browser_black_24dp"
|
app:srcCompat="@drawable/ic_menu_heart_60dp"
|
||||||
app:tint="?android:attr/textColorPrimary" />
|
app:tint="@color/ic_menu_heart_color" />
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
26
androidApp/src/main/res/layout/circle_image_view.xml
Normal file
26
androidApp/src/main/res/layout/circle_image_view.xml
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<com.google.android.material.imageview.ShapeableImageView
|
||||||
|
android:id="@+id/circleImage"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:scaleType="centerCrop"
|
||||||
|
app:shapeAppearanceOverlay="@style/circleImageView"
|
||||||
|
app:srcCompat="@drawable/background_splash" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/circleText"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:ellipsize="none"
|
||||||
|
android:gravity="center"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textIsSelectable="false"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:typeface="normal" />
|
||||||
|
</RelativeLayout>
|
96
androidApp/src/main/res/layout/filter_fragment.xml
Normal file
96
androidApp/src/main/res/layout/filter_fragment.xml
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progressBar2"
|
||||||
|
style="?android:attr/progressBarStyle"
|
||||||
|
android:layout_width="48dp"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:visibility="gone" />
|
||||||
|
|
||||||
|
<androidx.core.widget.NestedScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:fillViewport="true">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:id="@+id/filterView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/filterTagsTitle"
|
||||||
|
style="@style/MaterialAlertDialog.MaterialComponents.Title.Text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="24dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:text="@string/filter_item_tags"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/filterSourcesTitle"
|
||||||
|
style="@style/MaterialAlertDialog.MaterialComponents.Title.Text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="24dp"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
|
android:text="@string/filter_item_sources"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/tagsGroup" />
|
||||||
|
|
||||||
|
|
||||||
|
<com.google.android.material.chip.ChipGroup
|
||||||
|
android:id="@+id/tagsGroup"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/filterTagsTitle"
|
||||||
|
app:singleSelection="true">
|
||||||
|
|
||||||
|
</com.google.android.material.chip.ChipGroup>
|
||||||
|
|
||||||
|
<com.google.android.material.chip.ChipGroup
|
||||||
|
android:id="@+id/sourcesGroup"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/filterSourcesTitle">
|
||||||
|
|
||||||
|
</com.google.android.material.chip.ChipGroup>
|
||||||
|
|
||||||
|
|
||||||
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
android:id="@+id/floatingActionButton2"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:clickable="true"
|
||||||
|
android:contentDescription="@string/menu_home_search"
|
||||||
|
android:focusable="true"
|
||||||
|
app:backgroundTint="@color/colorAccent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:rippleColor="@color/colorAccentDark"
|
||||||
|
app:srcCompat="@drawable/ic_menu_search_white_24dp" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
</androidx.core.widget.NestedScrollView>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -1,5 +1,4 @@
|
|||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@ -22,10 +21,22 @@
|
|||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="200dp"
|
android:layout_height="200dp"
|
||||||
android:scaleType="centerCrop"
|
android:scaleType="centerCrop"
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
/>
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/titleView"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="16dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginRight="16dp"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Headline"
|
||||||
|
android:textStyle="bold"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/imageView" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/source"
|
android:id="@+id/source"
|
||||||
@ -36,40 +47,23 @@
|
|||||||
android:layout_marginRight="16dp"
|
android:layout_marginRight="16dp"
|
||||||
android:textColor="?android:textColorSecondary"
|
android:textColor="?android:textColorSecondary"
|
||||||
android:textSize="12sp"
|
android:textSize="12sp"
|
||||||
app:layout_constraintHorizontal_bias="0.0"
|
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/titleView" />
|
app:layout_constraintTop_toBottomOf="@+id/titleView" />
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/titleView"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginLeft="16dp"
|
|
||||||
android:layout_marginRight="16dp"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Headline"
|
|
||||||
android:textStyle="bold"
|
|
||||||
app:layout_constraintHorizontal_bias="0.0"
|
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/imageView" />
|
|
||||||
|
|
||||||
|
|
||||||
<WebView
|
<WebView
|
||||||
android:id="@+id/webcontent"
|
android:id="@+id/webcontent"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="16dp"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
|
android:layout_marginRight="16dp"
|
||||||
|
android:background="?attr/webviewBackground"
|
||||||
|
android:paddingBottom="48dp"
|
||||||
android:textColorLink="?attr/colorAccent"
|
android:textColorLink="?attr/colorAccent"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
android:layout_marginLeft="16dp"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
android:layout_marginRight="16dp"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
android:layout_marginTop="24dp"
|
|
||||||
android:paddingBottom="48dp"
|
|
||||||
android:background="?android:colorBackground"
|
|
||||||
app:layout_constraintHorizontal_bias="0.0"
|
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/source"
|
app:layout_constraintTop_toBottomOf="@+id/source"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
@ -80,10 +74,10 @@
|
|||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="start|bottom|end"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
app:layout_constraintStart_toStartOf="parent">
|
||||||
android:layout_gravity="end|bottom|right">
|
|
||||||
|
|
||||||
<com.github.rubensousa.floatingtoolbar.FloatingToolbar
|
<com.github.rubensousa.floatingtoolbar.FloatingToolbar
|
||||||
android:id="@+id/floatingToolbar"
|
android:id="@+id/floatingToolbar"
|
||||||
@ -96,12 +90,11 @@
|
|||||||
android:id="@+id/fab"
|
android:id="@+id/fab"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="end|bottom|right"
|
android:layout_gravity="end|bottom"
|
||||||
android:layout_marginBottom="16dp"
|
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:layout_marginRight="16dp"
|
android:layout_marginBottom="16dp"
|
||||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
|
||||||
android:paddingTop="@dimen/activity_vertical_margin"
|
android:paddingTop="@dimen/activity_vertical_margin"
|
||||||
|
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||||
android:src="@drawable/ic_add_white_24dp"
|
android:src="@drawable/ic_add_white_24dp"
|
||||||
app:backgroundTint="?attr/colorAccent"
|
app:backgroundTint="?attr/colorAccent"
|
||||||
app:fabSize="mini"
|
app:fabSize="mini"
|
||||||
@ -112,11 +105,11 @@
|
|||||||
android:id="@+id/progressBar"
|
android:id="@+id/progressBar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:visibility="gone"
|
|
||||||
android:animateLayoutChanges="true"
|
|
||||||
android:alpha="0.8"
|
android:alpha="0.8"
|
||||||
|
android:animateLayoutChanges="true"
|
||||||
android:background="@color/black"
|
android:background="@color/black"
|
||||||
android:clickable="false">
|
android:clickable="false"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
style="?android:attr/progressBarStyleLarge"
|
style="?android:attr/progressBarStyleLarge"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
@ -9,8 +9,8 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_centerVertical="true"
|
android:layout_centerVertical="true"
|
||||||
android:layout_centerHorizontal="true"
|
android:adjustViewBounds="true"
|
||||||
android:background="@android:color/black"
|
android:background="@drawable/checkerboard"
|
||||||
app:srcCompat="@android:drawable/screen_background_dark" />
|
app:srcCompat="@android:drawable/screen_background_dark" />
|
||||||
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -3,17 +3,16 @@
|
|||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="88dp">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
<ImageView
|
<bou.amine.apps.readerforselfossv2.android.utils.CircleImageView
|
||||||
android:id="@+id/itemImage"
|
android:id="@+id/itemImage"
|
||||||
android:layout_width="46dp"
|
android:layout_width="46dp"
|
||||||
android:layout_height="46dp"
|
android:layout_height="46dp"
|
||||||
android:layout_marginStart="8dp"
|
android:layout_marginStart="8dp"
|
||||||
android:layout_marginTop="21dp"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
android:layout_marginLeft="8dp" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/title"
|
android:id="@+id/title"
|
||||||
@ -24,39 +23,30 @@
|
|||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:fontFamily="sans-serif"
|
android:fontFamily="sans-serif"
|
||||||
android:gravity="start"
|
|
||||||
android:maxLines="3"
|
android:maxLines="3"
|
||||||
android:textAlignment="viewStart"
|
android:textAlignment="viewStart"
|
||||||
android:textAllCaps="false"
|
android:textColor="?android:textColorPrimary"
|
||||||
android:textSize="16sp"
|
android:textSize="16sp"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
android:textColor="?android:textColorPrimary"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintHorizontal_bias="0.0"
|
|
||||||
app:layout_constraintStart_toEndOf="@+id/itemImage"
|
app:layout_constraintStart_toEndOf="@+id/itemImage"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:text="Titre"
|
tools:text="Titre" />
|
||||||
android:layout_marginLeft="8dp"
|
|
||||||
android:layout_marginRight="16dp" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/sourceTitleAndDate"
|
android:id="@+id/sourceTitleAndDate"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="8dp"
|
android:layout_marginStart="8dp"
|
||||||
android:layout_marginTop="66dp"
|
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:gravity="start"
|
android:gravity="start"
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
android:textAlignment="viewStart"
|
android:textAlignment="viewStart"
|
||||||
android:textSize="14sp"
|
|
||||||
android:textColor="?android:textColorPrimary"
|
android:textColor="?android:textColorPrimary"
|
||||||
|
android:textSize="14sp"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintHorizontal_bias="0.0"
|
|
||||||
app:layout_constraintStart_toEndOf="@+id/itemImage"
|
app:layout_constraintStart_toEndOf="@+id/itemImage"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toBottomOf="@+id/itemImage"
|
||||||
tools:text="Google Actualité Il y a 5h"
|
tools:text="Google Actualité Il y a 5h" />
|
||||||
android:layout_marginLeft="8dp"
|
|
||||||
android:layout_marginRight="16dp" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -3,48 +3,74 @@
|
|||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="48dp"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/itemImage"
|
|
||||||
android:layout_width="36dp"
|
|
||||||
android:layout_height="36dp"
|
|
||||||
android:importantForAccessibility="no"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/sourceTitle"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="17dp"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:gravity="start"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:textAlignment="textStart"
|
|
||||||
android:textSize="13sp"
|
|
||||||
android:textColor="?android:textColorPrimary"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toStartOf="@+id/deleteBtn"
|
|
||||||
app:layout_constraintStart_toEndOf="@+id/itemImage"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
tools:text="source title" />
|
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/deleteBtn"
|
android:id="@+id/deleteBtn"
|
||||||
style="@style/Widget.AppCompat.Button.Borderless"
|
style="@style/Widget.AppCompat.Button.Borderless"
|
||||||
android:layout_width="34dp"
|
android:layout_width="48dp"
|
||||||
android:layout_height="34dp"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
android:layout_marginEnd="8dp"
|
android:layout_marginEnd="8dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
android:background="@drawable/ic_remove_circle_outline_black_24dp"
|
android:background="@drawable/ic_remove_circle_outline_black_24dp"
|
||||||
android:backgroundTint="?android:textColorSecondary"
|
android:backgroundTint="?android:textColorSecondary"
|
||||||
android:elevation="4dp"
|
|
||||||
android:contentDescription="@string/remove_source"
|
android:contentDescription="@string/remove_source"
|
||||||
|
android:elevation="4dp"
|
||||||
|
app:iconSize="34dp"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintVertical_bias="0.0" />
|
||||||
|
|
||||||
|
<bou.amine.apps.readerforselfossv2.android.utils.CircleImageView
|
||||||
|
android:id="@+id/itemImage"
|
||||||
|
android:layout_width="36dp"
|
||||||
|
android:layout_height="36dp"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintVertical_bias="0.0" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/sourceTitle"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textAlignment="viewStart"
|
||||||
|
android:textColor="?android:textColorPrimary"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/errorText"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/deleteBtn"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/itemImage"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:text="Source title" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/errorText"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="10sp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||||
|
android:textColor="@color/red"
|
||||||
|
android:textStyle="italic"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/deleteBtn"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/itemImage"
|
||||||
|
tools:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -8,18 +8,40 @@
|
|||||||
app:showAsAction="ifRoom|collapseActionView"
|
app:showAsAction="ifRoom|collapseActionView"
|
||||||
app:actionViewClass="androidx.appcompat.widget.SearchView" />
|
app:actionViewClass="androidx.appcompat.widget.SearchView" />
|
||||||
|
|
||||||
<item android:id="@+id/readAll"
|
<item android:id="@+id/action_filter"
|
||||||
android:icon="@drawable/ic_menu_done_all_white_24dp"
|
android:title="@string/menu_home_filter"
|
||||||
android:title="@string/readAll"
|
android:icon="@drawable/ic_baseline_filter_alt_24"
|
||||||
android:orderInCategory="1"
|
android:orderInCategory="1"
|
||||||
app:showAsAction="always" />
|
app:showAsAction="always" />
|
||||||
|
|
||||||
|
<item android:id="@+id/readAll"
|
||||||
|
android:icon="@drawable/ic_menu_done_all_white_24dp"
|
||||||
|
android:title="@string/readAll"
|
||||||
|
android:orderInCategory="2"
|
||||||
|
app:showAsAction="ifRoom"/>
|
||||||
|
|
||||||
|
<item android:id="@+id/action_sources"
|
||||||
|
android:title="@string/menu_home_sources"
|
||||||
|
android:orderInCategory="97"
|
||||||
|
app:showAsAction="never"/>
|
||||||
|
|
||||||
|
<item android:id="@+id/action_settings"
|
||||||
|
android:title="@string/title_activity_settings"
|
||||||
|
android:orderInCategory="98"
|
||||||
|
app:showAsAction="never"/>
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/refresh"
|
android:id="@+id/refresh"
|
||||||
android:icon="@drawable/ic_menu_refresh_white_24dp"
|
app:showAsAction="never"
|
||||||
android:orderInCategory="99"
|
android:orderInCategory="101"
|
||||||
android:title="@string/menu_home_refresh" />
|
android:title="@string/menu_home_refresh" />
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/issue_tracker"
|
||||||
|
app:showAsAction="never"
|
||||||
|
android:orderInCategory="103"
|
||||||
|
android:title="@string/issue_tracker_link" />
|
||||||
|
|
||||||
<item android:id="@+id/action_disconnect"
|
<item android:id="@+id/action_disconnect"
|
||||||
android:title="@string/action_disconnect"
|
android:title="@string/action_disconnect"
|
||||||
android:orderInCategory="104"
|
android:orderInCategory="104"
|
||||||
|
@ -3,6 +3,13 @@
|
|||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/issue_tracker"
|
||||||
|
app:showAsAction="never"
|
||||||
|
android:orderInCategory="101"
|
||||||
|
android:title="@string/issue_tracker_link" />
|
||||||
|
|
||||||
<item android:id="@+id/about"
|
<item android:id="@+id/about"
|
||||||
android:title="@string/action_about"
|
android:title="@string/action_about"
|
||||||
android:orderInCategory="102"
|
android:orderInCategory="102"
|
||||||
|
@ -8,12 +8,6 @@
|
|||||||
android:title="@string/unmark"
|
android:title="@string/unmark"
|
||||||
app:showAsAction="ifRoom" />
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/more_action"
|
|
||||||
android:icon="@drawable/ic_chrome_reader_mode_white_24dp"
|
|
||||||
android:title="@string/reader_action_more"
|
|
||||||
app:showAsAction="ifRoom" />
|
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/open_action"
|
android:id="@+id/open_action"
|
||||||
android:icon="@drawable/ic_open_in_browser_white_24dp"
|
android:icon="@drawable/ic_open_in_browser_white_24dp"
|
||||||
|
16
androidApp/src/main/res/menu/reader_toolbar_no_read.xml
Normal file
16
androidApp/src/main/res/menu/reader_toolbar_no_read.xml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/open_action"
|
||||||
|
android:icon="@drawable/ic_open_in_browser_white_24dp"
|
||||||
|
android:title="@string/reader_action_open"
|
||||||
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/share_action"
|
||||||
|
android:icon="@drawable/ic_share_white_24dp"
|
||||||
|
android:title="@string/reader_action_share"
|
||||||
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
|
</menu>
|
@ -1,10 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/clear"
|
|
||||||
android:icon="@drawable/ic_history_white_24dp"
|
|
||||||
android:title="@string/drawer_action_clear"
|
|
||||||
app:showAsAction="ifRoom" />
|
|
||||||
</menu>
|
|
@ -10,7 +10,6 @@
|
|||||||
<string name="withLoginSwitch">"Autenticació (si és necessària)"</string>
|
<string name="withLoginSwitch">"Autenticació (si és necessària)"</string>
|
||||||
<string name="login_url_problem">"Pot ser que falti una \"/\" al final de l'url."</string>
|
<string name="login_url_problem">"Pot ser que falti una \"/\" al final de l'url."</string>
|
||||||
<string name="prompt_login">"Nom d'usuari"</string>
|
<string name="prompt_login">"Nom d'usuari"</string>
|
||||||
<string name="label_share">"Comparteix"</string>
|
|
||||||
<string name="readAll">"Llegeix-ho tot"</string>
|
<string name="readAll">"Llegeix-ho tot"</string>
|
||||||
<string name="action_disconnect">"Desconnecta't"</string>
|
<string name="action_disconnect">"Desconnecta't"</string>
|
||||||
<string name="title_activity_settings">"Configuració"</string>
|
<string name="title_activity_settings">"Configuració"</string>
|
||||||
@ -47,12 +46,9 @@
|
|||||||
<string name="switch_unread_count_title">"Recompte d'articles no llegits"</string>
|
<string name="switch_unread_count_title">"Recompte d'articles no llegits"</string>
|
||||||
<string name="display_all_counts_title">"Recompte d'articles llegits i preferits"</string>
|
<string name="display_all_counts_title">"Recompte d'articles llegits i preferits"</string>
|
||||||
<string name="text_wrong_url">"Sembla que esteu utilitzant un URL no vàlid. Assegureu-vos que és correcte, i si el problema persisteix, poseu-vos en contacte amb mi (a través de l'enllaç de contacte que hi ha a la Botiga). Tingueu en compte que per utilitzar aquesta aplicació cal que també utilitzeu Selfoss. Si no, no podreu accedir a canals RSS."</string>
|
<string name="text_wrong_url">"Sembla que esteu utilitzant un URL no vàlid. Assegureu-vos que és correcte, i si el problema persisteix, poseu-vos en contacte amb mi (a través de l'enllaç de contacte que hi ha a la Botiga). Tingueu en compte que per utilitzar aquesta aplicació cal que també utilitzeu Selfoss. Si no, no podreu accedir a canals RSS."</string>
|
||||||
<string name="pref_general_internal_browser_title">"Obre els enllaços dins de l'aplicació"</string>
|
<string name="pref_article_viewer_title">"Obre els enllaços dins de l'aplicació"</string>
|
||||||
<string name="pref_general_internal_browser_on">"Els articles s'obriran dins de l'aplicació"</string>
|
<string name="pref_article_viewer_on">"Els articles s'obriran dins de l'aplicació"</string>
|
||||||
<string name="pref_general_internal_browser_off">"Els articles s'obriran amb el navegador predeterminat"</string>
|
<string name="pref_article_viewer_off">"Els articles s'obriran amb el navegador predeterminat"</string>
|
||||||
<string name="prefer_article_viewer_title">"Obre el visualitzador d'articles"</string>
|
|
||||||
<string name="prefer_article_viewer_on">"S'obrirà el visualitzador d'articles en lloc del navegador intern"</string>
|
|
||||||
<string name="prefer_article_viewer_off">"S'obrirà el navegador intern en lloc del visualitzador d'articles"</string>
|
|
||||||
<string name="pref_general_category_links">"Gestió d'enllaços"</string>
|
<string name="pref_general_category_links">"Gestió d'enllaços"</string>
|
||||||
<string name="pref_general_category_displaying">"Visualització"</string>
|
<string name="pref_general_category_displaying">"Visualització"</string>
|
||||||
<string name="pref_switch_card_view_on">"Els articles es mostraran com a targetes"</string>
|
<string name="pref_switch_card_view_on">"Els articles es mostraran com a targetes"</string>
|
||||||
@ -65,28 +61,18 @@
|
|||||||
<string name="card_height_on">L\'alçada de les targetes s\'ajustarà al seu contingut</string>
|
<string name="card_height_on">L\'alçada de les targetes s\'ajustarà al seu contingut</string>
|
||||||
<string name="card_height_off">L\'alçada de les targetes serà fixa</string>
|
<string name="card_height_off">L\'alçada de les targetes serà fixa</string>
|
||||||
<string name="source_code">Codi font</string>
|
<string name="source_code">Codi font</string>
|
||||||
<string name="drawer_error_loading_tags">S\'ha produït un error en carregar les etiquetes</string>
|
<string name="filter_item_tags">Etiquetes</string>
|
||||||
<string name="drawer_item_filters">Filtres</string>
|
<string name="filter_item_sources">Fonts</string>
|
||||||
<string name="drawer_action_clear">Esborra</string>
|
|
||||||
<string name="drawer_item_tags">Etiquetes</string>
|
|
||||||
<string name="drawer_item_sources">Fonts</string>
|
|
||||||
<string name="drawer_action_edit">Edita</string>
|
|
||||||
<string name="drawer_loading">S\'està carregant…</string>
|
|
||||||
<string name="menu_home_search">Cerca</string>
|
<string name="menu_home_search">Cerca</string>
|
||||||
<string name="can_delete_source">No es pot suprimir la font</string>
|
<string name="can_delete_source">No es pot suprimir la font</string>
|
||||||
<string name="base_url_error">S\'ha produït un error en comunicar-se amb la instància de Selfoss. Si el problema persisteix, posa\'t en contacte amb mi.</string>
|
<string name="base_url_error">S\'ha produït un error en comunicar-se amb la instància de Selfoss. Si el problema persisteix, posa\'t en contacte amb mi.</string>
|
||||||
<string name="pref_header_theme">Temes</string>
|
<string name="pref_header_theme">Temes</string>
|
||||||
<string name="default_theme">Predeterminat</string>
|
|
||||||
<string name="default_dark_theme">Predeterminat/Fosc</string>
|
|
||||||
<string name="pref_selfoss_category">API de Selfoss</string>
|
<string name="pref_selfoss_category">API de Selfoss</string>
|
||||||
<string name="pref_api_items_number_title">Nombre d\'elements carregats</string>
|
<string name="pref_api_items_number_title">Nombre d\'elements carregats</string>
|
||||||
<string name="pref_hidden_tags">Etiquetes ocultes</string>
|
|
||||||
<string name="pref_general_infinite_loading_title">Carrega articles en desplaçar</string>
|
<string name="pref_general_infinite_loading_title">Carrega articles en desplaçar</string>
|
||||||
<string name="translation">Traducció</string>
|
<string name="translation">Traducció</string>
|
||||||
<string name="cant_open_invalid_url">L\'element URL no és vàlid. Estic intentant solucionar aquest problema perquè l\'aplicació no falli.</string>
|
<string name="cant_open_invalid_url">L\'element URL no és vàlid. Estic intentant solucionar aquest problema perquè l\'aplicació no falli.</string>
|
||||||
<string name="drawer_report_bug">Informa d\'un error</string>
|
|
||||||
<string name="items_number_should_be_number">El nombre d\'elements ha de ser enter.</string>
|
<string name="items_number_should_be_number">El nombre d\'elements ha de ser enter.</string>
|
||||||
<string name="reader_action_more">Més informació</string>
|
|
||||||
<string name="reader_action_open">Obre al navegador</string>
|
<string name="reader_action_open">Obre al navegador</string>
|
||||||
<string name="reader_action_share">Comparteix</string>
|
<string name="reader_action_share">Comparteix</string>
|
||||||
<string name="pref_switch_actions_pager_scroll_on">Es marcaran els articles com a llegits en lliscar el dit d\'un article a l\'altre.</string>
|
<string name="pref_switch_actions_pager_scroll_on">Es marcaran els articles com a llegits en lliscar el dit d\'un article a l\'altre.</string>
|
||||||
@ -97,7 +83,6 @@
|
|||||||
<string name="markall_dialog_message">Aquesta acció marcarà els elements com a llegits.</string>
|
<string name="markall_dialog_message">Aquesta acció marcarà els elements com a llegits.</string>
|
||||||
<string name="pref_switch_actions_pager_scroll">Marca com a llegit en lliscar el dit</string>
|
<string name="pref_switch_actions_pager_scroll">Marca com a llegit en lliscar el dit</string>
|
||||||
<string name="pref_switch_actions_pager_scroll_off">No es marcaran els articles com a llegits en lliscar el dit d\'un article a l\'altre.</string>
|
<string name="pref_switch_actions_pager_scroll_off">No es marcaran els articles com a llegits en lliscar el dit d\'un article a l\'altre.</string>
|
||||||
<string name="drawer_item_hidden_tags">Etiquetes ocultes</string>
|
|
||||||
<string name="unmark">Marca com no llegit</string>
|
<string name="unmark">Marca com no llegit</string>
|
||||||
<string name="pref_header_offline">Sense connexió i memòria clau</string>
|
<string name="pref_header_offline">Sense connexió i memòria clau</string>
|
||||||
<string name="pref_switch_items_caching_off">Els articles no es guardaran a la memòria del dispositiu i l\'aplicació no es podrà utilitzar sense connexió.</string>
|
<string name="pref_switch_items_caching_off">Els articles no es guardaran a la memòria del dispositiu i l\'aplicació no es podrà utilitzar sense connexió.</string>
|
||||||
@ -112,7 +97,7 @@
|
|||||||
<string name="pref_switch_periodic_refresh_on">Els articles se sincronitzaran periòdicament</string>
|
<string name="pref_switch_periodic_refresh_on">Els articles se sincronitzaran periòdicament</string>
|
||||||
<string name="pref_periodic_refresh_minutes_title"><![CDATA[Interval de sincronització ( >= 15 minuts)]]></string>
|
<string name="pref_periodic_refresh_minutes_title"><![CDATA[Interval de sincronització ( >= 15 minuts)]]></string>
|
||||||
<string name="pref_switch_refresh_when_charging">Sincronitza només quan el telèfon s\'està carregant</string>
|
<string name="pref_switch_refresh_when_charging">Sincronitza només quan el telèfon s\'està carregant</string>
|
||||||
<string name="loading_notification_title">S\'està carregant...</string>
|
<string name="loading_notification_title">S\'està carregant…</string>
|
||||||
<string name="loading_notification_text">Selfoss està sincronitzant els articles</string>
|
<string name="loading_notification_text">Selfoss està sincronitzant els articles</string>
|
||||||
<string name="notification_channel_sync">Notificació de sincronització</string>
|
<string name="notification_channel_sync">Notificació de sincronització</string>
|
||||||
<string name="new_items_channel_sync">Notificació d\'elements nous</string>
|
<string name="new_items_channel_sync">Notificació d\'elements nous</string>
|
||||||
@ -131,4 +116,19 @@
|
|||||||
<string name="reader_static_bar_on">The bottom bar will always be displayed</string>
|
<string name="reader_static_bar_on">The bottom bar will always be displayed</string>
|
||||||
<string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string>
|
<string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string>
|
||||||
<string name="remove_source">Remove source</string>
|
<string name="remove_source">Remove source</string>
|
||||||
|
<string name="pref_theme_title">Light/Dark mode</string>
|
||||||
|
<string name="mode_dark">Dark mode</string>
|
||||||
|
<string name="mode_system">Follow the system setting</string>
|
||||||
|
<string name="mode_light">Light mode</string>
|
||||||
|
<string name="gdpr_dialog_title">The app does not share any personal data about you.</string>
|
||||||
|
<string name="gdpr_dialog_message"><![CDATA[Crash reports sending is now enabled. It can be disabled from the settings page. Keep in mind that crash reports are essential for the app development.]]></string>
|
||||||
|
<string name="crash_toast_text">A crash occured. Sending the details to the developper.</string>
|
||||||
|
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
|
||||||
|
<string name="menu_home_filter">Filters</string>
|
||||||
|
<string name="application_selfoss_only">This app only works with a Selfoss instance, and no other RSS feed.</string>
|
||||||
|
<string name="menu_home_sources">Sources</string>
|
||||||
|
<string name="update_source">Update source</string>
|
||||||
|
<string name="confirm_disconnect_title">Disconnect ?</string>
|
||||||
|
<string name="confirm_disconnect_description">You will be disconnected from your selfoss instance.</string>
|
||||||
|
<string name="disable_ssl">Disable SSL</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
<string name="withLoginSwitch">"Anmeldung erforderlich?"</string>
|
<string name="withLoginSwitch">"Anmeldung erforderlich?"</string>
|
||||||
<string name="login_url_problem">"Ups. Du musst eventuell ein \"/\" am Ende der URL anhängen."</string>
|
<string name="login_url_problem">"Ups. Du musst eventuell ein \"/\" am Ende der URL anhängen."</string>
|
||||||
<string name="prompt_login">"Benutzername"</string>
|
<string name="prompt_login">"Benutzername"</string>
|
||||||
<string name="label_share">"Teilen"</string>
|
|
||||||
<string name="readAll">"Alle gelesen"</string>
|
<string name="readAll">"Alle gelesen"</string>
|
||||||
<string name="action_disconnect">"Verbindung trennen"</string>
|
<string name="action_disconnect">"Verbindung trennen"</string>
|
||||||
<string name="title_activity_settings">"Einstellungen"</string>
|
<string name="title_activity_settings">"Einstellungen"</string>
|
||||||
@ -47,12 +46,9 @@
|
|||||||
<string name="switch_unread_count_title">"Zeige Anzahl ungelesener Artikel"</string>
|
<string name="switch_unread_count_title">"Zeige Anzahl ungelesener Artikel"</string>
|
||||||
<string name="display_all_counts_title">"Zeige Anzahl der Favoriten und gelesenen Artikel"</string>
|
<string name="display_all_counts_title">"Zeige Anzahl der Favoriten und gelesenen Artikel"</string>
|
||||||
<string name="text_wrong_url">"Sie scheinen eine ungültige URL verwenden. Stellen Sie sicher, dass die URL richtig ist. Sollte das Problem weiterhin bestehen kontaktieren Sie mich (über den Playstore-Kontakt-Link). Bitte beachten Sie, dass Sie Selfoss benötigen um RSS-Feeds zu lesen."</string>
|
<string name="text_wrong_url">"Sie scheinen eine ungültige URL verwenden. Stellen Sie sicher, dass die URL richtig ist. Sollte das Problem weiterhin bestehen kontaktieren Sie mich (über den Playstore-Kontakt-Link). Bitte beachten Sie, dass Sie Selfoss benötigen um RSS-Feeds zu lesen."</string>
|
||||||
<string name="pref_general_internal_browser_title">"Öffne Links innerhalb der App"</string>
|
<string name="pref_article_viewer_title">"Öffne Links innerhalb der App"</string>
|
||||||
<string name="pref_general_internal_browser_on">"Artikel werden innerhalb der App geöffnet"</string>
|
<string name="pref_article_viewer_on">"Artikel werden innerhalb der App geöffnet"</string>
|
||||||
<string name="pref_general_internal_browser_off">"Artikel werden mit deinem Standard-Browser geöffnet"</string>
|
<string name="pref_article_viewer_off">"Artikel werden mit deinem Standard-Browser geöffnet"</string>
|
||||||
<string name="prefer_article_viewer_title">"Verwenden Sie den Artikel-viewer"</string>
|
|
||||||
<string name="prefer_article_viewer_on">"Artikel-Viewer wird anstelle des internen Browser verwendet"</string>
|
|
||||||
<string name="prefer_article_viewer_off">"Der internen Browser wird anstelle des Artikel-Viewer verwendet"</string>
|
|
||||||
<string name="pref_general_category_links">"Umgang mit Links"</string>
|
<string name="pref_general_category_links">"Umgang mit Links"</string>
|
||||||
<string name="pref_general_category_displaying">"Ansicht"</string>
|
<string name="pref_general_category_displaying">"Ansicht"</string>
|
||||||
<string name="pref_switch_card_view_on">"Artikel werden als Kacheln angezeigt"</string>
|
<string name="pref_switch_card_view_on">"Artikel werden als Kacheln angezeigt"</string>
|
||||||
@ -65,28 +61,18 @@
|
|||||||
<string name="card_height_on">Kartenhöhe passt sich Inhalt an</string>
|
<string name="card_height_on">Kartenhöhe passt sich Inhalt an</string>
|
||||||
<string name="card_height_off">Kartenhöhe ist fix</string>
|
<string name="card_height_off">Kartenhöhe ist fix</string>
|
||||||
<string name="source_code">Quellcode</string>
|
<string name="source_code">Quellcode</string>
|
||||||
<string name="drawer_error_loading_tags">Fehler beim Laden der Tags…</string>
|
<string name="filter_item_tags">Tags</string>
|
||||||
<string name="drawer_item_filters">Filter</string>
|
<string name="filter_item_sources">Quellen</string>
|
||||||
<string name="drawer_action_clear">leeren</string>
|
|
||||||
<string name="drawer_item_tags">Tags</string>
|
|
||||||
<string name="drawer_item_sources">Quellen</string>
|
|
||||||
<string name="drawer_action_edit">bearbeiten</string>
|
|
||||||
<string name="drawer_loading">Lade…</string>
|
|
||||||
<string name="menu_home_search">Suche</string>
|
<string name="menu_home_search">Suche</string>
|
||||||
<string name="can_delete_source">Can\'t delete the source…</string>
|
<string name="can_delete_source">Can\'t delete the source…</string>
|
||||||
<string name="base_url_error">Beim Versuch deine Selfoss-Instanz zu erreichen ist ein Fehler aufgetreten. Solltet dieser Fehler bestehen bleiben, trete bitte mit mir in Kontakt.</string>
|
<string name="base_url_error">Beim Versuch deine Selfoss-Instanz zu erreichen ist ein Fehler aufgetreten. Solltet dieser Fehler bestehen bleiben, trete bitte mit mir in Kontakt.</string>
|
||||||
<string name="pref_header_theme">Designs</string>
|
<string name="pref_header_theme">Designs</string>
|
||||||
<string name="default_theme">Standard</string>
|
|
||||||
<string name="default_dark_theme">Standard (Dunkel)</string>
|
|
||||||
<string name="pref_selfoss_category">selfoss API</string>
|
<string name="pref_selfoss_category">selfoss API</string>
|
||||||
<string name="pref_api_items_number_title">Loaded items number</string>
|
<string name="pref_api_items_number_title">Loaded items number</string>
|
||||||
<string name="pref_hidden_tags">Hidden Tags</string>
|
|
||||||
<string name="pref_general_infinite_loading_title">Load more articles on scroll</string>
|
<string name="pref_general_infinite_loading_title">Load more articles on scroll</string>
|
||||||
<string name="translation">Übersetzung</string>
|
<string name="translation">Übersetzung</string>
|
||||||
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
|
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
|
||||||
<string name="drawer_report_bug">Melde einen Fehler</string>
|
|
||||||
<string name="items_number_should_be_number">The items number should be an integer.</string>
|
<string name="items_number_should_be_number">The items number should be an integer.</string>
|
||||||
<string name="reader_action_more">Read more</string>
|
|
||||||
<string name="reader_action_open">Im Browser öffnen</string>
|
<string name="reader_action_open">Im Browser öffnen</string>
|
||||||
<string name="reader_action_share">Teilen</string>
|
<string name="reader_action_share">Teilen</string>
|
||||||
<string name="pref_switch_actions_pager_scroll_on">Mark articles as read when swiping between articles.</string>
|
<string name="pref_switch_actions_pager_scroll_on">Mark articles as read when swiping between articles.</string>
|
||||||
@ -97,7 +83,6 @@
|
|||||||
<string name="markall_dialog_message">Dies wird alle Elemente als gelesen markieren.</string>
|
<string name="markall_dialog_message">Dies wird alle Elemente als gelesen markieren.</string>
|
||||||
<string name="pref_switch_actions_pager_scroll">Beim Wischen als gelesen markieren</string>
|
<string name="pref_switch_actions_pager_scroll">Beim Wischen als gelesen markieren</string>
|
||||||
<string name="pref_switch_actions_pager_scroll_off">Don\'t mark articles as read when swiping.</string>
|
<string name="pref_switch_actions_pager_scroll_off">Don\'t mark articles as read when swiping.</string>
|
||||||
<string name="drawer_item_hidden_tags">Hidden Tags</string>
|
|
||||||
<string name="unmark">Eintrag als ungelesen markieren</string>
|
<string name="unmark">Eintrag als ungelesen markieren</string>
|
||||||
<string name="pref_header_offline">Offline and cache</string>
|
<string name="pref_header_offline">Offline and cache</string>
|
||||||
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
|
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
|
||||||
@ -112,7 +97,7 @@
|
|||||||
<string name="pref_switch_periodic_refresh_on">Die Artikel werden regelmäßig synchronisiert</string>
|
<string name="pref_switch_periodic_refresh_on">Die Artikel werden regelmäßig synchronisiert</string>
|
||||||
<string name="pref_periodic_refresh_minutes_title"><![CDATA[Sync interval ( >= 15 minutes)]]></string>
|
<string name="pref_periodic_refresh_minutes_title"><![CDATA[Sync interval ( >= 15 minutes)]]></string>
|
||||||
<string name="pref_switch_refresh_when_charging">Nur aktualisieren, wenn das Telefon aufgeladen wird</string>
|
<string name="pref_switch_refresh_when_charging">Nur aktualisieren, wenn das Telefon aufgeladen wird</string>
|
||||||
<string name="loading_notification_title">Lädt...</string>
|
<string name="loading_notification_title">Lädt…</string>
|
||||||
<string name="loading_notification_text">Selfoss synchronisiert Ihre Artikel</string>
|
<string name="loading_notification_text">Selfoss synchronisiert Ihre Artikel</string>
|
||||||
<string name="notification_channel_sync">Sync notification</string>
|
<string name="notification_channel_sync">Sync notification</string>
|
||||||
<string name="new_items_channel_sync">New items notification</string>
|
<string name="new_items_channel_sync">New items notification</string>
|
||||||
@ -131,4 +116,19 @@
|
|||||||
<string name="reader_static_bar_on">The bottom bar will always be displayed</string>
|
<string name="reader_static_bar_on">The bottom bar will always be displayed</string>
|
||||||
<string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string>
|
<string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string>
|
||||||
<string name="remove_source">Remove source</string>
|
<string name="remove_source">Remove source</string>
|
||||||
|
<string name="pref_theme_title">Light/Dark mode</string>
|
||||||
|
<string name="mode_dark">Dark mode</string>
|
||||||
|
<string name="mode_system">Follow the system setting</string>
|
||||||
|
<string name="mode_light">Light mode</string>
|
||||||
|
<string name="gdpr_dialog_title">The app does not share any personal data about you.</string>
|
||||||
|
<string name="gdpr_dialog_message"><![CDATA[Crash reports sending is now enabled. It can be disabled from the settings page. Keep in mind that crash reports are essential for the app development.]]></string>
|
||||||
|
<string name="crash_toast_text">A crash occured. Sending the details to the developper.</string>
|
||||||
|
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
|
||||||
|
<string name="menu_home_filter">Filters</string>
|
||||||
|
<string name="application_selfoss_only">This app only works with a Selfoss instance, and no other RSS feed.</string>
|
||||||
|
<string name="menu_home_sources">Sources</string>
|
||||||
|
<string name="update_source">Update source</string>
|
||||||
|
<string name="confirm_disconnect_title">Disconnect ?</string>
|
||||||
|
<string name="confirm_disconnect_description">You will be disconnected from your selfoss instance.</string>
|
||||||
|
<string name="disable_ssl">Disable SSL</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
<string name="withLoginSwitch">"Inicio de sesión requerido ?"</string>
|
<string name="withLoginSwitch">"Inicio de sesión requerido ?"</string>
|
||||||
<string name="login_url_problem">"Oops. Puede que necesite añadir un \"/\" al final de la url."</string>
|
<string name="login_url_problem">"Oops. Puede que necesite añadir un \"/\" al final de la url."</string>
|
||||||
<string name="prompt_login">"Nombre de usuario"</string>
|
<string name="prompt_login">"Nombre de usuario"</string>
|
||||||
<string name="label_share">"Compartir"</string>
|
|
||||||
<string name="readAll">"Leer todo"</string>
|
<string name="readAll">"Leer todo"</string>
|
||||||
<string name="action_disconnect">"Desconectar"</string>
|
<string name="action_disconnect">"Desconectar"</string>
|
||||||
<string name="title_activity_settings">"Configuración"</string>
|
<string name="title_activity_settings">"Configuración"</string>
|
||||||
@ -47,12 +46,9 @@
|
|||||||
<string name="switch_unread_count_title">"Mostrar recuento no leído"</string>
|
<string name="switch_unread_count_title">"Mostrar recuento no leído"</string>
|
||||||
<string name="display_all_counts_title">"Mostrar recuento de favoritos y leídos"</string>
|
<string name="display_all_counts_title">"Mostrar recuento de favoritos y leídos"</string>
|
||||||
<string name="text_wrong_url">"Parece estar tratando de utilizar una dirección URL inválida. Asegúrese de que sea correcta y si el problema persiste, póngase en contacto conmigo (mediante el enlace de contacto de la tienda). Tenga en cuenta que la aplicación necesita utilizar Selfoss. No se puede acceder al contenido RSS sin él."</string>
|
<string name="text_wrong_url">"Parece estar tratando de utilizar una dirección URL inválida. Asegúrese de que sea correcta y si el problema persiste, póngase en contacto conmigo (mediante el enlace de contacto de la tienda). Tenga en cuenta que la aplicación necesita utilizar Selfoss. No se puede acceder al contenido RSS sin él."</string>
|
||||||
<string name="pref_general_internal_browser_title">"Abrir enlaces dentro de la aplicación"</string>
|
<string name="pref_article_viewer_title">"Abrir enlaces dentro de la aplicación"</string>
|
||||||
<string name="pref_general_internal_browser_on">"Los artículos se abrirán dentro de la aplicación"</string>
|
<string name="pref_article_viewer_on">"Los artículos se abrirán dentro de la aplicación"</string>
|
||||||
<string name="pref_general_internal_browser_off">"Los artículos se abrirán con tu navegador predeterminado"</string>
|
<string name="pref_article_viewer_off">"Los artículos se abrirán con tu navegador predeterminado"</string>
|
||||||
<string name="prefer_article_viewer_title">"Utilizar el visor de artículo"</string>
|
|
||||||
<string name="prefer_article_viewer_on">"Se usará el visor de artículos en lugar del navegador interno"</string>
|
|
||||||
<string name="prefer_article_viewer_off">"Se utilizará el navegador interno en lugar del visor de artículo"</string>
|
|
||||||
<string name="pref_general_category_links">"Control de enlaces"</string>
|
<string name="pref_general_category_links">"Control de enlaces"</string>
|
||||||
<string name="pref_general_category_displaying">"Mostrando"</string>
|
<string name="pref_general_category_displaying">"Mostrando"</string>
|
||||||
<string name="pref_switch_card_view_on">"Los artículos se mostrarán como tarjetas"</string>
|
<string name="pref_switch_card_view_on">"Los artículos se mostrarán como tarjetas"</string>
|
||||||
@ -65,28 +61,18 @@
|
|||||||
<string name="card_height_on">Altura de tarjetas se ajustará a su contenido</string>
|
<string name="card_height_on">Altura de tarjetas se ajustará a su contenido</string>
|
||||||
<string name="card_height_off">Se fijará la altura de la tarjeta</string>
|
<string name="card_height_off">Se fijará la altura de la tarjeta</string>
|
||||||
<string name="source_code">Código fuente</string>
|
<string name="source_code">Código fuente</string>
|
||||||
<string name="drawer_error_loading_tags">Error al cargar etiquetas…</string>
|
<string name="filter_item_tags">Etiquetas</string>
|
||||||
<string name="drawer_item_filters">Filtros</string>
|
<string name="filter_item_sources">Fuentes</string>
|
||||||
<string name="drawer_action_clear">limpiar</string>
|
|
||||||
<string name="drawer_item_tags">Etiquetas</string>
|
|
||||||
<string name="drawer_item_sources">Fuentes</string>
|
|
||||||
<string name="drawer_action_edit">editar</string>
|
|
||||||
<string name="drawer_loading">Cargando…</string>
|
|
||||||
<string name="menu_home_search">Buscar</string>
|
<string name="menu_home_search">Buscar</string>
|
||||||
<string name="can_delete_source">No se puede eliminar la fuente…</string>
|
<string name="can_delete_source">No se puede eliminar la fuente…</string>
|
||||||
<string name="base_url_error">Hubo un problema al intentar comunicarse con su instancia de Selfoss. Si el problema persiste, póngase en contacto conmigo.</string>
|
<string name="base_url_error">Hubo un problema al intentar comunicarse con su instancia de Selfoss. Si el problema persiste, póngase en contacto conmigo.</string>
|
||||||
<string name="pref_header_theme">Temas</string>
|
<string name="pref_header_theme">Temas</string>
|
||||||
<string name="default_theme">Predeterminado</string>
|
|
||||||
<string name="default_dark_theme">Predeterminado/Oscuro</string>
|
|
||||||
<string name="pref_selfoss_category">Api de Selfoss</string>
|
<string name="pref_selfoss_category">Api de Selfoss</string>
|
||||||
<string name="pref_api_items_number_title">Número de artículos cargados</string>
|
<string name="pref_api_items_number_title">Número de artículos cargados</string>
|
||||||
<string name="pref_hidden_tags">Etiquetas ocultas</string>
|
|
||||||
<string name="pref_general_infinite_loading_title">Cargar más artículos en desplazamiento</string>
|
<string name="pref_general_infinite_loading_title">Cargar más artículos en desplazamiento</string>
|
||||||
<string name="translation">Traducción</string>
|
<string name="translation">Traducción</string>
|
||||||
<string name="cant_open_invalid_url">La url del elemento no es válida. Estoy buscando resolver este problema para que la aplicación no colapse.</string>
|
<string name="cant_open_invalid_url">La url del elemento no es válida. Estoy buscando resolver este problema para que la aplicación no colapse.</string>
|
||||||
<string name="drawer_report_bug">Reportar un error</string>
|
|
||||||
<string name="items_number_should_be_number">El número de artículos debe ser un número entero.</string>
|
<string name="items_number_should_be_number">El número de artículos debe ser un número entero.</string>
|
||||||
<string name="reader_action_more">Leer más</string>
|
|
||||||
<string name="reader_action_open">Abrir en el navegador</string>
|
<string name="reader_action_open">Abrir en el navegador</string>
|
||||||
<string name="reader_action_share">Compartir</string>
|
<string name="reader_action_share">Compartir</string>
|
||||||
<string name="pref_switch_actions_pager_scroll_on">Marcar artículos como leidos al desplazarse entre ellos.</string>
|
<string name="pref_switch_actions_pager_scroll_on">Marcar artículos como leidos al desplazarse entre ellos.</string>
|
||||||
@ -97,7 +83,6 @@
|
|||||||
<string name="markall_dialog_message">Esto marcará todos los artículos como leídos.</string>
|
<string name="markall_dialog_message">Esto marcará todos los artículos como leídos.</string>
|
||||||
<string name="pref_switch_actions_pager_scroll">Marcar artículos como leídos al deslizar con el dedo hacia los lados</string>
|
<string name="pref_switch_actions_pager_scroll">Marcar artículos como leídos al deslizar con el dedo hacia los lados</string>
|
||||||
<string name="pref_switch_actions_pager_scroll_off">No marcar artículos como leídos al deslizar con el dedo hacia los lados.</string>
|
<string name="pref_switch_actions_pager_scroll_off">No marcar artículos como leídos al deslizar con el dedo hacia los lados.</string>
|
||||||
<string name="drawer_item_hidden_tags">Etiquetas ocultas</string>
|
|
||||||
<string name="unmark">Marcar artículo como no leído</string>
|
<string name="unmark">Marcar artículo como no leído</string>
|
||||||
<string name="pref_header_offline">Sin conexión y caché</string>
|
<string name="pref_header_offline">Sin conexión y caché</string>
|
||||||
<string name="pref_switch_items_caching_off">Los artículos no se guardarán en la memoria del dispositivo y la aplicación no se podrá utilizar sin conexión.</string>
|
<string name="pref_switch_items_caching_off">Los artículos no se guardarán en la memoria del dispositivo y la aplicación no se podrá utilizar sin conexión.</string>
|
||||||
@ -112,7 +97,7 @@
|
|||||||
<string name="pref_switch_periodic_refresh_on">Los artículos se sincronizarán periódicamente</string>
|
<string name="pref_switch_periodic_refresh_on">Los artículos se sincronizarán periódicamente</string>
|
||||||
<string name="pref_periodic_refresh_minutes_title"><![CDATA[Intervalo de sincronización (>= 15 minutos)]]></string>
|
<string name="pref_periodic_refresh_minutes_title"><![CDATA[Intervalo de sincronización (>= 15 minutos)]]></string>
|
||||||
<string name="pref_switch_refresh_when_charging">Sólo refrescar cuando el teléfono está cargando</string>
|
<string name="pref_switch_refresh_when_charging">Sólo refrescar cuando el teléfono está cargando</string>
|
||||||
<string name="loading_notification_title">Cargando...</string>
|
<string name="loading_notification_title">Cargando…</string>
|
||||||
<string name="loading_notification_text">Selfoss está sincronizando tus artículos</string>
|
<string name="loading_notification_text">Selfoss está sincronizando tus artículos</string>
|
||||||
<string name="notification_channel_sync">Notificación de sincronización</string>
|
<string name="notification_channel_sync">Notificación de sincronización</string>
|
||||||
<string name="new_items_channel_sync">Notificación de elementos nuevos</string>
|
<string name="new_items_channel_sync">Notificación de elementos nuevos</string>
|
||||||
@ -131,4 +116,19 @@
|
|||||||
<string name="reader_static_bar_on">The bottom bar will always be displayed</string>
|
<string name="reader_static_bar_on">The bottom bar will always be displayed</string>
|
||||||
<string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string>
|
<string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string>
|
||||||
<string name="remove_source">Remove source</string>
|
<string name="remove_source">Remove source</string>
|
||||||
|
<string name="pref_theme_title">Light/Dark mode</string>
|
||||||
|
<string name="mode_dark">Dark mode</string>
|
||||||
|
<string name="mode_system">Follow the system setting</string>
|
||||||
|
<string name="mode_light">Light mode</string>
|
||||||
|
<string name="gdpr_dialog_title">The app does not share any personal data about you.</string>
|
||||||
|
<string name="gdpr_dialog_message"><![CDATA[Crash reports sending is now enabled. It can be disabled from the settings page. Keep in mind that crash reports are essential for the app development.]]></string>
|
||||||
|
<string name="crash_toast_text">A crash occured. Sending the details to the developper.</string>
|
||||||
|
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
|
||||||
|
<string name="menu_home_filter">Filters</string>
|
||||||
|
<string name="application_selfoss_only">This app only works with a Selfoss instance, and no other RSS feed.</string>
|
||||||
|
<string name="menu_home_sources">Sources</string>
|
||||||
|
<string name="update_source">Update source</string>
|
||||||
|
<string name="confirm_disconnect_title">Disconnect ?</string>
|
||||||
|
<string name="confirm_disconnect_description">You will be disconnected from your selfoss instance.</string>
|
||||||
|
<string name="disable_ssl">Disable SSL</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
<string name="withLoginSwitch">"Login required ?"</string>
|
<string name="withLoginSwitch">"Login required ?"</string>
|
||||||
<string name="login_url_problem">"Oops. You may need to add a \"/\" at the end of the url."</string>
|
<string name="login_url_problem">"Oops. You may need to add a \"/\" at the end of the url."</string>
|
||||||
<string name="prompt_login">"Username"</string>
|
<string name="prompt_login">"Username"</string>
|
||||||
<string name="label_share">"Share"</string>
|
|
||||||
<string name="readAll">"Read all"</string>
|
<string name="readAll">"Read all"</string>
|
||||||
<string name="action_disconnect">"Disconnect"</string>
|
<string name="action_disconnect">"Disconnect"</string>
|
||||||
<string name="title_activity_settings">"Settings"</string>
|
<string name="title_activity_settings">"Settings"</string>
|
||||||
@ -47,12 +46,9 @@
|
|||||||
<string name="switch_unread_count_title">"Display unread count"</string>
|
<string name="switch_unread_count_title">"Display unread count"</string>
|
||||||
<string name="display_all_counts_title">"Display count for favorite and read"</string>
|
<string name="display_all_counts_title">"Display count for favorite and read"</string>
|
||||||
<string name="text_wrong_url">"You seem to be trying to use an invalid URL. Make sure it is correct, and if the problem persists, contact me (via the store contact link). Please note that the app needs you to be using Selfoss. You can't access RSS feeds without it."</string>
|
<string name="text_wrong_url">"You seem to be trying to use an invalid URL. Make sure it is correct, and if the problem persists, contact me (via the store contact link). Please note that the app needs you to be using Selfoss. You can't access RSS feeds without it."</string>
|
||||||
<string name="pref_general_internal_browser_title">"Open links inside the app"</string>
|
<string name="pref_article_viewer_title">"Open links inside the app"</string>
|
||||||
<string name="pref_general_internal_browser_on">"Articles will open inside the app"</string>
|
<string name="pref_article_viewer_on">"Articles will open inside the app"</string>
|
||||||
<string name="pref_general_internal_browser_off">"Articles will open with your default browser"</string>
|
<string name="pref_article_viewer_off">"Articles will open with your default browser"</string>
|
||||||
<string name="prefer_article_viewer_title">"Use the article viewer"</string>
|
|
||||||
<string name="prefer_article_viewer_on">"Will use the article viewer instead of the internal browser"</string>
|
|
||||||
<string name="prefer_article_viewer_off">"Will use the internal browser instead of the article viewer"</string>
|
|
||||||
<string name="pref_general_category_links">"Link handling"</string>
|
<string name="pref_general_category_links">"Link handling"</string>
|
||||||
<string name="pref_general_category_displaying">"Displaying"</string>
|
<string name="pref_general_category_displaying">"Displaying"</string>
|
||||||
<string name="pref_switch_card_view_on">"The articles will be displayed as cards"</string>
|
<string name="pref_switch_card_view_on">"The articles will be displayed as cards"</string>
|
||||||
@ -65,28 +61,18 @@
|
|||||||
<string name="card_height_on">Cards height will adjust to its content</string>
|
<string name="card_height_on">Cards height will adjust to its content</string>
|
||||||
<string name="card_height_off">Card height will be fixed</string>
|
<string name="card_height_off">Card height will be fixed</string>
|
||||||
<string name="source_code">Source code</string>
|
<string name="source_code">Source code</string>
|
||||||
<string name="drawer_error_loading_tags">Error loading tags…</string>
|
<string name="filter_item_tags">Tags</string>
|
||||||
<string name="drawer_item_filters">Filters</string>
|
<string name="filter_item_sources">Sources</string>
|
||||||
<string name="drawer_action_clear">clear</string>
|
|
||||||
<string name="drawer_item_tags">Tags</string>
|
|
||||||
<string name="drawer_item_sources">Sources</string>
|
|
||||||
<string name="drawer_action_edit">edit</string>
|
|
||||||
<string name="drawer_loading">Loading …</string>
|
|
||||||
<string name="menu_home_search">Search</string>
|
<string name="menu_home_search">Search</string>
|
||||||
<string name="can_delete_source">Can\'t delete the source…</string>
|
<string name="can_delete_source">Can\'t delete the source…</string>
|
||||||
<string name="base_url_error">There was an issue when trying to communicate with your Selfoss Instance. If the issue persists, please get in touch with me.</string>
|
<string name="base_url_error">There was an issue when trying to communicate with your Selfoss Instance. If the issue persists, please get in touch with me.</string>
|
||||||
<string name="pref_header_theme">Themes</string>
|
<string name="pref_header_theme">Themes</string>
|
||||||
<string name="default_theme">Default</string>
|
|
||||||
<string name="default_dark_theme">Default/Dark</string>
|
|
||||||
<string name="pref_selfoss_category">Selfoss Api</string>
|
<string name="pref_selfoss_category">Selfoss Api</string>
|
||||||
<string name="pref_api_items_number_title">Loaded items number</string>
|
<string name="pref_api_items_number_title">Loaded items number</string>
|
||||||
<string name="pref_hidden_tags">Hidden Tags</string>
|
|
||||||
<string name="pref_general_infinite_loading_title">Load more articles on scroll</string>
|
<string name="pref_general_infinite_loading_title">Load more articles on scroll</string>
|
||||||
<string name="translation">Translation</string>
|
<string name="translation">Translation</string>
|
||||||
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
|
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
|
||||||
<string name="drawer_report_bug">Report a bug</string>
|
|
||||||
<string name="items_number_should_be_number">The items number should be an integer.</string>
|
<string name="items_number_should_be_number">The items number should be an integer.</string>
|
||||||
<string name="reader_action_more">Read more</string>
|
|
||||||
<string name="reader_action_open">Open in browser</string>
|
<string name="reader_action_open">Open in browser</string>
|
||||||
<string name="reader_action_share">Share</string>
|
<string name="reader_action_share">Share</string>
|
||||||
<string name="pref_switch_actions_pager_scroll_on">Mark articles as read when swiping between articles.</string>
|
<string name="pref_switch_actions_pager_scroll_on">Mark articles as read when swiping between articles.</string>
|
||||||
@ -97,7 +83,6 @@
|
|||||||
<string name="markall_dialog_message">This will mark all the items as read.</string>
|
<string name="markall_dialog_message">This will mark all the items as read.</string>
|
||||||
<string name="pref_switch_actions_pager_scroll">Mark as read on swipe</string>
|
<string name="pref_switch_actions_pager_scroll">Mark as read on swipe</string>
|
||||||
<string name="pref_switch_actions_pager_scroll_off">Don\'t mark articles as read when swiping.</string>
|
<string name="pref_switch_actions_pager_scroll_off">Don\'t mark articles as read when swiping.</string>
|
||||||
<string name="drawer_item_hidden_tags">Hidden Tags</string>
|
|
||||||
<string name="unmark">Mark item as unread</string>
|
<string name="unmark">Mark item as unread</string>
|
||||||
<string name="pref_header_offline">Offline and cache</string>
|
<string name="pref_header_offline">Offline and cache</string>
|
||||||
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
|
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
|
||||||
@ -112,7 +97,7 @@
|
|||||||
<string name="pref_switch_periodic_refresh_on">Articles will periodically be synced</string>
|
<string name="pref_switch_periodic_refresh_on">Articles will periodically be synced</string>
|
||||||
<string name="pref_periodic_refresh_minutes_title"><![CDATA[Sync interval ( >= 15 minutes)]]></string>
|
<string name="pref_periodic_refresh_minutes_title"><![CDATA[Sync interval ( >= 15 minutes)]]></string>
|
||||||
<string name="pref_switch_refresh_when_charging">Only refresh when phone is charging</string>
|
<string name="pref_switch_refresh_when_charging">Only refresh when phone is charging</string>
|
||||||
<string name="loading_notification_title">Loading ...</string>
|
<string name="loading_notification_title">Loading …</string>
|
||||||
<string name="loading_notification_text">Selfoss is syncing your articles</string>
|
<string name="loading_notification_text">Selfoss is syncing your articles</string>
|
||||||
<string name="notification_channel_sync">Sync notification</string>
|
<string name="notification_channel_sync">Sync notification</string>
|
||||||
<string name="new_items_channel_sync">New items notification</string>
|
<string name="new_items_channel_sync">New items notification</string>
|
||||||
@ -131,4 +116,19 @@
|
|||||||
<string name="reader_static_bar_on">The bottom bar will always be displayed</string>
|
<string name="reader_static_bar_on">The bottom bar will always be displayed</string>
|
||||||
<string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string>
|
<string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string>
|
||||||
<string name="remove_source">Remove source</string>
|
<string name="remove_source">Remove source</string>
|
||||||
|
<string name="pref_theme_title">Light/Dark mode</string>
|
||||||
|
<string name="mode_dark">Dark mode</string>
|
||||||
|
<string name="mode_system">Follow the system setting</string>
|
||||||
|
<string name="mode_light">Light mode</string>
|
||||||
|
<string name="gdpr_dialog_title">The app does not share any personal data about you.</string>
|
||||||
|
<string name="gdpr_dialog_message"><![CDATA[Crash reports sending is now enabled. It can be disabled from the settings page. Keep in mind that crash reports are essential for the app development.]]></string>
|
||||||
|
<string name="crash_toast_text">A crash occured. Sending the details to the developper.</string>
|
||||||
|
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
|
||||||
|
<string name="menu_home_filter">Filters</string>
|
||||||
|
<string name="application_selfoss_only">This app only works with a Selfoss instance, and no other RSS feed.</string>
|
||||||
|
<string name="menu_home_sources">Sources</string>
|
||||||
|
<string name="update_source">Update source</string>
|
||||||
|
<string name="confirm_disconnect_title">Disconnect ?</string>
|
||||||
|
<string name="confirm_disconnect_description">You will be disconnected from your selfoss instance.</string>
|
||||||
|
<string name="disable_ssl">Disable SSL</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -8,9 +8,8 @@
|
|||||||
<string name="error_field_required">"Champ requis"</string>
|
<string name="error_field_required">"Champ requis"</string>
|
||||||
<string name="prompt_url">"Url Selfoss"</string>
|
<string name="prompt_url">"Url Selfoss"</string>
|
||||||
<string name="withLoginSwitch">"Avec login ?"</string>
|
<string name="withLoginSwitch">"Avec login ?"</string>
|
||||||
<string name="login_url_problem">"Petit souci. Il manque peut être un / à la fin ?"</string>
|
<string name="login_url_problem">"Petit souci. Il manque peut-être un / à la fin ?"</string>
|
||||||
<string name="prompt_login">"Utilisateur"</string>
|
<string name="prompt_login">"Utilisateur"</string>
|
||||||
<string name="label_share">"Partager"</string>
|
|
||||||
<string name="readAll">"Tout lire"</string>
|
<string name="readAll">"Tout lire"</string>
|
||||||
<string name="action_disconnect">"Déconnecter"</string>
|
<string name="action_disconnect">"Déconnecter"</string>
|
||||||
<string name="title_activity_settings">"Paramètres"</string>
|
<string name="title_activity_settings">"Paramètres"</string>
|
||||||
@ -47,12 +46,9 @@
|
|||||||
<string name="switch_unread_count_title">"Afficher le nombre de non lus"</string>
|
<string name="switch_unread_count_title">"Afficher le nombre de non lus"</string>
|
||||||
<string name="display_all_counts_title">"Afficher le nombre de favoris et d'articles lus"</string>
|
<string name="display_all_counts_title">"Afficher le nombre de favoris et d'articles lus"</string>
|
||||||
<string name="text_wrong_url">"Vous semblez essayer de vous connecter avec une URL invalide. Assurez-vous que c'est la bonne, et si le problème persiste, contactez-moi via le lien du play store. Notez aussi que l'application ne peut fonctionner sans l'application web Selfoss. Vous ne pouvez pas utiliser l'application pour accéder directement aux flux RSS."</string>
|
<string name="text_wrong_url">"Vous semblez essayer de vous connecter avec une URL invalide. Assurez-vous que c'est la bonne, et si le problème persiste, contactez-moi via le lien du play store. Notez aussi que l'application ne peut fonctionner sans l'application web Selfoss. Vous ne pouvez pas utiliser l'application pour accéder directement aux flux RSS."</string>
|
||||||
<string name="pref_general_internal_browser_title">"Ouvrir les liens dans l'application"</string>
|
<string name="pref_article_viewer_title">"Ouvrir les liens dans l'application"</string>
|
||||||
<string name="pref_general_internal_browser_on">"Les articles s'ouvriront dans l'application"</string>
|
<string name="pref_article_viewer_on">"Les articles s'ouvriront dans l'application"</string>
|
||||||
<string name="pref_general_internal_browser_off">"Les articles s'ouvriront dans votre naviguateur par défaut"</string>
|
<string name="pref_article_viewer_off">"Les articles s'ouvriront dans votre naviguateur par défaut"</string>
|
||||||
<string name="prefer_article_viewer_title">"Utiliser le visionneur d'articles"</string>
|
|
||||||
<string name="prefer_article_viewer_on">"Utiliser le naviguateur interne"</string>
|
|
||||||
<string name="prefer_article_viewer_off">"Utiliser le naviguateur interne au lieu du visionneur d'articles"</string>
|
|
||||||
<string name="pref_general_category_links">"Gestion des liens"</string>
|
<string name="pref_general_category_links">"Gestion des liens"</string>
|
||||||
<string name="pref_general_category_displaying">"Affichage"</string>
|
<string name="pref_general_category_displaying">"Affichage"</string>
|
||||||
<string name="pref_switch_card_view_on">"Les articles seront affichés en forme de carte"</string>
|
<string name="pref_switch_card_view_on">"Les articles seront affichés en forme de carte"</string>
|
||||||
@ -65,28 +61,18 @@
|
|||||||
<string name="card_height_on">La taille de la carte s\'adaptera au contenu</string>
|
<string name="card_height_on">La taille de la carte s\'adaptera au contenu</string>
|
||||||
<string name="card_height_off">La taille de la carte sera fixe</string>
|
<string name="card_height_off">La taille de la carte sera fixe</string>
|
||||||
<string name="source_code">Code source</string>
|
<string name="source_code">Code source</string>
|
||||||
<string name="drawer_error_loading_tags">Erreur lors du chargement des tags…</string>
|
<string name="filter_item_tags">Tags</string>
|
||||||
<string name="drawer_item_filters">Filtres</string>
|
<string name="filter_item_sources">Sources</string>
|
||||||
<string name="drawer_action_clear">raz</string>
|
|
||||||
<string name="drawer_item_tags">Tags</string>
|
|
||||||
<string name="drawer_item_sources">Sources</string>
|
|
||||||
<string name="drawer_action_edit">éditer</string>
|
|
||||||
<string name="drawer_loading">Chargement …</string>
|
|
||||||
<string name="menu_home_search">Rechercher</string>
|
<string name="menu_home_search">Rechercher</string>
|
||||||
<string name="can_delete_source">Impossible de supprimer la source…</string>
|
<string name="can_delete_source">Impossible de supprimer la source…</string>
|
||||||
<string name="base_url_error">Il y a eu un souci lors de la communication avec votre instance Selfoss. Si le problèmes persiste, contactez-moi pour trouver une solution.</string>
|
<string name="base_url_error">Il y a eu un souci lors de la communication avec votre instance Selfoss. Si le problèmes persiste, contactez-moi pour trouver une solution.</string>
|
||||||
<string name="pref_header_theme">Thèmes</string>
|
<string name="pref_header_theme">Thèmes</string>
|
||||||
<string name="default_theme">Par défaut</string>
|
|
||||||
<string name="default_dark_theme">Par défaut/Foncé</string>
|
|
||||||
<string name="pref_selfoss_category">Api Selfoss</string>
|
<string name="pref_selfoss_category">Api Selfoss</string>
|
||||||
<string name="pref_api_items_number_title">Nombre d\'articles chargés</string>
|
<string name="pref_api_items_number_title">Nombre d\'articles chargés</string>
|
||||||
<string name="pref_hidden_tags">Tags Cachés</string>
|
|
||||||
<string name="pref_general_infinite_loading_title">Charger plus d\'articles au scroll</string>
|
<string name="pref_general_infinite_loading_title">Charger plus d\'articles au scroll</string>
|
||||||
<string name="translation">Traduction</string>
|
<string name="translation">Traduction</string>
|
||||||
<string name="cant_open_invalid_url">L’url de l’élément n’est pas valide. En attendant la résolution du problème, le lien ne s\'ouvrira pas.</string>
|
<string name="cant_open_invalid_url">L’url de l’élément n’est pas valide. En attendant la résolution du problème, le lien ne s\'ouvrira pas.</string>
|
||||||
<string name="drawer_report_bug">Signaler un bug</string>
|
|
||||||
<string name="items_number_should_be_number">Le nombre d\'articles doit être un entier.</string>
|
<string name="items_number_should_be_number">Le nombre d\'articles doit être un entier.</string>
|
||||||
<string name="reader_action_more">Lire plus</string>
|
|
||||||
<string name="reader_action_open">Ouvrir</string>
|
<string name="reader_action_open">Ouvrir</string>
|
||||||
<string name="reader_action_share">Partager</string>
|
<string name="reader_action_share">Partager</string>
|
||||||
<string name="pref_switch_actions_pager_scroll_on">Marquer les articles comme lus à la navigation dans le lecteur d\'article.</string>
|
<string name="pref_switch_actions_pager_scroll_on">Marquer les articles comme lus à la navigation dans le lecteur d\'article.</string>
|
||||||
@ -97,7 +83,6 @@
|
|||||||
<string name="markall_dialog_message">Marquer tous les éléments comme lus ?</string>
|
<string name="markall_dialog_message">Marquer tous les éléments comme lus ?</string>
|
||||||
<string name="pref_switch_actions_pager_scroll">Marquer comme lu à la navigation.</string>
|
<string name="pref_switch_actions_pager_scroll">Marquer comme lu à la navigation.</string>
|
||||||
<string name="pref_switch_actions_pager_scroll_off">Ne pas marquer les articles comme lus à la navigation.</string>
|
<string name="pref_switch_actions_pager_scroll_off">Ne pas marquer les articles comme lus à la navigation.</string>
|
||||||
<string name="drawer_item_hidden_tags">Tags Cachés</string>
|
|
||||||
<string name="unmark">Marquer l\'article comme non lu</string>
|
<string name="unmark">Marquer l\'article comme non lu</string>
|
||||||
<string name="pref_header_offline">Hors ligne et cache</string>
|
<string name="pref_header_offline">Hors ligne et cache</string>
|
||||||
<string name="pref_switch_items_caching_off">Les articles ne seront pas enregistrés et l\'application ne sera pas utilisable hors ligne.</string>
|
<string name="pref_switch_items_caching_off">Les articles ne seront pas enregistrés et l\'application ne sera pas utilisable hors ligne.</string>
|
||||||
@ -112,7 +97,7 @@
|
|||||||
<string name="pref_switch_periodic_refresh_on">Articles seront périodiquement synchronisées</string>
|
<string name="pref_switch_periodic_refresh_on">Articles seront périodiquement synchronisées</string>
|
||||||
<string name="pref_periodic_refresh_minutes_title"><![CDATA[Interval de synchronisation ( >= 15 minutes)]]></string>
|
<string name="pref_periodic_refresh_minutes_title"><![CDATA[Interval de synchronisation ( >= 15 minutes)]]></string>
|
||||||
<string name="pref_switch_refresh_when_charging">Synchroniser uniquement lorsque le téléphone est en charge</string>
|
<string name="pref_switch_refresh_when_charging">Synchroniser uniquement lorsque le téléphone est en charge</string>
|
||||||
<string name="loading_notification_title">Chargement ...</string>
|
<string name="loading_notification_title">Chargement …</string>
|
||||||
<string name="loading_notification_text">Selfoss synchronise vos articles</string>
|
<string name="loading_notification_text">Selfoss synchronise vos articles</string>
|
||||||
<string name="notification_channel_sync">Notification de synchronisation</string>
|
<string name="notification_channel_sync">Notification de synchronisation</string>
|
||||||
<string name="new_items_channel_sync">Notification de nouveaux articles</string>
|
<string name="new_items_channel_sync">Notification de nouveaux articles</string>
|
||||||
@ -131,4 +116,19 @@
|
|||||||
<string name="reader_static_bar_on">La barre sera affichée</string>
|
<string name="reader_static_bar_on">La barre sera affichée</string>
|
||||||
<string name="reader_static_bar_off">La barre sera affichée grâce au bouton</string>
|
<string name="reader_static_bar_off">La barre sera affichée grâce au bouton</string>
|
||||||
<string name="remove_source">Supprimer la source</string>
|
<string name="remove_source">Supprimer la source</string>
|
||||||
|
<string name="pref_theme_title">Thème Clair/Sombre</string>
|
||||||
|
<string name="mode_dark">Thème sombre</string>
|
||||||
|
<string name="mode_system">Utiliser les paramètres système</string>
|
||||||
|
<string name="mode_light">Thème clair</string>
|
||||||
|
<string name="gdpr_dialog_title">The app does not share any personal data about you.</string>
|
||||||
|
<string name="gdpr_dialog_message"><![CDATA[Crash reports sending is now enabled. It can be disabled from the settings page. Keep in mind that crash reports are essential for the app development.]]></string>
|
||||||
|
<string name="crash_toast_text">A crash occured. Sending the details to the developper.</string>
|
||||||
|
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
|
||||||
|
<string name="menu_home_filter">Filters</string>
|
||||||
|
<string name="application_selfoss_only">This app only works with a Selfoss instance, and no other RSS feed.</string>
|
||||||
|
<string name="menu_home_sources">Sources</string>
|
||||||
|
<string name="update_source">Update source</string>
|
||||||
|
<string name="confirm_disconnect_title">Disconnect ?</string>
|
||||||
|
<string name="confirm_disconnect_description">You will be disconnected from your selfoss instance.</string>
|
||||||
|
<string name="disable_ssl">Disable SSL</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
<string name="withLoginSwitch">"É preciso iniciar sesión?"</string>
|
<string name="withLoginSwitch">"É preciso iniciar sesión?"</string>
|
||||||
<string name="login_url_problem">"Ups! Pode que precises engadir un \"/\" o final da URL."</string>
|
<string name="login_url_problem">"Ups! Pode que precises engadir un \"/\" o final da URL."</string>
|
||||||
<string name="prompt_login">"Nome de usuario"</string>
|
<string name="prompt_login">"Nome de usuario"</string>
|
||||||
<string name="label_share">"Compartir"</string>
|
|
||||||
<string name="readAll">"Ler todos"</string>
|
<string name="readAll">"Ler todos"</string>
|
||||||
<string name="action_disconnect">"Desconectar"</string>
|
<string name="action_disconnect">"Desconectar"</string>
|
||||||
<string name="title_activity_settings">"Axustes"</string>
|
<string name="title_activity_settings">"Axustes"</string>
|
||||||
@ -34,8 +33,8 @@
|
|||||||
<string name="addStringNoUrl">"Accede pra engadir fontes."</string>
|
<string name="addStringNoUrl">"Accede pra engadir fontes."</string>
|
||||||
<string name="cant_get_sources">"Non se pode obter a lista de fontes."</string>
|
<string name="cant_get_sources">"Non se pode obter a lista de fontes."</string>
|
||||||
<string name="cant_create_source">"Non se pode crear unha fonte."</string>
|
<string name="cant_create_source">"Non se pode crear unha fonte."</string>
|
||||||
<string name="cant_get_spouts_no_network">"Can't get spouts list because of a network issue."</string>
|
<string name="cant_get_spouts_no_network">"Non se pode obter a lista de spouts por mor dun erro de rede."</string>
|
||||||
<string name="cant_get_spouts">"Can't get spouts list. There may ben an api issue."</string>
|
<string name="cant_get_spouts">"Non se pode obter a lista de spoits. Pode que haxa algún problema coa api."</string>
|
||||||
<string name="form_not_complete">"O formulario non está completo"</string>
|
<string name="form_not_complete">"O formulario non está completo"</string>
|
||||||
<string name="pref_header_links">"Ligazóns"</string>
|
<string name="pref_header_links">"Ligazóns"</string>
|
||||||
<string name="issue_tracker_link">"Rastrexador de Incidencias"</string>
|
<string name="issue_tracker_link">"Rastrexador de Incidencias"</string>
|
||||||
@ -47,12 +46,9 @@
|
|||||||
<string name="switch_unread_count_title">"Mostrar reconto de artigos non lidos"</string>
|
<string name="switch_unread_count_title">"Mostrar reconto de artigos non lidos"</string>
|
||||||
<string name="display_all_counts_title">"Mostrar reconto de artigos lidos e favoritos"</string>
|
<string name="display_all_counts_title">"Mostrar reconto de artigos lidos e favoritos"</string>
|
||||||
<string name="text_wrong_url">"Semella que intentas usar unha URL non válida. Asegúrate de que é correcta, e se o problema persiste, ponte en contacto conmigo (a través da ligazón de contacto na tenda). Por favor ten en conta que a aplicación precisa que uses Selfoss. Non podes acceder a canles RSS se non o tes."</string>
|
<string name="text_wrong_url">"Semella que intentas usar unha URL non válida. Asegúrate de que é correcta, e se o problema persiste, ponte en contacto conmigo (a través da ligazón de contacto na tenda). Por favor ten en conta que a aplicación precisa que uses Selfoss. Non podes acceder a canles RSS se non o tes."</string>
|
||||||
<string name="pref_general_internal_browser_title">"Abrir ligazóns dentro da aplicación"</string>
|
<string name="pref_article_viewer_title">"Abrir ligazóns dentro da aplicación"</string>
|
||||||
<string name="pref_general_internal_browser_on">"Os artigos abriranse dentro da aplicación"</string>
|
<string name="pref_article_viewer_on">"Os artigos abriranse dentro da aplicación"</string>
|
||||||
<string name="pref_general_internal_browser_off">"Os artigos abriranse co teu navegador prederminado"</string>
|
<string name="pref_article_viewer_off">"Os artigos abriranse co teu navegador prederminado"</string>
|
||||||
<string name="prefer_article_viewer_title">"Usar o visor de artigos"</string>
|
|
||||||
<string name="prefer_article_viewer_on">"Usarase o visor de artigos en lugar do navegador interno"</string>
|
|
||||||
<string name="prefer_article_viewer_off">"Usarase o navegador interno en lugar do visor de artigos"</string>
|
|
||||||
<string name="pref_general_category_links">"Xestión de ligazóns"</string>
|
<string name="pref_general_category_links">"Xestión de ligazóns"</string>
|
||||||
<string name="pref_general_category_displaying">"Visualización"</string>
|
<string name="pref_general_category_displaying">"Visualización"</string>
|
||||||
<string name="pref_switch_card_view_on">"Os artigos amosaranse coma tarxetas"</string>
|
<string name="pref_switch_card_view_on">"Os artigos amosaranse coma tarxetas"</string>
|
||||||
@ -65,28 +61,18 @@
|
|||||||
<string name="card_height_on">A altura das tarxetas axustarase ao seu contido</string>
|
<string name="card_height_on">A altura das tarxetas axustarase ao seu contido</string>
|
||||||
<string name="card_height_off">A altura das tarxetas será fixa</string>
|
<string name="card_height_off">A altura das tarxetas será fixa</string>
|
||||||
<string name="source_code">Código fonte</string>
|
<string name="source_code">Código fonte</string>
|
||||||
<string name="drawer_error_loading_tags">Produciuse un erro ao cargar as etiquetas…</string>
|
<string name="filter_item_tags">Etiquetas</string>
|
||||||
<string name="drawer_item_filters">Filtros</string>
|
<string name="filter_item_sources">Fontes</string>
|
||||||
<string name="drawer_action_clear">limpar</string>
|
|
||||||
<string name="drawer_item_tags">Etiquetas</string>
|
|
||||||
<string name="drawer_item_sources">Fontes</string>
|
|
||||||
<string name="drawer_action_edit">editar</string>
|
|
||||||
<string name="drawer_loading">Cargando…</string>
|
|
||||||
<string name="menu_home_search">Procurar</string>
|
<string name="menu_home_search">Procurar</string>
|
||||||
<string name="can_delete_source">Non se puido eliminar a fonte…</string>
|
<string name="can_delete_source">Non se puido eliminar a fonte…</string>
|
||||||
<string name="base_url_error">Houno unha incidencia ao tratar de comunicarse coa túa instancia de Selfoss. Se o problema persiste, prégolle que se poña en contacto conmigo.</string>
|
<string name="base_url_error">Houno unha incidencia ao tratar de comunicarse coa túa instancia de Selfoss. Se o problema persiste, prégolle que se poña en contacto conmigo.</string>
|
||||||
<string name="pref_header_theme">Temas</string>
|
<string name="pref_header_theme">Temas</string>
|
||||||
<string name="default_theme">Predeterminado</string>
|
|
||||||
<string name="default_dark_theme">Predeterminado/Escuro</string>
|
|
||||||
<string name="pref_selfoss_category">API de Selfoss</string>
|
<string name="pref_selfoss_category">API de Selfoss</string>
|
||||||
<string name="pref_api_items_number_title">Número de elementos cargados</string>
|
<string name="pref_api_items_number_title">Número de elementos cargados</string>
|
||||||
<string name="pref_hidden_tags">Etiquetas ocultas</string>
|
|
||||||
<string name="pref_general_infinite_loading_title">Cargar máis artigos ao desprazarse</string>
|
<string name="pref_general_infinite_loading_title">Cargar máis artigos ao desprazarse</string>
|
||||||
<string name="translation">Traducción</string>
|
<string name="translation">Traducción</string>
|
||||||
<string name="cant_open_invalid_url">A URL do elemento non é válida. Estou tratando de solucionar isto pra que a aplicación non falle.</string>
|
<string name="cant_open_invalid_url">A URL do elemento non é válida. Estou tratando de solucionar isto pra que a aplicación non falle.</string>
|
||||||
<string name="drawer_report_bug">Informar dun erro</string>
|
|
||||||
<string name="items_number_should_be_number">O número de elementos debería ser un enteiro.</string>
|
<string name="items_number_should_be_number">O número de elementos debería ser un enteiro.</string>
|
||||||
<string name="reader_action_more">Ler máis</string>
|
|
||||||
<string name="reader_action_open">Abrir no navegador</string>
|
<string name="reader_action_open">Abrir no navegador</string>
|
||||||
<string name="reader_action_share">Compartir</string>
|
<string name="reader_action_share">Compartir</string>
|
||||||
<string name="pref_switch_actions_pager_scroll_on">Marcar artigos como lidos cando se desliza o dedo dun a outro.</string>
|
<string name="pref_switch_actions_pager_scroll_on">Marcar artigos como lidos cando se desliza o dedo dun a outro.</string>
|
||||||
@ -97,7 +83,6 @@
|
|||||||
<string name="markall_dialog_message">Isto marcara todos os elementos como lidos.</string>
|
<string name="markall_dialog_message">Isto marcara todos os elementos como lidos.</string>
|
||||||
<string name="pref_switch_actions_pager_scroll">Marcar artigos como lidos ao deslizar co dedo cara os lados</string>
|
<string name="pref_switch_actions_pager_scroll">Marcar artigos como lidos ao deslizar co dedo cara os lados</string>
|
||||||
<string name="pref_switch_actions_pager_scroll_off">Non marcar artigos como lidos ao deslizar co dedo cara os lados.</string>
|
<string name="pref_switch_actions_pager_scroll_off">Non marcar artigos como lidos ao deslizar co dedo cara os lados.</string>
|
||||||
<string name="drawer_item_hidden_tags">Etiquetas ocultas</string>
|
|
||||||
<string name="unmark">Marcar artículo como non lido</string>
|
<string name="unmark">Marcar artículo como non lido</string>
|
||||||
<string name="pref_header_offline">Sen conexión e caché</string>
|
<string name="pref_header_offline">Sen conexión e caché</string>
|
||||||
<string name="pref_switch_items_caching_off">Os artigos non se gardaran na memoria do dispositivo e non se poderá utilizar a aplicación sen conexión.</string>
|
<string name="pref_switch_items_caching_off">Os artigos non se gardaran na memoria do dispositivo e non se poderá utilizar a aplicación sen conexión.</string>
|
||||||
@ -112,7 +97,7 @@
|
|||||||
<string name="pref_switch_periodic_refresh_on">Os artigos sincronizaranse periódicamente</string>
|
<string name="pref_switch_periodic_refresh_on">Os artigos sincronizaranse periódicamente</string>
|
||||||
<string name="pref_periodic_refresh_minutes_title"><![CDATA[Intervalo de sincronización (>= 15 minutos)]]></string>
|
<string name="pref_periodic_refresh_minutes_title"><![CDATA[Intervalo de sincronización (>= 15 minutos)]]></string>
|
||||||
<string name="pref_switch_refresh_when_charging">Só refrescar cando o teléfono se está a cargar</string>
|
<string name="pref_switch_refresh_when_charging">Só refrescar cando o teléfono se está a cargar</string>
|
||||||
<string name="loading_notification_title">Cargando...</string>
|
<string name="loading_notification_title">Cargando…</string>
|
||||||
<string name="loading_notification_text">Selfoss está sincronizando os teus ar tigos</string>
|
<string name="loading_notification_text">Selfoss está sincronizando os teus ar tigos</string>
|
||||||
<string name="notification_channel_sync">Notificación de sincronización</string>
|
<string name="notification_channel_sync">Notificación de sincronización</string>
|
||||||
<string name="new_items_channel_sync">Notificación de actualizacións</string>
|
<string name="new_items_channel_sync">Notificación de actualizacións</string>
|
||||||
@ -131,4 +116,19 @@
|
|||||||
<string name="reader_static_bar_on">A barra inferior mostrarase sempre</string>
|
<string name="reader_static_bar_on">A barra inferior mostrarase sempre</string>
|
||||||
<string name="reader_static_bar_off">A barra inferior pode mostrarse a través do botón flotante</string>
|
<string name="reader_static_bar_off">A barra inferior pode mostrarse a través do botón flotante</string>
|
||||||
<string name="remove_source">Eliminar fonte</string>
|
<string name="remove_source">Eliminar fonte</string>
|
||||||
|
<string name="pref_theme_title">Modo Claro/Escuro</string>
|
||||||
|
<string name="mode_dark">Modo escuro</string>
|
||||||
|
<string name="mode_system">Seguir axustes do sistema</string>
|
||||||
|
<string name="mode_light">Modo claro</string>
|
||||||
|
<string name="gdpr_dialog_title">A aplicación non comparte ningún dato persoal seu.</string>
|
||||||
|
<string name="gdpr_dialog_message"><![CDATA[O envío de informes de erros está habilitado. Pode deshabilitarse dende a páxina de axustes. Ten en conta que os informes de erros son esenciais para o desenvolvemento da aplicación.]]></string>
|
||||||
|
<string name="crash_toast_text">Ocurriu un erro. Enviando os detalles o desenvolvedor.</string>
|
||||||
|
<string name="pref_switch_disable_acra">"Deshabilitar o reporte automático de erros. "</string>
|
||||||
|
<string name="menu_home_filter">Filtros</string>
|
||||||
|
<string name="application_selfoss_only">Esta aplicación só funciona cunha instancia de Selfoss, e con ningún outro filtro RSS.</string>
|
||||||
|
<string name="menu_home_sources">Sources</string>
|
||||||
|
<string name="update_source">Update source</string>
|
||||||
|
<string name="confirm_disconnect_title">Disconnect ?</string>
|
||||||
|
<string name="confirm_disconnect_description">You will be disconnected from your selfoss instance.</string>
|
||||||
|
<string name="disable_ssl">Disable SSL</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
<string name="withLoginSwitch">"Harus masuk?"</string>
|
<string name="withLoginSwitch">"Harus masuk?"</string>
|
||||||
<string name="login_url_problem">"Ups. Anda mungkin harus menambahkan \"/\" di akhir url."</string>
|
<string name="login_url_problem">"Ups. Anda mungkin harus menambahkan \"/\" di akhir url."</string>
|
||||||
<string name="prompt_login">"Nama pengguna"</string>
|
<string name="prompt_login">"Nama pengguna"</string>
|
||||||
<string name="label_share">"Bagikan"</string>
|
|
||||||
<string name="readAll">"Baca semua"</string>
|
<string name="readAll">"Baca semua"</string>
|
||||||
<string name="action_disconnect">"Putuskan sambungan"</string>
|
<string name="action_disconnect">"Putuskan sambungan"</string>
|
||||||
<string name="title_activity_settings">"Pengaturan"</string>
|
<string name="title_activity_settings">"Pengaturan"</string>
|
||||||
@ -47,12 +46,9 @@
|
|||||||
<string name="switch_unread_count_title">"Tampilkan jumlah item yang belum dibaca"</string>
|
<string name="switch_unread_count_title">"Tampilkan jumlah item yang belum dibaca"</string>
|
||||||
<string name="display_all_counts_title">"Tampilkan jumlah item untuk favorit dan sudah dibaca"</string>
|
<string name="display_all_counts_title">"Tampilkan jumlah item untuk favorit dan sudah dibaca"</string>
|
||||||
<string name="text_wrong_url">"Sepertinya Anda mencoba menggunakan URL yang tidak valid. Pastikan itu benar, jika masalah terus berlanjut, hubungi saya (melalui link kontak toko). Harap dicatat bahwa aplikasi ini mengharuskan Anda menggunakan Selfoss. Tanpa itu, Anda tidak bisa mengakses umpan RSS."</string>
|
<string name="text_wrong_url">"Sepertinya Anda mencoba menggunakan URL yang tidak valid. Pastikan itu benar, jika masalah terus berlanjut, hubungi saya (melalui link kontak toko). Harap dicatat bahwa aplikasi ini mengharuskan Anda menggunakan Selfoss. Tanpa itu, Anda tidak bisa mengakses umpan RSS."</string>
|
||||||
<string name="pref_general_internal_browser_title">"Buka tautan dalam aplikasi"</string>
|
<string name="pref_article_viewer_title">"Buka tautan dalam aplikasi"</string>
|
||||||
<string name="pref_general_internal_browser_on">"Artikel akan dibuka di dalam aplikasi"</string>
|
<string name="pref_article_viewer_on">"Artikel akan dibuka di dalam aplikasi"</string>
|
||||||
<string name="pref_general_internal_browser_off">"Artikel akan dibuka dalam peramban bawaan Anda"</string>
|
<string name="pref_article_viewer_off">"Artikel akan dibuka dalam peramban bawaan Anda"</string>
|
||||||
<string name="prefer_article_viewer_title">"Gunakan pratinjau artikel"</string>
|
|
||||||
<string name="prefer_article_viewer_on">"Lihat artikel di penampil daripada peramban internal"</string>
|
|
||||||
<string name="prefer_article_viewer_off">"Gunakan peramban internal dan bukan penampil artikel"</string>
|
|
||||||
<string name="pref_general_category_links">"Pengolahan tautan"</string>
|
<string name="pref_general_category_links">"Pengolahan tautan"</string>
|
||||||
<string name="pref_general_category_displaying">"Tampilan"</string>
|
<string name="pref_general_category_displaying">"Tampilan"</string>
|
||||||
<string name="pref_switch_card_view_on">"Artikel ini akan ditampilkan dalam bentuk kartu"</string>
|
<string name="pref_switch_card_view_on">"Artikel ini akan ditampilkan dalam bentuk kartu"</string>
|
||||||
@ -65,28 +61,18 @@
|
|||||||
<string name="card_height_on">Tinggi kartu akan disesuaikan dengan konten</string>
|
<string name="card_height_on">Tinggi kartu akan disesuaikan dengan konten</string>
|
||||||
<string name="card_height_off">Ukuran kartu akan tetap</string>
|
<string name="card_height_off">Ukuran kartu akan tetap</string>
|
||||||
<string name="source_code">Kode sumber</string>
|
<string name="source_code">Kode sumber</string>
|
||||||
<string name="drawer_error_loading_tags">Kesalahan saat memuat tag…</string>
|
<string name="filter_item_tags">Tag</string>
|
||||||
<string name="drawer_item_filters">Filter</string>
|
<string name="filter_item_sources">Sumber</string>
|
||||||
<string name="drawer_action_clear">kosongkan</string>
|
|
||||||
<string name="drawer_item_tags">Tag</string>
|
|
||||||
<string name="drawer_item_sources">Sumber</string>
|
|
||||||
<string name="drawer_action_edit">suntung</string>
|
|
||||||
<string name="drawer_loading">Memuat …</string>
|
|
||||||
<string name="menu_home_search">Cari</string>
|
<string name="menu_home_search">Cari</string>
|
||||||
<string name="can_delete_source">Tidak dapat menghapus sumber…</string>
|
<string name="can_delete_source">Tidak dapat menghapus sumber…</string>
|
||||||
<string name="base_url_error">Ada masalah saat berkomunikasi dengan Selfoss Anda. Jika masalah berlanjut, tolong hubungi saya.</string>
|
<string name="base_url_error">Ada masalah saat berkomunikasi dengan Selfoss Anda. Jika masalah berlanjut, tolong hubungi saya.</string>
|
||||||
<string name="pref_header_theme">Tema</string>
|
<string name="pref_header_theme">Tema</string>
|
||||||
<string name="default_theme">Bawaan</string>
|
|
||||||
<string name="default_dark_theme">Bawaan/Gelap</string>
|
|
||||||
<string name="pref_selfoss_category">Selfoss Api</string>
|
<string name="pref_selfoss_category">Selfoss Api</string>
|
||||||
<string name="pref_api_items_number_title">Item nomor dimuat</string>
|
<string name="pref_api_items_number_title">Item nomor dimuat</string>
|
||||||
<string name="pref_hidden_tags">Hidden Tags</string>
|
|
||||||
<string name="pref_general_infinite_loading_title">Muat lebih banyak artikel saat membalik halaman</string>
|
<string name="pref_general_infinite_loading_title">Muat lebih banyak artikel saat membalik halaman</string>
|
||||||
<string name="translation">Terjemahan</string>
|
<string name="translation">Terjemahan</string>
|
||||||
<string name="cant_open_invalid_url">Alamat tautan proyek tidak valid. Saya mencoba memecahkan masalah ini untuk menghindari aplikasi berhenti.</string>
|
<string name="cant_open_invalid_url">Alamat tautan proyek tidak valid. Saya mencoba memecahkan masalah ini untuk menghindari aplikasi berhenti.</string>
|
||||||
<string name="drawer_report_bug">Laporkan bug</string>
|
|
||||||
<string name="items_number_should_be_number">Jumlah item harus berupa bilangan bulat.</string>
|
<string name="items_number_should_be_number">Jumlah item harus berupa bilangan bulat.</string>
|
||||||
<string name="reader_action_more">Baca lebih lanjut</string>
|
|
||||||
<string name="reader_action_open">Buka di peramban</string>
|
<string name="reader_action_open">Buka di peramban</string>
|
||||||
<string name="reader_action_share">Bagikan</string>
|
<string name="reader_action_share">Bagikan</string>
|
||||||
<string name="pref_switch_actions_pager_scroll_on">Mark articles as read when swiping between articles.</string>
|
<string name="pref_switch_actions_pager_scroll_on">Mark articles as read when swiping between articles.</string>
|
||||||
@ -97,7 +83,6 @@
|
|||||||
<string name="markall_dialog_message">This will mark all the items as read.</string>
|
<string name="markall_dialog_message">This will mark all the items as read.</string>
|
||||||
<string name="pref_switch_actions_pager_scroll">Mark as read on swipe</string>
|
<string name="pref_switch_actions_pager_scroll">Mark as read on swipe</string>
|
||||||
<string name="pref_switch_actions_pager_scroll_off">Don\'t mark articles as read when swiping.</string>
|
<string name="pref_switch_actions_pager_scroll_off">Don\'t mark articles as read when swiping.</string>
|
||||||
<string name="drawer_item_hidden_tags">Hidden Tags</string>
|
|
||||||
<string name="unmark">Mark item as unread</string>
|
<string name="unmark">Mark item as unread</string>
|
||||||
<string name="pref_header_offline">Offline and cache</string>
|
<string name="pref_header_offline">Offline and cache</string>
|
||||||
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
|
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
|
||||||
@ -105,14 +90,14 @@
|
|||||||
<string name="pref_switch_items_caching">Save items for offline use</string>
|
<string name="pref_switch_items_caching">Save items for offline use</string>
|
||||||
<string name="pref_switch_update_sources">Check for new sources and tags</string>
|
<string name="pref_switch_update_sources">Check for new sources and tags</string>
|
||||||
<string name="pref_switch_update_sources_summary">Disable this if your server is receiving excessive amounts of database queries.</string>
|
<string name="pref_switch_update_sources_summary">Disable this if your server is receiving excessive amounts of database queries.</string>
|
||||||
<string name="network_connectivity_lost">"Network connection lost"</string>
|
<string name="network_connectivity_lost">"Koneksi jaringan hilang"</string>
|
||||||
<string name="network_connectivity_retrieved">"Network connection is now available"</string>
|
<string name="network_connectivity_retrieved">"Network connection is now available"</string>
|
||||||
<string name="pref_switch_periodic_refresh">Sync articles</string>
|
<string name="pref_switch_periodic_refresh">Sync articles</string>
|
||||||
<string name="pref_switch_periodic_refresh_off">Articles will not be synced in the background</string>
|
<string name="pref_switch_periodic_refresh_off">Articles will not be synced in the background</string>
|
||||||
<string name="pref_switch_periodic_refresh_on">Articles will periodically be synced</string>
|
<string name="pref_switch_periodic_refresh_on">Articles will periodically be synced</string>
|
||||||
<string name="pref_periodic_refresh_minutes_title"><![CDATA[Sync interval ( >= 15 minutes)]]></string>
|
<string name="pref_periodic_refresh_minutes_title"><![CDATA[Sync interval ( >= 15 minutes)]]></string>
|
||||||
<string name="pref_switch_refresh_when_charging">Only refresh when phone is charging</string>
|
<string name="pref_switch_refresh_when_charging">Only refresh when phone is charging</string>
|
||||||
<string name="loading_notification_title">Loading ...</string>
|
<string name="loading_notification_title">Loading …</string>
|
||||||
<string name="loading_notification_text">Selfoss is syncing your articles</string>
|
<string name="loading_notification_text">Selfoss is syncing your articles</string>
|
||||||
<string name="notification_channel_sync">Sync notification</string>
|
<string name="notification_channel_sync">Sync notification</string>
|
||||||
<string name="new_items_channel_sync">New items notification</string>
|
<string name="new_items_channel_sync">New items notification</string>
|
||||||
@ -131,4 +116,19 @@
|
|||||||
<string name="reader_static_bar_on">The bottom bar will always be displayed</string>
|
<string name="reader_static_bar_on">The bottom bar will always be displayed</string>
|
||||||
<string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string>
|
<string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string>
|
||||||
<string name="remove_source">Remove source</string>
|
<string name="remove_source">Remove source</string>
|
||||||
|
<string name="pref_theme_title">Light/Dark mode</string>
|
||||||
|
<string name="mode_dark">Dark mode</string>
|
||||||
|
<string name="mode_system">Follow the system setting</string>
|
||||||
|
<string name="mode_light">Light mode</string>
|
||||||
|
<string name="gdpr_dialog_title">The app does not share any personal data about you.</string>
|
||||||
|
<string name="gdpr_dialog_message"><![CDATA[Crash reports sending is now enabled. It can be disabled from the settings page. Keep in mind that crash reports are essential for the app development.]]></string>
|
||||||
|
<string name="crash_toast_text">A crash occured. Sending the details to the developper.</string>
|
||||||
|
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
|
||||||
|
<string name="menu_home_filter">Filters</string>
|
||||||
|
<string name="application_selfoss_only">This app only works with a Selfoss instance, and no other RSS feed.</string>
|
||||||
|
<string name="menu_home_sources">Sources</string>
|
||||||
|
<string name="update_source">Update source</string>
|
||||||
|
<string name="confirm_disconnect_title">Disconnect ?</string>
|
||||||
|
<string name="confirm_disconnect_description">You will be disconnected from your selfoss instance.</string>
|
||||||
|
<string name="disable_ssl">Disable SSL</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
<string name="withLoginSwitch">"È richiesto l'accesso?"</string>
|
<string name="withLoginSwitch">"È richiesto l'accesso?"</string>
|
||||||
<string name="login_url_problem">"Oops. Potrebbe essere necessario aggiungere un \"/\" alla fine dell'url."</string>
|
<string name="login_url_problem">"Oops. Potrebbe essere necessario aggiungere un \"/\" alla fine dell'url."</string>
|
||||||
<string name="prompt_login">"Nome utente"</string>
|
<string name="prompt_login">"Nome utente"</string>
|
||||||
<string name="label_share">"Condividi"</string>
|
|
||||||
<string name="readAll">"Segna tutte come lette"</string>
|
<string name="readAll">"Segna tutte come lette"</string>
|
||||||
<string name="action_disconnect">"Scollegati"</string>
|
<string name="action_disconnect">"Scollegati"</string>
|
||||||
<string name="title_activity_settings">"Impostazioni"</string>
|
<string name="title_activity_settings">"Impostazioni"</string>
|
||||||
@ -47,12 +46,9 @@
|
|||||||
<string name="switch_unread_count_title">"Display unread count"</string>
|
<string name="switch_unread_count_title">"Display unread count"</string>
|
||||||
<string name="display_all_counts_title">"Display count for favorite and read"</string>
|
<string name="display_all_counts_title">"Display count for favorite and read"</string>
|
||||||
<string name="text_wrong_url">"You seem to be trying to use an invalid URL. Make sure it is correct, and if the problem persists, contact me (via the store contact link). Please note that the app needs you to be using Selfoss. You can't access RSS feeds without it."</string>
|
<string name="text_wrong_url">"You seem to be trying to use an invalid URL. Make sure it is correct, and if the problem persists, contact me (via the store contact link). Please note that the app needs you to be using Selfoss. You can't access RSS feeds without it."</string>
|
||||||
<string name="pref_general_internal_browser_title">"Open links inside the app"</string>
|
<string name="pref_article_viewer_title">"Open links inside the app"</string>
|
||||||
<string name="pref_general_internal_browser_on">"Articles will open inside the app"</string>
|
<string name="pref_article_viewer_on">"Articles will open inside the app"</string>
|
||||||
<string name="pref_general_internal_browser_off">"Articles will open with your default browser"</string>
|
<string name="pref_article_viewer_off">"Articles will open with your default browser"</string>
|
||||||
<string name="prefer_article_viewer_title">"Use the article viewer"</string>
|
|
||||||
<string name="prefer_article_viewer_on">"Will use the article viewer instead of the internal browser"</string>
|
|
||||||
<string name="prefer_article_viewer_off">"Will use the internal browser instead of the article viewer"</string>
|
|
||||||
<string name="pref_general_category_links">"Link handling"</string>
|
<string name="pref_general_category_links">"Link handling"</string>
|
||||||
<string name="pref_general_category_displaying">"Displaying"</string>
|
<string name="pref_general_category_displaying">"Displaying"</string>
|
||||||
<string name="pref_switch_card_view_on">"The articles will be displayed as cards"</string>
|
<string name="pref_switch_card_view_on">"The articles will be displayed as cards"</string>
|
||||||
@ -65,28 +61,18 @@
|
|||||||
<string name="card_height_on">Cards height will adjust to its content</string>
|
<string name="card_height_on">Cards height will adjust to its content</string>
|
||||||
<string name="card_height_off">Card height will be fixed</string>
|
<string name="card_height_off">Card height will be fixed</string>
|
||||||
<string name="source_code">Codice sorgente</string>
|
<string name="source_code">Codice sorgente</string>
|
||||||
<string name="drawer_error_loading_tags">Errore nel caricamento dei tag…</string>
|
<string name="filter_item_tags">Tags</string>
|
||||||
<string name="drawer_item_filters">Filtri</string>
|
<string name="filter_item_sources">Fonti</string>
|
||||||
<string name="drawer_action_clear">cancella</string>
|
|
||||||
<string name="drawer_item_tags">Tags</string>
|
|
||||||
<string name="drawer_item_sources">Fonti</string>
|
|
||||||
<string name="drawer_action_edit">modifica</string>
|
|
||||||
<string name="drawer_loading">Caricamento…</string>
|
|
||||||
<string name="menu_home_search">Cerca</string>
|
<string name="menu_home_search">Cerca</string>
|
||||||
<string name="can_delete_source">Non è possibile eliminare la fonte…</string>
|
<string name="can_delete_source">Non è possibile eliminare la fonte…</string>
|
||||||
<string name="base_url_error">There was an issue when trying to communicate with your Selfoss Instance. If the issue persists, please get in touch with me.</string>
|
<string name="base_url_error">There was an issue when trying to communicate with your Selfoss Instance. If the issue persists, please get in touch with me.</string>
|
||||||
<string name="pref_header_theme">Temi</string>
|
<string name="pref_header_theme">Temi</string>
|
||||||
<string name="default_theme">Predefinito</string>
|
|
||||||
<string name="default_dark_theme">Predefinito (Scuro)</string>
|
|
||||||
<string name="pref_selfoss_category">Api di Selfoss</string>
|
<string name="pref_selfoss_category">Api di Selfoss</string>
|
||||||
<string name="pref_api_items_number_title">Numero di elementi caricati</string>
|
<string name="pref_api_items_number_title">Numero di elementi caricati</string>
|
||||||
<string name="pref_hidden_tags">Tag nascosti</string>
|
|
||||||
<string name="pref_general_infinite_loading_title">Load more articles on scroll</string>
|
<string name="pref_general_infinite_loading_title">Load more articles on scroll</string>
|
||||||
<string name="translation">Traduzioni</string>
|
<string name="translation">Traduzioni</string>
|
||||||
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
|
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
|
||||||
<string name="drawer_report_bug">Segnala un bug</string>
|
|
||||||
<string name="items_number_should_be_number">The items number should be an integer.</string>
|
<string name="items_number_should_be_number">The items number should be an integer.</string>
|
||||||
<string name="reader_action_more">Read more</string>
|
|
||||||
<string name="reader_action_open">Open in browser</string>
|
<string name="reader_action_open">Open in browser</string>
|
||||||
<string name="reader_action_share">Share</string>
|
<string name="reader_action_share">Share</string>
|
||||||
<string name="pref_switch_actions_pager_scroll_on">Mark articles as read when swiping between articles.</string>
|
<string name="pref_switch_actions_pager_scroll_on">Mark articles as read when swiping between articles.</string>
|
||||||
@ -97,7 +83,6 @@
|
|||||||
<string name="markall_dialog_message">This will mark all the items as read.</string>
|
<string name="markall_dialog_message">This will mark all the items as read.</string>
|
||||||
<string name="pref_switch_actions_pager_scroll">Mark as read on swipe</string>
|
<string name="pref_switch_actions_pager_scroll">Mark as read on swipe</string>
|
||||||
<string name="pref_switch_actions_pager_scroll_off">Don\'t mark articles as read when swiping.</string>
|
<string name="pref_switch_actions_pager_scroll_off">Don\'t mark articles as read when swiping.</string>
|
||||||
<string name="drawer_item_hidden_tags">Hidden Tags</string>
|
|
||||||
<string name="unmark">Segna come non letto</string>
|
<string name="unmark">Segna come non letto</string>
|
||||||
<string name="pref_header_offline">Offline and cache</string>
|
<string name="pref_header_offline">Offline and cache</string>
|
||||||
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
|
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
|
||||||
@ -112,7 +97,7 @@
|
|||||||
<string name="pref_switch_periodic_refresh_on">Articles will periodically be synced</string>
|
<string name="pref_switch_periodic_refresh_on">Articles will periodically be synced</string>
|
||||||
<string name="pref_periodic_refresh_minutes_title"><![CDATA[Sync interval ( >= 15 minutes)]]></string>
|
<string name="pref_periodic_refresh_minutes_title"><![CDATA[Sync interval ( >= 15 minutes)]]></string>
|
||||||
<string name="pref_switch_refresh_when_charging">Only refresh when phone is charging</string>
|
<string name="pref_switch_refresh_when_charging">Only refresh when phone is charging</string>
|
||||||
<string name="loading_notification_title">Loading ...</string>
|
<string name="loading_notification_title">Loading …</string>
|
||||||
<string name="loading_notification_text">Selfoss is syncing your articles</string>
|
<string name="loading_notification_text">Selfoss is syncing your articles</string>
|
||||||
<string name="notification_channel_sync">Sync notification</string>
|
<string name="notification_channel_sync">Sync notification</string>
|
||||||
<string name="new_items_channel_sync">New items notification</string>
|
<string name="new_items_channel_sync">New items notification</string>
|
||||||
@ -131,4 +116,19 @@
|
|||||||
<string name="reader_static_bar_on">The bottom bar will always be displayed</string>
|
<string name="reader_static_bar_on">The bottom bar will always be displayed</string>
|
||||||
<string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string>
|
<string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string>
|
||||||
<string name="remove_source">Remove source</string>
|
<string name="remove_source">Remove source</string>
|
||||||
|
<string name="pref_theme_title">Light/Dark mode</string>
|
||||||
|
<string name="mode_dark">Dark mode</string>
|
||||||
|
<string name="mode_system">Follow the system setting</string>
|
||||||
|
<string name="mode_light">Light mode</string>
|
||||||
|
<string name="gdpr_dialog_title">The app does not share any personal data about you.</string>
|
||||||
|
<string name="gdpr_dialog_message"><![CDATA[Crash reports sending is now enabled. It can be disabled from the settings page. Keep in mind that crash reports are essential for the app development.]]></string>
|
||||||
|
<string name="crash_toast_text">A crash occured. Sending the details to the developper.</string>
|
||||||
|
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
|
||||||
|
<string name="menu_home_filter">Filters</string>
|
||||||
|
<string name="application_selfoss_only">This app only works with a Selfoss instance, and no other RSS feed.</string>
|
||||||
|
<string name="menu_home_sources">Sources</string>
|
||||||
|
<string name="update_source">Update source</string>
|
||||||
|
<string name="confirm_disconnect_title">Disconnect ?</string>
|
||||||
|
<string name="confirm_disconnect_description">You will be disconnected from your selfoss instance.</string>
|
||||||
|
<string name="disable_ssl">Disable SSL</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
<string name="withLoginSwitch">"로그인이 필요합니까?"</string>
|
<string name="withLoginSwitch">"로그인이 필요합니까?"</string>
|
||||||
<string name="login_url_problem">"죄송합니다. Url의 끝에 \"/\"를 추가할 필요가 있습니다."</string>
|
<string name="login_url_problem">"죄송합니다. Url의 끝에 \"/\"를 추가할 필요가 있습니다."</string>
|
||||||
<string name="prompt_login">"사용자 이름"</string>
|
<string name="prompt_login">"사용자 이름"</string>
|
||||||
<string name="label_share">"공유"</string>
|
|
||||||
<string name="readAll">"모두 읽기"</string>
|
<string name="readAll">"모두 읽기"</string>
|
||||||
<string name="action_disconnect">"연결 해제"</string>
|
<string name="action_disconnect">"연결 해제"</string>
|
||||||
<string name="title_activity_settings">"설정"</string>
|
<string name="title_activity_settings">"설정"</string>
|
||||||
@ -47,12 +46,9 @@
|
|||||||
<string name="switch_unread_count_title">"Display unread count"</string>
|
<string name="switch_unread_count_title">"Display unread count"</string>
|
||||||
<string name="display_all_counts_title">"Display count for favorite and read"</string>
|
<string name="display_all_counts_title">"Display count for favorite and read"</string>
|
||||||
<string name="text_wrong_url">"You seem to be trying to use an invalid URL. Make sure it is correct, and if the problem persists, contact me (via the store contact link). Please note that the app needs you to be using Selfoss. You can't access RSS feeds without it."</string>
|
<string name="text_wrong_url">"You seem to be trying to use an invalid URL. Make sure it is correct, and if the problem persists, contact me (via the store contact link). Please note that the app needs you to be using Selfoss. You can't access RSS feeds without it."</string>
|
||||||
<string name="pref_general_internal_browser_title">"Open links inside the app"</string>
|
<string name="pref_article_viewer_title">"Open links inside the app"</string>
|
||||||
<string name="pref_general_internal_browser_on">"Articles will open inside the app"</string>
|
<string name="pref_article_viewer_on">"Articles will open inside the app"</string>
|
||||||
<string name="pref_general_internal_browser_off">"Articles will open with your default browser"</string>
|
<string name="pref_article_viewer_off">"Articles will open with your default browser"</string>
|
||||||
<string name="prefer_article_viewer_title">"Use the article viewer"</string>
|
|
||||||
<string name="prefer_article_viewer_on">"Will use the article viewer instead of the internal browser"</string>
|
|
||||||
<string name="prefer_article_viewer_off">"Will use the internal browser instead of the article viewer"</string>
|
|
||||||
<string name="pref_general_category_links">"Link handling"</string>
|
<string name="pref_general_category_links">"Link handling"</string>
|
||||||
<string name="pref_general_category_displaying">"Displaying"</string>
|
<string name="pref_general_category_displaying">"Displaying"</string>
|
||||||
<string name="pref_switch_card_view_on">"The articles will be displayed as cards"</string>
|
<string name="pref_switch_card_view_on">"The articles will be displayed as cards"</string>
|
||||||
@ -65,28 +61,18 @@
|
|||||||
<string name="card_height_on">Cards height will adjust to its content</string>
|
<string name="card_height_on">Cards height will adjust to its content</string>
|
||||||
<string name="card_height_off">Card height will be fixed</string>
|
<string name="card_height_off">Card height will be fixed</string>
|
||||||
<string name="source_code">Source code</string>
|
<string name="source_code">Source code</string>
|
||||||
<string name="drawer_error_loading_tags">Error loading tags…</string>
|
<string name="filter_item_tags">Tags</string>
|
||||||
<string name="drawer_item_filters">Filters</string>
|
<string name="filter_item_sources">Sources</string>
|
||||||
<string name="drawer_action_clear">clear</string>
|
|
||||||
<string name="drawer_item_tags">Tags</string>
|
|
||||||
<string name="drawer_item_sources">Sources</string>
|
|
||||||
<string name="drawer_action_edit">edit</string>
|
|
||||||
<string name="drawer_loading">Loading …</string>
|
|
||||||
<string name="menu_home_search">Search</string>
|
<string name="menu_home_search">Search</string>
|
||||||
<string name="can_delete_source">Can\'t delete the source…</string>
|
<string name="can_delete_source">Can\'t delete the source…</string>
|
||||||
<string name="base_url_error">There was an issue when trying to communicate with your Selfoss Instance. If the issue persists, please get in touch with me.</string>
|
<string name="base_url_error">There was an issue when trying to communicate with your Selfoss Instance. If the issue persists, please get in touch with me.</string>
|
||||||
<string name="pref_header_theme">Themes</string>
|
<string name="pref_header_theme">Themes</string>
|
||||||
<string name="default_theme">Default</string>
|
|
||||||
<string name="default_dark_theme">Default/Dark</string>
|
|
||||||
<string name="pref_selfoss_category">Selfoss Api</string>
|
<string name="pref_selfoss_category">Selfoss Api</string>
|
||||||
<string name="pref_api_items_number_title">Loaded items number</string>
|
<string name="pref_api_items_number_title">Loaded items number</string>
|
||||||
<string name="pref_hidden_tags">Hidden Tags</string>
|
|
||||||
<string name="pref_general_infinite_loading_title">Load more articles on scroll</string>
|
<string name="pref_general_infinite_loading_title">Load more articles on scroll</string>
|
||||||
<string name="translation">Translation</string>
|
<string name="translation">Translation</string>
|
||||||
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
|
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
|
||||||
<string name="drawer_report_bug">Report a bug</string>
|
|
||||||
<string name="items_number_should_be_number">The items number should be an integer.</string>
|
<string name="items_number_should_be_number">The items number should be an integer.</string>
|
||||||
<string name="reader_action_more">Read more</string>
|
|
||||||
<string name="reader_action_open">Open in browser</string>
|
<string name="reader_action_open">Open in browser</string>
|
||||||
<string name="reader_action_share">Share</string>
|
<string name="reader_action_share">Share</string>
|
||||||
<string name="pref_switch_actions_pager_scroll_on">Mark articles as read when swiping between articles.</string>
|
<string name="pref_switch_actions_pager_scroll_on">Mark articles as read when swiping between articles.</string>
|
||||||
@ -97,7 +83,6 @@
|
|||||||
<string name="markall_dialog_message">This will mark all the items as read.</string>
|
<string name="markall_dialog_message">This will mark all the items as read.</string>
|
||||||
<string name="pref_switch_actions_pager_scroll">Mark as read on swipe</string>
|
<string name="pref_switch_actions_pager_scroll">Mark as read on swipe</string>
|
||||||
<string name="pref_switch_actions_pager_scroll_off">Don\'t mark articles as read when swiping.</string>
|
<string name="pref_switch_actions_pager_scroll_off">Don\'t mark articles as read when swiping.</string>
|
||||||
<string name="drawer_item_hidden_tags">Hidden Tags</string>
|
|
||||||
<string name="unmark">Mark item as unread</string>
|
<string name="unmark">Mark item as unread</string>
|
||||||
<string name="pref_header_offline">Offline and cache</string>
|
<string name="pref_header_offline">Offline and cache</string>
|
||||||
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
|
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
|
||||||
@ -112,7 +97,7 @@
|
|||||||
<string name="pref_switch_periodic_refresh_on">Articles will periodically be synced</string>
|
<string name="pref_switch_periodic_refresh_on">Articles will periodically be synced</string>
|
||||||
<string name="pref_periodic_refresh_minutes_title"><![CDATA[Sync interval ( >= 15 minutes)]]></string>
|
<string name="pref_periodic_refresh_minutes_title"><![CDATA[Sync interval ( >= 15 minutes)]]></string>
|
||||||
<string name="pref_switch_refresh_when_charging">Only refresh when phone is charging</string>
|
<string name="pref_switch_refresh_when_charging">Only refresh when phone is charging</string>
|
||||||
<string name="loading_notification_title">Loading ...</string>
|
<string name="loading_notification_title">Loading …</string>
|
||||||
<string name="loading_notification_text">Selfoss is syncing your articles</string>
|
<string name="loading_notification_text">Selfoss is syncing your articles</string>
|
||||||
<string name="notification_channel_sync">Sync notification</string>
|
<string name="notification_channel_sync">Sync notification</string>
|
||||||
<string name="new_items_channel_sync">New items notification</string>
|
<string name="new_items_channel_sync">New items notification</string>
|
||||||
@ -131,4 +116,19 @@
|
|||||||
<string name="reader_static_bar_on">The bottom bar will always be displayed</string>
|
<string name="reader_static_bar_on">The bottom bar will always be displayed</string>
|
||||||
<string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string>
|
<string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string>
|
||||||
<string name="remove_source">Remove source</string>
|
<string name="remove_source">Remove source</string>
|
||||||
|
<string name="pref_theme_title">Light/Dark mode</string>
|
||||||
|
<string name="mode_dark">Dark mode</string>
|
||||||
|
<string name="mode_system">Follow the system setting</string>
|
||||||
|
<string name="mode_light">Light mode</string>
|
||||||
|
<string name="gdpr_dialog_title">The app does not share any personal data about you.</string>
|
||||||
|
<string name="gdpr_dialog_message"><![CDATA[Crash reports sending is now enabled. It can be disabled from the settings page. Keep in mind that crash reports are essential for the app development.]]></string>
|
||||||
|
<string name="crash_toast_text">A crash occured. Sending the details to the developper.</string>
|
||||||
|
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
|
||||||
|
<string name="menu_home_filter">Filters</string>
|
||||||
|
<string name="application_selfoss_only">This app only works with a Selfoss instance, and no other RSS feed.</string>
|
||||||
|
<string name="menu_home_sources">Sources</string>
|
||||||
|
<string name="update_source">Update source</string>
|
||||||
|
<string name="confirm_disconnect_title">Disconnect ?</string>
|
||||||
|
<string name="confirm_disconnect_description">You will be disconnected from your selfoss instance.</string>
|
||||||
|
<string name="disable_ssl">Disable SSL</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
13
androidApp/src/main/res/values-night/styles.xml
Normal file
13
androidApp/src/main/res/values-night/styles.xml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<resources>
|
||||||
|
<style name="NoBar" parent="Theme.MaterialComponents.DayNight.NoActionBar">
|
||||||
|
<item name="colorPrimary">@color/colorPrimary</item>
|
||||||
|
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||||
|
<item name="colorAccent">@color/colorAccent</item>
|
||||||
|
<item name="colorAccentDark">@color/colorAccentDark</item>
|
||||||
|
<item name="preferenceTheme">@style/PreferenceStyle</item>
|
||||||
|
<item name="android:statusBarColor">@color/dark</item>
|
||||||
|
<item name="bottomBarBackground">@color/dark</item>
|
||||||
|
<item name="toolbarPopupTheme">@style/ThemeOverlay.AppCompat.Dark</item>
|
||||||
|
<item name="webviewBackground">@color/dark</item>
|
||||||
|
</style>
|
||||||
|
</resources>
|
@ -10,7 +10,6 @@
|
|||||||
<string name="withLoginSwitch">"Authenticatie vereist?"</string>
|
<string name="withLoginSwitch">"Authenticatie vereist?"</string>
|
||||||
<string name="login_url_problem">"Oeps, ben je soms de \"/\" vergeten aan het eind?"</string>
|
<string name="login_url_problem">"Oeps, ben je soms de \"/\" vergeten aan het eind?"</string>
|
||||||
<string name="prompt_login">"Gebruikersnaam"</string>
|
<string name="prompt_login">"Gebruikersnaam"</string>
|
||||||
<string name="label_share">"Delen"</string>
|
|
||||||
<string name="readAll">"Alles lezen"</string>
|
<string name="readAll">"Alles lezen"</string>
|
||||||
<string name="action_disconnect">"Verbinding verbreken"</string>
|
<string name="action_disconnect">"Verbinding verbreken"</string>
|
||||||
<string name="title_activity_settings">"Instellingen"</string>
|
<string name="title_activity_settings">"Instellingen"</string>
|
||||||
@ -47,12 +46,9 @@
|
|||||||
<string name="switch_unread_count_title">"Geef aantal ongelezen weer"</string>
|
<string name="switch_unread_count_title">"Geef aantal ongelezen weer"</string>
|
||||||
<string name="display_all_counts_title">"Geef aantal weer bij favorieten en gelezen"</string>
|
<string name="display_all_counts_title">"Geef aantal weer bij favorieten en gelezen"</string>
|
||||||
<string name="text_wrong_url">"De gebruikte link lijkt onjuist. Controleer deze. Mocht het probleem blijven, neem dan contact met me op (via de contact link in de store). Om deze app te kunnen gebruiken heb je Selfoss nodig."</string>
|
<string name="text_wrong_url">"De gebruikte link lijkt onjuist. Controleer deze. Mocht het probleem blijven, neem dan contact met me op (via de contact link in de store). Om deze app te kunnen gebruiken heb je Selfoss nodig."</string>
|
||||||
<string name="pref_general_internal_browser_title">"Links opnemen in interne browser"</string>
|
<string name="pref_article_viewer_title">"Links opnemen in interne browser"</string>
|
||||||
<string name="pref_general_internal_browser_on">"Artikelen worden in de interne browser geopend"</string>
|
<string name="pref_article_viewer_on">"Artikelen worden in de interne browser geopend"</string>
|
||||||
<string name="pref_general_internal_browser_off">"Artikelen worden geopend in de standaard browser"</string>
|
<string name="pref_article_viewer_off">"Artikelen worden geopend in de standaard browser"</string>
|
||||||
<string name="prefer_article_viewer_title">"Gebruik artikel viewer"</string>
|
|
||||||
<string name="prefer_article_viewer_on">"Artikelen in viewer weergeven in plaats van de interne browser"</string>
|
|
||||||
<string name="prefer_article_viewer_off">"Artikelen in interne browser weergeven in plaats van viewer"</string>
|
|
||||||
<string name="pref_general_category_links">"Links"</string>
|
<string name="pref_general_category_links">"Links"</string>
|
||||||
<string name="pref_general_category_displaying">"Weergave"</string>
|
<string name="pref_general_category_displaying">"Weergave"</string>
|
||||||
<string name="pref_switch_card_view_on">"De artikelen worden als kaarten weergegeven"</string>
|
<string name="pref_switch_card_view_on">"De artikelen worden als kaarten weergegeven"</string>
|
||||||
@ -65,28 +61,18 @@
|
|||||||
<string name="card_height_on">Hoogte aanpassen aan de hand van kaartinhoud</string>
|
<string name="card_height_on">Hoogte aanpassen aan de hand van kaartinhoud</string>
|
||||||
<string name="card_height_off">Vaste hoogte</string>
|
<string name="card_height_off">Vaste hoogte</string>
|
||||||
<string name="source_code">Broncode</string>
|
<string name="source_code">Broncode</string>
|
||||||
<string name="drawer_error_loading_tags">Fout bij het laden van tags…</string>
|
<string name="filter_item_tags">Tags</string>
|
||||||
<string name="drawer_item_filters">Filters</string>
|
<string name="filter_item_sources">Bronnen</string>
|
||||||
<string name="drawer_action_clear">wissen</string>
|
|
||||||
<string name="drawer_item_tags">Tags</string>
|
|
||||||
<string name="drawer_item_sources">Bronnen</string>
|
|
||||||
<string name="drawer_action_edit">bewerken</string>
|
|
||||||
<string name="drawer_loading">Bezig met laden …</string>
|
|
||||||
<string name="menu_home_search">Zoeken</string>
|
<string name="menu_home_search">Zoeken</string>
|
||||||
<string name="can_delete_source">Kan de bron niet verwijderen…</string>
|
<string name="can_delete_source">Kan de bron niet verwijderen…</string>
|
||||||
<string name="base_url_error">Er was een probleem bij het communiceren met uw Selfoss Instance. Als het probleem blijft, neem dan contact met mij op.</string>
|
<string name="base_url_error">Er was een probleem bij het communiceren met uw Selfoss Instance. Als het probleem blijft, neem dan contact met mij op.</string>
|
||||||
<string name="pref_header_theme">Thema \'s</string>
|
<string name="pref_header_theme">Thema \'s</string>
|
||||||
<string name="default_theme">Standaard</string>
|
|
||||||
<string name="default_dark_theme">Standaard/Donker</string>
|
|
||||||
<string name="pref_selfoss_category">Selfoss Api</string>
|
<string name="pref_selfoss_category">Selfoss Api</string>
|
||||||
<string name="pref_api_items_number_title">Geladen items nummer</string>
|
<string name="pref_api_items_number_title">Geladen items nummer</string>
|
||||||
<string name="pref_hidden_tags">Hidden Tags</string>
|
|
||||||
<string name="pref_general_infinite_loading_title">Laad meer artikelen door te bladeren</string>
|
<string name="pref_general_infinite_loading_title">Laad meer artikelen door te bladeren</string>
|
||||||
<string name="translation">Vertaling</string>
|
<string name="translation">Vertaling</string>
|
||||||
<string name="cant_open_invalid_url">De URL is ongeldig. Ik probeer dit probleem op te lossen, zodat de toepassing niet wordt afgesloten.</string>
|
<string name="cant_open_invalid_url">De URL is ongeldig. Ik probeer dit probleem op te lossen, zodat de toepassing niet wordt afgesloten.</string>
|
||||||
<string name="drawer_report_bug">Een fout melden</string>
|
|
||||||
<string name="items_number_should_be_number">Het aantal items moet een geheel getal zijn.</string>
|
<string name="items_number_should_be_number">Het aantal items moet een geheel getal zijn.</string>
|
||||||
<string name="reader_action_more">Lees meer</string>
|
|
||||||
<string name="reader_action_open">Openen in browser</string>
|
<string name="reader_action_open">Openen in browser</string>
|
||||||
<string name="reader_action_share">Delen</string>
|
<string name="reader_action_share">Delen</string>
|
||||||
<string name="pref_switch_actions_pager_scroll_on">Mark articles as read when swiping between articles.</string>
|
<string name="pref_switch_actions_pager_scroll_on">Mark articles as read when swiping between articles.</string>
|
||||||
@ -97,7 +83,6 @@
|
|||||||
<string name="markall_dialog_message">This will mark all the items as read.</string>
|
<string name="markall_dialog_message">This will mark all the items as read.</string>
|
||||||
<string name="pref_switch_actions_pager_scroll">Mark as read on swipe</string>
|
<string name="pref_switch_actions_pager_scroll">Mark as read on swipe</string>
|
||||||
<string name="pref_switch_actions_pager_scroll_off">Don\'t mark articles as read when swiping.</string>
|
<string name="pref_switch_actions_pager_scroll_off">Don\'t mark articles as read when swiping.</string>
|
||||||
<string name="drawer_item_hidden_tags">Hidden Tags</string>
|
|
||||||
<string name="unmark">Mark item as unread</string>
|
<string name="unmark">Mark item as unread</string>
|
||||||
<string name="pref_header_offline">Offline and cache</string>
|
<string name="pref_header_offline">Offline and cache</string>
|
||||||
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
|
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
|
||||||
@ -112,7 +97,7 @@
|
|||||||
<string name="pref_switch_periodic_refresh_on">Articles will periodically be synced</string>
|
<string name="pref_switch_periodic_refresh_on">Articles will periodically be synced</string>
|
||||||
<string name="pref_periodic_refresh_minutes_title"><![CDATA[Sync interval ( >= 15 minutes)]]></string>
|
<string name="pref_periodic_refresh_minutes_title"><![CDATA[Sync interval ( >= 15 minutes)]]></string>
|
||||||
<string name="pref_switch_refresh_when_charging">Only refresh when phone is charging</string>
|
<string name="pref_switch_refresh_when_charging">Only refresh when phone is charging</string>
|
||||||
<string name="loading_notification_title">Loading ...</string>
|
<string name="loading_notification_title">Loading …</string>
|
||||||
<string name="loading_notification_text">Selfoss is syncing your articles</string>
|
<string name="loading_notification_text">Selfoss is syncing your articles</string>
|
||||||
<string name="notification_channel_sync">Sync notification</string>
|
<string name="notification_channel_sync">Sync notification</string>
|
||||||
<string name="new_items_channel_sync">New items notification</string>
|
<string name="new_items_channel_sync">New items notification</string>
|
||||||
@ -131,4 +116,19 @@
|
|||||||
<string name="reader_static_bar_on">The bottom bar will always be displayed</string>
|
<string name="reader_static_bar_on">The bottom bar will always be displayed</string>
|
||||||
<string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string>
|
<string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string>
|
||||||
<string name="remove_source">Remove source</string>
|
<string name="remove_source">Remove source</string>
|
||||||
|
<string name="pref_theme_title">Light/Dark mode</string>
|
||||||
|
<string name="mode_dark">Dark mode</string>
|
||||||
|
<string name="mode_system">Follow the system setting</string>
|
||||||
|
<string name="mode_light">Light mode</string>
|
||||||
|
<string name="gdpr_dialog_title">The app does not share any personal data about you.</string>
|
||||||
|
<string name="gdpr_dialog_message"><![CDATA[Crash reports sending is now enabled. It can be disabled from the settings page. Keep in mind that crash reports are essential for the app development.]]></string>
|
||||||
|
<string name="crash_toast_text">A crash occured. Sending the details to the developper.</string>
|
||||||
|
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
|
||||||
|
<string name="menu_home_filter">Filters</string>
|
||||||
|
<string name="application_selfoss_only">This app only works with a Selfoss instance, and no other RSS feed.</string>
|
||||||
|
<string name="menu_home_sources">Sources</string>
|
||||||
|
<string name="update_source">Update source</string>
|
||||||
|
<string name="confirm_disconnect_title">Disconnect ?</string>
|
||||||
|
<string name="confirm_disconnect_description">You will be disconnected from your selfoss instance.</string>
|
||||||
|
<string name="disable_ssl">Disable SSL</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
<string name="withLoginSwitch">"É necessário o login ?"</string>
|
<string name="withLoginSwitch">"É necessário o login ?"</string>
|
||||||
<string name="login_url_problem">"Oops. Talvez você precise adicionar uma \"/\" no final da url."</string>
|
<string name="login_url_problem">"Oops. Talvez você precise adicionar uma \"/\" no final da url."</string>
|
||||||
<string name="prompt_login">"Usuário"</string>
|
<string name="prompt_login">"Usuário"</string>
|
||||||
<string name="label_share">"Compartilhar"</string>
|
|
||||||
<string name="readAll">"Ler todos"</string>
|
<string name="readAll">"Ler todos"</string>
|
||||||
<string name="action_disconnect">"Desconectar"</string>
|
<string name="action_disconnect">"Desconectar"</string>
|
||||||
<string name="title_activity_settings">"Configurações"</string>
|
<string name="title_activity_settings">"Configurações"</string>
|
||||||
@ -47,12 +46,9 @@
|
|||||||
<string name="switch_unread_count_title">"Exibir contagem de artigos não lidos"</string>
|
<string name="switch_unread_count_title">"Exibir contagem de artigos não lidos"</string>
|
||||||
<string name="display_all_counts_title">"Exibir contagem de lidos e favoritos"</string>
|
<string name="display_all_counts_title">"Exibir contagem de lidos e favoritos"</string>
|
||||||
<string name="text_wrong_url">"Parece que você está tentando utilizar uma URL inválida. Certifique-se de que está correto, e se o problema persistir, entre em contato comigo (através do link de contato da loja). Por favor, note que o aplicativo precisa que você esteja usando o Selfoss. Você não pode acessar feeds RSS sem ele."</string>
|
<string name="text_wrong_url">"Parece que você está tentando utilizar uma URL inválida. Certifique-se de que está correto, e se o problema persistir, entre em contato comigo (através do link de contato da loja). Por favor, note que o aplicativo precisa que você esteja usando o Selfoss. Você não pode acessar feeds RSS sem ele."</string>
|
||||||
<string name="pref_general_internal_browser_title">"Abrir links dentro do aplicativo"</string>
|
<string name="pref_article_viewer_title">"Abrir links dentro do aplicativo"</string>
|
||||||
<string name="pref_general_internal_browser_on">"Os artigos serão abertos dentro do aplicativo"</string>
|
<string name="pref_article_viewer_on">"Os artigos serão abertos dentro do aplicativo"</string>
|
||||||
<string name="pref_general_internal_browser_off">"Os artigos serão abertos com seu navegador padrão"</string>
|
<string name="pref_article_viewer_off">"Os artigos serão abertos com seu navegador padrão"</string>
|
||||||
<string name="prefer_article_viewer_title">"Use o visualizador de artigos"</string>
|
|
||||||
<string name="prefer_article_viewer_on">"Usará o visualizador de artigos em vez do navegador"</string>
|
|
||||||
<string name="prefer_article_viewer_off">"Utilizará o navegador em vez do visualizador de artigos"</string>
|
|
||||||
<string name="pref_general_category_links">"Manipulação de links"</string>
|
<string name="pref_general_category_links">"Manipulação de links"</string>
|
||||||
<string name="pref_general_category_displaying">"Mostrando"</string>
|
<string name="pref_general_category_displaying">"Mostrando"</string>
|
||||||
<string name="pref_switch_card_view_on">"Os artigos serão exibidos no formato de cards"</string>
|
<string name="pref_switch_card_view_on">"Os artigos serão exibidos no formato de cards"</string>
|
||||||
@ -65,28 +61,18 @@
|
|||||||
<string name="card_height_on">Cards com altura ajustáveis de acordo com o conteúdo</string>
|
<string name="card_height_on">Cards com altura ajustáveis de acordo com o conteúdo</string>
|
||||||
<string name="card_height_off">Cards com altura de tamanho fixo</string>
|
<string name="card_height_off">Cards com altura de tamanho fixo</string>
|
||||||
<string name="source_code">Código fonte</string>
|
<string name="source_code">Código fonte</string>
|
||||||
<string name="drawer_error_loading_tags">Erro ao carregar as tags…</string>
|
<string name="filter_item_tags">Tags</string>
|
||||||
<string name="drawer_item_filters">Filtros</string>
|
<string name="filter_item_sources">Fontes</string>
|
||||||
<string name="drawer_action_clear">limpar</string>
|
|
||||||
<string name="drawer_item_tags">Tags</string>
|
|
||||||
<string name="drawer_item_sources">Fontes</string>
|
|
||||||
<string name="drawer_action_edit">editar</string>
|
|
||||||
<string name="drawer_loading">Carregando …</string>
|
|
||||||
<string name="menu_home_search">Procurar</string>
|
<string name="menu_home_search">Procurar</string>
|
||||||
<string name="can_delete_source">Não foi possível apagar a fonte…</string>
|
<string name="can_delete_source">Não foi possível apagar a fonte…</string>
|
||||||
<string name="base_url_error">Houve um problema ao tentar se comunicar com o seu Selfoss. Se o problema persistir, entre em contato comigo.</string>
|
<string name="base_url_error">Houve um problema ao tentar se comunicar com o seu Selfoss. Se o problema persistir, entre em contato comigo.</string>
|
||||||
<string name="pref_header_theme">Temas</string>
|
<string name="pref_header_theme">Temas</string>
|
||||||
<string name="default_theme">Padrão</string>
|
|
||||||
<string name="default_dark_theme">Padrão/Escuro</string>
|
|
||||||
<string name="pref_selfoss_category">Selfoss Api</string>
|
<string name="pref_selfoss_category">Selfoss Api</string>
|
||||||
<string name="pref_api_items_number_title">Quantidade de itens carregados</string>
|
<string name="pref_api_items_number_title">Quantidade de itens carregados</string>
|
||||||
<string name="pref_hidden_tags">Hidden Tags</string>
|
|
||||||
<string name="pref_general_infinite_loading_title">Carregar mais artigos ao realizar o scroll</string>
|
<string name="pref_general_infinite_loading_title">Carregar mais artigos ao realizar o scroll</string>
|
||||||
<string name="translation">Traduções</string>
|
<string name="translation">Traduções</string>
|
||||||
<string name="cant_open_invalid_url">A url está inválida. Estou tentando resolver esse problema para que o aplicativo não encerre.</string>
|
<string name="cant_open_invalid_url">A url está inválida. Estou tentando resolver esse problema para que o aplicativo não encerre.</string>
|
||||||
<string name="drawer_report_bug">Reportar erro</string>
|
|
||||||
<string name="items_number_should_be_number">O número dos itens deve ser um número inteiro.</string>
|
<string name="items_number_should_be_number">O número dos itens deve ser um número inteiro.</string>
|
||||||
<string name="reader_action_more">Leia mais</string>
|
|
||||||
<string name="reader_action_open">Abrir no navegador</string>
|
<string name="reader_action_open">Abrir no navegador</string>
|
||||||
<string name="reader_action_share">Compartilhar</string>
|
<string name="reader_action_share">Compartilhar</string>
|
||||||
<string name="pref_switch_actions_pager_scroll_on">Se esta configuração estiver ativada, os artigos serão marcados como lidos ao deslizar para a esquerda e para a direita no leitor do artigo.</string>
|
<string name="pref_switch_actions_pager_scroll_on">Se esta configuração estiver ativada, os artigos serão marcados como lidos ao deslizar para a esquerda e para a direita no leitor do artigo.</string>
|
||||||
@ -97,7 +83,6 @@
|
|||||||
<string name="markall_dialog_message">Isso marcará todos os itens como lidos.</string>
|
<string name="markall_dialog_message">Isso marcará todos os itens como lidos.</string>
|
||||||
<string name="pref_switch_actions_pager_scroll">Marcar Como Lida ao Abrir</string>
|
<string name="pref_switch_actions_pager_scroll">Marcar Como Lida ao Abrir</string>
|
||||||
<string name="pref_switch_actions_pager_scroll_off">Não marca artigos como lido quando abrir.</string>
|
<string name="pref_switch_actions_pager_scroll_off">Não marca artigos como lido quando abrir.</string>
|
||||||
<string name="drawer_item_hidden_tags">Hidden Tags</string>
|
|
||||||
<string name="unmark">Mark item as unread</string>
|
<string name="unmark">Mark item as unread</string>
|
||||||
<string name="pref_header_offline">Offline and cache</string>
|
<string name="pref_header_offline">Offline and cache</string>
|
||||||
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
|
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
|
||||||
@ -112,7 +97,7 @@
|
|||||||
<string name="pref_switch_periodic_refresh_on">Articles will periodically be synced</string>
|
<string name="pref_switch_periodic_refresh_on">Articles will periodically be synced</string>
|
||||||
<string name="pref_periodic_refresh_minutes_title"><![CDATA[Sync interval ( >= 15 minutes)]]></string>
|
<string name="pref_periodic_refresh_minutes_title"><![CDATA[Sync interval ( >= 15 minutes)]]></string>
|
||||||
<string name="pref_switch_refresh_when_charging">Only refresh when phone is charging</string>
|
<string name="pref_switch_refresh_when_charging">Only refresh when phone is charging</string>
|
||||||
<string name="loading_notification_title">Loading ...</string>
|
<string name="loading_notification_title">Loading …</string>
|
||||||
<string name="loading_notification_text">Selfoss is syncing your articles</string>
|
<string name="loading_notification_text">Selfoss is syncing your articles</string>
|
||||||
<string name="notification_channel_sync">Sync notification</string>
|
<string name="notification_channel_sync">Sync notification</string>
|
||||||
<string name="new_items_channel_sync">New items notification</string>
|
<string name="new_items_channel_sync">New items notification</string>
|
||||||
@ -131,4 +116,19 @@
|
|||||||
<string name="reader_static_bar_on">The bottom bar will always be displayed</string>
|
<string name="reader_static_bar_on">The bottom bar will always be displayed</string>
|
||||||
<string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string>
|
<string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string>
|
||||||
<string name="remove_source">Remove source</string>
|
<string name="remove_source">Remove source</string>
|
||||||
|
<string name="pref_theme_title">Light/Dark mode</string>
|
||||||
|
<string name="mode_dark">Dark mode</string>
|
||||||
|
<string name="mode_system">Follow the system setting</string>
|
||||||
|
<string name="mode_light">Light mode</string>
|
||||||
|
<string name="gdpr_dialog_title">The app does not share any personal data about you.</string>
|
||||||
|
<string name="gdpr_dialog_message"><![CDATA[Crash reports sending is now enabled. It can be disabled from the settings page. Keep in mind that crash reports are essential for the app development.]]></string>
|
||||||
|
<string name="crash_toast_text">A crash occured. Sending the details to the developper.</string>
|
||||||
|
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
|
||||||
|
<string name="menu_home_filter">Filters</string>
|
||||||
|
<string name="application_selfoss_only">This app only works with a Selfoss instance, and no other RSS feed.</string>
|
||||||
|
<string name="menu_home_sources">Sources</string>
|
||||||
|
<string name="update_source">Update source</string>
|
||||||
|
<string name="confirm_disconnect_title">Disconnect ?</string>
|
||||||
|
<string name="confirm_disconnect_description">You will be disconnected from your selfoss instance.</string>
|
||||||
|
<string name="disable_ssl">Disable SSL</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
<string name="withLoginSwitch">"É necessário fazer login?"</string>
|
<string name="withLoginSwitch">"É necessário fazer login?"</string>
|
||||||
<string name="login_url_problem">"Uups. Você pode precisar adicionar uma \"/\" no final da url."</string>
|
<string name="login_url_problem">"Uups. Você pode precisar adicionar uma \"/\" no final da url."</string>
|
||||||
<string name="prompt_login">"Nome do usuário"</string>
|
<string name="prompt_login">"Nome do usuário"</string>
|
||||||
<string name="label_share">"Compartilhar"</string>
|
|
||||||
<string name="readAll">"Ler tudo"</string>
|
<string name="readAll">"Ler tudo"</string>
|
||||||
<string name="action_disconnect">"Desligar"</string>
|
<string name="action_disconnect">"Desligar"</string>
|
||||||
<string name="title_activity_settings">"Configurações"</string>
|
<string name="title_activity_settings">"Configurações"</string>
|
||||||
@ -47,12 +46,9 @@
|
|||||||
<string name="switch_unread_count_title">"Exibir a contagem não lida"</string>
|
<string name="switch_unread_count_title">"Exibir a contagem não lida"</string>
|
||||||
<string name="display_all_counts_title">"Exibir a contagem para o favorito e leitura"</string>
|
<string name="display_all_counts_title">"Exibir a contagem para o favorito e leitura"</string>
|
||||||
<string name="text_wrong_url">"Você parece estar tentando usar um URL inválido. Certifique-se de que está correto, e se o problema persistir, entre em contato comigo (através do link de contato da loja). Por favor, note que o aplicativo precisa que você esteja usando o Selfoss. Você não pode acessar feeds RSS sem ele."</string>
|
<string name="text_wrong_url">"Você parece estar tentando usar um URL inválido. Certifique-se de que está correto, e se o problema persistir, entre em contato comigo (através do link de contato da loja). Por favor, note que o aplicativo precisa que você esteja usando o Selfoss. Você não pode acessar feeds RSS sem ele."</string>
|
||||||
<string name="pref_general_internal_browser_title">"Abrir links dentro do app"</string>
|
<string name="pref_article_viewer_title">"Abrir links dentro do app"</string>
|
||||||
<string name="pref_general_internal_browser_on">"Artigos serão aberto dentro do aplicativo"</string>
|
<string name="pref_article_viewer_on">"Artigos serão aberto dentro do aplicativo"</string>
|
||||||
<string name="pref_general_internal_browser_off">"Artigos serão aberto com o seu navegador padrão"</string>
|
<string name="pref_article_viewer_off">"Artigos serão aberto com o seu navegador padrão"</string>
|
||||||
<string name="prefer_article_viewer_title">"Use o Visualizador de artigo"</string>
|
|
||||||
<string name="prefer_article_viewer_on">"Vai usar o Visualizador de artigo em vez do navegador interno"</string>
|
|
||||||
<string name="prefer_article_viewer_off">"Vai usar o navegador interno em vez do Visualizador de artigo"</string>
|
|
||||||
<string name="pref_general_category_links">"Manipulação de ligações"</string>
|
<string name="pref_general_category_links">"Manipulação de ligações"</string>
|
||||||
<string name="pref_general_category_displaying">"Mostrando"</string>
|
<string name="pref_general_category_displaying">"Mostrando"</string>
|
||||||
<string name="pref_switch_card_view_on">"Os artigos serão exibidos como cartões"</string>
|
<string name="pref_switch_card_view_on">"Os artigos serão exibidos como cartões"</string>
|
||||||
@ -65,28 +61,18 @@
|
|||||||
<string name="card_height_on">Altura de cartas irá ajustar ao seu conteúdo</string>
|
<string name="card_height_on">Altura de cartas irá ajustar ao seu conteúdo</string>
|
||||||
<string name="card_height_off">Altura do cartão será corrigida</string>
|
<string name="card_height_off">Altura do cartão será corrigida</string>
|
||||||
<string name="source_code">Código fonte</string>
|
<string name="source_code">Código fonte</string>
|
||||||
<string name="drawer_error_loading_tags">Erro ao carregar etiquetas…</string>
|
<string name="filter_item_tags">Etiquetas</string>
|
||||||
<string name="drawer_item_filters">Filtros</string>
|
<string name="filter_item_sources">Fontes</string>
|
||||||
<string name="drawer_action_clear">limpar</string>
|
|
||||||
<string name="drawer_item_tags">Etiquetas</string>
|
|
||||||
<string name="drawer_item_sources">Fontes</string>
|
|
||||||
<string name="drawer_action_edit">editar</string>
|
|
||||||
<string name="drawer_loading">A carregar…</string>
|
|
||||||
<string name="menu_home_search">Buscar</string>
|
<string name="menu_home_search">Buscar</string>
|
||||||
<string name="can_delete_source">Não é possível excluir a fonte…</string>
|
<string name="can_delete_source">Não é possível excluir a fonte…</string>
|
||||||
<string name="base_url_error">Houve um problema ao tentar se comunicar com sua instância de Selfoss. Se o problema persistir, por favor entre em contato comigo.</string>
|
<string name="base_url_error">Houve um problema ao tentar se comunicar com sua instância de Selfoss. Se o problema persistir, por favor entre em contato comigo.</string>
|
||||||
<string name="pref_header_theme">Temas</string>
|
<string name="pref_header_theme">Temas</string>
|
||||||
<string name="default_theme">Predefinição</string>
|
|
||||||
<string name="default_dark_theme">Padrão/escuro</string>
|
|
||||||
<string name="pref_selfoss_category">Api de Selfoss</string>
|
<string name="pref_selfoss_category">Api de Selfoss</string>
|
||||||
<string name="pref_api_items_number_title">Número de itens carregados</string>
|
<string name="pref_api_items_number_title">Número de itens carregados</string>
|
||||||
<string name="pref_hidden_tags">Hidden Tags</string>
|
|
||||||
<string name="pref_general_infinite_loading_title">Carregar mais artigos no pergaminho</string>
|
<string name="pref_general_infinite_loading_title">Carregar mais artigos no pergaminho</string>
|
||||||
<string name="translation">Tradução</string>
|
<string name="translation">Tradução</string>
|
||||||
<string name="cant_open_invalid_url">A url do item é inválido. Eu estou olhando para resolver esta questão, para que o app não vai falhar.</string>
|
<string name="cant_open_invalid_url">A url do item é inválido. Eu estou olhando para resolver esta questão, para que o app não vai falhar.</string>
|
||||||
<string name="drawer_report_bug">Reportar falha</string>
|
|
||||||
<string name="items_number_should_be_number">O número de itens deve ser um número inteiro.</string>
|
<string name="items_number_should_be_number">O número de itens deve ser um número inteiro.</string>
|
||||||
<string name="reader_action_more">Ler mais</string>
|
|
||||||
<string name="reader_action_open">Abrir no browser</string>
|
<string name="reader_action_open">Abrir no browser</string>
|
||||||
<string name="reader_action_share">Compartilhar</string>
|
<string name="reader_action_share">Compartilhar</string>
|
||||||
<string name="pref_switch_actions_pager_scroll_on">Artigos de marca como lida quando passar entre artigos.</string>
|
<string name="pref_switch_actions_pager_scroll_on">Artigos de marca como lida quando passar entre artigos.</string>
|
||||||
@ -97,7 +83,6 @@
|
|||||||
<string name="markall_dialog_message">This will mark all the items as read.</string>
|
<string name="markall_dialog_message">This will mark all the items as read.</string>
|
||||||
<string name="pref_switch_actions_pager_scroll">Mark as read on swipe</string>
|
<string name="pref_switch_actions_pager_scroll">Mark as read on swipe</string>
|
||||||
<string name="pref_switch_actions_pager_scroll_off">Don\'t mark articles as read when swiping.</string>
|
<string name="pref_switch_actions_pager_scroll_off">Don\'t mark articles as read when swiping.</string>
|
||||||
<string name="drawer_item_hidden_tags">Hidden Tags</string>
|
|
||||||
<string name="unmark">Mark item as unread</string>
|
<string name="unmark">Mark item as unread</string>
|
||||||
<string name="pref_header_offline">Offline and cache</string>
|
<string name="pref_header_offline">Offline and cache</string>
|
||||||
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
|
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
|
||||||
@ -112,7 +97,7 @@
|
|||||||
<string name="pref_switch_periodic_refresh_on">Articles will periodically be synced</string>
|
<string name="pref_switch_periodic_refresh_on">Articles will periodically be synced</string>
|
||||||
<string name="pref_periodic_refresh_minutes_title"><![CDATA[Sync interval ( >= 15 minutes)]]></string>
|
<string name="pref_periodic_refresh_minutes_title"><![CDATA[Sync interval ( >= 15 minutes)]]></string>
|
||||||
<string name="pref_switch_refresh_when_charging">Only refresh when phone is charging</string>
|
<string name="pref_switch_refresh_when_charging">Only refresh when phone is charging</string>
|
||||||
<string name="loading_notification_title">Loading ...</string>
|
<string name="loading_notification_title">Loading …</string>
|
||||||
<string name="loading_notification_text">Selfoss is syncing your articles</string>
|
<string name="loading_notification_text">Selfoss is syncing your articles</string>
|
||||||
<string name="notification_channel_sync">Sync notification</string>
|
<string name="notification_channel_sync">Sync notification</string>
|
||||||
<string name="new_items_channel_sync">New items notification</string>
|
<string name="new_items_channel_sync">New items notification</string>
|
||||||
@ -131,4 +116,19 @@
|
|||||||
<string name="reader_static_bar_on">The bottom bar will always be displayed</string>
|
<string name="reader_static_bar_on">The bottom bar will always be displayed</string>
|
||||||
<string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string>
|
<string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string>
|
||||||
<string name="remove_source">Remove source</string>
|
<string name="remove_source">Remove source</string>
|
||||||
|
<string name="pref_theme_title">Light/Dark mode</string>
|
||||||
|
<string name="mode_dark">Dark mode</string>
|
||||||
|
<string name="mode_system">Follow the system setting</string>
|
||||||
|
<string name="mode_light">Light mode</string>
|
||||||
|
<string name="gdpr_dialog_title">The app does not share any personal data about you.</string>
|
||||||
|
<string name="gdpr_dialog_message"><![CDATA[Crash reports sending is now enabled. It can be disabled from the settings page. Keep in mind that crash reports are essential for the app development.]]></string>
|
||||||
|
<string name="crash_toast_text">A crash occured. Sending the details to the developper.</string>
|
||||||
|
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
|
||||||
|
<string name="menu_home_filter">Filters</string>
|
||||||
|
<string name="application_selfoss_only">This app only works with a Selfoss instance, and no other RSS feed.</string>
|
||||||
|
<string name="menu_home_sources">Sources</string>
|
||||||
|
<string name="update_source">Update source</string>
|
||||||
|
<string name="confirm_disconnect_title">Disconnect ?</string>
|
||||||
|
<string name="confirm_disconnect_description">You will be disconnected from your selfoss instance.</string>
|
||||||
|
<string name="disable_ssl">Disable SSL</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
<string name="withLoginSwitch">"Login required ?"</string>
|
<string name="withLoginSwitch">"Login required ?"</string>
|
||||||
<string name="login_url_problem">"Oops. You may need to add a \"/\" at the end of the url."</string>
|
<string name="login_url_problem">"Oops. You may need to add a \"/\" at the end of the url."</string>
|
||||||
<string name="prompt_login">"පරිශීලක නාමය"</string>
|
<string name="prompt_login">"පරිශීලක නාමය"</string>
|
||||||
<string name="label_share">"Share"</string>
|
|
||||||
<string name="readAll">"Read all"</string>
|
<string name="readAll">"Read all"</string>
|
||||||
<string name="action_disconnect">"Disconnect"</string>
|
<string name="action_disconnect">"Disconnect"</string>
|
||||||
<string name="title_activity_settings">"සැකසුම්"</string>
|
<string name="title_activity_settings">"සැකසුම්"</string>
|
||||||
@ -47,12 +46,9 @@
|
|||||||
<string name="switch_unread_count_title">"Display unread count"</string>
|
<string name="switch_unread_count_title">"Display unread count"</string>
|
||||||
<string name="display_all_counts_title">"Display count for favorite and read"</string>
|
<string name="display_all_counts_title">"Display count for favorite and read"</string>
|
||||||
<string name="text_wrong_url">"You seem to be trying to use an invalid URL. Make sure it is correct, and if the problem persists, contact me (via the store contact link). Please note that the app needs you to be using Selfoss. You can't access RSS feeds without it."</string>
|
<string name="text_wrong_url">"You seem to be trying to use an invalid URL. Make sure it is correct, and if the problem persists, contact me (via the store contact link). Please note that the app needs you to be using Selfoss. You can't access RSS feeds without it."</string>
|
||||||
<string name="pref_general_internal_browser_title">"Open links inside the app"</string>
|
<string name="pref_article_viewer_title">"Open links inside the app"</string>
|
||||||
<string name="pref_general_internal_browser_on">"Articles will open inside the app"</string>
|
<string name="pref_article_viewer_on">"Articles will open inside the app"</string>
|
||||||
<string name="pref_general_internal_browser_off">"Articles will open with your default browser"</string>
|
<string name="pref_article_viewer_off">"Articles will open with your default browser"</string>
|
||||||
<string name="prefer_article_viewer_title">"Use the article viewer"</string>
|
|
||||||
<string name="prefer_article_viewer_on">"Will use the article viewer instead of the internal browser"</string>
|
|
||||||
<string name="prefer_article_viewer_off">"Will use the internal browser instead of the article viewer"</string>
|
|
||||||
<string name="pref_general_category_links">"Link handling"</string>
|
<string name="pref_general_category_links">"Link handling"</string>
|
||||||
<string name="pref_general_category_displaying">"Displaying"</string>
|
<string name="pref_general_category_displaying">"Displaying"</string>
|
||||||
<string name="pref_switch_card_view_on">"The articles will be displayed as cards"</string>
|
<string name="pref_switch_card_view_on">"The articles will be displayed as cards"</string>
|
||||||
@ -65,28 +61,18 @@
|
|||||||
<string name="card_height_on">Cards height will adjust to its content</string>
|
<string name="card_height_on">Cards height will adjust to its content</string>
|
||||||
<string name="card_height_off">Card height will be fixed</string>
|
<string name="card_height_off">Card height will be fixed</string>
|
||||||
<string name="source_code">Source code</string>
|
<string name="source_code">Source code</string>
|
||||||
<string name="drawer_error_loading_tags">Error loading tags…</string>
|
<string name="filter_item_tags">Tags</string>
|
||||||
<string name="drawer_item_filters">Filters</string>
|
<string name="filter_item_sources">Sources</string>
|
||||||
<string name="drawer_action_clear">clear</string>
|
|
||||||
<string name="drawer_item_tags">Tags</string>
|
|
||||||
<string name="drawer_item_sources">Sources</string>
|
|
||||||
<string name="drawer_action_edit">edit</string>
|
|
||||||
<string name="drawer_loading">Loading …</string>
|
|
||||||
<string name="menu_home_search">Search</string>
|
<string name="menu_home_search">Search</string>
|
||||||
<string name="can_delete_source">Can\'t delete the source…</string>
|
<string name="can_delete_source">Can\'t delete the source…</string>
|
||||||
<string name="base_url_error">There was an issue when trying to communicate with your Selfoss Instance. If the issue persists, please get in touch with me.</string>
|
<string name="base_url_error">There was an issue when trying to communicate with your Selfoss Instance. If the issue persists, please get in touch with me.</string>
|
||||||
<string name="pref_header_theme">Themes</string>
|
<string name="pref_header_theme">Themes</string>
|
||||||
<string name="default_theme">Default</string>
|
|
||||||
<string name="default_dark_theme">Default/Dark</string>
|
|
||||||
<string name="pref_selfoss_category">Selfoss Api</string>
|
<string name="pref_selfoss_category">Selfoss Api</string>
|
||||||
<string name="pref_api_items_number_title">Loaded items number</string>
|
<string name="pref_api_items_number_title">Loaded items number</string>
|
||||||
<string name="pref_hidden_tags">Hidden Tags</string>
|
|
||||||
<string name="pref_general_infinite_loading_title">Load more articles on scroll</string>
|
<string name="pref_general_infinite_loading_title">Load more articles on scroll</string>
|
||||||
<string name="translation">Translation</string>
|
<string name="translation">Translation</string>
|
||||||
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
|
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
|
||||||
<string name="drawer_report_bug">Report a bug</string>
|
|
||||||
<string name="items_number_should_be_number">The items number should be an integer.</string>
|
<string name="items_number_should_be_number">The items number should be an integer.</string>
|
||||||
<string name="reader_action_more">Read more</string>
|
|
||||||
<string name="reader_action_open">Open in browser</string>
|
<string name="reader_action_open">Open in browser</string>
|
||||||
<string name="reader_action_share">Share</string>
|
<string name="reader_action_share">Share</string>
|
||||||
<string name="pref_switch_actions_pager_scroll_on">Mark articles as read when swiping between articles.</string>
|
<string name="pref_switch_actions_pager_scroll_on">Mark articles as read when swiping between articles.</string>
|
||||||
@ -97,7 +83,6 @@
|
|||||||
<string name="markall_dialog_message">This will mark all the items as read.</string>
|
<string name="markall_dialog_message">This will mark all the items as read.</string>
|
||||||
<string name="pref_switch_actions_pager_scroll">Mark as read on swipe</string>
|
<string name="pref_switch_actions_pager_scroll">Mark as read on swipe</string>
|
||||||
<string name="pref_switch_actions_pager_scroll_off">Don\'t mark articles as read when swiping.</string>
|
<string name="pref_switch_actions_pager_scroll_off">Don\'t mark articles as read when swiping.</string>
|
||||||
<string name="drawer_item_hidden_tags">Hidden Tags</string>
|
|
||||||
<string name="unmark">Mark item as unread</string>
|
<string name="unmark">Mark item as unread</string>
|
||||||
<string name="pref_header_offline">Offline and cache</string>
|
<string name="pref_header_offline">Offline and cache</string>
|
||||||
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
|
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
|
||||||
@ -112,7 +97,7 @@
|
|||||||
<string name="pref_switch_periodic_refresh_on">Articles will periodically be synced</string>
|
<string name="pref_switch_periodic_refresh_on">Articles will periodically be synced</string>
|
||||||
<string name="pref_periodic_refresh_minutes_title"><![CDATA[Sync interval ( >= 15 minutes)]]></string>
|
<string name="pref_periodic_refresh_minutes_title"><![CDATA[Sync interval ( >= 15 minutes)]]></string>
|
||||||
<string name="pref_switch_refresh_when_charging">Only refresh when phone is charging</string>
|
<string name="pref_switch_refresh_when_charging">Only refresh when phone is charging</string>
|
||||||
<string name="loading_notification_title">Loading ...</string>
|
<string name="loading_notification_title">Loading …</string>
|
||||||
<string name="loading_notification_text">Selfoss is syncing your articles</string>
|
<string name="loading_notification_text">Selfoss is syncing your articles</string>
|
||||||
<string name="notification_channel_sync">Sync notification</string>
|
<string name="notification_channel_sync">Sync notification</string>
|
||||||
<string name="new_items_channel_sync">New items notification</string>
|
<string name="new_items_channel_sync">New items notification</string>
|
||||||
@ -131,4 +116,19 @@
|
|||||||
<string name="reader_static_bar_on">The bottom bar will always be displayed</string>
|
<string name="reader_static_bar_on">The bottom bar will always be displayed</string>
|
||||||
<string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string>
|
<string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string>
|
||||||
<string name="remove_source">Remove source</string>
|
<string name="remove_source">Remove source</string>
|
||||||
|
<string name="pref_theme_title">Light/Dark mode</string>
|
||||||
|
<string name="mode_dark">Dark mode</string>
|
||||||
|
<string name="mode_system">Follow the system setting</string>
|
||||||
|
<string name="mode_light">Light mode</string>
|
||||||
|
<string name="gdpr_dialog_title">The app does not share any personal data about you.</string>
|
||||||
|
<string name="gdpr_dialog_message"><![CDATA[Crash reports sending is now enabled. It can be disabled from the settings page. Keep in mind that crash reports are essential for the app development.]]></string>
|
||||||
|
<string name="crash_toast_text">A crash occured. Sending the details to the developper.</string>
|
||||||
|
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
|
||||||
|
<string name="menu_home_filter">Filters</string>
|
||||||
|
<string name="application_selfoss_only">This app only works with a Selfoss instance, and no other RSS feed.</string>
|
||||||
|
<string name="menu_home_sources">Sources</string>
|
||||||
|
<string name="update_source">Update source</string>
|
||||||
|
<string name="confirm_disconnect_title">Disconnect ?</string>
|
||||||
|
<string name="confirm_disconnect_description">You will be disconnected from your selfoss instance.</string>
|
||||||
|
<string name="disable_ssl">Disable SSL</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
<string name="withLoginSwitch">"Kullanıcı Girişi Gerekli?"</string>
|
<string name="withLoginSwitch">"Kullanıcı Girişi Gerekli?"</string>
|
||||||
<string name="login_url_problem">"Oops. Url'nin sonuna \"/\" eklemek gerekebilir."</string>
|
<string name="login_url_problem">"Oops. Url'nin sonuna \"/\" eklemek gerekebilir."</string>
|
||||||
<string name="prompt_login">"Kullanıcı adı"</string>
|
<string name="prompt_login">"Kullanıcı adı"</string>
|
||||||
<string name="label_share">"Paylaş"</string>
|
|
||||||
<string name="readAll">"Tümünü oku"</string>
|
<string name="readAll">"Tümünü oku"</string>
|
||||||
<string name="action_disconnect">"Bağlantıyı kes"</string>
|
<string name="action_disconnect">"Bağlantıyı kes"</string>
|
||||||
<string name="title_activity_settings">"Ayarlar"</string>
|
<string name="title_activity_settings">"Ayarlar"</string>
|
||||||
@ -47,12 +46,9 @@
|
|||||||
<string name="switch_unread_count_title">"Okunmamış sayıyı görüntüle"</string>
|
<string name="switch_unread_count_title">"Okunmamış sayıyı görüntüle"</string>
|
||||||
<string name="display_all_counts_title">"Favori ve okunan sayıları göster"</string>
|
<string name="display_all_counts_title">"Favori ve okunan sayıları göster"</string>
|
||||||
<string name="text_wrong_url">"Geçersiz bir URL kullanmaya çalışıyormuş gibi görünüyorsunuz. Doğru olduğundan emin olun ve sorun devam ederse, bana ulaşın (mağaza iletişim bağlantısıyla). Uygulamanın, Selfoss'u kullanmanız gerektiğini lütfen unutmayın. RSS özet akışlarına olmadan erişemezsiniz."</string>
|
<string name="text_wrong_url">"Geçersiz bir URL kullanmaya çalışıyormuş gibi görünüyorsunuz. Doğru olduğundan emin olun ve sorun devam ederse, bana ulaşın (mağaza iletişim bağlantısıyla). Uygulamanın, Selfoss'u kullanmanız gerektiğini lütfen unutmayın. RSS özet akışlarına olmadan erişemezsiniz."</string>
|
||||||
<string name="pref_general_internal_browser_title">"Uygulamadaki bağlantıları açın"</string>
|
<string name="pref_article_viewer_title">"Uygulamadaki bağlantıları açın"</string>
|
||||||
<string name="pref_general_internal_browser_on">"Makale, uygulama içinde açılacaktır"</string>
|
<string name="pref_article_viewer_on">"Makale, uygulama içinde açılacaktır"</string>
|
||||||
<string name="pref_general_internal_browser_off">"Makaleler varsayılan tarayıcınızla açılır"</string>
|
<string name="pref_article_viewer_off">"Makaleler varsayılan tarayıcınızla açılır"</string>
|
||||||
<string name="prefer_article_viewer_title">"Makale görüntüleyiciyi kullanın"</string>
|
|
||||||
<string name="prefer_article_viewer_on">"Dahili tarayıcı yerine makale görüntüleyicisini kullanacak"</string>
|
|
||||||
<string name="prefer_article_viewer_off">"Makale görüntüleyicisi yerine dahili tarayıcıyı kullanacak"</string>
|
|
||||||
<string name="pref_general_category_links">"Bağlantı açma şekli"</string>
|
<string name="pref_general_category_links">"Bağlantı açma şekli"</string>
|
||||||
<string name="pref_general_category_displaying">"Gösteriliyor"</string>
|
<string name="pref_general_category_displaying">"Gösteriliyor"</string>
|
||||||
<string name="pref_switch_card_view_on">"Makaleler kart olarak gösterilecek"</string>
|
<string name="pref_switch_card_view_on">"Makaleler kart olarak gösterilecek"</string>
|
||||||
@ -65,28 +61,18 @@
|
|||||||
<string name="card_height_on">Kartların yüksekliği içeriğine göre ayarlanır</string>
|
<string name="card_height_on">Kartların yüksekliği içeriğine göre ayarlanır</string>
|
||||||
<string name="card_height_off">Kart yüksekliği sabit olacak</string>
|
<string name="card_height_off">Kart yüksekliği sabit olacak</string>
|
||||||
<string name="source_code">Kaynak kodu</string>
|
<string name="source_code">Kaynak kodu</string>
|
||||||
<string name="drawer_error_loading_tags">Etiketler yükleme hatası…</string>
|
<string name="filter_item_tags">Etiketler</string>
|
||||||
<string name="drawer_item_filters">Filtreler</string>
|
<string name="filter_item_sources">Kaynaklar</string>
|
||||||
<string name="drawer_action_clear">temizle</string>
|
|
||||||
<string name="drawer_item_tags">Etiketler</string>
|
|
||||||
<string name="drawer_item_sources">Kaynaklar</string>
|
|
||||||
<string name="drawer_action_edit">düzenle</string>
|
|
||||||
<string name="drawer_loading">Yükleniyor…</string>
|
|
||||||
<string name="menu_home_search">Ara</string>
|
<string name="menu_home_search">Ara</string>
|
||||||
<string name="can_delete_source">Kaynak silinemiyor…</string>
|
<string name="can_delete_source">Kaynak silinemiyor…</string>
|
||||||
<string name="base_url_error">Selfoss Örneğinizle iletişim kurmaya çalışırken bir sorun oluştu. Sorun devam ederse, lütfen benimle iletişime geçin.</string>
|
<string name="base_url_error">Selfoss Örneğinizle iletişim kurmaya çalışırken bir sorun oluştu. Sorun devam ederse, lütfen benimle iletişime geçin.</string>
|
||||||
<string name="pref_header_theme">Temalar</string>
|
<string name="pref_header_theme">Temalar</string>
|
||||||
<string name="default_theme">Varsayılan</string>
|
|
||||||
<string name="default_dark_theme">Varsayılan/koyu</string>
|
|
||||||
<string name="pref_selfoss_category">Selfoss Uygulaması</string>
|
<string name="pref_selfoss_category">Selfoss Uygulaması</string>
|
||||||
<string name="pref_api_items_number_title">Yüklenen öğe numarası</string>
|
<string name="pref_api_items_number_title">Yüklenen öğe numarası</string>
|
||||||
<string name="pref_hidden_tags">Hidden Tags</string>
|
|
||||||
<string name="pref_general_infinite_loading_title">Kaydırma üzerine daha fazla makale yükleyin</string>
|
<string name="pref_general_infinite_loading_title">Kaydırma üzerine daha fazla makale yükleyin</string>
|
||||||
<string name="translation">Çeviri</string>
|
<string name="translation">Çeviri</string>
|
||||||
<string name="cant_open_invalid_url">Öğe url geçersiz. Uygulama çökmeyeceği için bu sorunu çözmeye çalışıyorum.</string>
|
<string name="cant_open_invalid_url">Öğe url geçersiz. Uygulama çökmeyeceği için bu sorunu çözmeye çalışıyorum.</string>
|
||||||
<string name="drawer_report_bug">Hata bildir</string>
|
|
||||||
<string name="items_number_should_be_number">Öğe sayısı bir tamsayı olmalıdır.</string>
|
<string name="items_number_should_be_number">Öğe sayısı bir tamsayı olmalıdır.</string>
|
||||||
<string name="reader_action_more">Daha fazlasını görüntüle</string>
|
|
||||||
<string name="reader_action_open">Tarayıcıda aç</string>
|
<string name="reader_action_open">Tarayıcıda aç</string>
|
||||||
<string name="reader_action_share">Paylaş</string>
|
<string name="reader_action_share">Paylaş</string>
|
||||||
<string name="pref_switch_actions_pager_scroll_on">Mark articles as read when swiping between articles.</string>
|
<string name="pref_switch_actions_pager_scroll_on">Mark articles as read when swiping between articles.</string>
|
||||||
@ -97,7 +83,6 @@
|
|||||||
<string name="markall_dialog_message">This will mark all the items as read.</string>
|
<string name="markall_dialog_message">This will mark all the items as read.</string>
|
||||||
<string name="pref_switch_actions_pager_scroll">Mark as read on swipe</string>
|
<string name="pref_switch_actions_pager_scroll">Mark as read on swipe</string>
|
||||||
<string name="pref_switch_actions_pager_scroll_off">Don\'t mark articles as read when swiping.</string>
|
<string name="pref_switch_actions_pager_scroll_off">Don\'t mark articles as read when swiping.</string>
|
||||||
<string name="drawer_item_hidden_tags">Hidden Tags</string>
|
|
||||||
<string name="unmark">Mark item as unread</string>
|
<string name="unmark">Mark item as unread</string>
|
||||||
<string name="pref_header_offline">Offline and cache</string>
|
<string name="pref_header_offline">Offline and cache</string>
|
||||||
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
|
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
|
||||||
@ -112,7 +97,7 @@
|
|||||||
<string name="pref_switch_periodic_refresh_on">Articles will periodically be synced</string>
|
<string name="pref_switch_periodic_refresh_on">Articles will periodically be synced</string>
|
||||||
<string name="pref_periodic_refresh_minutes_title"><![CDATA[Sync interval ( >= 15 minutes)]]></string>
|
<string name="pref_periodic_refresh_minutes_title"><![CDATA[Sync interval ( >= 15 minutes)]]></string>
|
||||||
<string name="pref_switch_refresh_when_charging">Only refresh when phone is charging</string>
|
<string name="pref_switch_refresh_when_charging">Only refresh when phone is charging</string>
|
||||||
<string name="loading_notification_title">Loading ...</string>
|
<string name="loading_notification_title">Loading …</string>
|
||||||
<string name="loading_notification_text">Selfoss is syncing your articles</string>
|
<string name="loading_notification_text">Selfoss is syncing your articles</string>
|
||||||
<string name="notification_channel_sync">Sync notification</string>
|
<string name="notification_channel_sync">Sync notification</string>
|
||||||
<string name="new_items_channel_sync">New items notification</string>
|
<string name="new_items_channel_sync">New items notification</string>
|
||||||
@ -131,4 +116,19 @@
|
|||||||
<string name="reader_static_bar_on">The bottom bar will always be displayed</string>
|
<string name="reader_static_bar_on">The bottom bar will always be displayed</string>
|
||||||
<string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string>
|
<string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string>
|
||||||
<string name="remove_source">Remove source</string>
|
<string name="remove_source">Remove source</string>
|
||||||
|
<string name="pref_theme_title">Light/Dark mode</string>
|
||||||
|
<string name="mode_dark">Dark mode</string>
|
||||||
|
<string name="mode_system">Follow the system setting</string>
|
||||||
|
<string name="mode_light">Light mode</string>
|
||||||
|
<string name="gdpr_dialog_title">The app does not share any personal data about you.</string>
|
||||||
|
<string name="gdpr_dialog_message"><![CDATA[Crash reports sending is now enabled. It can be disabled from the settings page. Keep in mind that crash reports are essential for the app development.]]></string>
|
||||||
|
<string name="crash_toast_text">A crash occured. Sending the details to the developper.</string>
|
||||||
|
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
|
||||||
|
<string name="menu_home_filter">Filters</string>
|
||||||
|
<string name="application_selfoss_only">This app only works with a Selfoss instance, and no other RSS feed.</string>
|
||||||
|
<string name="menu_home_sources">Sources</string>
|
||||||
|
<string name="update_source">Update source</string>
|
||||||
|
<string name="confirm_disconnect_title">Disconnect ?</string>
|
||||||
|
<string name="confirm_disconnect_description">You will be disconnected from your selfoss instance.</string>
|
||||||
|
<string name="disable_ssl">Disable SSL</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
<string name="withLoginSwitch">"需要登录?"</string>
|
<string name="withLoginSwitch">"需要登录?"</string>
|
||||||
<string name="login_url_problem">"哎呀。您可能需要在网址的末尾添加一个 \"/\"。"</string>
|
<string name="login_url_problem">"哎呀。您可能需要在网址的末尾添加一个 \"/\"。"</string>
|
||||||
<string name="prompt_login">"用户名"</string>
|
<string name="prompt_login">"用户名"</string>
|
||||||
<string name="label_share">"分享"</string>
|
|
||||||
<string name="readAll">"全部阅读"</string>
|
<string name="readAll">"全部阅读"</string>
|
||||||
<string name="action_disconnect">"断开连接"</string>
|
<string name="action_disconnect">"断开连接"</string>
|
||||||
<string name="title_activity_settings">"设置"</string>
|
<string name="title_activity_settings">"设置"</string>
|
||||||
@ -47,12 +46,9 @@
|
|||||||
<string name="switch_unread_count_title">"显示未读数"</string>
|
<string name="switch_unread_count_title">"显示未读数"</string>
|
||||||
<string name="display_all_counts_title">"显示收藏和已读的计数"</string>
|
<string name="display_all_counts_title">"显示收藏和已读的计数"</string>
|
||||||
<string name="text_wrong_url">"您似乎试图使用无效的 URL。确保它是正确的,如果问题仍然存在,请与我联系 (通过商店的联系链接)。请注意,该应用程序需要您使用 Selfoss。没有它,您无法访问 RSS 源。"</string>
|
<string name="text_wrong_url">"您似乎试图使用无效的 URL。确保它是正确的,如果问题仍然存在,请与我联系 (通过商店的联系链接)。请注意,该应用程序需要您使用 Selfoss。没有它,您无法访问 RSS 源。"</string>
|
||||||
<string name="pref_general_internal_browser_title">"打开应用程序中的链接"</string>
|
<string name="pref_article_viewer_title">"在应用内打开链接"</string>
|
||||||
<string name="pref_general_internal_browser_on">"文章将在应用程序内打开"</string>
|
<string name="pref_article_viewer_on">"文章将在应用程序内打开"</string>
|
||||||
<string name="pref_general_internal_browser_off">"文章将使用默认浏览器打开"</string>
|
<string name="pref_article_viewer_off">"文章将使用默认浏览器打开"</string>
|
||||||
<string name="prefer_article_viewer_title">"使用文章查看器"</string>
|
|
||||||
<string name="prefer_article_viewer_on">"将使用文章查看器而不是内部浏览器"</string>
|
|
||||||
<string name="prefer_article_viewer_off">"将使用内部浏览器而不是文章查看器"</string>
|
|
||||||
<string name="pref_general_category_links">"链接处理"</string>
|
<string name="pref_general_category_links">"链接处理"</string>
|
||||||
<string name="pref_general_category_displaying">"显示"</string>
|
<string name="pref_general_category_displaying">"显示"</string>
|
||||||
<string name="pref_switch_card_view_on">"这些文章将以卡片形式显示"</string>
|
<string name="pref_switch_card_view_on">"这些文章将以卡片形式显示"</string>
|
||||||
@ -65,28 +61,18 @@
|
|||||||
<string name="card_height_on">卡片高度将根据内容调整</string>
|
<string name="card_height_on">卡片高度将根据内容调整</string>
|
||||||
<string name="card_height_off">卡片高度将被固定</string>
|
<string name="card_height_off">卡片高度将被固定</string>
|
||||||
<string name="source_code">源代码</string>
|
<string name="source_code">源代码</string>
|
||||||
<string name="drawer_error_loading_tags">加载标记时出错..。</string>
|
<string name="filter_item_tags">标签</string>
|
||||||
<string name="drawer_item_filters">搜索条件</string>
|
<string name="filter_item_sources">来源</string>
|
||||||
<string name="drawer_action_clear">清空</string>
|
|
||||||
<string name="drawer_item_tags">标签</string>
|
|
||||||
<string name="drawer_item_sources">来源</string>
|
|
||||||
<string name="drawer_action_edit">编辑</string>
|
|
||||||
<string name="drawer_loading">正在载入…</string>
|
|
||||||
<string name="menu_home_search">搜索</string>
|
<string name="menu_home_search">搜索</string>
|
||||||
<string name="can_delete_source">无法删除数据源…</string>
|
<string name="can_delete_source">无法删除数据源…</string>
|
||||||
<string name="base_url_error">与您的 Selfoss 通信时出现问题。如果问题一直存在,请与我联系。</string>
|
<string name="base_url_error">与您的 Selfoss 通信时出现问题。如果问题一直存在,请与我联系。</string>
|
||||||
<string name="pref_header_theme">主题</string>
|
<string name="pref_header_theme">主题</string>
|
||||||
<string name="default_theme">默认</string>
|
|
||||||
<string name="default_dark_theme">默认值/暗</string>
|
|
||||||
<string name="pref_selfoss_category">塞尔福斯 Api</string>
|
<string name="pref_selfoss_category">塞尔福斯 Api</string>
|
||||||
<string name="pref_api_items_number_title">已加载项目编号</string>
|
<string name="pref_api_items_number_title">已加载项目编号</string>
|
||||||
<string name="pref_hidden_tags">隐藏标签</string>
|
|
||||||
<string name="pref_general_infinite_loading_title">翻页时载入更多文章</string>
|
<string name="pref_general_infinite_loading_title">翻页时载入更多文章</string>
|
||||||
<string name="translation">翻译</string>
|
<string name="translation">翻译</string>
|
||||||
<string name="cant_open_invalid_url">项目链接地址无效。我正在设法解决这个问题,以避免应用程序崩溃。</string>
|
<string name="cant_open_invalid_url">项目链接地址无效。我正在设法解决这个问题,以避免应用程序崩溃。</string>
|
||||||
<string name="drawer_report_bug">报告错误</string>
|
|
||||||
<string name="items_number_should_be_number">项目数应为整数。</string>
|
<string name="items_number_should_be_number">项目数应为整数。</string>
|
||||||
<string name="reader_action_more">阅读更多</string>
|
|
||||||
<string name="reader_action_open">在浏览器中打开</string>
|
<string name="reader_action_open">在浏览器中打开</string>
|
||||||
<string name="reader_action_share">分享</string>
|
<string name="reader_action_share">分享</string>
|
||||||
<string name="pref_switch_actions_pager_scroll_on">切换文章时将文章标记为已读。</string>
|
<string name="pref_switch_actions_pager_scroll_on">切换文章时将文章标记为已读。</string>
|
||||||
@ -97,7 +83,6 @@
|
|||||||
<string name="markall_dialog_message">这将标记所有项目为已读。</string>
|
<string name="markall_dialog_message">这将标记所有项目为已读。</string>
|
||||||
<string name="pref_switch_actions_pager_scroll">滑动时标为已读</string>
|
<string name="pref_switch_actions_pager_scroll">滑动时标为已读</string>
|
||||||
<string name="pref_switch_actions_pager_scroll_off">滑动时不标记文章为已读</string>
|
<string name="pref_switch_actions_pager_scroll_off">滑动时不标记文章为已读</string>
|
||||||
<string name="drawer_item_hidden_tags">隐藏标签</string>
|
|
||||||
<string name="unmark">标记条目为未读</string>
|
<string name="unmark">标记条目为未读</string>
|
||||||
<string name="pref_header_offline">离线和缓存</string>
|
<string name="pref_header_offline">离线和缓存</string>
|
||||||
<string name="pref_switch_items_caching_off">文章不会被保存到设备内存,应用程序在离线时将无法阅读它们</string>
|
<string name="pref_switch_items_caching_off">文章不会被保存到设备内存,应用程序在离线时将无法阅读它们</string>
|
||||||
@ -112,7 +97,7 @@
|
|||||||
<string name="pref_switch_periodic_refresh_on">将定期同步文章</string>
|
<string name="pref_switch_periodic_refresh_on">将定期同步文章</string>
|
||||||
<string name="pref_periodic_refresh_minutes_title"><![CDATA[同步间隔 (>= 15分钟)]]></string>
|
<string name="pref_periodic_refresh_minutes_title"><![CDATA[同步间隔 (>= 15分钟)]]></string>
|
||||||
<string name="pref_switch_refresh_when_charging">仅在手机充电时刷新</string>
|
<string name="pref_switch_refresh_when_charging">仅在手机充电时刷新</string>
|
||||||
<string name="loading_notification_title">加载中...</string>
|
<string name="loading_notification_title">加载中…</string>
|
||||||
<string name="loading_notification_text">Selfoss 正在同步您的文章</string>
|
<string name="loading_notification_text">Selfoss 正在同步您的文章</string>
|
||||||
<string name="notification_channel_sync">同步通知</string>
|
<string name="notification_channel_sync">同步通知</string>
|
||||||
<string name="new_items_channel_sync">新条目通知</string>
|
<string name="new_items_channel_sync">新条目通知</string>
|
||||||
@ -131,4 +116,19 @@
|
|||||||
<string name="reader_static_bar_on">底部栏将始终显示</string>
|
<string name="reader_static_bar_on">底部栏将始终显示</string>
|
||||||
<string name="reader_static_bar_off">底部栏可以通过浮动按钮显示</string>
|
<string name="reader_static_bar_off">底部栏可以通过浮动按钮显示</string>
|
||||||
<string name="remove_source">删除源</string>
|
<string name="remove_source">删除源</string>
|
||||||
|
<string name="pref_theme_title">浅色/深色模式</string>
|
||||||
|
<string name="mode_dark">深色模式</string>
|
||||||
|
<string name="mode_system">遵循系统设置</string>
|
||||||
|
<string name="mode_light">浅色模式</string>
|
||||||
|
<string name="gdpr_dialog_title">该应用不分享任何关于您的个人数据。</string>
|
||||||
|
<string name="gdpr_dialog_message"><![CDATA[崩溃报告发送现已启用。 可以从设置页面禁用它。 请记住,崩溃报告对于应用程序开发是必需的。]]></string>
|
||||||
|
<string name="crash_toast_text">发生崩溃。请将细节发送给开发人员。</string>
|
||||||
|
<string name="pref_switch_disable_acra">"禁用自动错误报告 "</string>
|
||||||
|
<string name="menu_home_filter">筛选器</string>
|
||||||
|
<string name="application_selfoss_only">此应用只适用于 Selfoss 实例,不适用于其他 RSS 。</string>
|
||||||
|
<string name="menu_home_sources">源</string>
|
||||||
|
<string name="update_source">更新源</string>
|
||||||
|
<string name="confirm_disconnect_title">Disconnect ?</string>
|
||||||
|
<string name="confirm_disconnect_description">You will be disconnected from your selfoss instance.</string>
|
||||||
|
<string name="disable_ssl">Disable SSL</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
<string name="withLoginSwitch">"需要登入?"</string>
|
<string name="withLoginSwitch">"需要登入?"</string>
|
||||||
<string name="login_url_problem">"哎呀。您可能需要在网址的末尾添加一个 \"/\"。"</string>
|
<string name="login_url_problem">"哎呀。您可能需要在网址的末尾添加一个 \"/\"。"</string>
|
||||||
<string name="prompt_login">"使用者名稱"</string>
|
<string name="prompt_login">"使用者名稱"</string>
|
||||||
<string name="label_share">"分享"</string>
|
|
||||||
<string name="readAll">"全部阅读"</string>
|
<string name="readAll">"全部阅读"</string>
|
||||||
<string name="action_disconnect">"断开连接"</string>
|
<string name="action_disconnect">"断开连接"</string>
|
||||||
<string name="title_activity_settings">"设置"</string>
|
<string name="title_activity_settings">"设置"</string>
|
||||||
@ -47,12 +46,9 @@
|
|||||||
<string name="switch_unread_count_title">"显示未读数"</string>
|
<string name="switch_unread_count_title">"显示未读数"</string>
|
||||||
<string name="display_all_counts_title">"显示收藏和已读的计数"</string>
|
<string name="display_all_counts_title">"显示收藏和已读的计数"</string>
|
||||||
<string name="text_wrong_url">"您似乎试图使用无效的 URL。确保它是正确的,如果问题仍然存在,请与我联系 (通过商店的联系链接)。请注意,该应用程序需要您使用 Selfoss。没有它,您无法访问 RSS 源。"</string>
|
<string name="text_wrong_url">"您似乎试图使用无效的 URL。确保它是正确的,如果问题仍然存在,请与我联系 (通过商店的联系链接)。请注意,该应用程序需要您使用 Selfoss。没有它,您无法访问 RSS 源。"</string>
|
||||||
<string name="pref_general_internal_browser_title">"打开应用程序中的链接"</string>
|
<string name="pref_article_viewer_title">"打开应用程序中的链接"</string>
|
||||||
<string name="pref_general_internal_browser_on">"文章将在应用程序内打开"</string>
|
<string name="pref_article_viewer_on">"文章将在应用程序内打开"</string>
|
||||||
<string name="pref_general_internal_browser_off">"文章将使用默认浏览器打开"</string>
|
<string name="pref_article_viewer_off">"文章将使用默认浏览器打开"</string>
|
||||||
<string name="prefer_article_viewer_title">"使用文章查看器"</string>
|
|
||||||
<string name="prefer_article_viewer_on">"将使用文章查看器而不是内部浏览器"</string>
|
|
||||||
<string name="prefer_article_viewer_off">"将使用内部浏览器而不是文章查看器"</string>
|
|
||||||
<string name="pref_general_category_links">"链接处理"</string>
|
<string name="pref_general_category_links">"链接处理"</string>
|
||||||
<string name="pref_general_category_displaying">"显示"</string>
|
<string name="pref_general_category_displaying">"显示"</string>
|
||||||
<string name="pref_switch_card_view_on">"这些文章将以卡片形式显示"</string>
|
<string name="pref_switch_card_view_on">"这些文章将以卡片形式显示"</string>
|
||||||
@ -65,28 +61,18 @@
|
|||||||
<string name="card_height_on">卡片高度将根据内容调整</string>
|
<string name="card_height_on">卡片高度将根据内容调整</string>
|
||||||
<string name="card_height_off">卡片高度将被固定</string>
|
<string name="card_height_off">卡片高度将被固定</string>
|
||||||
<string name="source_code">源代码</string>
|
<string name="source_code">源代码</string>
|
||||||
<string name="drawer_error_loading_tags">加载标记时出错..。</string>
|
<string name="filter_item_tags">标签</string>
|
||||||
<string name="drawer_item_filters">搜索条件</string>
|
<string name="filter_item_sources">来源</string>
|
||||||
<string name="drawer_action_clear">清空</string>
|
|
||||||
<string name="drawer_item_tags">标签</string>
|
|
||||||
<string name="drawer_item_sources">来源</string>
|
|
||||||
<string name="drawer_action_edit">编辑</string>
|
|
||||||
<string name="drawer_loading">正在载入…</string>
|
|
||||||
<string name="menu_home_search">搜索</string>
|
<string name="menu_home_search">搜索</string>
|
||||||
<string name="can_delete_source">无法删除数据源…</string>
|
<string name="can_delete_source">无法删除数据源…</string>
|
||||||
<string name="base_url_error">与您的 Selfoss 通信时出现问题。如果问题一直存在,请与我联系。</string>
|
<string name="base_url_error">与您的 Selfoss 通信时出现问题。如果问题一直存在,请与我联系。</string>
|
||||||
<string name="pref_header_theme">主题</string>
|
<string name="pref_header_theme">主题</string>
|
||||||
<string name="default_theme">默认</string>
|
|
||||||
<string name="default_dark_theme">默认值/暗</string>
|
|
||||||
<string name="pref_selfoss_category">塞尔福斯 Api</string>
|
<string name="pref_selfoss_category">塞尔福斯 Api</string>
|
||||||
<string name="pref_api_items_number_title">已加载项目编号</string>
|
<string name="pref_api_items_number_title">已加载项目编号</string>
|
||||||
<string name="pref_hidden_tags">Hidden Tags</string>
|
|
||||||
<string name="pref_general_infinite_loading_title">翻页时载入更多文章</string>
|
<string name="pref_general_infinite_loading_title">翻页时载入更多文章</string>
|
||||||
<string name="translation">翻译</string>
|
<string name="translation">翻译</string>
|
||||||
<string name="cant_open_invalid_url">项目链接地址无效。我正在设法解决这个问题,以避免应用程序崩溃。</string>
|
<string name="cant_open_invalid_url">项目链接地址无效。我正在设法解决这个问题,以避免应用程序崩溃。</string>
|
||||||
<string name="drawer_report_bug">报告错误</string>
|
|
||||||
<string name="items_number_should_be_number">项目数应为整数。</string>
|
<string name="items_number_should_be_number">项目数应为整数。</string>
|
||||||
<string name="reader_action_more">阅读更多</string>
|
|
||||||
<string name="reader_action_open">在浏览器中打开</string>
|
<string name="reader_action_open">在浏览器中打开</string>
|
||||||
<string name="reader_action_share">分享</string>
|
<string name="reader_action_share">分享</string>
|
||||||
<string name="pref_switch_actions_pager_scroll_on">Mark articles as read when swiping between articles.</string>
|
<string name="pref_switch_actions_pager_scroll_on">Mark articles as read when swiping between articles.</string>
|
||||||
@ -97,7 +83,6 @@
|
|||||||
<string name="markall_dialog_message">This will mark all the items as read.</string>
|
<string name="markall_dialog_message">This will mark all the items as read.</string>
|
||||||
<string name="pref_switch_actions_pager_scroll">Mark as read on swipe</string>
|
<string name="pref_switch_actions_pager_scroll">Mark as read on swipe</string>
|
||||||
<string name="pref_switch_actions_pager_scroll_off">Don\'t mark articles as read when swiping.</string>
|
<string name="pref_switch_actions_pager_scroll_off">Don\'t mark articles as read when swiping.</string>
|
||||||
<string name="drawer_item_hidden_tags">Hidden Tags</string>
|
|
||||||
<string name="unmark">Mark item as unread</string>
|
<string name="unmark">Mark item as unread</string>
|
||||||
<string name="pref_header_offline">Offline and cache</string>
|
<string name="pref_header_offline">Offline and cache</string>
|
||||||
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
|
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
|
||||||
@ -112,7 +97,7 @@
|
|||||||
<string name="pref_switch_periodic_refresh_on">Articles will periodically be synced</string>
|
<string name="pref_switch_periodic_refresh_on">Articles will periodically be synced</string>
|
||||||
<string name="pref_periodic_refresh_minutes_title"><![CDATA[Sync interval ( >= 15 minutes)]]></string>
|
<string name="pref_periodic_refresh_minutes_title"><![CDATA[Sync interval ( >= 15 minutes)]]></string>
|
||||||
<string name="pref_switch_refresh_when_charging">Only refresh when phone is charging</string>
|
<string name="pref_switch_refresh_when_charging">Only refresh when phone is charging</string>
|
||||||
<string name="loading_notification_title">Loading ...</string>
|
<string name="loading_notification_title">Loading …</string>
|
||||||
<string name="loading_notification_text">Selfoss is syncing your articles</string>
|
<string name="loading_notification_text">Selfoss is syncing your articles</string>
|
||||||
<string name="notification_channel_sync">Sync notification</string>
|
<string name="notification_channel_sync">Sync notification</string>
|
||||||
<string name="new_items_channel_sync">New items notification</string>
|
<string name="new_items_channel_sync">New items notification</string>
|
||||||
@ -131,4 +116,19 @@
|
|||||||
<string name="reader_static_bar_on">The bottom bar will always be displayed</string>
|
<string name="reader_static_bar_on">The bottom bar will always be displayed</string>
|
||||||
<string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string>
|
<string name="reader_static_bar_off">The bottom bar can be shown through the floating button</string>
|
||||||
<string name="remove_source">Remove source</string>
|
<string name="remove_source">Remove source</string>
|
||||||
|
<string name="pref_theme_title">Light/Dark mode</string>
|
||||||
|
<string name="mode_dark">Dark mode</string>
|
||||||
|
<string name="mode_system">Follow the system setting</string>
|
||||||
|
<string name="mode_light">Light mode</string>
|
||||||
|
<string name="gdpr_dialog_title">The app does not share any personal data about you.</string>
|
||||||
|
<string name="gdpr_dialog_message"><![CDATA[Crash reports sending is now enabled. It can be disabled from the settings page. Keep in mind that crash reports are essential for the app development.]]></string>
|
||||||
|
<string name="crash_toast_text">A crash occured. Sending the details to the developper.</string>
|
||||||
|
<string name="pref_switch_disable_acra">"Disable automatic bug reporting. "</string>
|
||||||
|
<string name="menu_home_filter">Filters</string>
|
||||||
|
<string name="application_selfoss_only">This app only works with a Selfoss instance, and no other RSS feed.</string>
|
||||||
|
<string name="menu_home_sources">Sources</string>
|
||||||
|
<string name="update_source">Update source</string>
|
||||||
|
<string name="confirm_disconnect_title">Disconnect ?</string>
|
||||||
|
<string name="confirm_disconnect_description">You will be disconnected from your selfoss instance.</string>
|
||||||
|
<string name="disable_ssl">Disable SSL</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -2,5 +2,8 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<declare-styleable name="Theme">
|
<declare-styleable name="Theme">
|
||||||
<attr name="colorAccentDark" format="reference|color" />
|
<attr name="colorAccentDark" format="reference|color" />
|
||||||
|
<attr name="bottomBarBackground" format="reference|color" />
|
||||||
|
<attr name="toolbarPopupTheme" format="reference|color" />
|
||||||
|
<attr name="webviewBackground" format="reference|color" />
|
||||||
</declare-styleable>
|
</declare-styleable>
|
||||||
</resources>
|
</resources>
|
@ -11,6 +11,6 @@
|
|||||||
<color name="refresh_progress_1">@color/colorAccentDark</color>
|
<color name="refresh_progress_1">@color/colorAccentDark</color>
|
||||||
<color name="refresh_progress_2">@color/colorAccent</color>
|
<color name="refresh_progress_2">@color/colorAccent</color>
|
||||||
<color name="refresh_progress_3">@color/pink</color>
|
<color name="refresh_progress_3">@color/pink</color>
|
||||||
|
<color name="dark">#FF282828</color>
|
||||||
<color name="darkBackground">#303030</color>
|
<color name="transparent_dark_background">#33000000</color>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
<array name="com_google_android_gms_fonts_certs">
|
|
||||||
<item>@array/com_google_android_gms_fonts_certs_dev</item>
|
|
||||||
<item>@array/com_google_android_gms_fonts_certs_prod</item>
|
|
||||||
</array>
|
|
||||||
<string-array name="com_google_android_gms_fonts_certs_dev">
|
|
||||||
<item>
|
|
||||||
MIIEqDCCA5CgAwIBAgIJANWFuGx90071MA0GCSqGSIb3DQEBBAUAMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAeFw0wODA0MTUyMzM2NTZaFw0zNTA5MDEyMzM2NTZaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBANbOLggKv+IxTdGNs8/TGFy0PTP6DHThvbbR24kT9ixcOd9W+EaBPWW+wPPKQmsHxajtWjmQwWfna8mZuSeJS48LIgAZlKkpFeVyxW0qMBujb8X8ETrWy550NaFtI6t9+u7hZeTfHwqNvacKhp1RbE6dBRGWynwMVX8XW8N1+UjFaq6GCJukT4qmpN2afb8sCjUigq0GuMwYXrFVee74bQgLHWGJwPmvmLHC69EH6kWr22ijx4OKXlSIx2xT1AsSHee70w5iDBiK4aph27yH3TxkXy9V89TDdexAcKk/cVHYNnDBapcavl7y0RiQ4biu8ymM8Ga/nmzhRKya6G0cGw8CAQOjgfwwgfkwHQYDVR0OBBYEFI0cxb6VTEM8YYY6FbBMvAPyT+CyMIHJBgNVHSMEgcEwgb6AFI0cxb6VTEM8YYY6FbBMvAPyT+CyoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJANWFuGx90071MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEBABnTDPEF+3iSP0wNfdIjIz1AlnrPzgAIHVvXxunW7SBrDhEglQZBbKJEk5kT0mtKoOD1JMrSu1xuTKEBahWRbqHsXclaXjoBADb0kkjVEJu/Lh5hgYZnOjvlba8Ld7HCKePCVePoTJBdI4fvugnL8TsgK05aIskyY0hKI9L8KfqfGTl1lzOv2KoWD0KWwtAWPoGChZxmQ+nBli+gwYMzM1vAkP+aayLe0a1EQimlOalO762r0GXO0ks+UeXde2Z4e+8S/pf7pITEI/tP+MxJTALw9QUWEv9lKTk+jkbqxbsh8nfBUapfKqYn0eidpwq2AzVp3juYl7//fKnaPhJD9gs=
|
|
||||||
</item>
|
|
||||||
</string-array>
|
|
||||||
<string-array name="com_google_android_gms_fonts_certs_prod">
|
|
||||||
<item>
|
|
||||||
MIIEQzCCAyugAwIBAgIJAMLgh0ZkSjCNMA0GCSqGSIb3DQEBBAUAMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDAeFw0wODA4MjEyMzEzMzRaFw0zNjAxMDcyMzEzMzRaMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBAKtWLgDYO6IIrgqWbxJOKdoR8qtW0I9Y4sypEwPpt1TTcvZApxsdyxMJZ2JORland2qSGT2y5b+3JKkedxiLDmpHpDsz2WCbdxgxRczfey5YZnTJ4VZbH0xqWVW/8lGmPav5xVwnIiJS6HXk+BVKZF+JcWjAsb/GEuq/eFdpuzSqeYTcfi6idkyugwfYwXFU1+5fZKUaRKYCwkkFQVfcAs1fXA5V+++FGfvjJ/CxURaSxaBvGdGDhfXE28LWuT9ozCl5xw4Yq5OGazvV24mZVSoOO0yZ31j7kYvtwYK6NeADwbSxDdJEqO4k//0zOHKrUiGYXtqw/A0LFFtqoZKFjnkCAQOjgdkwgdYwHQYDVR0OBBYEFMd9jMIhF1Ylmn/Tgt9r45jk14alMIGmBgNVHSMEgZ4wgZuAFMd9jMIhF1Ylmn/Tgt9r45jk14aloXikdjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLR29vZ2xlIEluYy4xEDAOBgNVBAsTB0FuZHJvaWQxEDAOBgNVBAMTB0FuZHJvaWSCCQDC4IdGZEowjTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBAUAA4IBAQBt0lLO74UwLDYKqs6Tm8/yzKkEu116FmH4rkaymUIE0P9KaMftGlMexFlaYjzmB2OxZyl6euNXEsQH8gjwyxCUKRJNexBiGcCEyj6z+a1fuHHvkiaai+KL8W1EyNmgjmyy8AW7P+LLlkR+ho5zEHatRbM/YAnqGcFh5iZBqpknHf1SKMXFh4dd239FJ1jWYfbMDMy3NS5CTMQ2XFI1MvcyUTdZPErjQfTbQe3aDQsQcafEQPD+nqActifKZ0Np0IS9L9kR/wbNvyz6ENwPiTrjV2KRkEjH78ZMcUQXg0L3BYHJ3lc69Vs5Ddf9uUGGMYldX3WfMBEmh/9iFBDAaTCK
|
|
||||||
</item>
|
|
||||||
</string-array>
|
|
||||||
</resources>
|
|
14
androidApp/src/main/res/values/mode_settings.xml
Normal file
14
androidApp/src/main/res/values/mode_settings.xml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string-array name="ModeTitles">
|
||||||
|
<item>@string/mode_light</item>
|
||||||
|
<item>@string/mode_dark</item>
|
||||||
|
<item>@string/mode_system</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="ModeValues">
|
||||||
|
<item>1</item> <!--MODE_NIGHT_NO-->
|
||||||
|
<item>2</item> <!--MODE_NIGHT_YES-->
|
||||||
|
<item>-1</item> <!--MODE_NIGHT_FOLLOW_SYSTEM-->
|
||||||
|
</string-array>
|
||||||
|
</resources>
|
@ -1,7 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
<array name="preloaded_fonts" translatable="false">
|
|
||||||
<item>@font/open_sans</item>
|
|
||||||
<item>@font/roboto</item>
|
|
||||||
</array>
|
|
||||||
</resources>
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user