Compare commits
	
		
			158 Commits
		
	
	
		
			8cbb225e6d
			...
			v122092691
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					a76b3dd2a9 | ||
| 
						 | 
					91aed5a777 | ||
| 
						 | 
					8823cc6c6c | ||
| 
						 | 
					74ef4da15b | ||
| 
						 | 
					bd96c67788 | ||
| 
						 | 
					da71de6806 | ||
| 
						 | 
					0264da8ccc | ||
| 
						 | 
					270d959ee0 | ||
| 
						 | 
					6d11dfb80c | ||
| 
						 | 
					4184bbb900 | ||
| 
						 | 
					4c12c9d570 | ||
| 
						 | 
					f4db02521d | ||
| 
						 | 
					01763556b1 | ||
| 
						 | 
					e2411c00d8 | ||
| 
						 | 
					0473a5f7bc | ||
| 
						 | 
					d0d6a4378c | ||
| 
						 | 
					1dfa3c9f07 | ||
| 
						 | 
					815f00e764 | ||
| bdc77ab8ef | |||
| 6bd06cb458 | |||
| 
						 | 
					e9e8bee6c9 | ||
| 
						 | 
					ff6038dbd4 | ||
| 
						 | 
					8146cff011 | ||
| 
						 | 
					fc4c48dd12 | ||
| 
						 | 
					94f1ec943c | ||
| 
						 | 
					0278540fb2 | ||
| 
						 | 
					109050d0cf | ||
| 
						 | 
					0392e1b406 | ||
| 
						 | 
					8b2be5c55c | ||
| 
						 | 
					e6afb4702d | ||
| 
						 | 
					8cf462a755 | ||
| 
						 | 
					17293e5574 | ||
| 
						 | 
					a99286a9b7 | ||
| 
						 | 
					5531034086 | ||
| 
						 | 
					fbcb428e96 | ||
| e281751bb0 | |||
| 
						 | 
					0eed9a8d07 | ||
| 
						 | 
					9603860bae | ||
| 
						 | 
					75b566a38d | ||
| 
						 | 
					fb572dbb27 | ||
| 
						 | 
					34028949d7 | ||
| 
						 | 
					44a0469b17 | ||
| 
						 | 
					c87473e8f1 | ||
| 
						 | 
					de43abf019 | ||
| 
						 | 
					e60f3a9d91 | ||
| 
						 | 
					255fbcb12f | ||
| 
						 | 
					0caeb94e64 | ||
| 
						 | 
					6f6a42b878 | ||
| 
						 | 
					67d54f0dd7 | ||
| 
						 | 
					437aa0abec | ||
| 
						 | 
					216c639a23 | ||
| 
						 | 
					7258452625 | ||
| 
						 | 
					d0d82751e2 | ||
| 
						 | 
					3b8f4991e9 | ||
| 
						 | 
					2547ce824a | ||
| 
						 | 
					59eb399cfa | ||
| 
						 | 
					495b101355 | ||
| 
						 | 
					afcc55e907 | ||
| 
						 | 
					0c570efc47 | ||
| 
						 | 
					a23a4cea0e | ||
| 
						 | 
					78cb5d047f | ||
| 
						 | 
					a9caaefb4d | ||
| 4c78b22614 | |||
| 1d5ab3205e | |||
| df4903cae5 | |||
| 2a78be69b5 | |||
| 8c69bb8c3c | |||
| 9203012a97 | |||
| 2a44162c5a | |||
| 20588aab81 | |||
| 0c8e49214f | |||
| 97d5063339 | |||
| 7c37b183d7 | |||
| 82c4a5a1f9 | |||
| 47b7062e16 | |||
| b9497ca939 | |||
| 1258ed3ad3 | |||
| d838f509d4 | |||
| 3c5b606a02 | |||
| d1481a1db6 | |||
| d654b1b0bd | |||
| f56861a3c2 | |||
| 492e7e4aed | |||
| 551a3e3caa | |||
| c224b8a0b3 | |||
| 13ea7a693b | |||
| 0f3c48dd8e | |||
| d4c2373bac | |||
| 4f32097821 | |||
| 
						 | 
					37fa4a1a8e | ||
| 
						 | 
					112194dd4f | ||
| 72d9ef92d2 | |||
| 
						 | 
					1392e2a571 | ||
| 
						 | 
					e9cb3d2f37 | ||
| 
						 | 
					dec620a409 | ||
| 
						 | 
					4d29ee0b92 | ||
| 
						 | 
					33333ca998 | ||
| 
						 | 
					8d87eef0fc | ||
| 
						 | 
					5a26513ed7 | ||
| 
						 | 
					5b7f5225d8 | ||
| 
						 | 
					03f53bf9c9 | ||
| 
						 | 
					e06e6d580d | ||
| 
						 | 
					63e8649512 | ||
| 
						 | 
					6260c3fc06 | ||
| 
						 | 
					77917dd940 | ||
| 
						 | 
					88f11762cb | ||
| 
						 | 
					e3e6b6f8b8 | ||
| 
						 | 
					d0d285b315 | ||
| 
						 | 
					096344241d | ||
| 
						 | 
					a3253d5a7b | ||
| 
						 | 
					32e7a8f19c | ||
| 
						 | 
					00ef93f0c5 | ||
| 
						 | 
					7fb7e45093 | ||
| 
						 | 
					edc705ec8e | ||
| 
						 | 
					bcaa6624c9 | ||
| 
						 | 
					0556500c5d | ||
| 
						 | 
					f624a35fe2 | ||
| 
						 | 
					38f1dbd34d | ||
| 
						 | 
					1fb16bcbdd | ||
| 
						 | 
					29619e1b2b | ||
| 
						 | 
					bb5c521387 | ||
| 
						 | 
					d47cca2f5a | ||
| 
						 | 
					fe59177efb | ||
| 
						 | 
					baa4b81e77 | ||
| 
						 | 
					7f8d04618a | ||
| 
						 | 
					1890297c9d | ||
| 
						 | 
					22f0ff664c | ||
| 
						 | 
					88c5c6ff4b | ||
| 
						 | 
					3e97ee30a1 | ||
| 
						 | 
					5377e6c0f8 | ||
| 
						 | 
					8c5f4268a4 | ||
| 
						 | 
					5ea75a5352 | ||
| 
						 | 
					e6c70c66fc | ||
| 
						 | 
					554b8df9d0 | ||
| 
						 | 
					442e4bf876 | ||
| 
						 | 
					b14b34441b | ||
| 
						 | 
					da4bdd2355 | ||
| 
						 | 
					73e6742cee | ||
| 
						 | 
					924f4da1ec | ||
| 
						 | 
					11eac7b141 | ||
| 
						 | 
					77fada1b02 | ||
| 
						 | 
					0859854610 | ||
| 
						 | 
					da088ec89e | ||
| 
						 | 
					dbbc191704 | ||
| 
						 | 
					e37eae8d16 | ||
| 
						 | 
					e3d35bd653 | ||
| 
						 | 
					c0137ea5e7 | ||
| 
						 | 
					b14a6427da | ||
| 
						 | 
					12e174dacd | ||
| 
						 | 
					8898e85f02 | ||
| 
						 | 
					7221f11f80 | ||
| 
						 | 
					9373024147 | ||
| 
						 | 
					dc10cafb1b | ||
| 
						 | 
					3be942a807 | ||
| 
						 | 
					bbec7745fe | ||
| 
						 | 
					e4fbdce30e | ||
| 
						 | 
					21f39d64b3 | ||
| 
						 | 
					c0e7b1fa0e | 
							
								
								
									
										117
									
								
								.drone.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								.drone.yml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,117 @@
 | 
			
		||||
kind: pipeline
 | 
			
		||||
type: docker
 | 
			
		||||
name: test
 | 
			
		||||
 | 
			
		||||
steps:
 | 
			
		||||
  - name: AnylyseBuildTest
 | 
			
		||||
    image: mingc/android-build-box:latest
 | 
			
		||||
    failure: ignore
 | 
			
		||||
    commands:
 | 
			
		||||
      - echo "---------------------------------------------------------"
 | 
			
		||||
      - echo "Analysing..."
 | 
			
		||||
      - ./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\""
 | 
			
		||||
      - echo "---------------------------------------------------------"
 | 
			
		||||
      - echo "Building..."
 | 
			
		||||
      - ./gradlew :androidApp:build -PignoreGitVersion=true -P appLoginUrl="\"URL\"" -P appLoginUsername="\"LOGIN\"" -P appLoginPassword="\"PASS\"" -P pushCache=false
 | 
			
		||||
      - echo "---------------------------------------------------------"
 | 
			
		||||
      - echo "Testing..."
 | 
			
		||||
      - echo "---------------------------------------------------------"
 | 
			
		||||
    environment:
 | 
			
		||||
      SONAR_HOST_URL:
 | 
			
		||||
        from_secret: sonarScannerHostUrl
 | 
			
		||||
      SONAR_LOGIN:
 | 
			
		||||
        from_secret: sonarScannerLogin
 | 
			
		||||
trigger:
 | 
			
		||||
  event:
 | 
			
		||||
    - push
 | 
			
		||||
    - pull_request
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
kind: pipeline
 | 
			
		||||
type: docker
 | 
			
		||||
name: Publish
 | 
			
		||||
 | 
			
		||||
steps:
 | 
			
		||||
  - name: createTag
 | 
			
		||||
    image: ubuntu:latest
 | 
			
		||||
    commands:
 | 
			
		||||
      - apt-get update && apt-get install -y git
 | 
			
		||||
      - ./build.sh --publish --from-ci
 | 
			
		||||
      - git remote add pushing https://$GITEA_USR:$GITEA_PASS@gitea.amine-louveau.fr/Louvorg/ReaderForSelfoss-multiplatform.git
 | 
			
		||||
      - git push pushing --tags
 | 
			
		||||
    environment:
 | 
			
		||||
      GITEA_USR:
 | 
			
		||||
        from_secret: giteaUsr
 | 
			
		||||
      GITEA_PASS:
 | 
			
		||||
        from_secret: giteaPass
 | 
			
		||||
 | 
			
		||||
  - name: scpFiles
 | 
			
		||||
    image: appleboy/drone-scp
 | 
			
		||||
    settings:
 | 
			
		||||
      host: amine-louveau.fr
 | 
			
		||||
      username: ubuntu
 | 
			
		||||
      key:
 | 
			
		||||
        from_secret: privateKey
 | 
			
		||||
      port: 22
 | 
			
		||||
      target: /home/ubuntu/
 | 
			
		||||
      source: version.txt
 | 
			
		||||
 | 
			
		||||
  - name: deploy
 | 
			
		||||
    image: appleboy/drone-ssh
 | 
			
		||||
    settings:
 | 
			
		||||
      host: amine-louveau.fr
 | 
			
		||||
      user: ubuntu
 | 
			
		||||
      key:
 | 
			
		||||
        from_secret: privateKey
 | 
			
		||||
      command_timeout: 2m
 | 
			
		||||
      script:
 | 
			
		||||
        - 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/
 | 
			
		||||
 | 
			
		||||
trigger:
 | 
			
		||||
  event:
 | 
			
		||||
    - promote
 | 
			
		||||
  target:
 | 
			
		||||
    - production
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
kind: pipeline
 | 
			
		||||
type: docker
 | 
			
		||||
name: Release
 | 
			
		||||
 | 
			
		||||
steps:
 | 
			
		||||
  - name: build
 | 
			
		||||
    image: mingc/android-build-box:latest
 | 
			
		||||
    commands:
 | 
			
		||||
      - echo "Generate APK"
 | 
			
		||||
      - ./gradlew :androidApp:assembleGithubConfigRelease -PignoreGitVersion=true -P appLoginUrl="\"URL\"" -P appLoginUsername="\"LOGIN\"" -P appLoginPassword="\"PASS\"" -P pushCache=false
 | 
			
		||||
      - echo "---------------------------------------------------------"
 | 
			
		||||
      - echo "Get Key"
 | 
			
		||||
      - wget https://amine-louveau.fr/key
 | 
			
		||||
      - echo "---------------------------------------------------------"
 | 
			
		||||
      - 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
 | 
			
		||||
      - echo "---------------------------------------------------------"
 | 
			
		||||
      - echo "Sign"
 | 
			
		||||
      - $ANDROID_HOME/build-tools/31.0.0/apksigner sign -v --out signed.apk --ks ./key --ks-key-alias $YOUR_KEY_ALIAS --ks-pass pass:$YOUR_KEYSTORE_PASSWORD --v1-signing-enabled true --v2-signing-enabled true androidApp/build/outputs/apk/githubConfig/release/android-prod-released-ziped.apk
 | 
			
		||||
      - echo "---------------------------------------------------------"
 | 
			
		||||
      - echo "Verify"
 | 
			
		||||
      - $ANDROID_HOME/build-tools/31.0.0/apksigner verify signed.apk
 | 
			
		||||
    environment:
 | 
			
		||||
      YOUR_KEYSTORE_PASSWORD:
 | 
			
		||||
        from_secret: keyPass
 | 
			
		||||
      YOUR_KEY_ALIAS:
 | 
			
		||||
        from_secret: keyAlias
 | 
			
		||||
 | 
			
		||||
  - name: gitea_release
 | 
			
		||||
    image: plugins/gitea-release
 | 
			
		||||
    settings:
 | 
			
		||||
      api_key:
 | 
			
		||||
        from_secret: giteaAPI
 | 
			
		||||
      base_url: https://gitea.amine-louveau.fr
 | 
			
		||||
      files: signed.apk
 | 
			
		||||
trigger:
 | 
			
		||||
  event:
 | 
			
		||||
    - tag
 | 
			
		||||
							
								
								
									
										4
									
								
								.github/CONTRIBUTING.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.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.
 | 
			
		||||
 | 
			
		||||
You can fork the repository, and [help me solve some issues](https://github.com/aminecmi/ReaderforSelfoss/issues?q=is%3Aissue+is%3Aopen+label%3A%22Up+For+Grabs%22) or [develop new things](https://github.com/aminecmi/ReaderforSelfoss/issues)
 | 
			
		||||
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)
 | 
			
		||||
 | 
			
		||||
### What I can't help you with.
 | 
			
		||||
 | 
			
		||||
@@ -28,7 +28,7 @@ Always check if the web version of your instance is working.
 | 
			
		||||
 | 
			
		||||
### Pull requests
 | 
			
		||||
 | 
			
		||||
* Don't create a PR for translations. See [here](https://github.com/aminecmi/ReaderforSelfoss/pull/170#issuecomment-355715654) for an explanation why.
 | 
			
		||||
* Don't create a PR for translations. 
 | 
			
		||||
* Please ask before starting to work on an issue. I may be working on it, or someone else could be doing so.
 | 
			
		||||
* Each pull request should implement **ONE** feature or bugfix. Keep in mind that you can submit as many PR as you want.
 | 
			
		||||
* Your code must be simple and clear enough to avoid using comments to explain what it does.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								.github/PULL_REQUEST_TEMPLATE.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/PULL_REQUEST_TEMPLATE.md
									
									
									
									
										vendored
									
									
								
							@@ -5,7 +5,7 @@
 | 
			
		||||
- [ ] I have updated the documentation accordingly.
 | 
			
		||||
- [ ] I have added tests to cover my changes.
 | 
			
		||||
- [ ] All new and existing tests passed.
 | 
			
		||||
- [ ] This is **NOT** translation related. (See [here](https://github.com/aminecmi/ReaderforSelfoss/pull/170#issuecomment-355715654))
 | 
			
		||||
- [ ] This is **NOT** translation related.
 | 
			
		||||
 | 
			
		||||
This closes issue #XXX
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -319,3 +319,5 @@ fabric.properties
 | 
			
		||||
 | 
			
		||||
# End of https://www.toptal.com/developers/gitignore/api/gradle,kotlin,androidstudio,android,xcode,swift
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
crowdin.properties
 | 
			
		||||
							
								
								
									
										11
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@@ -1,3 +1,14 @@
 | 
			
		||||
# V2/Multiplatform rewrite
 | 
			
		||||
 | 
			
		||||
**v1**
 | 
			
		||||
 | 
			
		||||
- The app has the same functionalities as before.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--------------------------------------------------------------------
 | 
			
		||||
                                                                      
 | 
			
		||||
# Old version changes
 | 
			
		||||
 | 
			
		||||
**1.7.x**
 | 
			
		||||
 | 
			
		||||
- Hiding tags with 0 articles
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										12
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								README.md
									
									
									
									
									
								
							@@ -1,4 +1,4 @@
 | 
			
		||||
# ReaderForSelfoss-multiplatform
 | 
			
		||||
# ReaderForSelfoss-multiplatform [](https://build.amine-louveau.fr/Louvorg/ReaderForSelfoss-multiplatform)
 | 
			
		||||
 | 
			
		||||
[](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/).
 | 
			
		||||
 | 
			
		||||
2. Check the [Contribution guide](https://github.com/aminecmi/ReaderforSelfoss-multiplatform/blob/master/.github/CONTRIBUTING.md).
 | 
			
		||||
2. Check the [Contribution guide](https://gitea.amine-louveau.fr/Louvorg/ReaderforSelfoss-multiplatform/src/branch/master/.github/CONTRIBUTING.md).
 | 
			
		||||
 | 
			
		||||
3. Build the project by following [these steps](https://github.com/aminecmi/ReaderforSelfoss-multiplatform/blob/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-louveau.fr/Louvorg/ReaderforSelfoss-multiplatform/src/branch/master/.github/CONTRIBUTING.md#build-the-project) (you should have read them after the contribution guide)
 | 
			
		||||
 | 
			
		||||
## Useful links
 | 
			
		||||
 | 
			
		||||
- [Check what changed](https://github.com/aminecmi/ReaderforSelfoss-multiplatform/blob/master/CHANGELOG.md)
 | 
			
		||||
- [See what I'm doing](https://github.com/aminecmi/ReaderforSelfoss-multiplatform/projects/1)
 | 
			
		||||
- [Create an issue, or request a new feature](https://github.com/aminecmi/ReaderforSelfoss-multiplatform/issues)
 | 
			
		||||
- [Check what changed](https://gitea.amine-louveau.fr/Louvorg/ReaderforSelfoss-multiplatform/src/branch/master/CHANGELOG.md)
 | 
			
		||||
- [See what I'm doing](https://gitea.amine-louveau.fr/Louvorg/ReaderforSelfoss-multiplatform/projects/1)
 | 
			
		||||
- [Create an issue, or request a new feature](https://gitea.amine-louveau.fr/Louvorg/ReaderforSelfoss-multiplatform/issues)
 | 
			
		||||
- [Help translation the app](https://crowdin.com/project/readerforselfoss)
 | 
			
		||||
 | 
			
		||||
## Contributors (V1) (Alphabetical order) ❤️
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,7 @@
 | 
			
		||||
import java.io.ByteArrayOutputStream
 | 
			
		||||
 | 
			
		||||
val ignoreGitVersion: String by project
 | 
			
		||||
 | 
			
		||||
plugins {
 | 
			
		||||
    id("com.android.application")
 | 
			
		||||
    kotlin("android")
 | 
			
		||||
@@ -28,15 +30,23 @@ fun gitVersion(): String {
 | 
			
		||||
        println("Tag found on current commit")
 | 
			
		||||
        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 {
 | 
			
		||||
    if (ignoreGitVersion == "true") {
 | 
			
		||||
        // don't care
 | 
			
		||||
        return 1
 | 
			
		||||
    }
 | 
			
		||||
    println("version code " + gitVersion())
 | 
			
		||||
    return gitVersion().toInt()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fun versionNameFromGit(): String {
 | 
			
		||||
    if (ignoreGitVersion == "true") {
 | 
			
		||||
        // don't care
 | 
			
		||||
        return "1"
 | 
			
		||||
    }
 | 
			
		||||
    println("version name " + gitVersion())
 | 
			
		||||
    return gitVersion()
 | 
			
		||||
}
 | 
			
		||||
@@ -68,12 +78,6 @@ android {
 | 
			
		||||
 | 
			
		||||
        // tests
 | 
			
		||||
        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
 | 
			
		||||
 | 
			
		||||
        javaCompileOptions {
 | 
			
		||||
            annotationProcessorOptions {
 | 
			
		||||
                arguments += mapOf("room.schemaLocation" to "$projectDir/schemas")
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    buildTypes {
 | 
			
		||||
        getByName("release") {
 | 
			
		||||
@@ -89,7 +93,7 @@ android {
 | 
			
		||||
    }
 | 
			
		||||
    flavorDimensions.add("build")
 | 
			
		||||
    productFlavors {
 | 
			
		||||
        create("github") {
 | 
			
		||||
        create("githubConfig") {
 | 
			
		||||
            versionNameSuffix = "-github"
 | 
			
		||||
            dimension = "build"
 | 
			
		||||
        }
 | 
			
		||||
@@ -97,6 +101,7 @@ android {
 | 
			
		||||
    kotlinOptions {
 | 
			
		||||
        jvmTarget = "1.8"
 | 
			
		||||
    }
 | 
			
		||||
    namespace = "bou.amine.apps.readerforselfossv2.android"
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -170,16 +175,30 @@ dependencies {
 | 
			
		||||
    implementation("me.relex:circleindicator:2.1.6")
 | 
			
		||||
    implementation("androidx.viewpager2:viewpager2:1.1.0-beta01")
 | 
			
		||||
 | 
			
		||||
    //Dependency Injection
 | 
			
		||||
    implementation("org.kodein.di:kodein-di:7.14.0")
 | 
			
		||||
    implementation("org.kodein.di:kodein-di-framework-android-x:7.14.0")
 | 
			
		||||
    implementation("org.kodein.di:kodein-di-framework-android-x-viewmodel:7.14.0")
 | 
			
		||||
 | 
			
		||||
    //Settings
 | 
			
		||||
    implementation("com.russhwolf:multiplatform-settings-no-arg:0.9")
 | 
			
		||||
 | 
			
		||||
    //Logging
 | 
			
		||||
    implementation("io.github.aakira:napier:2.6.1")
 | 
			
		||||
 | 
			
		||||
    //PhotoView
 | 
			
		||||
    implementation("com.github.chrisbanes:PhotoView:2.3.0")
 | 
			
		||||
 | 
			
		||||
    implementation("androidx.core:core-ktx:1.7.0")
 | 
			
		||||
    implementation("androidx.core:core-ktx:1.8.0")
 | 
			
		||||
 | 
			
		||||
    implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.4.0")
 | 
			
		||||
    implementation("androidx.lifecycle:lifecycle-common-java8:2.4.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.room:room-ktx:2.4.0-beta01")
 | 
			
		||||
    kapt("androidx.room:room-compiler:2.4.0-beta01")
 | 
			
		||||
    // Network information
 | 
			
		||||
     implementation("com.github.ln-12:multiplatform-connectivity-status:1.3.0")
 | 
			
		||||
 | 
			
		||||
    implementation("android.arch.work:work-runtime-ktx:1.0.1")
 | 
			
		||||
    // SQLDELIGHT
 | 
			
		||||
    implementation("com.squareup.sqldelight:android-driver:1.5.3")
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										31
									
								
								androidApp/proguard-rules.pro
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										31
									
								
								androidApp/proguard-rules.pro
									
									
									
									
										vendored
									
									
								
							@@ -55,11 +55,38 @@
 | 
			
		||||
  public *;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
-dontwarn com.anupcowkur.reservoir.**
 | 
			
		||||
 | 
			
		||||
-dontwarn javax.annotation.**
 | 
			
		||||
 | 
			
		||||
-keep class android.support.v7.widget.SearchView { *; }
 | 
			
		||||
 | 
			
		||||
# maybe remove later ?
 | 
			
		||||
-keep class * extends androidx.fragment.app.Fragment
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Keep `Companion` object fields of serializable classes.
 | 
			
		||||
# This avoids serializer lookup through `getDeclaredClasses` as done for named companion objects.
 | 
			
		||||
-if @kotlinx.serialization.Serializable class **
 | 
			
		||||
-keepclassmembers class <1> {
 | 
			
		||||
   static <1>$Companion Companion;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Keep `serializer()` on companion objects (both default and named) of serializable classes.
 | 
			
		||||
-if @kotlinx.serialization.Serializable class ** {
 | 
			
		||||
   static **$* *;
 | 
			
		||||
}
 | 
			
		||||
-keepclassmembers class <2>$<3> {
 | 
			
		||||
   kotlinx.serialization.KSerializer serializer(...);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Keep `INSTANCE.serializer()` of serializable objects.
 | 
			
		||||
-if @kotlinx.serialization.Serializable class ** {
 | 
			
		||||
   public static ** INSTANCE;
 | 
			
		||||
}
 | 
			
		||||
-keepclassmembers class <1> {
 | 
			
		||||
   public static <1> INSTANCE;
 | 
			
		||||
   kotlinx.serialization.KSerializer serializer(...);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# @Serializable and @Polymorphic are used at runtime for polymorphic serialization.
 | 
			
		||||
-keepattributes RuntimeVisibleAnnotations,AnnotationDefault
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +0,0 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
 | 
			
		||||
# NOTE: This is copy/pasted in jenkins
 | 
			
		||||
 | 
			
		||||
rm -f version.txt
 | 
			
		||||
printf "versionName=$1-github\nversionCode=$1" >> version.txt
 | 
			
		||||
 | 
			
		||||
# You'll need to change server as your server and define a VERSION_PATH.
 | 
			
		||||
scp version.txt server:$VERSION_PATH
 | 
			
		||||
 | 
			
		||||
rm version.txt
 | 
			
		||||
@@ -1,96 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
  "formatVersion": 1,
 | 
			
		||||
  "database": {
 | 
			
		||||
    "version": 1,
 | 
			
		||||
    "identityHash": "08ca537d7ac9d4dd216e8e395d70801a",
 | 
			
		||||
    "entities": [
 | 
			
		||||
      {
 | 
			
		||||
        "tableName": "tags",
 | 
			
		||||
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`tag` TEXT NOT NULL, `color` TEXT NOT NULL, `unread` INTEGER NOT NULL, PRIMARY KEY(`tag`))",
 | 
			
		||||
        "fields": [
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "tag",
 | 
			
		||||
            "columnName": "tag",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "color",
 | 
			
		||||
            "columnName": "color",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "unread",
 | 
			
		||||
            "columnName": "unread",
 | 
			
		||||
            "affinity": "INTEGER",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          }
 | 
			
		||||
        ],
 | 
			
		||||
        "primaryKey": {
 | 
			
		||||
          "columnNames": [
 | 
			
		||||
            "tag"
 | 
			
		||||
          ],
 | 
			
		||||
          "autoGenerate": false
 | 
			
		||||
        },
 | 
			
		||||
        "indices": [],
 | 
			
		||||
        "foreignKeys": []
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "tableName": "sources",
 | 
			
		||||
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `title` TEXT NOT NULL, `tags` TEXT NOT NULL, `spout` TEXT NOT NULL, `error` TEXT NOT NULL, `icon` TEXT NOT NULL, PRIMARY KEY(`id`))",
 | 
			
		||||
        "fields": [
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "id",
 | 
			
		||||
            "columnName": "id",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "title",
 | 
			
		||||
            "columnName": "title",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "tags",
 | 
			
		||||
            "columnName": "tags",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "spout",
 | 
			
		||||
            "columnName": "spout",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "error",
 | 
			
		||||
            "columnName": "error",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "icon",
 | 
			
		||||
            "columnName": "icon",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          }
 | 
			
		||||
        ],
 | 
			
		||||
        "primaryKey": {
 | 
			
		||||
          "columnNames": [
 | 
			
		||||
            "id"
 | 
			
		||||
          ],
 | 
			
		||||
          "autoGenerate": false
 | 
			
		||||
        },
 | 
			
		||||
        "indices": [],
 | 
			
		||||
        "foreignKeys": []
 | 
			
		||||
      }
 | 
			
		||||
    ],
 | 
			
		||||
    "views": [],
 | 
			
		||||
    "setupQueries": [
 | 
			
		||||
      "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
 | 
			
		||||
      "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"08ca537d7ac9d4dd216e8e395d70801a\")"
 | 
			
		||||
    ]
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,176 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
  "formatVersion": 1,
 | 
			
		||||
  "database": {
 | 
			
		||||
    "version": 2,
 | 
			
		||||
    "identityHash": "6fa6944b04100d68eab61039876a8804",
 | 
			
		||||
    "entities": [
 | 
			
		||||
      {
 | 
			
		||||
        "tableName": "tags",
 | 
			
		||||
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`tag` TEXT NOT NULL, `color` TEXT NOT NULL, `unread` INTEGER NOT NULL, PRIMARY KEY(`tag`))",
 | 
			
		||||
        "fields": [
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "tag",
 | 
			
		||||
            "columnName": "tag",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "color",
 | 
			
		||||
            "columnName": "color",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "unread",
 | 
			
		||||
            "columnName": "unread",
 | 
			
		||||
            "affinity": "INTEGER",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          }
 | 
			
		||||
        ],
 | 
			
		||||
        "primaryKey": {
 | 
			
		||||
          "columnNames": [
 | 
			
		||||
            "tag"
 | 
			
		||||
          ],
 | 
			
		||||
          "autoGenerate": false
 | 
			
		||||
        },
 | 
			
		||||
        "indices": [],
 | 
			
		||||
        "foreignKeys": []
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "tableName": "sources",
 | 
			
		||||
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `title` TEXT NOT NULL, `tags` TEXT NOT NULL, `spout` TEXT NOT NULL, `error` TEXT NOT NULL, `icon` TEXT NOT NULL, PRIMARY KEY(`id`))",
 | 
			
		||||
        "fields": [
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "id",
 | 
			
		||||
            "columnName": "id",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "title",
 | 
			
		||||
            "columnName": "title",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "tags",
 | 
			
		||||
            "columnName": "tags",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "spout",
 | 
			
		||||
            "columnName": "spout",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "error",
 | 
			
		||||
            "columnName": "error",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "icon",
 | 
			
		||||
            "columnName": "icon",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          }
 | 
			
		||||
        ],
 | 
			
		||||
        "primaryKey": {
 | 
			
		||||
          "columnNames": [
 | 
			
		||||
            "id"
 | 
			
		||||
          ],
 | 
			
		||||
          "autoGenerate": false
 | 
			
		||||
        },
 | 
			
		||||
        "indices": [],
 | 
			
		||||
        "foreignKeys": []
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "tableName": "items",
 | 
			
		||||
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `datetime` TEXT NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `unread` INTEGER NOT NULL, `starred` INTEGER NOT NULL, `thumbnail` TEXT NOT NULL, `icon` TEXT NOT NULL, `link` TEXT NOT NULL, `sourcetitle` TEXT NOT NULL, `tags` TEXT NOT NULL, PRIMARY KEY(`id`))",
 | 
			
		||||
        "fields": [
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "id",
 | 
			
		||||
            "columnName": "id",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "datetime",
 | 
			
		||||
            "columnName": "datetime",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "title",
 | 
			
		||||
            "columnName": "title",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "content",
 | 
			
		||||
            "columnName": "content",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "unread",
 | 
			
		||||
            "columnName": "unread",
 | 
			
		||||
            "affinity": "INTEGER",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "starred",
 | 
			
		||||
            "columnName": "starred",
 | 
			
		||||
            "affinity": "INTEGER",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "thumbnail",
 | 
			
		||||
            "columnName": "thumbnail",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "icon",
 | 
			
		||||
            "columnName": "icon",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "link",
 | 
			
		||||
            "columnName": "link",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "sourcetitle",
 | 
			
		||||
            "columnName": "sourcetitle",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "tags",
 | 
			
		||||
            "columnName": "tags",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          }
 | 
			
		||||
        ],
 | 
			
		||||
        "primaryKey": {
 | 
			
		||||
          "columnNames": [
 | 
			
		||||
            "id"
 | 
			
		||||
          ],
 | 
			
		||||
          "autoGenerate": false
 | 
			
		||||
        },
 | 
			
		||||
        "indices": [],
 | 
			
		||||
        "foreignKeys": []
 | 
			
		||||
      }
 | 
			
		||||
    ],
 | 
			
		||||
    "views": [],
 | 
			
		||||
    "setupQueries": [
 | 
			
		||||
      "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
 | 
			
		||||
      "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"6fa6944b04100d68eab61039876a8804\")"
 | 
			
		||||
    ]
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,226 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
  "formatVersion": 1,
 | 
			
		||||
  "database": {
 | 
			
		||||
    "version": 3,
 | 
			
		||||
    "identityHash": "7ad9c4961992c13b670128485ebb3efc",
 | 
			
		||||
    "entities": [
 | 
			
		||||
      {
 | 
			
		||||
        "tableName": "tags",
 | 
			
		||||
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`tag` TEXT NOT NULL, `color` TEXT NOT NULL, `unread` INTEGER NOT NULL, PRIMARY KEY(`tag`))",
 | 
			
		||||
        "fields": [
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "tag",
 | 
			
		||||
            "columnName": "tag",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "color",
 | 
			
		||||
            "columnName": "color",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "unread",
 | 
			
		||||
            "columnName": "unread",
 | 
			
		||||
            "affinity": "INTEGER",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          }
 | 
			
		||||
        ],
 | 
			
		||||
        "primaryKey": {
 | 
			
		||||
          "columnNames": [
 | 
			
		||||
            "tag"
 | 
			
		||||
          ],
 | 
			
		||||
          "autoGenerate": false
 | 
			
		||||
        },
 | 
			
		||||
        "indices": [],
 | 
			
		||||
        "foreignKeys": []
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "tableName": "sources",
 | 
			
		||||
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `title` TEXT NOT NULL, `tags` TEXT NOT NULL, `spout` TEXT NOT NULL, `error` TEXT NOT NULL, `icon` TEXT NOT NULL, PRIMARY KEY(`id`))",
 | 
			
		||||
        "fields": [
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "id",
 | 
			
		||||
            "columnName": "id",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "title",
 | 
			
		||||
            "columnName": "title",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "tags",
 | 
			
		||||
            "columnName": "tags",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "spout",
 | 
			
		||||
            "columnName": "spout",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "error",
 | 
			
		||||
            "columnName": "error",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "icon",
 | 
			
		||||
            "columnName": "icon",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          }
 | 
			
		||||
        ],
 | 
			
		||||
        "primaryKey": {
 | 
			
		||||
          "columnNames": [
 | 
			
		||||
            "id"
 | 
			
		||||
          ],
 | 
			
		||||
          "autoGenerate": false
 | 
			
		||||
        },
 | 
			
		||||
        "indices": [],
 | 
			
		||||
        "foreignKeys": []
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "tableName": "items",
 | 
			
		||||
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `datetime` TEXT NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `unread` INTEGER NOT NULL, `starred` INTEGER NOT NULL, `thumbnail` TEXT NOT NULL, `icon` TEXT NOT NULL, `link` TEXT NOT NULL, `sourcetitle` TEXT NOT NULL, `tags` TEXT NOT NULL, PRIMARY KEY(`id`))",
 | 
			
		||||
        "fields": [
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "id",
 | 
			
		||||
            "columnName": "id",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "datetime",
 | 
			
		||||
            "columnName": "datetime",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "title",
 | 
			
		||||
            "columnName": "title",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "content",
 | 
			
		||||
            "columnName": "content",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "unread",
 | 
			
		||||
            "columnName": "unread",
 | 
			
		||||
            "affinity": "INTEGER",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "starred",
 | 
			
		||||
            "columnName": "starred",
 | 
			
		||||
            "affinity": "INTEGER",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "thumbnail",
 | 
			
		||||
            "columnName": "thumbnail",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "icon",
 | 
			
		||||
            "columnName": "icon",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "link",
 | 
			
		||||
            "columnName": "link",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "sourcetitle",
 | 
			
		||||
            "columnName": "sourcetitle",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "tags",
 | 
			
		||||
            "columnName": "tags",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          }
 | 
			
		||||
        ],
 | 
			
		||||
        "primaryKey": {
 | 
			
		||||
          "columnNames": [
 | 
			
		||||
            "id"
 | 
			
		||||
          ],
 | 
			
		||||
          "autoGenerate": false
 | 
			
		||||
        },
 | 
			
		||||
        "indices": [],
 | 
			
		||||
        "foreignKeys": []
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "tableName": "actions",
 | 
			
		||||
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `articleid` TEXT NOT NULL, `read` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `starred` INTEGER NOT NULL, `unstarred` INTEGER NOT NULL)",
 | 
			
		||||
        "fields": [
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "id",
 | 
			
		||||
            "columnName": "id",
 | 
			
		||||
            "affinity": "INTEGER",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "articleId",
 | 
			
		||||
            "columnName": "articleid",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "read",
 | 
			
		||||
            "columnName": "read",
 | 
			
		||||
            "affinity": "INTEGER",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "unread",
 | 
			
		||||
            "columnName": "unread",
 | 
			
		||||
            "affinity": "INTEGER",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "starred",
 | 
			
		||||
            "columnName": "starred",
 | 
			
		||||
            "affinity": "INTEGER",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "unstarred",
 | 
			
		||||
            "columnName": "unstarred",
 | 
			
		||||
            "affinity": "INTEGER",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          }
 | 
			
		||||
        ],
 | 
			
		||||
        "primaryKey": {
 | 
			
		||||
          "columnNames": [
 | 
			
		||||
            "id"
 | 
			
		||||
          ],
 | 
			
		||||
          "autoGenerate": true
 | 
			
		||||
        },
 | 
			
		||||
        "indices": [],
 | 
			
		||||
        "foreignKeys": []
 | 
			
		||||
      }
 | 
			
		||||
    ],
 | 
			
		||||
    "views": [],
 | 
			
		||||
    "setupQueries": [
 | 
			
		||||
      "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
 | 
			
		||||
      "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"7ad9c4961992c13b670128485ebb3efc\")"
 | 
			
		||||
    ]
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,226 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
  "formatVersion": 1,
 | 
			
		||||
  "database": {
 | 
			
		||||
    "version": 4,
 | 
			
		||||
    "identityHash": "9cf8b03d32f80dfd58160599a1df197d",
 | 
			
		||||
    "entities": [
 | 
			
		||||
      {
 | 
			
		||||
        "tableName": "tags",
 | 
			
		||||
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`tag` TEXT NOT NULL, `color` TEXT NOT NULL, `unread` INTEGER NOT NULL, PRIMARY KEY(`tag`))",
 | 
			
		||||
        "fields": [
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "tag",
 | 
			
		||||
            "columnName": "tag",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "color",
 | 
			
		||||
            "columnName": "color",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "unread",
 | 
			
		||||
            "columnName": "unread",
 | 
			
		||||
            "affinity": "INTEGER",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          }
 | 
			
		||||
        ],
 | 
			
		||||
        "primaryKey": {
 | 
			
		||||
          "columnNames": [
 | 
			
		||||
            "tag"
 | 
			
		||||
          ],
 | 
			
		||||
          "autoGenerate": false
 | 
			
		||||
        },
 | 
			
		||||
        "indices": [],
 | 
			
		||||
        "foreignKeys": []
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "tableName": "sources",
 | 
			
		||||
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `title` TEXT NOT NULL, `tags` TEXT NOT NULL, `spout` TEXT NOT NULL, `error` TEXT NOT NULL, `icon` TEXT NOT NULL, PRIMARY KEY(`id`))",
 | 
			
		||||
        "fields": [
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "id",
 | 
			
		||||
            "columnName": "id",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "title",
 | 
			
		||||
            "columnName": "title",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "tags",
 | 
			
		||||
            "columnName": "tags",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "spout",
 | 
			
		||||
            "columnName": "spout",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "error",
 | 
			
		||||
            "columnName": "error",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "icon",
 | 
			
		||||
            "columnName": "icon",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          }
 | 
			
		||||
        ],
 | 
			
		||||
        "primaryKey": {
 | 
			
		||||
          "columnNames": [
 | 
			
		||||
            "id"
 | 
			
		||||
          ],
 | 
			
		||||
          "autoGenerate": false
 | 
			
		||||
        },
 | 
			
		||||
        "indices": [],
 | 
			
		||||
        "foreignKeys": []
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "tableName": "items",
 | 
			
		||||
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `datetime` TEXT NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `unread` INTEGER NOT NULL, `starred` INTEGER NOT NULL, `thumbnail` TEXT, `icon` TEXT, `link` TEXT NOT NULL, `sourcetitle` TEXT NOT NULL, `tags` TEXT NOT NULL, PRIMARY KEY(`id`))",
 | 
			
		||||
        "fields": [
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "id",
 | 
			
		||||
            "columnName": "id",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "datetime",
 | 
			
		||||
            "columnName": "datetime",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "title",
 | 
			
		||||
            "columnName": "title",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "content",
 | 
			
		||||
            "columnName": "content",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "unread",
 | 
			
		||||
            "columnName": "unread",
 | 
			
		||||
            "affinity": "INTEGER",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "starred",
 | 
			
		||||
            "columnName": "starred",
 | 
			
		||||
            "affinity": "INTEGER",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "thumbnail",
 | 
			
		||||
            "columnName": "thumbnail",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": false
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "icon",
 | 
			
		||||
            "columnName": "icon",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": false
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "link",
 | 
			
		||||
            "columnName": "link",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "sourcetitle",
 | 
			
		||||
            "columnName": "sourcetitle",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "tags",
 | 
			
		||||
            "columnName": "tags",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          }
 | 
			
		||||
        ],
 | 
			
		||||
        "primaryKey": {
 | 
			
		||||
          "columnNames": [
 | 
			
		||||
            "id"
 | 
			
		||||
          ],
 | 
			
		||||
          "autoGenerate": false
 | 
			
		||||
        },
 | 
			
		||||
        "indices": [],
 | 
			
		||||
        "foreignKeys": []
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "tableName": "actions",
 | 
			
		||||
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `articleid` TEXT NOT NULL, `read` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `starred` INTEGER NOT NULL, `unstarred` INTEGER NOT NULL)",
 | 
			
		||||
        "fields": [
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "id",
 | 
			
		||||
            "columnName": "id",
 | 
			
		||||
            "affinity": "INTEGER",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "articleId",
 | 
			
		||||
            "columnName": "articleid",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "read",
 | 
			
		||||
            "columnName": "read",
 | 
			
		||||
            "affinity": "INTEGER",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "unread",
 | 
			
		||||
            "columnName": "unread",
 | 
			
		||||
            "affinity": "INTEGER",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "starred",
 | 
			
		||||
            "columnName": "starred",
 | 
			
		||||
            "affinity": "INTEGER",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "unstarred",
 | 
			
		||||
            "columnName": "unstarred",
 | 
			
		||||
            "affinity": "INTEGER",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          }
 | 
			
		||||
        ],
 | 
			
		||||
        "primaryKey": {
 | 
			
		||||
          "columnNames": [
 | 
			
		||||
            "id"
 | 
			
		||||
          ],
 | 
			
		||||
          "autoGenerate": true
 | 
			
		||||
        },
 | 
			
		||||
        "indices": [],
 | 
			
		||||
        "foreignKeys": []
 | 
			
		||||
      }
 | 
			
		||||
    ],
 | 
			
		||||
    "views": [],
 | 
			
		||||
    "setupQueries": [
 | 
			
		||||
      "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
 | 
			
		||||
      "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"9cf8b03d32f80dfd58160599a1df197d\")"
 | 
			
		||||
    ]
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,226 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
  "formatVersion": 1,
 | 
			
		||||
  "database": {
 | 
			
		||||
    "version": 4,
 | 
			
		||||
    "identityHash": "9cf8b03d32f80dfd58160599a1df197d",
 | 
			
		||||
    "entities": [
 | 
			
		||||
      {
 | 
			
		||||
        "tableName": "tags",
 | 
			
		||||
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`tag` TEXT NOT NULL, `color` TEXT NOT NULL, `unread` INTEGER NOT NULL, PRIMARY KEY(`tag`))",
 | 
			
		||||
        "fields": [
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "tag",
 | 
			
		||||
            "columnName": "tag",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "color",
 | 
			
		||||
            "columnName": "color",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "unread",
 | 
			
		||||
            "columnName": "unread",
 | 
			
		||||
            "affinity": "INTEGER",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          }
 | 
			
		||||
        ],
 | 
			
		||||
        "primaryKey": {
 | 
			
		||||
          "columnNames": [
 | 
			
		||||
            "tag"
 | 
			
		||||
          ],
 | 
			
		||||
          "autoGenerate": false
 | 
			
		||||
        },
 | 
			
		||||
        "indices": [],
 | 
			
		||||
        "foreignKeys": []
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "tableName": "sources",
 | 
			
		||||
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `title` TEXT NOT NULL, `tags` TEXT NOT NULL, `spout` TEXT NOT NULL, `error` TEXT NOT NULL, `icon` TEXT NOT NULL, PRIMARY KEY(`id`))",
 | 
			
		||||
        "fields": [
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "id",
 | 
			
		||||
            "columnName": "id",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "title",
 | 
			
		||||
            "columnName": "title",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "tags",
 | 
			
		||||
            "columnName": "tags",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "spout",
 | 
			
		||||
            "columnName": "spout",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "error",
 | 
			
		||||
            "columnName": "error",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "icon",
 | 
			
		||||
            "columnName": "icon",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          }
 | 
			
		||||
        ],
 | 
			
		||||
        "primaryKey": {
 | 
			
		||||
          "columnNames": [
 | 
			
		||||
            "id"
 | 
			
		||||
          ],
 | 
			
		||||
          "autoGenerate": false
 | 
			
		||||
        },
 | 
			
		||||
        "indices": [],
 | 
			
		||||
        "foreignKeys": []
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "tableName": "items",
 | 
			
		||||
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `datetime` TEXT NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `unread` INTEGER NOT NULL, `starred` INTEGER NOT NULL, `thumbnail` TEXT, `icon` TEXT, `link` TEXT NOT NULL, `sourcetitle` TEXT NOT NULL, `tags` TEXT NOT NULL, PRIMARY KEY(`id`))",
 | 
			
		||||
        "fields": [
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "id",
 | 
			
		||||
            "columnName": "id",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "datetime",
 | 
			
		||||
            "columnName": "datetime",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "title",
 | 
			
		||||
            "columnName": "title",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "content",
 | 
			
		||||
            "columnName": "content",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "unread",
 | 
			
		||||
            "columnName": "unread",
 | 
			
		||||
            "affinity": "INTEGER",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "starred",
 | 
			
		||||
            "columnName": "starred",
 | 
			
		||||
            "affinity": "INTEGER",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "thumbnail",
 | 
			
		||||
            "columnName": "thumbnail",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": false
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "icon",
 | 
			
		||||
            "columnName": "icon",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": false
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "link",
 | 
			
		||||
            "columnName": "link",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "sourcetitle",
 | 
			
		||||
            "columnName": "sourcetitle",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "tags",
 | 
			
		||||
            "columnName": "tags",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          }
 | 
			
		||||
        ],
 | 
			
		||||
        "primaryKey": {
 | 
			
		||||
          "columnNames": [
 | 
			
		||||
            "id"
 | 
			
		||||
          ],
 | 
			
		||||
          "autoGenerate": false
 | 
			
		||||
        },
 | 
			
		||||
        "indices": [],
 | 
			
		||||
        "foreignKeys": []
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "tableName": "actions",
 | 
			
		||||
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`articleid` TEXT NOT NULL, `read` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `starred` INTEGER NOT NULL, `unstarred` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
 | 
			
		||||
        "fields": [
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "articleId",
 | 
			
		||||
            "columnName": "articleid",
 | 
			
		||||
            "affinity": "TEXT",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "read",
 | 
			
		||||
            "columnName": "read",
 | 
			
		||||
            "affinity": "INTEGER",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "unread",
 | 
			
		||||
            "columnName": "unread",
 | 
			
		||||
            "affinity": "INTEGER",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "starred",
 | 
			
		||||
            "columnName": "starred",
 | 
			
		||||
            "affinity": "INTEGER",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "unstarred",
 | 
			
		||||
            "columnName": "unstarred",
 | 
			
		||||
            "affinity": "INTEGER",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "fieldPath": "id",
 | 
			
		||||
            "columnName": "id",
 | 
			
		||||
            "affinity": "INTEGER",
 | 
			
		||||
            "notNull": true
 | 
			
		||||
          }
 | 
			
		||||
        ],
 | 
			
		||||
        "primaryKey": {
 | 
			
		||||
          "columnNames": [
 | 
			
		||||
            "id"
 | 
			
		||||
          ],
 | 
			
		||||
          "autoGenerate": true
 | 
			
		||||
        },
 | 
			
		||||
        "indices": [],
 | 
			
		||||
        "foreignKeys": []
 | 
			
		||||
      }
 | 
			
		||||
    ],
 | 
			
		||||
    "views": [],
 | 
			
		||||
    "setupQueries": [
 | 
			
		||||
      "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
 | 
			
		||||
      "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '9cf8b03d32f80dfd58160599a1df197d')"
 | 
			
		||||
    ]
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,3 +0,0 @@
 | 
			
		||||
package bou.amine.apps.readerforselfossv2.android
 | 
			
		||||
 | 
			
		||||
// TODO: test source adding
 | 
			
		||||
@@ -1,102 +0,0 @@
 | 
			
		||||
package bou.amine.apps.readerforselfossv2.android
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import androidx.test.InstrumentationRegistry
 | 
			
		||||
import androidx.test.espresso.Espresso.onView
 | 
			
		||||
import androidx.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu
 | 
			
		||||
import androidx.test.espresso.action.ViewActions.click
 | 
			
		||||
import androidx.test.espresso.action.ViewActions.closeSoftKeyboard
 | 
			
		||||
import androidx.test.espresso.action.ViewActions.pressKey
 | 
			
		||||
import androidx.test.espresso.action.ViewActions.typeText
 | 
			
		||||
import androidx.test.espresso.assertion.ViewAssertions.matches
 | 
			
		||||
import androidx.test.espresso.intent.Intents
 | 
			
		||||
import androidx.test.espresso.intent.Intents.intended
 | 
			
		||||
import androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent
 | 
			
		||||
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
 | 
			
		||||
import androidx.test.espresso.matcher.ViewMatchers.withContentDescription
 | 
			
		||||
import androidx.test.espresso.matcher.ViewMatchers.withId
 | 
			
		||||
import androidx.test.espresso.matcher.ViewMatchers.withText
 | 
			
		||||
import androidx.test.rule.ActivityTestRule
 | 
			
		||||
import androidx.test.runner.AndroidJUnit4
 | 
			
		||||
import android.view.KeyEvent
 | 
			
		||||
import androidx.test.espresso.matcher.RootMatchers.isDialog
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.HomeActivity
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.LoginActivity
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.utils.Config
 | 
			
		||||
import org.junit.After
 | 
			
		||||
import org.junit.Before
 | 
			
		||||
import org.junit.Rule
 | 
			
		||||
import org.junit.Test
 | 
			
		||||
import org.junit.runner.RunWith
 | 
			
		||||
 | 
			
		||||
@RunWith(AndroidJUnit4::class)
 | 
			
		||||
class HomeActivityEspressoTest {
 | 
			
		||||
    lateinit var context: Context
 | 
			
		||||
 | 
			
		||||
    @Rule @JvmField
 | 
			
		||||
    val rule = ActivityTestRule(HomeActivity::class.java, true, false)
 | 
			
		||||
 | 
			
		||||
    @Before
 | 
			
		||||
    fun clearData() {
 | 
			
		||||
        context = InstrumentationRegistry.getInstrumentation().targetContext
 | 
			
		||||
 | 
			
		||||
        val editor =
 | 
			
		||||
                context
 | 
			
		||||
                        .getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
 | 
			
		||||
                        .edit()
 | 
			
		||||
        editor.clear()
 | 
			
		||||
 | 
			
		||||
        editor.putString("url", BuildConfig.LOGIN_URL)
 | 
			
		||||
        editor.putString("login", BuildConfig.LOGIN_USERNAME)
 | 
			
		||||
        editor.putString("password", BuildConfig.LOGIN_PASSWORD)
 | 
			
		||||
 | 
			
		||||
        editor.commit()
 | 
			
		||||
 | 
			
		||||
        Intents.init()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun menuItems() {
 | 
			
		||||
 | 
			
		||||
        rule.launchActivity(Intent())
 | 
			
		||||
 | 
			
		||||
        onView(
 | 
			
		||||
                withMenu(
 | 
			
		||||
                        id = R.id.action_search,
 | 
			
		||||
                        titleId = R.string.menu_home_search
 | 
			
		||||
                )
 | 
			
		||||
        ).perform(click())
 | 
			
		||||
 | 
			
		||||
        onView(withId(R.id.search_bar)).check(matches(isDisplayed()))
 | 
			
		||||
 | 
			
		||||
        onView(withId(R.id.search_src_text)).perform(
 | 
			
		||||
                typeText("android"),
 | 
			
		||||
                pressKey(KeyEvent.KEYCODE_SEARCH),
 | 
			
		||||
                closeSoftKeyboard()
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        onView(withContentDescription(R.string.abc_toolbar_collapse_description)).perform(click())
 | 
			
		||||
 | 
			
		||||
        openActionBarOverflowOrOptionsMenu(context)
 | 
			
		||||
 | 
			
		||||
        onView(withMenu(id = R.id.refresh, titleId = R.string.menu_home_refresh))
 | 
			
		||||
                .perform(click())
 | 
			
		||||
 | 
			
		||||
        onView(withText(android.R.string.ok))
 | 
			
		||||
            .inRoot(isDialog()).check(matches(isDisplayed())).perform(click())
 | 
			
		||||
 | 
			
		||||
        openActionBarOverflowOrOptionsMenu(context)
 | 
			
		||||
 | 
			
		||||
        onView(withText(R.string.action_disconnect)).perform(click())
 | 
			
		||||
 | 
			
		||||
        intended(hasComponent(LoginActivity::class.java.name))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // TODO: test articles opening and actions for cards and lists
 | 
			
		||||
 | 
			
		||||
    @After
 | 
			
		||||
    fun releaseIntents() {
 | 
			
		||||
        Intents.release()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,180 +0,0 @@
 | 
			
		||||
package bou.amine.apps.readerforselfossv2.android
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import androidx.test.InstrumentationRegistry
 | 
			
		||||
import androidx.test.espresso.Espresso.onView
 | 
			
		||||
import androidx.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu
 | 
			
		||||
import androidx.test.espresso.action.ViewActions.click
 | 
			
		||||
import androidx.test.espresso.action.ViewActions.closeSoftKeyboard
 | 
			
		||||
import androidx.test.espresso.action.ViewActions.pressBack
 | 
			
		||||
import androidx.test.espresso.action.ViewActions.typeText
 | 
			
		||||
import androidx.test.espresso.assertion.ViewAssertions.matches
 | 
			
		||||
import androidx.test.espresso.intent.Intents
 | 
			
		||||
import androidx.test.espresso.intent.Intents.intended
 | 
			
		||||
import androidx.test.espresso.intent.Intents.times
 | 
			
		||||
import androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent
 | 
			
		||||
import androidx.test.espresso.matcher.ViewMatchers
 | 
			
		||||
import androidx.test.espresso.matcher.ViewMatchers.isRoot
 | 
			
		||||
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
 | 
			
		||||
import androidx.test.espresso.matcher.ViewMatchers.withId
 | 
			
		||||
import androidx.test.espresso.matcher.ViewMatchers.withText
 | 
			
		||||
import androidx.test.rule.ActivityTestRule
 | 
			
		||||
import androidx.test.runner.AndroidJUnit4
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.HomeActivity
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.LoginActivity
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.utils.Config
 | 
			
		||||
import com.mikepenz.aboutlibraries.ui.LibsActivity
 | 
			
		||||
import org.junit.After
 | 
			
		||||
import org.junit.Before
 | 
			
		||||
import org.junit.Rule
 | 
			
		||||
import org.junit.Test
 | 
			
		||||
import org.junit.runner.RunWith
 | 
			
		||||
 | 
			
		||||
@RunWith(AndroidJUnit4::class)
 | 
			
		||||
class LoginActivityEspressoTest {
 | 
			
		||||
 | 
			
		||||
    @Rule @JvmField
 | 
			
		||||
    val rule = ActivityTestRule(LoginActivity::class.java, true, false)
 | 
			
		||||
 | 
			
		||||
    private lateinit var context: Context
 | 
			
		||||
    private lateinit var url: String
 | 
			
		||||
    private lateinit var username: String
 | 
			
		||||
    private lateinit var password: String
 | 
			
		||||
 | 
			
		||||
    @Before
 | 
			
		||||
    fun setUp() {
 | 
			
		||||
        context = InstrumentationRegistry.getInstrumentation().targetContext
 | 
			
		||||
        val editor =
 | 
			
		||||
                context
 | 
			
		||||
                        .getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
 | 
			
		||||
                        .edit()
 | 
			
		||||
        editor.clear()
 | 
			
		||||
        editor.commit()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        url = BuildConfig.LOGIN_URL
 | 
			
		||||
        username = BuildConfig.LOGIN_USERNAME
 | 
			
		||||
        password = BuildConfig.LOGIN_PASSWORD
 | 
			
		||||
 | 
			
		||||
        Intents.init()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun menuItems() {
 | 
			
		||||
 | 
			
		||||
        rule.launchActivity(Intent())
 | 
			
		||||
 | 
			
		||||
        openActionBarOverflowOrOptionsMenu(context)
 | 
			
		||||
 | 
			
		||||
        onView(withText(R.string.action_about)).perform(click())
 | 
			
		||||
 | 
			
		||||
        intended(hasComponent(LibsActivity::class.java.name), times(1))
 | 
			
		||||
 | 
			
		||||
        onView(isRoot()).perform(pressBack())
 | 
			
		||||
 | 
			
		||||
        intended(hasComponent(LoginActivity::class.java.name))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun wrongLoginUrl() {
 | 
			
		||||
        rule.launchActivity(Intent())
 | 
			
		||||
 | 
			
		||||
        onView(withId(R.id.loginProgress))
 | 
			
		||||
                .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)))
 | 
			
		||||
 | 
			
		||||
        onView(withId(R.id.urlView)).perform(click()).perform(typeText("WRONGURL"))
 | 
			
		||||
 | 
			
		||||
        onView(withId(R.id.signInButton)).perform(click())
 | 
			
		||||
 | 
			
		||||
        onView(withId(R.id.urlView)).check(matches(isHintOrErrorEnabled()))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // TODO: Add tests for multiple false urls with dialog
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun emptyAuthData() {
 | 
			
		||||
 | 
			
		||||
        rule.launchActivity(Intent())
 | 
			
		||||
 | 
			
		||||
        onView(withId(R.id.urlView)).perform(click()).perform(typeText(url), closeSoftKeyboard())
 | 
			
		||||
 | 
			
		||||
        onView(withId(R.id.withLogin)).perform(click())
 | 
			
		||||
 | 
			
		||||
        onView(withId(R.id.signInButton)).perform(click())
 | 
			
		||||
 | 
			
		||||
        onView(withId(R.id.loginView)).check(matches(isHintOrErrorEnabled()))
 | 
			
		||||
        onView(withId(R.id.passwordView)).check(matches(isHintOrErrorEnabled()))
 | 
			
		||||
 | 
			
		||||
        onView(withId(R.id.loginView)).perform(click()).perform(
 | 
			
		||||
                typeText(username),
 | 
			
		||||
                closeSoftKeyboard()
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        onView(withId(R.id.passwordView)).check(matches(isHintOrErrorEnabled()))
 | 
			
		||||
 | 
			
		||||
        onView(withId(R.id.signInButton)).perform(click())
 | 
			
		||||
 | 
			
		||||
        onView(withId(R.id.passwordView)).check(
 | 
			
		||||
                matches(
 | 
			
		||||
                        isHintOrErrorEnabled()
 | 
			
		||||
                )
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun wrongAuthData() {
 | 
			
		||||
 | 
			
		||||
        rule.launchActivity(Intent())
 | 
			
		||||
 | 
			
		||||
        onView(withId(R.id.urlView)).perform(click()).perform(typeText(url), closeSoftKeyboard())
 | 
			
		||||
 | 
			
		||||
        onView(withId(R.id.withLogin)).perform(click())
 | 
			
		||||
 | 
			
		||||
        onView(withId(R.id.loginView)).perform(click()).perform(
 | 
			
		||||
                typeText(username),
 | 
			
		||||
                closeSoftKeyboard()
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        onView(withId(R.id.passwordView)).perform(click()).perform(
 | 
			
		||||
                typeText("WRONGPASS"),
 | 
			
		||||
                closeSoftKeyboard()
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        onView(withId(R.id.signInButton)).perform(click())
 | 
			
		||||
 | 
			
		||||
        onView(withId(R.id.urlView)).check(matches(isHintOrErrorEnabled()))
 | 
			
		||||
        onView(withId(R.id.loginView)).check(matches(isHintOrErrorEnabled()))
 | 
			
		||||
        onView(withId(R.id.passwordView)).check(matches(isHintOrErrorEnabled()))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun workingAuth() {
 | 
			
		||||
 | 
			
		||||
        rule.launchActivity(Intent())
 | 
			
		||||
 | 
			
		||||
        onView(withId(R.id.urlView)).perform(click()).perform(typeText(url), closeSoftKeyboard())
 | 
			
		||||
 | 
			
		||||
        onView(withId(R.id.withLogin)).perform(click())
 | 
			
		||||
 | 
			
		||||
        onView(withId(R.id.loginView)).perform(click()).perform(
 | 
			
		||||
                typeText(username),
 | 
			
		||||
                closeSoftKeyboard()
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        onView(withId(R.id.passwordView)).perform(click()).perform(
 | 
			
		||||
                typeText(password),
 | 
			
		||||
                closeSoftKeyboard()
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        onView(withId(R.id.signInButton)).perform(click())
 | 
			
		||||
 | 
			
		||||
        Thread.sleep(2000)
 | 
			
		||||
        intended(hasComponent(HomeActivity::class.java.name))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @After
 | 
			
		||||
    fun releaseIntents() {
 | 
			
		||||
        Intents.release()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,81 +0,0 @@
 | 
			
		||||
package bou.amine.apps.readerforselfossv2.android
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.content.SharedPreferences
 | 
			
		||||
import androidx.test.InstrumentationRegistry.getInstrumentation
 | 
			
		||||
import androidx.test.espresso.intent.Intents
 | 
			
		||||
import androidx.test.espresso.intent.Intents.intended
 | 
			
		||||
import androidx.test.espresso.intent.Intents.times
 | 
			
		||||
import androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent
 | 
			
		||||
import androidx.test.rule.ActivityTestRule
 | 
			
		||||
import androidx.test.runner.AndroidJUnit4
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.HomeActivity
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.LoginActivity
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.MainActivity
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.utils.Config
 | 
			
		||||
import org.junit.After
 | 
			
		||||
 | 
			
		||||
import org.junit.Before
 | 
			
		||||
import org.junit.Rule
 | 
			
		||||
import org.junit.Test
 | 
			
		||||
import org.junit.runner.RunWith
 | 
			
		||||
 | 
			
		||||
@RunWith(AndroidJUnit4::class)
 | 
			
		||||
class MainActivityEspressoTest {
 | 
			
		||||
 | 
			
		||||
    lateinit var intent: Intent
 | 
			
		||||
    lateinit var preferencesEditor: SharedPreferences.Editor
 | 
			
		||||
    private lateinit var url: String
 | 
			
		||||
    private lateinit var username: String
 | 
			
		||||
    private lateinit var password: String
 | 
			
		||||
 | 
			
		||||
    @Rule @JvmField
 | 
			
		||||
    val rule = ActivityTestRule(MainActivity::class.java, true, false)
 | 
			
		||||
 | 
			
		||||
    @Before
 | 
			
		||||
    fun setUp() {
 | 
			
		||||
        intent = Intent()
 | 
			
		||||
        val context = getInstrumentation().targetContext
 | 
			
		||||
 | 
			
		||||
        // create a SharedPreferences editor
 | 
			
		||||
        preferencesEditor = context.getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE).edit()
 | 
			
		||||
 | 
			
		||||
        url = BuildConfig.LOGIN_URL
 | 
			
		||||
        username = BuildConfig.LOGIN_USERNAME
 | 
			
		||||
        password = BuildConfig.LOGIN_PASSWORD
 | 
			
		||||
 | 
			
		||||
        Intents.init()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun checkFirstOpenLaunchesIntro() {
 | 
			
		||||
        preferencesEditor.putString("url", "")
 | 
			
		||||
        preferencesEditor.putString("password", "")
 | 
			
		||||
        preferencesEditor.putString("login", "")
 | 
			
		||||
        preferencesEditor.commit()
 | 
			
		||||
 | 
			
		||||
        rule.launchActivity(intent)
 | 
			
		||||
 | 
			
		||||
        intended(hasComponent(LoginActivity::class.java.name))
 | 
			
		||||
        intended(hasComponent(HomeActivity::class.java.name), times(0))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun checkNotFirstOpenLaunchesLogin() {
 | 
			
		||||
        preferencesEditor.putString("url", url)
 | 
			
		||||
        preferencesEditor.putString("password", password)
 | 
			
		||||
        preferencesEditor.putString("login", username)
 | 
			
		||||
        preferencesEditor.commit()
 | 
			
		||||
 | 
			
		||||
        rule.launchActivity(intent)
 | 
			
		||||
 | 
			
		||||
        intended(hasComponent(MainActivity::class.java.name))
 | 
			
		||||
        intended(hasComponent(HomeActivity::class.java.name))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @After
 | 
			
		||||
    fun releaseIntents() {
 | 
			
		||||
        Intents.release()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,29 +0,0 @@
 | 
			
		||||
package bou.amine.apps.readerforselfossv2.android
 | 
			
		||||
 | 
			
		||||
import androidx.test.espresso.matcher.ViewMatchers
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.widget.EditText
 | 
			
		||||
import org.hamcrest.Description
 | 
			
		||||
import org.hamcrest.Matcher
 | 
			
		||||
import org.hamcrest.Matchers
 | 
			
		||||
import org.hamcrest.TypeSafeMatcher
 | 
			
		||||
 | 
			
		||||
fun isHintOrErrorEnabled(): Matcher<View> =
 | 
			
		||||
        object : TypeSafeMatcher<View>() {
 | 
			
		||||
            override fun describeTo(description: Description?) {
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            override fun matchesSafely(item: View?): Boolean {
 | 
			
		||||
                if (item !is EditText) {
 | 
			
		||||
                    return false
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return item.error.isNotEmpty()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
fun withMenu(id: Int, titleId: Int): Matcher<View> =
 | 
			
		||||
        Matchers.anyOf(
 | 
			
		||||
                ViewMatchers.withId(id),
 | 
			
		||||
                ViewMatchers.withText(titleId)
 | 
			
		||||
        )
 | 
			
		||||
@@ -1,31 +0,0 @@
 | 
			
		||||
package bou.amine.apps.readerforselfossv2.android.utils
 | 
			
		||||
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.utils.Config
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.utils.parseDate
 | 
			
		||||
import org.junit.Test
 | 
			
		||||
 | 
			
		||||
class DateUtilsTest {
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun parseDateV4() {
 | 
			
		||||
 | 
			
		||||
        Config.apiVersion = 4
 | 
			
		||||
        val dateString = "2013-04-07T13:43:00+01:00"
 | 
			
		||||
 | 
			
		||||
        val milliseconds = parseDate(dateString).toEpochMilli()
 | 
			
		||||
        val correctMilliseconds : Long = 1365338580000
 | 
			
		||||
 | 
			
		||||
        assert(milliseconds == correctMilliseconds)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun parseDateV1() {
 | 
			
		||||
        Config.apiVersion = 0
 | 
			
		||||
        val dateString = "2013-04-07 13:43:00"
 | 
			
		||||
 | 
			
		||||
        val milliseconds = parseDate(dateString).toEpochMilli()
 | 
			
		||||
        val correctMilliseconds = 1365342180000
 | 
			
		||||
 | 
			
		||||
        assert(milliseconds == correctMilliseconds)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,18 +1,21 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    package="bou.amine.apps.readerforselfossv2.android">
 | 
			
		||||
    xmlns:tools="http://schemas.android.com/tools">
 | 
			
		||||
 | 
			
		||||
    <uses-permission android:name="android.permission.INTERNET" />
 | 
			
		||||
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
 | 
			
		||||
 | 
			
		||||
    <application
 | 
			
		||||
        android:allowBackup="false"
 | 
			
		||||
        android:fullBackupContent="false"
 | 
			
		||||
        tools:replace="android:allowBackup"
 | 
			
		||||
        android:name=".MyApp"
 | 
			
		||||
        android:allowBackup="true"
 | 
			
		||||
        android:icon="@mipmap/ic_launcher"
 | 
			
		||||
        android:label="@string/app_name"
 | 
			
		||||
        android:supportsRtl="true"
 | 
			
		||||
        android:networkSecurityConfig="@xml/network_security_config"
 | 
			
		||||
        android:theme="@style/NoBar">
 | 
			
		||||
        android:theme="@style/NoBar"
 | 
			
		||||
        android:dataExtractionRules="@xml/data_extraction_rules">
 | 
			
		||||
        <activity
 | 
			
		||||
            android:name=".MainActivity"
 | 
			
		||||
            android:theme="@style/SplashTheme"
 | 
			
		||||
@@ -68,10 +71,6 @@
 | 
			
		||||
            android:name=".ImageActivity">
 | 
			
		||||
        </activity>
 | 
			
		||||
 | 
			
		||||
        <meta-data
 | 
			
		||||
            android:name="bou.amine.apps.readerforselfossv2.android.utils.glide.SelfSignedGlideModule"
 | 
			
		||||
            android:value="GlideModule" />
 | 
			
		||||
 | 
			
		||||
        <meta-data android:name="android.webkit.WebView.MetricsOptOut"
 | 
			
		||||
            android:value="true" />
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,47 +1,38 @@
 | 
			
		||||
package bou.amine.apps.readerforselfossv2.android
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import androidx.preference.PreferenceManager
 | 
			
		||||
import androidx.constraintlayout.widget.ConstraintLayout
 | 
			
		||||
import androidx.appcompat.app.AppCompatActivity
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.widget.AdapterView
 | 
			
		||||
import android.widget.ArrayAdapter
 | 
			
		||||
import android.widget.EditText
 | 
			
		||||
import android.widget.ProgressBar
 | 
			
		||||
import android.widget.Spinner
 | 
			
		||||
import android.widget.TextView
 | 
			
		||||
import android.widget.Toast
 | 
			
		||||
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.Config
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.utils.isBaseUrlValid
 | 
			
		||||
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 retrofit2.Call
 | 
			
		||||
import retrofit2.Callback
 | 
			
		||||
import retrofit2.Response
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.databinding.ActivityAddSourceBinding
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.service.AndroidApiDetailsService
 | 
			
		||||
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.rest.SelfossApi
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.rest.SelfossModel
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.service.ApiDetailsService
 | 
			
		||||
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() {
 | 
			
		||||
class AddSourceActivity : AppCompatActivity(), DIAware {
 | 
			
		||||
 | 
			
		||||
    private lateinit var apiDetailsService: ApiDetailsService
 | 
			
		||||
    private var mSpoutsValue: String? = null
 | 
			
		||||
    private lateinit var api: SelfossApi
 | 
			
		||||
 | 
			
		||||
    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)
 | 
			
		||||
 | 
			
		||||
@@ -76,45 +67,32 @@ class AddSourceActivity : AppCompatActivity() {
 | 
			
		||||
        supportActionBar?.setDisplayHomeAsUpEnabled(true)
 | 
			
		||||
        supportActionBar?.setDisplayShowHomeEnabled(true)
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            val prefs = PreferenceManager.getDefaultSharedPreferences(this)
 | 
			
		||||
            val settings =
 | 
			
		||||
                getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
 | 
			
		||||
            apiDetailsService = AndroidApiDetailsService(this@AddSourceActivity)
 | 
			
		||||
            api = SelfossApi(
 | 
			
		||||
//                this,
 | 
			
		||||
//                this@AddSourceActivity,
 | 
			
		||||
//                settings.getBoolean("isSelfSignedCert", false),
 | 
			
		||||
//                prefs.getString("api_timeout", "-1")!!.toLong()
 | 
			
		||||
                apiDetailsService
 | 
			
		||||
            )
 | 
			
		||||
        } catch (e: IllegalArgumentException) {
 | 
			
		||||
            mustLoginToAddSource()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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(), api)
 | 
			
		||||
            handleSaveSource(
 | 
			
		||||
                binding.tags,
 | 
			
		||||
                binding.nameInput.text.toString(),
 | 
			
		||||
                binding.sourceUri.text.toString()
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onResume() {
 | 
			
		||||
        super.onResume()
 | 
			
		||||
        val config = Config(this)
 | 
			
		||||
 | 
			
		||||
        if (config.baseUrl.isEmpty() || !config.baseUrl.isBaseUrlValid(this@AddSourceActivity)) {
 | 
			
		||||
        val baseUrl = appSettingsService.getBaseUrl()
 | 
			
		||||
        if (baseUrl.isEmpty() || baseUrl.isBaseUrlInvalid()) {
 | 
			
		||||
            mustLoginToAddSource()
 | 
			
		||||
        } else {
 | 
			
		||||
            handleSpoutsSpinner(binding.spoutsSpinner, api, binding.progress, binding.formContainer)
 | 
			
		||||
            handleSpoutsSpinner(binding.spoutsSpinner, binding.progress, binding.formContainer)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun handleSpoutsSpinner(
 | 
			
		||||
        spoutsSpinner: Spinner,
 | 
			
		||||
        api: SelfossApi?,
 | 
			
		||||
        mProgress: ProgressBar,
 | 
			
		||||
        formContainer: ConstraintLayout
 | 
			
		||||
    ) {
 | 
			
		||||
@@ -133,33 +111,40 @@ class AddSourceActivity : AppCompatActivity() {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        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 {
 | 
			
		||||
            var items = api!!.spouts()
 | 
			
		||||
            if (items != null) {
 | 
			
		||||
            try {
 | 
			
		||||
                val items = repository.getSpouts()
 | 
			
		||||
                if (items != null) {
 | 
			
		||||
                    val itemsStrings = items.map { it.value.name }
 | 
			
		||||
                    for ((key, value) in items) {
 | 
			
		||||
                        spoutsKV[value.name] = key
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                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()
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                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 {
 | 
			
		||||
                Toast.makeText(
 | 
			
		||||
                    this@AddSourceActivity,
 | 
			
		||||
                    R.string.cant_get_spouts,
 | 
			
		||||
                    Toast.LENGTH_SHORT
 | 
			
		||||
                ).show()
 | 
			
		||||
                mProgress.visibility = View.GONE
 | 
			
		||||
            } catch (e: NetworkUnavailableException) {
 | 
			
		||||
                handleSpoutFailure(networkIssue = true)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -182,7 +167,7 @@ class AddSourceActivity : AppCompatActivity() {
 | 
			
		||||
        finish()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun handleSaveSource(tags: EditText, title: String, url: String, api: SelfossApi) {
 | 
			
		||||
    private fun handleSaveSource(tags: EditText, title: String, url: String) {
 | 
			
		||||
 | 
			
		||||
        val sourceDetailsUnavailable =
 | 
			
		||||
            title.isEmpty() || url.isEmpty() || mSpoutsValue == null || mSpoutsValue!!.isEmpty()
 | 
			
		||||
@@ -193,15 +178,14 @@ class AddSourceActivity : AppCompatActivity() {
 | 
			
		||||
            }
 | 
			
		||||
            else -> {
 | 
			
		||||
                CoroutineScope(Dispatchers.Main).launch {
 | 
			
		||||
                    val response: SelfossModel.SuccessResponse? = api.createSourceForVersion(
 | 
			
		||||
                            title,
 | 
			
		||||
                            url,
 | 
			
		||||
                            mSpoutsValue!!,
 | 
			
		||||
                            tags.text.toString(),
 | 
			
		||||
                            "",
 | 
			
		||||
                            PreferenceManager.getDefaultSharedPreferences(this@AddSourceActivity).getInt("apiVersionMajor", 0)
 | 
			
		||||
                        )
 | 
			
		||||
                    if (response != null) {
 | 
			
		||||
                    val successfullyAddedSource = repository.createSource(
 | 
			
		||||
                        title,
 | 
			
		||||
                        url,
 | 
			
		||||
                        mSpoutsValue!!,
 | 
			
		||||
                        tags.text.toString(),
 | 
			
		||||
                        "",
 | 
			
		||||
                    )
 | 
			
		||||
                    if (successfullyAddedSource) {
 | 
			
		||||
                        finish()
 | 
			
		||||
                    } else {
 | 
			
		||||
                        Toast.makeText(
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -3,48 +3,40 @@ package bou.amine.apps.readerforselfossv2.android
 | 
			
		||||
import android.animation.Animator
 | 
			
		||||
import android.animation.AnimatorListenerAdapter
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.content.SharedPreferences
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import androidx.appcompat.app.AlertDialog
 | 
			
		||||
import androidx.appcompat.app.AppCompatActivity
 | 
			
		||||
import android.text.TextUtils
 | 
			
		||||
import android.util.Log
 | 
			
		||||
import android.view.Menu
 | 
			
		||||
import android.view.MenuItem
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.view.inputmethod.EditorInfo
 | 
			
		||||
import android.widget.TextView
 | 
			
		||||
import androidx.preference.PreferenceManager
 | 
			
		||||
import androidx.work.Logger
 | 
			
		||||
import androidx.appcompat.app.AlertDialog
 | 
			
		||||
import androidx.appcompat.app.AppCompatActivity
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.databinding.ActivityLoginBinding
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.service.AndroidApiDetailsService
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.themes.AppColors
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.utils.Config
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.utils.isBaseUrlValid
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.utils.network.isNetworkAvailable
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.rest.SelfossApi
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.service.ApiDetailsService
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.utils.isBaseUrlInvalid
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.repository.Repository
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
 | 
			
		||||
import com.mikepenz.aboutlibraries.LibsBuilder
 | 
			
		||||
import kotlinx.coroutines.CoroutineScope
 | 
			
		||||
import kotlinx.coroutines.Dispatchers
 | 
			
		||||
import kotlinx.coroutines.launch
 | 
			
		||||
import retrofit2.Call
 | 
			
		||||
import retrofit2.Callback
 | 
			
		||||
import retrofit2.Response
 | 
			
		||||
import org.kodein.di.DIAware
 | 
			
		||||
import org.kodein.di.android.closestDI
 | 
			
		||||
import org.kodein.di.instance
 | 
			
		||||
 | 
			
		||||
class LoginActivity : AppCompatActivity() {
 | 
			
		||||
class LoginActivity : AppCompatActivity(), DIAware {
 | 
			
		||||
 | 
			
		||||
    private var inValidCount: Int = 0
 | 
			
		||||
    private var isWithSelfSignedCert = false
 | 
			
		||||
    private var isWithLogin = false
 | 
			
		||||
    private var isWithHTTPLogin = false
 | 
			
		||||
 | 
			
		||||
    private lateinit var settings: SharedPreferences
 | 
			
		||||
    private lateinit var editor: SharedPreferences.Editor
 | 
			
		||||
    private lateinit var userIdentifier: String
 | 
			
		||||
    private lateinit var appColors: AppColors
 | 
			
		||||
    private lateinit var binding: ActivityLoginBinding
 | 
			
		||||
 | 
			
		||||
    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@LoginActivity)
 | 
			
		||||
 | 
			
		||||
@@ -58,12 +50,7 @@ class LoginActivity : AppCompatActivity() {
 | 
			
		||||
 | 
			
		||||
        handleBaseUrlFail()
 | 
			
		||||
 | 
			
		||||
        settings = PreferenceManager.getDefaultSharedPreferences(applicationContext)
 | 
			
		||||
        userIdentifier = settings.getString("unique_id", "")!!
 | 
			
		||||
 | 
			
		||||
        editor = settings.edit()
 | 
			
		||||
 | 
			
		||||
        if (settings.getString("url", "")!!.isNotEmpty()) {
 | 
			
		||||
        if (appSettingsService.getBaseUrl().isNotEmpty()) {
 | 
			
		||||
            goToMain()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -72,13 +59,6 @@ class LoginActivity : AppCompatActivity() {
 | 
			
		||||
 | 
			
		||||
    private fun handleActions() {
 | 
			
		||||
 | 
			
		||||
        binding.withSelfhostedCert.setOnCheckedChangeListener { _, b ->
 | 
			
		||||
            isWithSelfSignedCert = !isWithSelfSignedCert
 | 
			
		||||
            val visi: Int = if (b) View.VISIBLE else View.GONE
 | 
			
		||||
 | 
			
		||||
            binding.warningText.visibility = visi
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        binding.passwordView.setOnEditorActionListener(
 | 
			
		||||
            TextView.OnEditorActionListener { _, id, _ ->
 | 
			
		||||
                if (id == R.id.loginView || id == EditorInfo.IME_NULL) {
 | 
			
		||||
@@ -98,14 +78,6 @@ class LoginActivity : AppCompatActivity() {
 | 
			
		||||
            binding.loginView.visibility = visi
 | 
			
		||||
            binding.passwordView.visibility = visi
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        binding.withHttpLogin.setOnCheckedChangeListener { _, b ->
 | 
			
		||||
            isWithHTTPLogin = !isWithHTTPLogin
 | 
			
		||||
            val visi: Int = if (b) View.VISIBLE else View.GONE
 | 
			
		||||
 | 
			
		||||
            binding.httpLoginView.visibility = visi
 | 
			
		||||
            binding.httpPasswordView.visibility = visi
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun handleBaseUrlFail() {
 | 
			
		||||
@@ -128,18 +100,11 @@ class LoginActivity : AppCompatActivity() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun preferenceError(t: Throwable) {
 | 
			
		||||
        editor.remove("url")
 | 
			
		||||
        editor.remove("login")
 | 
			
		||||
        editor.remove("httpUserName")
 | 
			
		||||
        editor.remove("password")
 | 
			
		||||
        editor.remove("httpPassword")
 | 
			
		||||
        editor.apply()
 | 
			
		||||
        appSettingsService.resetLoginInformation()
 | 
			
		||||
 | 
			
		||||
        binding.urlView.error = getString(R.string.wrong_infos)
 | 
			
		||||
        binding.loginView.error = getString(R.string.wrong_infos)
 | 
			
		||||
        binding.passwordView.error = getString(R.string.wrong_infos)
 | 
			
		||||
        binding.httpLoginView.error = getString(R.string.wrong_infos)
 | 
			
		||||
        binding.httpPasswordView.error = getString(R.string.wrong_infos)
 | 
			
		||||
        showProgress(false)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun attemptLogin() {
 | 
			
		||||
@@ -147,21 +112,17 @@ class LoginActivity : AppCompatActivity() {
 | 
			
		||||
        // Reset errors.
 | 
			
		||||
        binding.urlView.error = null
 | 
			
		||||
        binding.loginView.error = null
 | 
			
		||||
        binding.httpLoginView.error = null
 | 
			
		||||
        binding.passwordView.error = null
 | 
			
		||||
        binding.httpPasswordView.error = null
 | 
			
		||||
 | 
			
		||||
        // Store values at the time of the login attempt.
 | 
			
		||||
        val url = binding.urlView.text.toString()
 | 
			
		||||
        val login = binding.loginView.text.toString()
 | 
			
		||||
        val httpLogin = binding.httpLoginView.text.toString()
 | 
			
		||||
        val password = binding.passwordView.text.toString()
 | 
			
		||||
        val httpPassword = binding.httpPasswordView.text.toString()
 | 
			
		||||
        val url = binding.urlView.text.toString().trim()
 | 
			
		||||
        val login = binding.loginView.text.toString().trim()
 | 
			
		||||
        val password = binding.passwordView.text.toString().trim()
 | 
			
		||||
 | 
			
		||||
        var cancel = false
 | 
			
		||||
        var focusView: View? = null
 | 
			
		||||
 | 
			
		||||
        if (!url.isBaseUrlValid(this@LoginActivity)) {
 | 
			
		||||
        if (url.isBaseUrlInvalid()) {
 | 
			
		||||
            binding.urlView.error = getString(R.string.login_url_problem)
 | 
			
		||||
            focusView = binding.urlView
 | 
			
		||||
            cancel = true
 | 
			
		||||
@@ -193,58 +154,25 @@ class LoginActivity : AppCompatActivity() {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (isWithHTTPLogin) {
 | 
			
		||||
            if (TextUtils.isEmpty(httpPassword)) {
 | 
			
		||||
                binding.httpPasswordView.error = getString(R.string.error_invalid_password)
 | 
			
		||||
                focusView = binding.httpPasswordView
 | 
			
		||||
                cancel = true
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (TextUtils.isEmpty(httpLogin)) {
 | 
			
		||||
                binding.httpLoginView.error = getString(R.string.error_field_required)
 | 
			
		||||
                focusView = binding.httpLoginView
 | 
			
		||||
                cancel = true
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (cancel) {
 | 
			
		||||
            focusView?.requestFocus()
 | 
			
		||||
        } else {
 | 
			
		||||
            showProgress(true)
 | 
			
		||||
 | 
			
		||||
            editor.putString("url", url)
 | 
			
		||||
            editor.putString("login", login)
 | 
			
		||||
            editor.putString("httpUserName", httpLogin)
 | 
			
		||||
            editor.putString("password", password)
 | 
			
		||||
            editor.putString("httpPassword", httpPassword)
 | 
			
		||||
            editor.putBoolean("isSelfSignedCert", isWithSelfSignedCert)
 | 
			
		||||
            editor.apply()
 | 
			
		||||
            repository.refreshLoginInformation(url, login, password)
 | 
			
		||||
 | 
			
		||||
            val apiDetailsService = AndroidApiDetailsService(this@LoginActivity)
 | 
			
		||||
            val api = SelfossApi(
 | 
			
		||||
//                this,
 | 
			
		||||
//                this@LoginActivity,
 | 
			
		||||
//                isWithSelfSignedCert,
 | 
			
		||||
//                -1L
 | 
			
		||||
                apiDetailsService
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            if (this@LoginActivity.isNetworkAvailable(this@LoginActivity.findViewById(R.id.loginForm))) {
 | 
			
		||||
                CoroutineScope(Dispatchers.IO).launch {
 | 
			
		||||
                    try {
 | 
			
		||||
                        val result = api.login()
 | 
			
		||||
                        if (result != null && result.isSuccess) {
 | 
			
		||||
                            goToMain()
 | 
			
		||||
                        } else {
 | 
			
		||||
                            preferenceError(Exception("Not success"))
 | 
			
		||||
                        }
 | 
			
		||||
                    } catch (cause: Throwable) {
 | 
			
		||||
                        Log.e("1", "LOL")
 | 
			
		||||
            CoroutineScope(Dispatchers.IO).launch {
 | 
			
		||||
                val result = repository.login()
 | 
			
		||||
                if (result) {
 | 
			
		||||
                    repository.updateApiVersion()
 | 
			
		||||
                    goToMain()
 | 
			
		||||
                } else {
 | 
			
		||||
                    CoroutineScope(Dispatchers.Main).launch {
 | 
			
		||||
                        preferenceError(Exception("Not success"))
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                showProgress(false)
 | 
			
		||||
            }
 | 
			
		||||
            showProgress(false)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -6,31 +6,51 @@ import android.content.Context
 | 
			
		||||
import android.graphics.drawable.Drawable
 | 
			
		||||
import android.net.Uri
 | 
			
		||||
import android.os.Build
 | 
			
		||||
import androidx.preference.PreferenceManager
 | 
			
		||||
import android.widget.ImageView
 | 
			
		||||
import android.widget.Toast
 | 
			
		||||
import androidx.lifecycle.DefaultLifecycleObserver
 | 
			
		||||
import androidx.lifecycle.LifecycleOwner
 | 
			
		||||
import androidx.lifecycle.ProcessLifecycleOwner
 | 
			
		||||
import androidx.multidex.MultiDexApplication
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.utils.Config
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.utils.glide.loadMaybeBasicAuth
 | 
			
		||||
import androidx.preference.PreferenceManager
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.DI.networkModule
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.viewmodel.AppViewModel
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.dao.DriverFactory
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.dao.ReaderForSelfossDB
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.repository.Repository
 | 
			
		||||
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.mikepenz.materialdrawer.util.AbstractDrawerImageLoader
 | 
			
		||||
import com.mikepenz.materialdrawer.util.DrawerImageLoader
 | 
			
		||||
import java.util.UUID.randomUUID
 | 
			
		||||
import io.github.aakira.napier.DebugAntilog
 | 
			
		||||
import io.github.aakira.napier.Napier
 | 
			
		||||
import kotlinx.coroutines.CoroutineScope
 | 
			
		||||
import kotlinx.coroutines.Dispatchers
 | 
			
		||||
import kotlinx.coroutines.launch
 | 
			
		||||
import org.kodein.di.*
 | 
			
		||||
 | 
			
		||||
class MyApp : MultiDexApplication() {
 | 
			
		||||
    private lateinit var config: Config
 | 
			
		||||
class MyApp : MultiDexApplication(), DIAware {
 | 
			
		||||
 | 
			
		||||
    override val di by DI.lazy {
 | 
			
		||||
        import(networkModule)
 | 
			
		||||
        bind<DriverFactory>() with singleton { DriverFactory(applicationContext) }
 | 
			
		||||
        bind<ReaderForSelfossDB>() with singleton { ReaderForSelfossDB(driverFactory.createDriver()) }
 | 
			
		||||
        bind<Repository>() with singleton { Repository(instance(), instance(), connectivityStatus, instance()) }
 | 
			
		||||
        bind<ConnectivityStatus>() with singleton { ConnectivityStatus(applicationContext) }
 | 
			
		||||
        bind<AppViewModel>() with singleton { AppViewModel(repository = instance()) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private val repository: Repository by instance()
 | 
			
		||||
    private val viewModel: AppViewModel by instance()
 | 
			
		||||
    private val connectivityStatus: ConnectivityStatus by instance()
 | 
			
		||||
    private val driverFactory: DriverFactory by instance()
 | 
			
		||||
 | 
			
		||||
    override fun onCreate() {
 | 
			
		||||
        super.onCreate()
 | 
			
		||||
        config = Config(baseContext)
 | 
			
		||||
 | 
			
		||||
        val prefs = getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
 | 
			
		||||
        if (prefs.getString("unique_id", "")!!.isEmpty()) {
 | 
			
		||||
            val editor = prefs.edit()
 | 
			
		||||
            editor.putString("unique_id", randomUUID().toString())
 | 
			
		||||
            editor.apply()
 | 
			
		||||
        }
 | 
			
		||||
        Napier.base(DebugAntilog())
 | 
			
		||||
 | 
			
		||||
        initDrawerImageLoader()
 | 
			
		||||
 | 
			
		||||
@@ -39,6 +59,26 @@ class MyApp : MultiDexApplication() {
 | 
			
		||||
        tryToHandleBug()
 | 
			
		||||
 | 
			
		||||
        handleNotificationChannels()
 | 
			
		||||
 | 
			
		||||
        ProcessLifecycleOwner.get().lifecycle.addObserver(AppLifeCycleObserver(connectivityStatus, repository))
 | 
			
		||||
 | 
			
		||||
        CoroutineScope(Dispatchers.Main).launch {
 | 
			
		||||
            viewModel.networkAvailableProvider.collect { networkAvailable ->
 | 
			
		||||
                val toastMessage = if (networkAvailable) {
 | 
			
		||||
                    repository.handleDBActions()
 | 
			
		||||
                    R.string.network_connectivity_retrieved
 | 
			
		||||
                } else {
 | 
			
		||||
                    R.string.network_connectivity_lost
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                Toast.makeText(
 | 
			
		||||
                    applicationContext,
 | 
			
		||||
                    toastMessage,
 | 
			
		||||
                    Toast.LENGTH_SHORT
 | 
			
		||||
                ).show()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun handleNotificationChannels() {
 | 
			
		||||
@@ -47,11 +87,11 @@ class MyApp : MultiDexApplication() {
 | 
			
		||||
 | 
			
		||||
            val name = getString(R.string.notification_channel_sync)
 | 
			
		||||
            val importance = NotificationManager.IMPORTANCE_LOW
 | 
			
		||||
            val mChannel = NotificationChannel(Config.syncChannelId, name, importance)
 | 
			
		||||
            val mChannel = NotificationChannel(AppSettingsService.syncChannelId, name, importance)
 | 
			
		||||
 | 
			
		||||
            val newItemsChannelname = getString(R.string.new_items_channel_sync)
 | 
			
		||||
            val newItemsChannelimportance = NotificationManager.IMPORTANCE_DEFAULT
 | 
			
		||||
            val newItemsChannelmChannel = NotificationChannel(Config.newItemsChannelId, newItemsChannelname, newItemsChannelimportance)
 | 
			
		||||
            val newItemsChannelmChannel = NotificationChannel(AppSettingsService.newItemsChannelId, newItemsChannelname, newItemsChannelimportance)
 | 
			
		||||
 | 
			
		||||
            notificationManager.createNotificationChannel(mChannel)
 | 
			
		||||
            notificationManager.createNotificationChannel(newItemsChannelmChannel)
 | 
			
		||||
@@ -62,7 +102,7 @@ class MyApp : MultiDexApplication() {
 | 
			
		||||
        DrawerImageLoader.init(object : AbstractDrawerImageLoader() {
 | 
			
		||||
            override fun set(imageView: ImageView, uri: Uri, placeholder: Drawable, tag: String?) {
 | 
			
		||||
                Glide.with(imageView.context)
 | 
			
		||||
                    .loadMaybeBasicAuth(config, uri.toString())
 | 
			
		||||
                    .load(uri.toString())
 | 
			
		||||
                    .apply(RequestOptions.fitCenterTransform().placeholder(placeholder))
 | 
			
		||||
                    .into(imageView)
 | 
			
		||||
            }
 | 
			
		||||
@@ -98,4 +138,19 @@ class MyApp : MultiDexApplication() {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    class AppLifeCycleObserver(val connectivityStatus: ConnectivityStatus, val repository: Repository) : DefaultLifecycleObserver {
 | 
			
		||||
 | 
			
		||||
        override fun onResume(owner: LifecycleOwner) {
 | 
			
		||||
            super.onResume(owner)
 | 
			
		||||
            repository.connectionMonitored = true
 | 
			
		||||
            connectivityStatus.start()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        override fun onPause(owner: LifecycleOwner) {
 | 
			
		||||
            repository.connectionMonitored = false
 | 
			
		||||
            connectivityStatus.stop()
 | 
			
		||||
            super.onPause(owner)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,7 +1,5 @@
 | 
			
		||||
package bou.amine.apps.readerforselfossv2.android
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.content.SharedPreferences
 | 
			
		||||
import android.graphics.Color
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.view.KeyEvent
 | 
			
		||||
@@ -10,47 +8,35 @@ import android.view.MenuItem
 | 
			
		||||
import androidx.appcompat.app.AppCompatActivity
 | 
			
		||||
import androidx.fragment.app.Fragment
 | 
			
		||||
import androidx.fragment.app.FragmentActivity
 | 
			
		||||
import androidx.preference.PreferenceManager
 | 
			
		||||
import androidx.room.Room
 | 
			
		||||
import androidx.viewpager2.adapter.FragmentStateAdapter
 | 
			
		||||
import androidx.viewpager2.widget.ViewPager2
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.databinding.ActivityReaderBinding
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.fragments.ArticleFragment
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.database.AppDatabase
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.migrations.MIGRATION_1_2
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.migrations.MIGRATION_2_3
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.migrations.MIGRATION_3_4
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.service.AndroidApiDetailsService
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.themes.AppColors
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.themes.Toppings
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.utils.Config
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.utils.toggleStar
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.rest.SelfossApi
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.rest.SelfossModel
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.service.ApiDetailsService
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.model.SelfossModel
 | 
			
		||||
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 ReaderActivity : AppCompatActivity() {
 | 
			
		||||
class ReaderActivity : AppCompatActivity(), DIAware {
 | 
			
		||||
 | 
			
		||||
    private var markOnScroll: Boolean = false
 | 
			
		||||
    private var currentItem: Int = 0
 | 
			
		||||
    private lateinit var userIdentifier: String
 | 
			
		||||
    private lateinit var appColors: AppColors
 | 
			
		||||
 | 
			
		||||
    private lateinit var api: SelfossApi
 | 
			
		||||
 | 
			
		||||
    private lateinit var toolbarMenu: Menu
 | 
			
		||||
 | 
			
		||||
    private lateinit var db: AppDatabase
 | 
			
		||||
    private lateinit var prefs: SharedPreferences
 | 
			
		||||
    private lateinit var binding: ActivityReaderBinding
 | 
			
		||||
 | 
			
		||||
    private var activeAlignment: Int = 1
 | 
			
		||||
    private val JUSTIFY = 1
 | 
			
		||||
    private val ALIGN_LEFT = 2
 | 
			
		||||
    override val di by closestDI()
 | 
			
		||||
    private val repository: Repository by instance()
 | 
			
		||||
    private val appSettingsService: AppSettingsService by instance()
 | 
			
		||||
 | 
			
		||||
    private fun showMenuItem(willAddToFavorite: Boolean) {
 | 
			
		||||
        if (willAddToFavorite) {
 | 
			
		||||
@@ -68,8 +54,6 @@ class ReaderActivity : AppCompatActivity() {
 | 
			
		||||
        showMenuItem(false)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private lateinit var editor: SharedPreferences.Editor
 | 
			
		||||
 | 
			
		||||
    override fun onCreate(savedInstanceState: Bundle?) {
 | 
			
		||||
        super.onCreate(savedInstanceState)
 | 
			
		||||
        appColors = AppColors(this)
 | 
			
		||||
@@ -78,11 +62,6 @@ class ReaderActivity : AppCompatActivity() {
 | 
			
		||||
 | 
			
		||||
        setContentView(view)
 | 
			
		||||
 | 
			
		||||
        db = Room.databaseBuilder(
 | 
			
		||||
            applicationContext,
 | 
			
		||||
            AppDatabase::class.java, "selfoss-database"
 | 
			
		||||
        ).addMigrations(MIGRATION_1_2).addMigrations(MIGRATION_2_3).addMigrations(MIGRATION_3_4).build()
 | 
			
		||||
 | 
			
		||||
        val scoop = Scoop.getInstance()
 | 
			
		||||
        scoop.bind(this, Toppings.PRIMARY.value, binding.toolBar)
 | 
			
		||||
        scoop.bindStatusBar(this, Toppings.PRIMARY_DARK.value)
 | 
			
		||||
@@ -91,24 +70,6 @@ class ReaderActivity : AppCompatActivity() {
 | 
			
		||||
        supportActionBar?.setDisplayHomeAsUpEnabled(true)
 | 
			
		||||
        supportActionBar?.setDisplayShowHomeEnabled(true)
 | 
			
		||||
 | 
			
		||||
        val settings =
 | 
			
		||||
            getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
 | 
			
		||||
 | 
			
		||||
        prefs = PreferenceManager.getDefaultSharedPreferences(this)
 | 
			
		||||
        editor = prefs.edit()
 | 
			
		||||
 | 
			
		||||
        userIdentifier = prefs.getString("unique_id", "")!!
 | 
			
		||||
        markOnScroll = prefs.getBoolean("mark_on_scroll", false)
 | 
			
		||||
        activeAlignment = prefs.getInt("text_align", JUSTIFY)
 | 
			
		||||
 | 
			
		||||
        api = SelfossApi(
 | 
			
		||||
//            this,
 | 
			
		||||
//            this@ReaderActivity,
 | 
			
		||||
//            settings.getBoolean("isSelfSignedCert", false),
 | 
			
		||||
//            prefs.getString("api_timeout", "-1")!!.toLong()
 | 
			
		||||
            AndroidApiDetailsService(this@ReaderActivity)
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        if (allItems.isEmpty()) {
 | 
			
		||||
            finish()
 | 
			
		||||
        }
 | 
			
		||||
@@ -128,12 +89,11 @@ class ReaderActivity : AppCompatActivity() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun readItem(item: SelfossModel.Item) {
 | 
			
		||||
        if (markOnScroll) {
 | 
			
		||||
                CoroutineScope(Dispatchers.IO).launch {
 | 
			
		||||
                    api.markAsRead(item.id.toString())
 | 
			
		||||
                    // TODO: update item in DB
 | 
			
		||||
                }
 | 
			
		||||
        if (appSettingsService.isMarkOnScrollEnabled()) {
 | 
			
		||||
            CoroutineScope(Dispatchers.IO).launch {
 | 
			
		||||
                repository.markAsRead(item)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onSaveInstanceState(oldInstanceState: Bundle) {
 | 
			
		||||
@@ -146,19 +106,22 @@ class ReaderActivity : AppCompatActivity() {
 | 
			
		||||
 | 
			
		||||
        override fun getItemCount(): Int = allItems.size
 | 
			
		||||
 | 
			
		||||
        override fun createFragment(position: Int): Fragment = ArticleFragment.newInstance(allItems[position])
 | 
			
		||||
        override fun createFragment(position: Int): Fragment =
 | 
			
		||||
            ArticleFragment.newInstance(allItems[position])
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
 | 
			
		||||
        return when (keyCode) {
 | 
			
		||||
            KeyEvent.KEYCODE_VOLUME_DOWN -> {
 | 
			
		||||
                val currentFragment = supportFragmentManager.findFragmentByTag("f" + binding.pager.currentItem) as ArticleFragment
 | 
			
		||||
                val currentFragment =
 | 
			
		||||
                    supportFragmentManager.findFragmentByTag("f" + binding.pager.currentItem) as ArticleFragment
 | 
			
		||||
                currentFragment.scrollDown()
 | 
			
		||||
                true
 | 
			
		||||
            }
 | 
			
		||||
            KeyEvent.KEYCODE_VOLUME_UP -> {
 | 
			
		||||
                val currentFragment = supportFragmentManager.findFragmentByTag("f" + binding.pager.currentItem) as ArticleFragment
 | 
			
		||||
                val currentFragment =
 | 
			
		||||
                    supportFragmentManager.findFragmentByTag("f" + binding.pager.currentItem) as ArticleFragment
 | 
			
		||||
                currentFragment.scrollUp()
 | 
			
		||||
                true
 | 
			
		||||
            }
 | 
			
		||||
@@ -168,7 +131,8 @@ class ReaderActivity : AppCompatActivity() {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun alignmentMenu(showJustify: Boolean) {
 | 
			
		||||
    private fun alignmentMenu() {
 | 
			
		||||
        val showJustify = appSettingsService.getActiveAllignment() == AppSettingsService.ALIGN_LEFT
 | 
			
		||||
        toolbarMenu.findItem(R.id.align_left).isVisible = !showJustify
 | 
			
		||||
        toolbarMenu.findItem(R.id.align_justify).isVisible = showJustify
 | 
			
		||||
    }
 | 
			
		||||
@@ -183,26 +147,22 @@ class ReaderActivity : AppCompatActivity() {
 | 
			
		||||
        } else {
 | 
			
		||||
            canFavorite()
 | 
			
		||||
        }
 | 
			
		||||
        if (activeAlignment == JUSTIFY) {
 | 
			
		||||
            alignmentMenu(false)
 | 
			
		||||
        } else {
 | 
			
		||||
            alignmentMenu(true)
 | 
			
		||||
        }
 | 
			
		||||
        alignmentMenu()
 | 
			
		||||
 | 
			
		||||
        binding.pager.registerOnPageChangeCallback(
 | 
			
		||||
                object : ViewPager2.OnPageChangeCallback() {
 | 
			
		||||
            object : ViewPager2.OnPageChangeCallback() {
 | 
			
		||||
 | 
			
		||||
                    override fun onPageSelected(position: Int) {
 | 
			
		||||
                        super.onPageSelected(position)
 | 
			
		||||
                override fun onPageSelected(position: Int) {
 | 
			
		||||
                    super.onPageSelected(position)
 | 
			
		||||
 | 
			
		||||
                        if (allItems[position].starred) {
 | 
			
		||||
                            canRemoveFromFavorite()
 | 
			
		||||
                        } else {
 | 
			
		||||
                            canFavorite()
 | 
			
		||||
                        }
 | 
			
		||||
                        readItem(allItems[position])
 | 
			
		||||
                    if (allItems[position].starred) {
 | 
			
		||||
                        canRemoveFromFavorite()
 | 
			
		||||
                    } else {
 | 
			
		||||
                        canFavorite()
 | 
			
		||||
                    }
 | 
			
		||||
                    readItem(allItems[position])
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        return true
 | 
			
		||||
@@ -211,7 +171,7 @@ class ReaderActivity : AppCompatActivity() {
 | 
			
		||||
    override fun onOptionsItemSelected(item: MenuItem): Boolean {
 | 
			
		||||
        fun afterSave() {
 | 
			
		||||
            allItems[binding.pager.currentItem] =
 | 
			
		||||
                    allItems[binding.pager.currentItem].toggleStar()
 | 
			
		||||
                allItems[binding.pager.currentItem].toggleStar()
 | 
			
		||||
            canRemoveFromFavorite()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -228,34 +188,35 @@ class ReaderActivity : AppCompatActivity() {
 | 
			
		||||
            R.id.star -> {
 | 
			
		||||
                if (allItems[binding.pager.currentItem].starred) {
 | 
			
		||||
                    CoroutineScope(Dispatchers.IO).launch {
 | 
			
		||||
                        api.unstarr(allItems[binding.pager.currentItem].id.toString())
 | 
			
		||||
                        // TODO: update in DB
 | 
			
		||||
                        repository.unstarr(allItems[binding.pager.currentItem])
 | 
			
		||||
                        // TODO: Handle failure
 | 
			
		||||
                    }
 | 
			
		||||
                    afterUnsave()
 | 
			
		||||
                } else {
 | 
			
		||||
                    CoroutineScope(Dispatchers.IO).launch {
 | 
			
		||||
                        api.starr(allItems[binding.pager.currentItem].id.toString())
 | 
			
		||||
                        // TODO: update in DB
 | 
			
		||||
                        repository.starr(allItems[binding.pager.currentItem])
 | 
			
		||||
                        // TODO: Handle failure
 | 
			
		||||
                    }
 | 
			
		||||
                    afterSave()
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            R.id.align_left -> {
 | 
			
		||||
                editor.putInt("text_align", ALIGN_LEFT)
 | 
			
		||||
                editor.apply()
 | 
			
		||||
                alignmentMenu(true)
 | 
			
		||||
                switchAlignmentSetting(AppSettingsService.ALIGN_LEFT)
 | 
			
		||||
                refreshFragment()
 | 
			
		||||
            }
 | 
			
		||||
            R.id.align_justify -> {
 | 
			
		||||
                editor.putInt("text_align", JUSTIFY)
 | 
			
		||||
                editor.apply()
 | 
			
		||||
                alignmentMenu(false)
 | 
			
		||||
                switchAlignmentSetting(AppSettingsService.JUSTIFY)
 | 
			
		||||
                refreshFragment()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return super.onOptionsItemSelected(item)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun switchAlignmentSetting(allignment: Int) {
 | 
			
		||||
        appSettingsService.changeAllignment(allignment)
 | 
			
		||||
        alignmentMenu()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun refreshFragment() {
 | 
			
		||||
        finish()
 | 
			
		||||
        overridePendingTransition(0, 0)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,37 +1,33 @@
 | 
			
		||||
package bou.amine.apps.readerforselfossv2.android
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.content.res.ColorStateList
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import androidx.preference.PreferenceManager
 | 
			
		||||
import android.widget.Toast
 | 
			
		||||
import androidx.appcompat.app.AppCompatActivity
 | 
			
		||||
import androidx.recyclerview.widget.LinearLayoutManager
 | 
			
		||||
import android.widget.Toast
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.adapters.SourcesListAdapter
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.databinding.ActivitySourcesBinding
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.service.AndroidApiDetailsService
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.themes.AppColors
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.themes.Toppings
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.utils.Config
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.utils.network.isNetworkAvailable
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.rest.SelfossApi
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.rest.SelfossModel
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.service.ApiDetailsService
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.model.SelfossModel
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.repository.Repository
 | 
			
		||||
import com.ftinc.scoop.Scoop
 | 
			
		||||
import kotlinx.coroutines.CoroutineScope
 | 
			
		||||
import kotlinx.coroutines.Dispatchers
 | 
			
		||||
import kotlinx.coroutines.launch
 | 
			
		||||
import retrofit2.Call
 | 
			
		||||
import retrofit2.Callback
 | 
			
		||||
import retrofit2.Response
 | 
			
		||||
import java.util.ArrayList
 | 
			
		||||
import org.kodein.di.DIAware
 | 
			
		||||
import org.kodein.di.android.closestDI
 | 
			
		||||
import org.kodein.di.instance
 | 
			
		||||
 | 
			
		||||
class SourcesActivity : AppCompatActivity() {
 | 
			
		||||
class SourcesActivity : AppCompatActivity(), DIAware {
 | 
			
		||||
 | 
			
		||||
    private lateinit var appColors: AppColors
 | 
			
		||||
    private lateinit var binding: ActivitySourcesBinding
 | 
			
		||||
 | 
			
		||||
    override val di by closestDI()
 | 
			
		||||
    private val repository : Repository by instance()
 | 
			
		||||
 | 
			
		||||
    override fun onCreate(savedInstanceState: Bundle?) {
 | 
			
		||||
        appColors = AppColors(this@SourcesActivity)
 | 
			
		||||
        binding = ActivitySourcesBinding.inflate(layoutInflater)
 | 
			
		||||
@@ -62,47 +58,33 @@ class SourcesActivity : AppCompatActivity() {
 | 
			
		||||
        super.onResume()
 | 
			
		||||
        val mLayoutManager = LinearLayoutManager(this)
 | 
			
		||||
 | 
			
		||||
        val settings =
 | 
			
		||||
            getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
 | 
			
		||||
        val prefs = PreferenceManager.getDefaultSharedPreferences(this)
 | 
			
		||||
 | 
			
		||||
        val apiDetailsService = AndroidApiDetailsService(this@SourcesActivity)
 | 
			
		||||
        val api = SelfossApi(
 | 
			
		||||
//            this,
 | 
			
		||||
//            this@SourcesActivity,
 | 
			
		||||
//            settings.getBoolean("isSelfSignedCert", false),
 | 
			
		||||
//            prefs.getString("api_timeout", "-1")!!.toLong()
 | 
			
		||||
            apiDetailsService
 | 
			
		||||
        )
 | 
			
		||||
        var items: ArrayList<SelfossModel.Source>
 | 
			
		||||
 | 
			
		||||
        binding.recyclerView.setHasFixedSize(true)
 | 
			
		||||
        binding.recyclerView.layoutManager = mLayoutManager
 | 
			
		||||
 | 
			
		||||
        if (this@SourcesActivity.isNetworkAvailable(binding.recyclerView)) {
 | 
			
		||||
            CoroutineScope(Dispatchers.Main).launch {
 | 
			
		||||
                val response = api.sources()
 | 
			
		||||
                if (response != null) {
 | 
			
		||||
                    items = response
 | 
			
		||||
                    val mAdapter = SourcesListAdapter(this@SourcesActivity, items, api,
 | 
			
		||||
                        apiDetailsService
 | 
			
		||||
                    )
 | 
			
		||||
                    binding.recyclerView.adapter = mAdapter
 | 
			
		||||
                    mAdapter.notifyDataSetChanged()
 | 
			
		||||
                    if (items.isEmpty()) {
 | 
			
		||||
                        Toast.makeText(
 | 
			
		||||
                            this@SourcesActivity,
 | 
			
		||||
                            R.string.nothing_here,
 | 
			
		||||
                            Toast.LENGTH_SHORT
 | 
			
		||||
                        ).show()
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
        CoroutineScope(Dispatchers.Main).launch {
 | 
			
		||||
            val response = repository.getSources()
 | 
			
		||||
            if (response != null) {
 | 
			
		||||
                items = response
 | 
			
		||||
                val mAdapter = SourcesListAdapter(
 | 
			
		||||
                    this@SourcesActivity, items
 | 
			
		||||
                )
 | 
			
		||||
                binding.recyclerView.adapter = mAdapter
 | 
			
		||||
                mAdapter.notifyDataSetChanged()
 | 
			
		||||
                if (items.isEmpty()) {
 | 
			
		||||
                    Toast.makeText(
 | 
			
		||||
                        this@SourcesActivity,
 | 
			
		||||
                        R.string.cant_get_sources,
 | 
			
		||||
                        R.string.nothing_here,
 | 
			
		||||
                        Toast.LENGTH_SHORT
 | 
			
		||||
                    ).show()
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                Toast.makeText(
 | 
			
		||||
                    this@SourcesActivity,
 | 
			
		||||
                    R.string.cant_get_sources,
 | 
			
		||||
                    Toast.LENGTH_SHORT
 | 
			
		||||
                ).show()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -9,40 +9,33 @@ import android.widget.ImageView.ScaleType
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.R
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.databinding.CardItemBinding
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.model.*
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.database.AppDatabase
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.model.toTextDrawableString
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.themes.AppColors
 | 
			
		||||
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.circularBitmapDrawable
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.utils.network.isNetworkAvailable
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.rest.SelfossApi
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.rest.SelfossModel
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.service.ApiDetailsService
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.service.SearchService
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.utils.DateUtils
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.model.SelfossModel
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.repository.Repository
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.utils.getHtmlDecoded
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.utils.getIcon
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.utils.getThumbnail
 | 
			
		||||
import com.amulyakhare.textdrawable.TextDrawable
 | 
			
		||||
import com.amulyakhare.textdrawable.util.ColorGenerator
 | 
			
		||||
import com.bumptech.glide.Glide
 | 
			
		||||
import kotlinx.coroutines.CoroutineScope
 | 
			
		||||
import kotlinx.coroutines.Dispatchers
 | 
			
		||||
import kotlinx.coroutines.launch
 | 
			
		||||
import org.kodein.di.DI
 | 
			
		||||
import org.kodein.di.android.closestDI
 | 
			
		||||
import org.kodein.di.instance
 | 
			
		||||
 | 
			
		||||
class ItemCardAdapter(
 | 
			
		||||
    override val app: Activity,
 | 
			
		||||
    override var items: ArrayList<SelfossModel.Item>,
 | 
			
		||||
    override val api: SelfossApi,
 | 
			
		||||
    override val apiDetailsService: ApiDetailsService,
 | 
			
		||||
    override val db: AppDatabase,
 | 
			
		||||
    private val helper: CustomTabActivityHelper,
 | 
			
		||||
    private val internalBrowser: Boolean,
 | 
			
		||||
    private val articleViewer: Boolean,
 | 
			
		||||
    private val fullHeightCards: Boolean,
 | 
			
		||||
    override val appColors: AppColors,
 | 
			
		||||
    override val userIdentifier: String,
 | 
			
		||||
    override val config: Config,
 | 
			
		||||
    override val searchService: SearchService,
 | 
			
		||||
    override val updateItems: (ArrayList<SelfossModel.Item>) -> Unit
 | 
			
		||||
) : ItemsAdapter<ItemCardAdapter.ViewHolder>() {
 | 
			
		||||
    private val c: Context = app.baseContext
 | 
			
		||||
@@ -50,6 +43,10 @@ class ItemCardAdapter(
 | 
			
		||||
    private val imageMaxHeight: Int =
 | 
			
		||||
        c.resources.getDimension(R.dimen.card_image_max_height).toInt()
 | 
			
		||||
 | 
			
		||||
    override val di: DI by closestDI(app)
 | 
			
		||||
    override val repository : Repository by instance()
 | 
			
		||||
    override val appSettingsService : AppSettingsService by instance()
 | 
			
		||||
 | 
			
		||||
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
 | 
			
		||||
        val binding = CardItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
 | 
			
		||||
        return ViewHolder(binding)
 | 
			
		||||
@@ -60,39 +57,39 @@ class ItemCardAdapter(
 | 
			
		||||
            val itm = items[position]
 | 
			
		||||
 | 
			
		||||
            binding.favButton.isSelected = itm.starred
 | 
			
		||||
            binding.title.text = itm.getTitleDecoded()
 | 
			
		||||
            binding.title.text = itm.title.getHtmlDecoded()
 | 
			
		||||
 | 
			
		||||
            binding.title.setOnTouchListener(LinkOnTouchListener())
 | 
			
		||||
 | 
			
		||||
            binding.title.setLinkTextColor(appColors.colorAccent)
 | 
			
		||||
 | 
			
		||||
            binding.sourceTitleAndDate.text = itm.sourceAndDateText(DateUtils(apiDetailsService))
 | 
			
		||||
            binding.sourceTitleAndDate.text = itm.sourceAndDateText(repository.dateUtils)
 | 
			
		||||
 | 
			
		||||
            if (!fullHeightCards) {
 | 
			
		||||
            if (!appSettingsService.isFullHeightCardsEnabled()) {
 | 
			
		||||
                binding.itemImage.maxHeight = imageMaxHeight
 | 
			
		||||
                binding.itemImage.scaleType = ScaleType.CENTER_CROP
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (itm.getThumbnail(apiDetailsService.getBaseUrl()).isEmpty()) {
 | 
			
		||||
            if (itm.getThumbnail(repository.baseUrl).isEmpty()) {
 | 
			
		||||
                binding.itemImage.visibility = View.GONE
 | 
			
		||||
                Glide.with(c).clear(binding.itemImage)
 | 
			
		||||
                binding.itemImage.setImageDrawable(null)
 | 
			
		||||
            } else {
 | 
			
		||||
                binding.itemImage.visibility = View.VISIBLE
 | 
			
		||||
                c.bitmapCenterCrop(config, itm.getThumbnail(apiDetailsService.getBaseUrl()), binding.itemImage)
 | 
			
		||||
                c.bitmapCenterCrop(itm.getThumbnail(repository.baseUrl), binding.itemImage)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (itm.getIcon(apiDetailsService.getBaseUrl()).isEmpty()) {
 | 
			
		||||
                val color = generator.getColor(itm.getSourceTitle())
 | 
			
		||||
            if (itm.getIcon(repository.baseUrl).isEmpty()) {
 | 
			
		||||
                val color = generator.getColor(itm.title.getHtmlDecoded())
 | 
			
		||||
 | 
			
		||||
                val drawable =
 | 
			
		||||
                        TextDrawable
 | 
			
		||||
                                .builder()
 | 
			
		||||
                                .round()
 | 
			
		||||
                                .build(itm.getSourceTitle().toTextDrawableString(c), color)
 | 
			
		||||
                                .build(itm.title.getHtmlDecoded().toTextDrawableString(), color)
 | 
			
		||||
                binding.sourceImage.setImageDrawable(drawable)
 | 
			
		||||
            } else {
 | 
			
		||||
                c.circularBitmapDrawable(config, itm.getIcon(apiDetailsService.getBaseUrl()), binding.sourceImage)
 | 
			
		||||
                c.circularBitmapDrawable(itm.getIcon(repository.baseUrl), binding.sourceImage)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -111,28 +108,26 @@ class ItemCardAdapter(
 | 
			
		||||
 | 
			
		||||
            binding.favButton.setOnClickListener {
 | 
			
		||||
                val item = items[bindingAdapterPosition]
 | 
			
		||||
                if (c.isNetworkAvailable()) {
 | 
			
		||||
                    if (item.starred) {
 | 
			
		||||
                        CoroutineScope(Dispatchers.IO).launch {
 | 
			
		||||
                            api.unstarr(item.id.toString())
 | 
			
		||||
                            // TODO: save to db
 | 
			
		||||
                        }
 | 
			
		||||
                        item.starred = false
 | 
			
		||||
                        binding.favButton.isSelected = false
 | 
			
		||||
                    } else {
 | 
			
		||||
                        CoroutineScope(Dispatchers.IO).launch {
 | 
			
		||||
                            api.starr(item.id.toString())
 | 
			
		||||
                            // TODO: save to db
 | 
			
		||||
                        }
 | 
			
		||||
                        item.starred = true
 | 
			
		||||
                        binding.favButton.isSelected = true
 | 
			
		||||
                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.getTitleDecoded())
 | 
			
		||||
                    c.shareLink(item.getLinkDecoded(), item.title.getHtmlDecoded())
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                binding.browserBtn.setOnClickListener {
 | 
			
		||||
@@ -150,10 +145,9 @@ class ItemCardAdapter(
 | 
			
		||||
                    bindingAdapterPosition,
 | 
			
		||||
                    items[bindingAdapterPosition].getLinkDecoded(),
 | 
			
		||||
                    customTabsIntent,
 | 
			
		||||
                    internalBrowser,
 | 
			
		||||
                    articleViewer,
 | 
			
		||||
                    app,
 | 
			
		||||
                    searchService
 | 
			
		||||
                    appSettingsService.isInternalBrowserEnabled(),
 | 
			
		||||
                    appSettingsService.isArticleViewerEnabled(),
 | 
			
		||||
                    app
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -6,39 +6,40 @@ import android.view.LayoutInflater
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.databinding.ListItemBinding
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.model.*
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.database.AppDatabase
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.model.toTextDrawableString
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.themes.AppColors
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.utils.*
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.utils.LinkOnTouchListener
 | 
			
		||||
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.bitmapCenterCrop
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.utils.glide.circularBitmapDrawable
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.rest.SelfossApi
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.rest.SelfossModel
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.service.ApiDetailsService
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.service.SearchService
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.utils.DateUtils
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.utils.openItemUrl
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.model.SelfossModel
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.repository.Repository
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.utils.getHtmlDecoded
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.utils.getIcon
 | 
			
		||||
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.android.closestDI
 | 
			
		||||
import org.kodein.di.instance
 | 
			
		||||
 | 
			
		||||
class ItemListAdapter(
 | 
			
		||||
    override val app: Activity,
 | 
			
		||||
    override var items: ArrayList<SelfossModel.Item>,
 | 
			
		||||
    override val api: SelfossApi,
 | 
			
		||||
    override val apiDetailsService: ApiDetailsService,
 | 
			
		||||
    override val db: AppDatabase,
 | 
			
		||||
    private val helper: CustomTabActivityHelper,
 | 
			
		||||
    private val internalBrowser: Boolean,
 | 
			
		||||
    private val articleViewer: Boolean,
 | 
			
		||||
    override val userIdentifier: String,
 | 
			
		||||
    override val appColors: AppColors,
 | 
			
		||||
    override val config: Config,
 | 
			
		||||
    override val searchService: SearchService,
 | 
			
		||||
    override val updateItems: (ArrayList<SelfossModel.Item>) -> Unit
 | 
			
		||||
) : ItemsAdapter<ItemListAdapter.ViewHolder>() {
 | 
			
		||||
    private val generator: ColorGenerator = ColorGenerator.MATERIAL
 | 
			
		||||
    private val c: Context = app.baseContext
 | 
			
		||||
 | 
			
		||||
    override val di: DI by closestDI(app)
 | 
			
		||||
    override val repository : Repository by instance()
 | 
			
		||||
    override val appSettingsService : AppSettingsService by instance()
 | 
			
		||||
 | 
			
		||||
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
 | 
			
		||||
        val binding = ListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
 | 
			
		||||
        return ViewHolder(binding)
 | 
			
		||||
@@ -48,31 +49,31 @@ class ItemListAdapter(
 | 
			
		||||
        with(holder) {
 | 
			
		||||
            val itm = items[position]
 | 
			
		||||
 | 
			
		||||
            binding.title.text = itm.getTitleDecoded()
 | 
			
		||||
            binding.title.text = itm.title.getHtmlDecoded()
 | 
			
		||||
 | 
			
		||||
            binding.title.setOnTouchListener(LinkOnTouchListener())
 | 
			
		||||
 | 
			
		||||
            binding.title.setLinkTextColor(appColors.colorAccent)
 | 
			
		||||
 | 
			
		||||
            binding.sourceTitleAndDate.text = itm.sourceAndDateText(DateUtils(apiDetailsService))
 | 
			
		||||
            binding.sourceTitleAndDate.text = itm.sourceAndDateText(repository.dateUtils)
 | 
			
		||||
 | 
			
		||||
            if (itm.getThumbnail(apiDetailsService.getBaseUrl()).isEmpty()) {
 | 
			
		||||
            if (itm.getThumbnail(repository.baseUrl).isEmpty()) {
 | 
			
		||||
 | 
			
		||||
                if (itm.getIcon(apiDetailsService.getBaseUrl()).isEmpty()) {
 | 
			
		||||
                    val color = generator.getColor(itm.getSourceTitle())
 | 
			
		||||
                if (itm.getIcon(repository.baseUrl).isEmpty()) {
 | 
			
		||||
                    val color = generator.getColor(itm.title.getHtmlDecoded())
 | 
			
		||||
 | 
			
		||||
                    val drawable =
 | 
			
		||||
                            TextDrawable
 | 
			
		||||
                                    .builder()
 | 
			
		||||
                                    .round()
 | 
			
		||||
                                    .build(itm.getSourceTitle().toTextDrawableString(c), color)
 | 
			
		||||
                                    .build(itm.title.getHtmlDecoded().toTextDrawableString(), color)
 | 
			
		||||
 | 
			
		||||
                    binding.itemImage.setImageDrawable(drawable)
 | 
			
		||||
                } else {
 | 
			
		||||
                    c.circularBitmapDrawable(config, itm.getIcon(apiDetailsService.getBaseUrl()), binding.itemImage)
 | 
			
		||||
                    c.circularBitmapDrawable(itm.getIcon(repository.baseUrl), binding.itemImage)
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                c.bitmapCenterCrop(config, itm.getThumbnail(apiDetailsService.getBaseUrl()), binding.itemImage)
 | 
			
		||||
                c.bitmapCenterCrop(itm.getThumbnail(repository.baseUrl), binding.itemImage)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -95,10 +96,9 @@ class ItemListAdapter(
 | 
			
		||||
                    bindingAdapterPosition,
 | 
			
		||||
                    items[bindingAdapterPosition].getLinkDecoded(),
 | 
			
		||||
                    customTabsIntent,
 | 
			
		||||
                    internalBrowser,
 | 
			
		||||
                    articleViewer,
 | 
			
		||||
                    app,
 | 
			
		||||
                    searchService
 | 
			
		||||
                    appSettingsService.isInternalBrowserEnabled(),
 | 
			
		||||
                    appSettingsService.isArticleViewerEnabled(),
 | 
			
		||||
                    app
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -5,28 +5,23 @@ import android.graphics.Color
 | 
			
		||||
import android.widget.TextView
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.R
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.database.AppDatabase
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.themes.AppColors
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.utils.Config
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.rest.SelfossApi
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.rest.SelfossModel
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.service.ApiDetailsService
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.service.SearchService
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.model.SelfossModel
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.repository.Repository
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.utils.ItemType
 | 
			
		||||
import com.google.android.material.snackbar.Snackbar
 | 
			
		||||
import kotlinx.coroutines.CoroutineScope
 | 
			
		||||
import kotlinx.coroutines.Dispatchers
 | 
			
		||||
import kotlinx.coroutines.launch
 | 
			
		||||
import org.kodein.di.DIAware
 | 
			
		||||
 | 
			
		||||
abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapter<VH>() {
 | 
			
		||||
abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapter<VH>(), DIAware {
 | 
			
		||||
    abstract var items: ArrayList<SelfossModel.Item>
 | 
			
		||||
    abstract val api: SelfossApi
 | 
			
		||||
    abstract val apiDetailsService: ApiDetailsService
 | 
			
		||||
    abstract val db: AppDatabase
 | 
			
		||||
    abstract val userIdentifier: String
 | 
			
		||||
    abstract val repository: Repository
 | 
			
		||||
    abstract val appSettingsService: AppSettingsService
 | 
			
		||||
    abstract val app: Activity
 | 
			
		||||
    abstract val appColors: AppColors
 | 
			
		||||
    abstract val config: Config
 | 
			
		||||
    abstract val searchService: SearchService
 | 
			
		||||
    abstract val updateItems: (ArrayList<SelfossModel.Item>) -> Unit
 | 
			
		||||
 | 
			
		||||
    fun updateAllItems(items: ArrayList<SelfossModel.Item>) {
 | 
			
		||||
@@ -35,7 +30,7 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
 | 
			
		||||
        updateItems(this.items)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun unmarkSnackbar(i: SelfossModel.Item, position: Int) {
 | 
			
		||||
    private fun unmarkSnackbar(position: Int) {
 | 
			
		||||
        val s = Snackbar
 | 
			
		||||
            .make(
 | 
			
		||||
                app.findViewById(R.id.coordLayout),
 | 
			
		||||
@@ -82,28 +77,23 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
 | 
			
		||||
    private fun readItemAtIndex(position: Int, showSnackbar: Boolean = true) {
 | 
			
		||||
        val i = items[position]
 | 
			
		||||
        CoroutineScope(Dispatchers.IO).launch {
 | 
			
		||||
            api.markAsRead(i.id.toString())
 | 
			
		||||
            // TODO: update db
 | 
			
		||||
 | 
			
		||||
            repository.markAsRead(i)
 | 
			
		||||
        }
 | 
			
		||||
        if (repository.displayedItems == ItemType.UNREAD) {
 | 
			
		||||
            items.remove(i)
 | 
			
		||||
            notifyItemRemoved(position)
 | 
			
		||||
            updateItems(items)
 | 
			
		||||
        } else {
 | 
			
		||||
            notifyItemChanged(position)
 | 
			
		||||
        }
 | 
			
		||||
        // Todo:
 | 
			
		||||
//        if (SharedItems.displayedItems == "unread") {
 | 
			
		||||
//            items.remove(i)
 | 
			
		||||
//            notifyItemRemoved(position)
 | 
			
		||||
//            updateItems(items)
 | 
			
		||||
//        } else {
 | 
			
		||||
//            notifyItemChanged(position)
 | 
			
		||||
//        }
 | 
			
		||||
        if (showSnackbar) {
 | 
			
		||||
            unmarkSnackbar(i, position)
 | 
			
		||||
            unmarkSnackbar(position)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun unreadItemAtIndex(position: Int, showSnackbar: Boolean = true) {
 | 
			
		||||
        CoroutineScope(Dispatchers.IO).launch {
 | 
			
		||||
            api.unmarkAsRead(items[position].id.toString())
 | 
			
		||||
            // Todo: SharedItems.unreadItem(app, api, db, items[position])
 | 
			
		||||
            // TODO: update db
 | 
			
		||||
            repository.unmarkAsRead(items[position])
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        notifyItemChanged(position)
 | 
			
		||||
 
 | 
			
		||||
@@ -10,32 +10,33 @@ import androidx.constraintlayout.widget.ConstraintLayout
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.R
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.databinding.SourceListItemBinding
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.model.getIcon
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.model.getTitleDecoded
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.utils.Config
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.model.toTextDrawableString
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.utils.glide.circularBitmapDrawable
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.utils.network.isNetworkAvailable
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.utils.toTextDrawableString
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.rest.SelfossApi
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.rest.SelfossModel
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.service.ApiDetailsService
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.model.SelfossModel
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.repository.Repository
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.utils.getHtmlDecoded
 | 
			
		||||
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.Dispatchers
 | 
			
		||||
import kotlinx.coroutines.launch
 | 
			
		||||
import org.kodein.di.DI
 | 
			
		||||
import org.kodein.di.DIAware
 | 
			
		||||
import org.kodein.di.android.closestDI
 | 
			
		||||
import org.kodein.di.instance
 | 
			
		||||
 | 
			
		||||
class SourcesListAdapter(
 | 
			
		||||
    private val app: Activity,
 | 
			
		||||
    private val items: ArrayList<SelfossModel.Source>,
 | 
			
		||||
    private val api: SelfossApi,
 | 
			
		||||
    private val apiDetailsService: ApiDetailsService
 | 
			
		||||
) : RecyclerView.Adapter<SourcesListAdapter.ViewHolder>() {
 | 
			
		||||
    private val items: ArrayList<SelfossModel.Source>
 | 
			
		||||
) : RecyclerView.Adapter<SourcesListAdapter.ViewHolder>(), DIAware {
 | 
			
		||||
    private val c: Context = app.baseContext
 | 
			
		||||
    private val generator: ColorGenerator = ColorGenerator.MATERIAL
 | 
			
		||||
    private lateinit var config: Config
 | 
			
		||||
    private lateinit var binding: SourceListItemBinding
 | 
			
		||||
 | 
			
		||||
    override val di: DI by closestDI(app)
 | 
			
		||||
    private val repository : Repository by instance()
 | 
			
		||||
 | 
			
		||||
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
 | 
			
		||||
        binding = SourceListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
 | 
			
		||||
        return ViewHolder(binding.root)
 | 
			
		||||
@@ -43,22 +44,21 @@ class SourcesListAdapter(
 | 
			
		||||
 | 
			
		||||
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
 | 
			
		||||
        val itm = items[position]
 | 
			
		||||
        config = Config(c)
 | 
			
		||||
 | 
			
		||||
        if (itm.getIcon(apiDetailsService.getBaseUrl()).isEmpty()) {
 | 
			
		||||
            val color = generator.getColor(itm.getTitleDecoded())
 | 
			
		||||
        if (itm.getIcon(repository.baseUrl).isEmpty()) {
 | 
			
		||||
            val color = generator.getColor(itm.title.getHtmlDecoded())
 | 
			
		||||
 | 
			
		||||
            val drawable =
 | 
			
		||||
                TextDrawable
 | 
			
		||||
                    .builder()
 | 
			
		||||
                    .round()
 | 
			
		||||
                    .build(itm.getTitleDecoded().toTextDrawableString(c), color)
 | 
			
		||||
                    .build(itm.title.getHtmlDecoded().toTextDrawableString(), color)
 | 
			
		||||
            binding.itemImage.setImageDrawable(drawable)
 | 
			
		||||
        } else {
 | 
			
		||||
            c.circularBitmapDrawable(config, itm.getIcon(apiDetailsService.getBaseUrl()), binding.itemImage)
 | 
			
		||||
            c.circularBitmapDrawable(itm.getIcon(repository.baseUrl), binding.itemImage)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        binding.sourceTitle.text = itm.getTitleDecoded()
 | 
			
		||||
        binding.sourceTitle.text = itm.title.getHtmlDecoded()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun getItemCount(): Int = items.size
 | 
			
		||||
@@ -74,21 +74,19 @@ class SourcesListAdapter(
 | 
			
		||||
            val deleteBtn: Button = mView.findViewById(R.id.deleteBtn)
 | 
			
		||||
 | 
			
		||||
            deleteBtn.setOnClickListener {
 | 
			
		||||
                if (c.isNetworkAvailable(null)) {
 | 
			
		||||
                    val (id) = items[adapterPosition]
 | 
			
		||||
                    CoroutineScope(Dispatchers.IO).launch {
 | 
			
		||||
                        val action = api.deleteSource(id)
 | 
			
		||||
                        if (action != null && action.isSuccess) {
 | 
			
		||||
                            items.removeAt(adapterPosition)
 | 
			
		||||
                            notifyItemRemoved(adapterPosition)
 | 
			
		||||
                            notifyItemRangeChanged(adapterPosition, itemCount)
 | 
			
		||||
                        } else {
 | 
			
		||||
                            Toast.makeText(
 | 
			
		||||
                                app,
 | 
			
		||||
                                R.string.can_delete_source,
 | 
			
		||||
                                Toast.LENGTH_SHORT
 | 
			
		||||
                            ).show()
 | 
			
		||||
                        }
 | 
			
		||||
                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()
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,7 @@ class MercuryApi() {
 | 
			
		||||
        val retrofit =
 | 
			
		||||
            Retrofit
 | 
			
		||||
                .Builder()
 | 
			
		||||
                .baseUrl("https://www.amine-bou.fr")
 | 
			
		||||
                .baseUrl("https://www.amine-louveau.fr")
 | 
			
		||||
                .client(client)
 | 
			
		||||
                .addConverterFactory(GsonConverterFactory.create(gson))
 | 
			
		||||
                .build()
 | 
			
		||||
 
 | 
			
		||||
@@ -5,119 +5,56 @@ import android.app.PendingIntent
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.os.Build
 | 
			
		||||
import androidx.preference.PreferenceManager
 | 
			
		||||
import androidx.core.app.NotificationCompat
 | 
			
		||||
import androidx.core.app.NotificationCompat.PRIORITY_DEFAULT
 | 
			
		||||
import androidx.core.app.NotificationCompat.PRIORITY_LOW
 | 
			
		||||
import androidx.room.Room
 | 
			
		||||
import androidx.work.Worker
 | 
			
		||||
import androidx.work.WorkerParameters
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.MainActivity
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.MyApp
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.R
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.model.preloadImages
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.AndroidDeviceDatabase
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.AndroidDeviceDatabaseService
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.database.AppDatabase
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.entities.ActionEntity
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.migrations.MIGRATION_1_2
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.migrations.MIGRATION_2_3
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.migrations.MIGRATION_3_4
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.service.AndroidApiDetailsService
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.utils.Config
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.utils.network.isNetworkAvailable
 | 
			
		||||
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.rest.SelfossApi
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.rest.SelfossModel
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.service.SearchService
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.service.SelfossService
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.utils.DateUtils
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.utils.network.isNetworkAccessible
 | 
			
		||||
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.instance
 | 
			
		||||
import java.util.*
 | 
			
		||||
import kotlin.concurrent.schedule
 | 
			
		||||
import kotlin.concurrent.thread
 | 
			
		||||
 | 
			
		||||
class LoadingWorker(val context: Context, params: WorkerParameters) : Worker(context, params) {
 | 
			
		||||
    lateinit var db: AppDatabase
 | 
			
		||||
class LoadingWorker(val context: Context, params: WorkerParameters) : Worker(context, params), DIAware {
 | 
			
		||||
 | 
			
		||||
    override val di by lazy { (applicationContext as MyApp).di }
 | 
			
		||||
    private val repository : Repository by instance()
 | 
			
		||||
    private val appSettingsService : AppSettingsService by instance()
 | 
			
		||||
 | 
			
		||||
override fun doWork(): Result {
 | 
			
		||||
    val settings =
 | 
			
		||||
        this.context.getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
 | 
			
		||||
    val sharedPref = PreferenceManager.getDefaultSharedPreferences(this.context)
 | 
			
		||||
    val periodicRefresh = sharedPref.getBoolean("periodic_refresh", false)
 | 
			
		||||
    if (periodicRefresh) {
 | 
			
		||||
        val apiDetailsService = AndroidApiDetailsService(this.context)
 | 
			
		||||
        val api = SelfossApi(
 | 
			
		||||
//            this.context,
 | 
			
		||||
//            null,
 | 
			
		||||
//            settings.getBoolean("isSelfSignedCert", false),
 | 
			
		||||
//            sharedPref.getString("api_timeout", "-1")!!.toLong()
 | 
			
		||||
            apiDetailsService
 | 
			
		||||
        )
 | 
			
		||||
    if (appSettingsService.isPeriodicRefreshEnabled() && isNetworkAccessible(context)) {
 | 
			
		||||
 | 
			
		||||
        val dateUtils = DateUtils(apiDetailsService)
 | 
			
		||||
        val searchService = SearchService(dateUtils)
 | 
			
		||||
        val service = SelfossService(api, AndroidDeviceDatabaseService(AndroidDeviceDatabase(applicationContext), searchService), searchService)
 | 
			
		||||
        CoroutineScope(Dispatchers.IO).launch {
 | 
			
		||||
            val notificationManager =
 | 
			
		||||
                applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
 | 
			
		||||
 | 
			
		||||
        if (context.isNetworkAvailable()) {
 | 
			
		||||
            val notification =
 | 
			
		||||
                NotificationCompat.Builder(applicationContext, AppSettingsService.syncChannelId)
 | 
			
		||||
                    .setContentTitle(context.getString(R.string.loading_notification_title))
 | 
			
		||||
                    .setContentText(context.getString(R.string.loading_notification_text))
 | 
			
		||||
                    .setOngoing(true)
 | 
			
		||||
                    .setPriority(PRIORITY_LOW)
 | 
			
		||||
                    .setChannelId(AppSettingsService.syncChannelId)
 | 
			
		||||
                    .setSmallIcon(R.drawable.ic_stat_cloud_download_black_24dp)
 | 
			
		||||
 | 
			
		||||
            CoroutineScope(Dispatchers.IO).launch {
 | 
			
		||||
                val notificationManager =
 | 
			
		||||
                    applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
 | 
			
		||||
            notificationManager.notify(1, notification.build())
 | 
			
		||||
 | 
			
		||||
                val notification =
 | 
			
		||||
                    NotificationCompat.Builder(applicationContext, Config.syncChannelId)
 | 
			
		||||
                        .setContentTitle(context.getString(R.string.loading_notification_title))
 | 
			
		||||
                        .setContentText(context.getString(R.string.loading_notification_text))
 | 
			
		||||
                        .setOngoing(true)
 | 
			
		||||
                        .setPriority(PRIORITY_LOW)
 | 
			
		||||
                        .setChannelId(Config.syncChannelId)
 | 
			
		||||
                        .setSmallIcon(R.drawable.ic_stat_cloud_download_black_24dp)
 | 
			
		||||
            repository.handleDBActions()
 | 
			
		||||
 | 
			
		||||
                notificationManager.notify(1, notification.build())
 | 
			
		||||
 | 
			
		||||
                val notifyNewItems = sharedPref.getBoolean("notify_new_items", false)
 | 
			
		||||
 | 
			
		||||
                db = Room.databaseBuilder(
 | 
			
		||||
                    applicationContext,
 | 
			
		||||
                    AppDatabase::class.java, "selfoss-database"
 | 
			
		||||
                ).addMigrations(MIGRATION_1_2).addMigrations(MIGRATION_2_3)
 | 
			
		||||
                    .addMigrations(MIGRATION_3_4).build()
 | 
			
		||||
 | 
			
		||||
                val actions = db.actionsDao().actions()
 | 
			
		||||
 | 
			
		||||
                actions.forEach { action ->
 | 
			
		||||
                    when {
 | 
			
		||||
                        action.read -> doAndReportOnFail(
 | 
			
		||||
                            api.markAsRead(action.articleId),
 | 
			
		||||
                            action
 | 
			
		||||
                        )
 | 
			
		||||
                        action.unread -> doAndReportOnFail(
 | 
			
		||||
                            api.unmarkAsRead(action.articleId),
 | 
			
		||||
                            action
 | 
			
		||||
                        )
 | 
			
		||||
                        action.starred -> doAndReportOnFail(
 | 
			
		||||
                            api.starr(action.articleId),
 | 
			
		||||
                            action
 | 
			
		||||
                        )
 | 
			
		||||
                        action.unstarred -> doAndReportOnFail(
 | 
			
		||||
                            api.unstarr(action.articleId),
 | 
			
		||||
                            action
 | 
			
		||||
                        )
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (context.isNetworkAvailable()) {
 | 
			
		||||
                    launch {
 | 
			
		||||
                        try {
 | 
			
		||||
                            val newItems = service.allNewItems()
 | 
			
		||||
                            handleNewItemsNotification(newItems, notifyNewItems, notificationManager)
 | 
			
		||||
                            val readItems = service.allReadItems()
 | 
			
		||||
                            val starredItems = service.allStarredItems()
 | 
			
		||||
                            // TODO: save all to DB
 | 
			
		||||
                        } catch (e: Throwable) {}
 | 
			
		||||
                    }
 | 
			
		||||
            if (appSettingsService.isNotifyNewItemsEnabled()) {
 | 
			
		||||
                launch {
 | 
			
		||||
                    handleNewItemsNotification(repository.tryToCacheItemsAndGetNewOnes(), notificationManager)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -127,7 +64,6 @@ override fun doWork(): Result {
 | 
			
		||||
 | 
			
		||||
    private fun handleNewItemsNotification(
 | 
			
		||||
        newItems: List<SelfossModel.Item>?,
 | 
			
		||||
        notifyNewItems: Boolean,
 | 
			
		||||
        notificationManager: NotificationManager
 | 
			
		||||
    ) {
 | 
			
		||||
        CoroutineScope(Dispatchers.IO).launch {
 | 
			
		||||
@@ -135,7 +71,7 @@ override fun doWork(): Result {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                val newSize = apiItems.filter { it.unread }.size
 | 
			
		||||
                if (notifyNewItems && newSize > 0) {
 | 
			
		||||
                if (newSize > 0) {
 | 
			
		||||
 | 
			
		||||
                    val intent = Intent(context, MainActivity::class.java).apply {
 | 
			
		||||
                        flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
 | 
			
		||||
@@ -148,7 +84,7 @@ override fun doWork(): Result {
 | 
			
		||||
                    val pendingIntent: PendingIntent = PendingIntent.getActivity(context, 0, intent, pflags)
 | 
			
		||||
 | 
			
		||||
                    val newItemsNotification =
 | 
			
		||||
                        NotificationCompat.Builder(applicationContext, Config.newItemsChannelId)
 | 
			
		||||
                        NotificationCompat.Builder(applicationContext, AppSettingsService.newItemsChannelId)
 | 
			
		||||
                            .setContentTitle(context.getString(R.string.new_items_notification_title))
 | 
			
		||||
                            .setContentText(
 | 
			
		||||
                                context.getString(
 | 
			
		||||
@@ -157,7 +93,7 @@ override fun doWork(): Result {
 | 
			
		||||
                                )
 | 
			
		||||
                            )
 | 
			
		||||
                            .setPriority(PRIORITY_DEFAULT)
 | 
			
		||||
                            .setChannelId(Config.newItemsChannelId)
 | 
			
		||||
                            .setChannelId(AppSettingsService.newItemsChannelId)
 | 
			
		||||
                            .setContentIntent(pendingIntent)
 | 
			
		||||
                            .setAutoCancel(true)
 | 
			
		||||
                            .setSmallIcon(R.drawable.ic_tab_fiber_new_black_24dp)
 | 
			
		||||
@@ -172,12 +108,4 @@ override fun doWork(): Result {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun doAndReportOnFail(result: SelfossModel.SuccessResponse?, action: ActionEntity) {
 | 
			
		||||
        if (result != null && result.isSuccess) {
 | 
			
		||||
            thread {
 | 
			
		||||
                db.actionsDao().delete(action)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,8 +1,6 @@
 | 
			
		||||
package bou.amine.apps.readerforselfossv2.android.fragments
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.content.SharedPreferences
 | 
			
		||||
import android.content.res.ColorStateList
 | 
			
		||||
import android.content.res.TypedArray
 | 
			
		||||
import android.graphics.Bitmap
 | 
			
		||||
@@ -11,41 +9,37 @@ import android.graphics.drawable.ColorDrawable
 | 
			
		||||
import android.net.Uri
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.view.*
 | 
			
		||||
import android.webkit.*
 | 
			
		||||
import android.webkit.WebResourceResponse
 | 
			
		||||
import android.webkit.WebSettings
 | 
			
		||||
import android.webkit.WebView
 | 
			
		||||
import android.webkit.WebViewClient
 | 
			
		||||
import android.widget.Toast
 | 
			
		||||
import androidx.appcompat.app.AlertDialog
 | 
			
		||||
import androidx.browser.customtabs.CustomTabsIntent
 | 
			
		||||
import androidx.core.content.res.ResourcesCompat
 | 
			
		||||
import androidx.core.widget.NestedScrollView
 | 
			
		||||
import androidx.fragment.app.Fragment
 | 
			
		||||
import androidx.preference.PreferenceManager
 | 
			
		||||
import androidx.room.Room
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.ImageActivity
 | 
			
		||||
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.model.*
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.AndroidDeviceDatabase
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.AndroidDeviceDatabaseService
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.database.AppDatabase
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.entities.AndroidItemEntity
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.migrations.MIGRATION_1_2
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.migrations.MIGRATION_2_3
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.migrations.MIGRATION_3_4
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.service.AndroidApiDetailsService
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.model.ParecelableItem
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.model.toModel
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.model.toParcelable
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.themes.AppColors
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.utils.*
 | 
			
		||||
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.loadMaybeBasicAuth
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.utils.network.isNetworkAvailable
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.rest.SelfossApi
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.rest.SelfossModel
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.service.ApiDetailsService
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.service.SearchService
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.service.SelfossService
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.utils.DateUtils
 | 
			
		||||
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.model.SelfossModel
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.repository.Repository
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.utils.getHtmlDecoded
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.utils.getImages
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.utils.getThumbnail
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.utils.isEmptyOrNullOrNullString
 | 
			
		||||
import com.bumptech.glide.Glide
 | 
			
		||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
 | 
			
		||||
@@ -55,6 +49,10 @@ import com.google.android.material.floatingactionbutton.FloatingActionButton
 | 
			
		||||
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
 | 
			
		||||
import retrofit2.Call
 | 
			
		||||
import retrofit2.Callback
 | 
			
		||||
import retrofit2.Response
 | 
			
		||||
@@ -63,10 +61,7 @@ import java.net.URL
 | 
			
		||||
import java.util.*
 | 
			
		||||
import java.util.concurrent.ExecutionException
 | 
			
		||||
 | 
			
		||||
class ArticleFragment : Fragment() {
 | 
			
		||||
    private lateinit var dbService: AndroidDeviceDatabaseService
 | 
			
		||||
    private lateinit var apiDetailsService: ApiDetailsService
 | 
			
		||||
    private lateinit var service: SelfossService<AndroidItemEntity>
 | 
			
		||||
class ArticleFragment : Fragment(), DIAware {
 | 
			
		||||
    private var fontSize: Int = 16
 | 
			
		||||
    private lateinit var item: SelfossModel.Item
 | 
			
		||||
    private var mCustomTabActivityHelper: CustomTabActivityHelper? = null
 | 
			
		||||
@@ -76,16 +71,15 @@ class ArticleFragment : Fragment() {
 | 
			
		||||
    private lateinit var contentImage: String
 | 
			
		||||
    private lateinit var contentTitle: String
 | 
			
		||||
    private lateinit var allImages : ArrayList<String>
 | 
			
		||||
    private lateinit var editor: SharedPreferences.Editor
 | 
			
		||||
    private lateinit var fab: FloatingActionButton
 | 
			
		||||
    private lateinit var appColors: AppColors
 | 
			
		||||
    private lateinit var db: AppDatabase
 | 
			
		||||
    private lateinit var textAlignment: String
 | 
			
		||||
    private lateinit var config: Config
 | 
			
		||||
    private var _binding: FragmentArticleBinding? = null
 | 
			
		||||
    private val binding get() = _binding!!
 | 
			
		||||
 | 
			
		||||
    private lateinit var prefs: SharedPreferences
 | 
			
		||||
    override val di : DI by closestDI()
 | 
			
		||||
    private val repository: Repository by instance()
 | 
			
		||||
    private val appSettingsService: AppSettingsService by instance()
 | 
			
		||||
 | 
			
		||||
    private var typeface: Typeface? = null
 | 
			
		||||
    private var resId: Int = 0
 | 
			
		||||
@@ -101,24 +95,12 @@ class ArticleFragment : Fragment() {
 | 
			
		||||
 | 
			
		||||
    override fun onCreate(savedInstanceState: Bundle?) {
 | 
			
		||||
        appColors = AppColors(requireActivity())
 | 
			
		||||
        config = Config(requireActivity())
 | 
			
		||||
 | 
			
		||||
        super.onCreate(savedInstanceState)
 | 
			
		||||
 | 
			
		||||
        apiDetailsService = AndroidApiDetailsService(requireContext())
 | 
			
		||||
 | 
			
		||||
        dbService = AndroidDeviceDatabaseService(AndroidDeviceDatabase(requireContext()), SearchService(DateUtils(apiDetailsService)))
 | 
			
		||||
 | 
			
		||||
        service = SelfossService(SelfossApi(apiDetailsService), dbService, SearchService(DateUtils(apiDetailsService)))
 | 
			
		||||
 | 
			
		||||
        val pi: ParecelableItem = requireArguments().getParcelable(ARG_ITEMS)!!
 | 
			
		||||
 | 
			
		||||
        item = pi.toModel()
 | 
			
		||||
 | 
			
		||||
        db = Room.databaseBuilder(
 | 
			
		||||
            requireContext(),
 | 
			
		||||
            AppDatabase::class.java, "selfoss-database"
 | 
			
		||||
        ).addMigrations(MIGRATION_1_2).addMigrations(MIGRATION_2_3).addMigrations(MIGRATION_3_4).build()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onCreateView(
 | 
			
		||||
@@ -131,23 +113,20 @@ class ArticleFragment : Fragment() {
 | 
			
		||||
 | 
			
		||||
            url = item.getLinkDecoded()
 | 
			
		||||
            contentText = item.content
 | 
			
		||||
            contentTitle = item.getTitleDecoded()
 | 
			
		||||
            contentImage = item.getThumbnail(apiDetailsService.getBaseUrl())
 | 
			
		||||
            contentSource = item.sourceAndDateText(DateUtils(apiDetailsService))
 | 
			
		||||
            contentTitle = item.title.getHtmlDecoded()
 | 
			
		||||
            contentImage = item.getThumbnail(repository.baseUrl)
 | 
			
		||||
            contentSource = item.sourceAndDateText(repository.dateUtils)
 | 
			
		||||
            allImages = item.getImages()
 | 
			
		||||
 | 
			
		||||
            prefs = PreferenceManager.getDefaultSharedPreferences(activity)
 | 
			
		||||
            editor = prefs.edit()
 | 
			
		||||
            fontSize = prefs.getString("reader_font_size", "16")!!.toInt()
 | 
			
		||||
            staticBar = prefs.getBoolean("reader_static_bar", false)
 | 
			
		||||
            fontSize = appSettingsService.getFontSize()
 | 
			
		||||
            staticBar = appSettingsService.isStaticBarEnabled()
 | 
			
		||||
            font = appSettingsService.getFont()
 | 
			
		||||
 | 
			
		||||
            font = prefs.getString("reader_font", "")!!
 | 
			
		||||
            if (font.isNotEmpty()) {
 | 
			
		||||
                resId = requireContext().resources.getIdentifier(font, "font", requireContext().packageName)
 | 
			
		||||
                typeface = try {
 | 
			
		||||
                    ResourcesCompat.getFont(requireContext(), resId)!!
 | 
			
		||||
                } catch (e: java.lang.Exception) {
 | 
			
		||||
                    // ACRA.getErrorReporter().maybeHandleSilentException(Throwable("Font loading issue: ${e.message}"), requireContext())
 | 
			
		||||
                    // Just to be sure
 | 
			
		||||
                    null
 | 
			
		||||
                }
 | 
			
		||||
@@ -155,16 +134,6 @@ class ArticleFragment : Fragment() {
 | 
			
		||||
 | 
			
		||||
            refreshAlignment()
 | 
			
		||||
 | 
			
		||||
            val settings = requireActivity().getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
 | 
			
		||||
 | 
			
		||||
            val api = SelfossApi(
 | 
			
		||||
//                requireContext(),
 | 
			
		||||
//                requireActivity(),
 | 
			
		||||
//                settings.getBoolean("isSelfSignedCert", false),
 | 
			
		||||
//                prefs.getString("api_timeout", "-1")!!.toLong()
 | 
			
		||||
                apiDetailsService
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            fab = binding.fab
 | 
			
		||||
 | 
			
		||||
            fab.backgroundTintList = ColorStateList.valueOf(appColors.colorAccent)
 | 
			
		||||
@@ -191,8 +160,7 @@ class ArticleFragment : Fragment() {
 | 
			
		||||
                            R.id.unread_action -> if (context != null) {
 | 
			
		||||
                                if (this@ArticleFragment.item.unread) {
 | 
			
		||||
                                    CoroutineScope(Dispatchers.IO).launch {
 | 
			
		||||
                                        api.markAsRead(this@ArticleFragment.item.id.toString())
 | 
			
		||||
                                        // TODO: Update in DB
 | 
			
		||||
                                        repository.markAsRead(this@ArticleFragment.item)
 | 
			
		||||
                                    }
 | 
			
		||||
                                    this@ArticleFragment.item.unread = false
 | 
			
		||||
                                    Toast.makeText(
 | 
			
		||||
@@ -202,8 +170,7 @@ class ArticleFragment : Fragment() {
 | 
			
		||||
                                    ).show()
 | 
			
		||||
                                } else {
 | 
			
		||||
                                    CoroutineScope(Dispatchers.IO).launch {
 | 
			
		||||
                                        api.unmarkAsRead(this@ArticleFragment.item.id.toString())
 | 
			
		||||
                                        // TODO: Update in DB
 | 
			
		||||
                                        repository.unmarkAsRead(this@ArticleFragment.item)
 | 
			
		||||
                                    }
 | 
			
		||||
                                    this@ArticleFragment.item.unread = true
 | 
			
		||||
                                    Toast.makeText(
 | 
			
		||||
@@ -247,7 +214,7 @@ class ArticleFragment : Fragment() {
 | 
			
		||||
                    Glide
 | 
			
		||||
                        .with(requireContext())
 | 
			
		||||
                        .asBitmap()
 | 
			
		||||
                        .loadMaybeBasicAuth(config, contentImage)
 | 
			
		||||
                        .load(contentImage)
 | 
			
		||||
                        .apply(RequestOptions.fitCenterTransform())
 | 
			
		||||
                        .into(binding.imageView)
 | 
			
		||||
                } else {
 | 
			
		||||
@@ -276,10 +243,7 @@ class ArticleFragment : Fragment() {
 | 
			
		||||
                .setTitle(requireContext().getString(R.string.webview_dialog_issue_title))
 | 
			
		||||
                .setPositiveButton(android.R.string.ok
 | 
			
		||||
                ) { _, _ ->
 | 
			
		||||
                    val sharedPref = PreferenceManager.getDefaultSharedPreferences(requireContext())
 | 
			
		||||
                    val editor = sharedPref.edit()
 | 
			
		||||
                    editor.putBoolean("prefer_article_viewer", false)
 | 
			
		||||
                    editor.apply()
 | 
			
		||||
                    appSettingsService.disableArticleViewer()
 | 
			
		||||
                    requireActivity().finish()
 | 
			
		||||
                }
 | 
			
		||||
                .create()
 | 
			
		||||
@@ -295,7 +259,7 @@ class ArticleFragment : Fragment() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun refreshAlignment() {
 | 
			
		||||
        textAlignment = when (prefs.getInt("text_align", 1)) {
 | 
			
		||||
        textAlignment = when (appSettingsService.getActiveAllignment()) {
 | 
			
		||||
            1 -> "justify"
 | 
			
		||||
            2 -> "left"
 | 
			
		||||
            else -> "justify"
 | 
			
		||||
@@ -303,7 +267,7 @@ class ArticleFragment : Fragment() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun getContentFromMercury(customTabsIntent: CustomTabsIntent) {
 | 
			
		||||
        if ((context != null && requireContext().isNetworkAvailable(null)) || context == null) {
 | 
			
		||||
        if (repository.isNetworkAvailable()) {
 | 
			
		||||
            binding.progressBar.visibility = View.VISIBLE
 | 
			
		||||
            val parser = MercuryApi()
 | 
			
		||||
 | 
			
		||||
@@ -344,7 +308,9 @@ class ArticleFragment : Fragment() {
 | 
			
		||||
                                            Glide
 | 
			
		||||
                                                .with(requireContext())
 | 
			
		||||
                                                .asBitmap()
 | 
			
		||||
                                                .loadMaybeBasicAuth(config, response.body()!!.lead_image_url.orEmpty())
 | 
			
		||||
                                                .load(
 | 
			
		||||
                                                    response.body()!!.lead_image_url.orEmpty()
 | 
			
		||||
                                                )
 | 
			
		||||
                                                .apply(RequestOptions.fitCenterTransform())
 | 
			
		||||
                                                .into(binding.imageView)
 | 
			
		||||
                                        } catch (e: Exception) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,9 @@
 | 
			
		||||
package bou.amine.apps.readerforselfossv2.android.fragments
 | 
			
		||||
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.view.*
 | 
			
		||||
import android.view.LayoutInflater
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
import androidx.fragment.app.Fragment
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.databinding.FragmentImageBinding
 | 
			
		||||
import com.bumptech.glide.Glide
 | 
			
		||||
 
 | 
			
		||||
@@ -1,43 +1,12 @@
 | 
			
		||||
package bou.amine.apps.readerforselfossv2.android.model
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.net.Uri
 | 
			
		||||
import android.text.Html
 | 
			
		||||
import android.webkit.URLUtil
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.rest.SelfossModel
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.model.SelfossModel
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.utils.getImages
 | 
			
		||||
import com.bumptech.glide.Glide
 | 
			
		||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
 | 
			
		||||
import com.bumptech.glide.request.RequestOptions
 | 
			
		||||
import org.jsoup.Jsoup
 | 
			
		||||
import java.util.*
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Items extension methods
 | 
			
		||||
 */
 | 
			
		||||
fun SelfossModel.Item.getIcon(baseUrl: String): String {
 | 
			
		||||
    return constructUrl(baseUrl, "favicons", icon)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fun SelfossModel.Item.getThumbnail(baseUrl: String): String {
 | 
			
		||||
    return constructUrl(baseUrl, "thumbnails", thumbnail)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fun SelfossModel.Item.getImages() : ArrayList<String> {
 | 
			
		||||
    val allImages = ArrayList<String>()
 | 
			
		||||
 | 
			
		||||
    for ( image in Jsoup.parse(content).getElementsByTag("img")) {
 | 
			
		||||
        val url = image.attr("src")
 | 
			
		||||
        if (url.lowercase(Locale.US).contains(".jpg") ||
 | 
			
		||||
            url.lowercase(Locale.US).contains(".jpeg") ||
 | 
			
		||||
            url.lowercase(Locale.US).contains(".png") ||
 | 
			
		||||
            url.lowercase(Locale.US).contains(".webp"))
 | 
			
		||||
        {
 | 
			
		||||
            allImages.add(url)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return allImages
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fun SelfossModel.Item.preloadImages(context: Context) : Boolean {
 | 
			
		||||
    val imageUrls = this.getImages()
 | 
			
		||||
@@ -60,66 +29,14 @@ fun SelfossModel.Item.preloadImages(context: Context) : Boolean {
 | 
			
		||||
    return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fun SelfossModel.Item.getTitleDecoded(): String {
 | 
			
		||||
    return Html.fromHtml(title).toString()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fun SelfossModel.Item.getSourceTitle(): String {
 | 
			
		||||
    return Html.fromHtml(sourcetitle).toString()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TODO: maybe find a better way to handle these kind of urls
 | 
			
		||||
fun SelfossModel.Item.getLinkDecoded(): String {
 | 
			
		||||
    var stringUrl: String
 | 
			
		||||
    stringUrl =
 | 
			
		||||
        if (link.startsWith("http://news.google.com/news/") || link.startsWith("https://news.google.com/news/")) {
 | 
			
		||||
            if (link.contains("&url=")) {
 | 
			
		||||
                link.substringAfter("&url=")
 | 
			
		||||
            } else {
 | 
			
		||||
                this.link.replace("&", "&")
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            this.link.replace("&", "&")
 | 
			
		||||
fun String.toTextDrawableString(): String {
 | 
			
		||||
    val textDrawable = StringBuilder()
 | 
			
		||||
    for (s in this.split(" ".toRegex()).filter { it.isNotEmpty() }.toTypedArray()) {
 | 
			
		||||
        try {
 | 
			
		||||
            textDrawable.append(s[0])
 | 
			
		||||
        } catch (e: StringIndexOutOfBoundsException) {
 | 
			
		||||
            // We do nothing
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    // handle :443 => https
 | 
			
		||||
    if (stringUrl.contains(":443")) {
 | 
			
		||||
        stringUrl = stringUrl.replace(":443", "").replace("http://", "https://")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // handle url not starting with http
 | 
			
		||||
    if (stringUrl.startsWith("//")) {
 | 
			
		||||
        stringUrl = "http:$stringUrl"
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return stringUrl
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Sources extension methods
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
fun SelfossModel.Source.getIcon(baseUrl: String): String {
 | 
			
		||||
    return constructUrl(baseUrl, "favicons", icon)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fun SelfossModel.Source.getTitleDecoded(): String {
 | 
			
		||||
    return Html.fromHtml(title).toString()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Common methods
 | 
			
		||||
 */
 | 
			
		||||
private fun constructUrl(baseUrl: String, path: String, file: String?): String {
 | 
			
		||||
    return if (file == null || file == "null" || file.isEmpty()) {
 | 
			
		||||
        ""
 | 
			
		||||
    } else {
 | 
			
		||||
        val baseUriBuilder = Uri.parse(baseUrl).buildUpon()
 | 
			
		||||
        baseUriBuilder.appendPath(path).appendPath(file)
 | 
			
		||||
 | 
			
		||||
        baseUriBuilder.toString()
 | 
			
		||||
    }
 | 
			
		||||
    return textDrawable.toString()
 | 
			
		||||
}
 | 
			
		||||
@@ -1,10 +1,8 @@
 | 
			
		||||
package bou.amine.apps.readerforselfossv2.android.model
 | 
			
		||||
 | 
			
		||||
import android.os.Build
 | 
			
		||||
import android.os.Parcel
 | 
			
		||||
import android.os.Parcelable
 | 
			
		||||
import androidx.annotation.RequiresApi
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.rest.SelfossModel
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.model.SelfossModel
 | 
			
		||||
import com.google.gson.annotations.SerializedName
 | 
			
		||||
 | 
			
		||||
fun SelfossModel.Item.toParcelable() : ParecelableItem =
 | 
			
		||||
 
 | 
			
		||||
@@ -1,28 +0,0 @@
 | 
			
		||||
package bou.amine.apps.readerforselfossv2.android.persistence
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import androidx.room.Room
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.database.AppDatabase
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.entities.AndroidItemEntity
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.migrations.MIGRATION_1_2
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.migrations.MIGRATION_2_3
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.migrations.MIGRATION_3_4
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.dao.DeviceDatabase
 | 
			
		||||
 | 
			
		||||
class AndroidDeviceDatabase(applicationContext: Context): DeviceDatabase<AndroidItemEntity> {
 | 
			
		||||
    var db: AppDatabase = Room.databaseBuilder(
 | 
			
		||||
        applicationContext,
 | 
			
		||||
        AppDatabase::class.java, "selfoss-database"
 | 
			
		||||
    ).addMigrations(MIGRATION_1_2).addMigrations(MIGRATION_2_3).addMigrations(MIGRATION_3_4).build()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    override suspend fun items(): List<AndroidItemEntity> = db.itemsDao().items()
 | 
			
		||||
 | 
			
		||||
    override suspend fun insertAllItems(vararg items: AndroidItemEntity) = db.itemsDao().insertAllItems(*items)
 | 
			
		||||
 | 
			
		||||
    override suspend fun deleteAllItems() = db.itemsDao().deleteAllItems()
 | 
			
		||||
 | 
			
		||||
    override suspend fun delete(item: AndroidItemEntity) = db.itemsDao().delete(item)
 | 
			
		||||
 | 
			
		||||
    override suspend fun updateItem(item: AndroidItemEntity) = db.itemsDao().updateItem(item)
 | 
			
		||||
}
 | 
			
		||||
@@ -1,40 +0,0 @@
 | 
			
		||||
package bou.amine.apps.readerforselfossv2.android.persistence
 | 
			
		||||
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.entities.AndroidItemEntity
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.utils.persistence.toEntity
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.rest.SelfossModel
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.service.DeviceDataBaseService
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.service.SearchService
 | 
			
		||||
 | 
			
		||||
class AndroidDeviceDatabaseService(db: AndroidDeviceDatabase, searchService: SearchService) :
 | 
			
		||||
    DeviceDataBaseService<AndroidItemEntity>(db, searchService) {
 | 
			
		||||
    override suspend fun updateDatabase() {
 | 
			
		||||
        if (itemsCaching) {
 | 
			
		||||
            if (items.isEmpty()) {
 | 
			
		||||
                getFromDB()
 | 
			
		||||
            }
 | 
			
		||||
            db.deleteAllItems()
 | 
			
		||||
            db.insertAllItems(*(items.map { it.toEntity() }).toTypedArray())
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun clearDBItems() {
 | 
			
		||||
        db.deleteAllItems()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun appendNewItems(newItems: List<SelfossModel.Item>) {
 | 
			
		||||
        var oldItems = items
 | 
			
		||||
        if (oldItems != newItems) {
 | 
			
		||||
            oldItems = oldItems.filter { item -> newItems.find { it.id == item.id } == null } as ArrayList<SelfossModel.Item>
 | 
			
		||||
            oldItems.addAll(newItems)
 | 
			
		||||
            items = oldItems
 | 
			
		||||
 | 
			
		||||
            sortItems()
 | 
			
		||||
            getFocusedItems()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun getFromDB() {
 | 
			
		||||
        TODO("Not yet implemented")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,23 +0,0 @@
 | 
			
		||||
package bou.amine.apps.readerforselfossv2.android.persistence.dao
 | 
			
		||||
 | 
			
		||||
import androidx.room.Dao
 | 
			
		||||
import androidx.room.Delete
 | 
			
		||||
import androidx.room.Insert
 | 
			
		||||
import androidx.room.OnConflictStrategy
 | 
			
		||||
import androidx.room.Query
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.entities.ActionEntity
 | 
			
		||||
 | 
			
		||||
@Dao
 | 
			
		||||
interface ActionsDao {
 | 
			
		||||
    @Query("SELECT * FROM actions order by id asc")
 | 
			
		||||
    suspend fun actions(): List<ActionEntity>
 | 
			
		||||
 | 
			
		||||
    @Insert(onConflict = OnConflictStrategy.REPLACE)
 | 
			
		||||
    fun insertAllActions(vararg actions: ActionEntity)
 | 
			
		||||
 | 
			
		||||
    @Query("DELETE FROM actions WHERE articleid = :article_id AND read = 1")
 | 
			
		||||
    fun deleteReadActionForArticle(article_id: String)
 | 
			
		||||
 | 
			
		||||
    @Delete
 | 
			
		||||
    fun delete(action: ActionEntity)
 | 
			
		||||
}
 | 
			
		||||
@@ -1,36 +0,0 @@
 | 
			
		||||
package bou.amine.apps.readerforselfossv2.android.persistence.dao
 | 
			
		||||
 | 
			
		||||
import androidx.room.Delete
 | 
			
		||||
import androidx.room.Dao
 | 
			
		||||
import androidx.room.Insert
 | 
			
		||||
import androidx.room.OnConflictStrategy
 | 
			
		||||
import androidx.room.Query
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.entities.SourceEntity
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.entities.TagEntity
 | 
			
		||||
 | 
			
		||||
@Dao
 | 
			
		||||
interface DrawerDataDao {
 | 
			
		||||
    @Query("SELECT * FROM tags")
 | 
			
		||||
    fun tags(): List<TagEntity>
 | 
			
		||||
 | 
			
		||||
    @Query("SELECT * FROM sources")
 | 
			
		||||
    fun sources(): List<SourceEntity>
 | 
			
		||||
 | 
			
		||||
    @Insert(onConflict = OnConflictStrategy.REPLACE)
 | 
			
		||||
    fun insertAllTags(vararg tags: TagEntity)
 | 
			
		||||
 | 
			
		||||
    @Insert(onConflict = OnConflictStrategy.REPLACE)
 | 
			
		||||
    fun insertAllSources(vararg sources: SourceEntity)
 | 
			
		||||
 | 
			
		||||
    @Query("DELETE FROM tags")
 | 
			
		||||
    fun deleteAllTags()
 | 
			
		||||
 | 
			
		||||
    @Query("DELETE FROM sources")
 | 
			
		||||
    fun deleteAllSources()
 | 
			
		||||
 | 
			
		||||
    @Delete
 | 
			
		||||
    fun deleteTag(tag: TagEntity)
 | 
			
		||||
 | 
			
		||||
    @Delete
 | 
			
		||||
    fun deleteSource(source: SourceEntity)
 | 
			
		||||
}
 | 
			
		||||
@@ -1,29 +0,0 @@
 | 
			
		||||
package bou.amine.apps.readerforselfossv2.android.persistence.dao
 | 
			
		||||
 | 
			
		||||
import androidx.room.Dao
 | 
			
		||||
import androidx.room.Delete
 | 
			
		||||
import androidx.room.Insert
 | 
			
		||||
import androidx.room.OnConflictStrategy
 | 
			
		||||
import androidx.room.Query
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.entities.AndroidItemEntity
 | 
			
		||||
import androidx.room.Update
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@Dao
 | 
			
		||||
interface ItemsDao {
 | 
			
		||||
    @Query("SELECT * FROM items order by id desc")
 | 
			
		||||
    suspend fun items(): List<AndroidItemEntity>
 | 
			
		||||
 | 
			
		||||
    @Insert(onConflict = OnConflictStrategy.REPLACE)
 | 
			
		||||
    suspend fun insertAllItems(vararg items: AndroidItemEntity)
 | 
			
		||||
 | 
			
		||||
    @Query("DELETE FROM items")
 | 
			
		||||
    suspend fun deleteAllItems()
 | 
			
		||||
 | 
			
		||||
    @Delete
 | 
			
		||||
    suspend fun delete(item: AndroidItemEntity)
 | 
			
		||||
 | 
			
		||||
    @Update
 | 
			
		||||
    suspend fun updateItem(item: AndroidItemEntity)
 | 
			
		||||
}
 | 
			
		||||
@@ -1,20 +0,0 @@
 | 
			
		||||
package bou.amine.apps.readerforselfossv2.android.persistence.database
 | 
			
		||||
 | 
			
		||||
import androidx.room.RoomDatabase
 | 
			
		||||
import androidx.room.Database
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.dao.ActionsDao
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.dao.DrawerDataDao
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.dao.ItemsDao
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.entities.ActionEntity
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.entities.AndroidItemEntity
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.entities.SourceEntity
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.entities.TagEntity
 | 
			
		||||
 | 
			
		||||
@Database(entities = [TagEntity::class, SourceEntity::class, AndroidItemEntity::class, ActionEntity::class], version = 4)
 | 
			
		||||
abstract class AppDatabase : RoomDatabase() {
 | 
			
		||||
    abstract fun drawerDataDao(): DrawerDataDao
 | 
			
		||||
 | 
			
		||||
    abstract fun itemsDao(): ItemsDao
 | 
			
		||||
 | 
			
		||||
    abstract fun actionsDao(): ActionsDao
 | 
			
		||||
}
 | 
			
		||||
@@ -1,22 +0,0 @@
 | 
			
		||||
package bou.amine.apps.readerforselfossv2.android.persistence.entities
 | 
			
		||||
 | 
			
		||||
import androidx.room.ColumnInfo
 | 
			
		||||
import androidx.room.Entity
 | 
			
		||||
import androidx.room.PrimaryKey
 | 
			
		||||
 | 
			
		||||
@Entity(tableName = "actions")
 | 
			
		||||
data class ActionEntity(
 | 
			
		||||
    @ColumnInfo(name = "articleid")
 | 
			
		||||
    val articleId: String,
 | 
			
		||||
    @ColumnInfo(name = "read")
 | 
			
		||||
    val read: Boolean,
 | 
			
		||||
    @ColumnInfo(name = "unread")
 | 
			
		||||
    val unread: Boolean,
 | 
			
		||||
    @ColumnInfo(name = "starred")
 | 
			
		||||
    var starred: Boolean,
 | 
			
		||||
    @ColumnInfo(name = "unstarred")
 | 
			
		||||
    var unstarred: Boolean
 | 
			
		||||
) {
 | 
			
		||||
    @PrimaryKey(autoGenerate = true)
 | 
			
		||||
    var id: Int = 0
 | 
			
		||||
}
 | 
			
		||||
@@ -1,33 +0,0 @@
 | 
			
		||||
package bou.amine.apps.readerforselfossv2.android.persistence.entities
 | 
			
		||||
 | 
			
		||||
import androidx.room.ColumnInfo
 | 
			
		||||
import androidx.room.Entity
 | 
			
		||||
import androidx.room.PrimaryKey
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.rest.SelfossModel
 | 
			
		||||
 | 
			
		||||
@Entity(tableName = "items")
 | 
			
		||||
data class AndroidItemEntity(
 | 
			
		||||
    @PrimaryKey
 | 
			
		||||
    @ColumnInfo(name = "id")
 | 
			
		||||
    val id: String,
 | 
			
		||||
    @ColumnInfo(name = "datetime")
 | 
			
		||||
    val datetime: String,
 | 
			
		||||
    @ColumnInfo(name = "title")
 | 
			
		||||
    val title: String,
 | 
			
		||||
    @ColumnInfo(name = "content")
 | 
			
		||||
    val content: String,
 | 
			
		||||
    @ColumnInfo(name = "unread")
 | 
			
		||||
    val unread: Boolean,
 | 
			
		||||
    @ColumnInfo(name = "starred")
 | 
			
		||||
    var starred: Boolean,
 | 
			
		||||
    @ColumnInfo(name = "thumbnail")
 | 
			
		||||
    val thumbnail: String?,
 | 
			
		||||
    @ColumnInfo(name = "icon")
 | 
			
		||||
    val icon: String?,
 | 
			
		||||
    @ColumnInfo(name = "link")
 | 
			
		||||
    val link: String,
 | 
			
		||||
    @ColumnInfo(name = "sourcetitle")
 | 
			
		||||
    val sourcetitle: String,
 | 
			
		||||
    @ColumnInfo(name = "tags")
 | 
			
		||||
    val tags: String
 | 
			
		||||
)
 | 
			
		||||
@@ -1,33 +0,0 @@
 | 
			
		||||
package bou.amine.apps.readerforselfossv2.android.persistence.entities
 | 
			
		||||
 | 
			
		||||
import androidx.room.ColumnInfo
 | 
			
		||||
import androidx.room.Entity
 | 
			
		||||
import androidx.room.PrimaryKey
 | 
			
		||||
 | 
			
		||||
@Entity(tableName = "tags")
 | 
			
		||||
data class TagEntity(
 | 
			
		||||
    @PrimaryKey
 | 
			
		||||
    @ColumnInfo(name = "tag")
 | 
			
		||||
    val tag: String,
 | 
			
		||||
    @ColumnInfo(name = "color")
 | 
			
		||||
    val color: String,
 | 
			
		||||
    @ColumnInfo(name = "unread")
 | 
			
		||||
    val unread: Int
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@Entity(tableName = "sources")
 | 
			
		||||
data class SourceEntity(
 | 
			
		||||
    @PrimaryKey
 | 
			
		||||
    @ColumnInfo(name = "id")
 | 
			
		||||
    val id: String,
 | 
			
		||||
    @ColumnInfo(name = "title")
 | 
			
		||||
    val title: String,
 | 
			
		||||
    @ColumnInfo(name = "tags")
 | 
			
		||||
    val tags: String,
 | 
			
		||||
    @ColumnInfo(name = "spout")
 | 
			
		||||
    val spout: String,
 | 
			
		||||
    @ColumnInfo(name = "error")
 | 
			
		||||
    val error: String,
 | 
			
		||||
    @ColumnInfo(name = "icon")
 | 
			
		||||
    val icon: String
 | 
			
		||||
)
 | 
			
		||||
@@ -1,34 +0,0 @@
 | 
			
		||||
package bou.amine.apps.readerforselfossv2.android.persistence.migrations
 | 
			
		||||
 | 
			
		||||
import androidx.sqlite.db.SupportSQLiteDatabase
 | 
			
		||||
import androidx.room.migration.Migration
 | 
			
		||||
 | 
			
		||||
val MIGRATION_1_2: Migration = object : Migration(1, 2) {
 | 
			
		||||
    override fun migrate(database: SupportSQLiteDatabase) {
 | 
			
		||||
        database.execSQL("CREATE TABLE IF NOT EXISTS `items` (`id` TEXT NOT NULL, `datetime` TEXT NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `unread` INTEGER NOT NULL, `starred` INTEGER NOT NULL, `thumbnail` TEXT NOT NULL, `icon` TEXT NOT NULL, `link` TEXT NOT NULL, `sourcetitle` TEXT NOT NULL, `tags` TEXT NOT NULL, PRIMARY KEY(`id`))")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
val MIGRATION_2_3: Migration = object : Migration(2, 3) {
 | 
			
		||||
    override fun migrate(database: SupportSQLiteDatabase) {
 | 
			
		||||
        database.execSQL("CREATE TABLE IF NOT EXISTS `actions` (`id` INTEGER NOT NULL, `articleid` TEXT NOT NULL, `read` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `starred` INTEGER NOT NULL, `unstarred` INTEGER NOT NULL, PRIMARY KEY(`id`))")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
val MIGRATION_3_4: Migration = object : Migration(3, 4) {
 | 
			
		||||
    override fun migrate(database: SupportSQLiteDatabase) {
 | 
			
		||||
        // @see https://stackoverflow.com/questions/57392015/how-to-migrate-not-null-table-column-into-null-in-android-room-database
 | 
			
		||||
        // Create the new table
 | 
			
		||||
        database.execSQL("CREATE TABLE IF NOT EXISTS `itemstmp` (`id` TEXT NOT NULL, `datetime` TEXT NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `unread` INTEGER NOT NULL, `starred` INTEGER NOT NULL, `thumbnail` TEXT, `icon` TEXT, `link` TEXT NOT NULL, `sourcetitle` TEXT NOT NULL, `tags` TEXT NOT NULL, PRIMARY KEY(`id`))")
 | 
			
		||||
 | 
			
		||||
        // Copy the data
 | 
			
		||||
        database.execSQL(
 | 
			
		||||
                "INSERT INTO itemstmp (`id`, `datetime`, `title`, `content`, `unread`, `starred`, `thumbnail`, `icon`, `link`, `sourcetitle`, `tags`) SELECT `id`, `datetime`, `title`, `content`, `unread`, `starred`, `thumbnail`, `icon`, `link`, `sourcetitle`, `tags` FROM items")
 | 
			
		||||
 | 
			
		||||
        // Remove the old table
 | 
			
		||||
        database.execSQL("DROP TABLE items")
 | 
			
		||||
 | 
			
		||||
        // Change the table name to the correct one
 | 
			
		||||
        database.execSQL("ALTER TABLE itemstmp RENAME TO items")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,48 +0,0 @@
 | 
			
		||||
package bou.amine.apps.readerforselfossv2.android.service
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.content.SharedPreferences
 | 
			
		||||
import android.util.Log
 | 
			
		||||
import androidx.preference.PreferenceManager
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.service.ApiDetailsService
 | 
			
		||||
 | 
			
		||||
class AndroidApiDetailsService(c: Context) : ApiDetailsService {
 | 
			
		||||
    val settings: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(c)
 | 
			
		||||
    private var _apiVersion: Int = -1
 | 
			
		||||
    private var _baseUrl: String = ""
 | 
			
		||||
    private var _userName: String = ""
 | 
			
		||||
    private var _password: String = ""
 | 
			
		||||
    override fun logApiCalls(message: String) {
 | 
			
		||||
        Log.d("LogApiCalls", message)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    override fun getApiVersion(): Int {
 | 
			
		||||
        if (_apiVersion == -1) {
 | 
			
		||||
            _apiVersion = settings.getInt("apiVersionMajor", -1)!!
 | 
			
		||||
            return settings.getInt("apiVersionMajor", -1)!!
 | 
			
		||||
        }
 | 
			
		||||
        return _apiVersion
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun getBaseUrl(): String {
 | 
			
		||||
        if (_baseUrl.isEmpty()) {
 | 
			
		||||
            _baseUrl = settings.getString("url", "")!!
 | 
			
		||||
        }
 | 
			
		||||
        return _baseUrl
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun getUserName(): String {
 | 
			
		||||
        if (_userName.isEmpty()) {
 | 
			
		||||
            _userName = settings.getString("login", "")!!
 | 
			
		||||
        }
 | 
			
		||||
        return _userName
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun getPassword(): String {
 | 
			
		||||
        if (_password.isEmpty()) {
 | 
			
		||||
            _password = settings.getString("password", "")!!
 | 
			
		||||
        }
 | 
			
		||||
        return _password
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -3,21 +3,26 @@ package bou.amine.apps.readerforselfossv2.android.settings
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.net.Uri
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.text.*
 | 
			
		||||
import androidx.preference.EditTextPreference
 | 
			
		||||
import androidx.preference.PreferenceManager
 | 
			
		||||
import android.view.*
 | 
			
		||||
import android.text.Editable
 | 
			
		||||
import android.text.InputFilter
 | 
			
		||||
import android.text.InputType
 | 
			
		||||
import android.text.TextWatcher
 | 
			
		||||
import android.view.Menu
 | 
			
		||||
import android.view.MenuInflater
 | 
			
		||||
import android.view.MenuItem
 | 
			
		||||
import android.widget.Toast
 | 
			
		||||
import androidx.appcompat.app.AppCompatActivity
 | 
			
		||||
import androidx.core.widget.addTextChangedListener
 | 
			
		||||
import androidx.preference.EditTextPreference
 | 
			
		||||
import androidx.preference.Preference
 | 
			
		||||
import androidx.preference.PreferenceFragmentCompat
 | 
			
		||||
import androidx.preference.PreferenceManager
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.R
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.databinding.ActivitySettingsBinding
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.themes.AppColors
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.themes.Toppings
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.utils.Config
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
 | 
			
		||||
import com.ftinc.scoop.Scoop
 | 
			
		||||
import java.lang.NumberFormatException
 | 
			
		||||
 | 
			
		||||
private const val TITLE_TAG = "settingsActivityTitle"
 | 
			
		||||
 | 
			
		||||
@@ -64,11 +69,13 @@ class SettingsActivity : AppCompatActivity(),
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onSupportNavigateUp(): Boolean {
 | 
			
		||||
        if (supportFragmentManager.popBackStackImmediate()) {
 | 
			
		||||
        return if (supportFragmentManager.popBackStackImmediate()) {
 | 
			
		||||
            supportActionBar?.title = getText(R.string.title_activity_settings)
 | 
			
		||||
            return true
 | 
			
		||||
            false
 | 
			
		||||
        } else {
 | 
			
		||||
            super.onBackPressed()
 | 
			
		||||
            true
 | 
			
		||||
        }
 | 
			
		||||
        return super.onSupportNavigateUp()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onPreferenceStartFragment(
 | 
			
		||||
@@ -173,14 +180,7 @@ class SettingsActivity : AppCompatActivity(),
 | 
			
		||||
        override fun onOptionsItemSelected(item: MenuItem): Boolean {
 | 
			
		||||
            val id = item.itemId
 | 
			
		||||
            if (id == R.id.clear) {
 | 
			
		||||
                val pref = PreferenceManager.getDefaultSharedPreferences(activity)
 | 
			
		||||
                val editor = pref.edit()
 | 
			
		||||
                editor.remove("color_primary")
 | 
			
		||||
                editor.remove("color_primary_dark")
 | 
			
		||||
                editor.remove("color_accent")
 | 
			
		||||
                editor.remove("color_accent_dark")
 | 
			
		||||
                editor.remove("dark_theme")
 | 
			
		||||
                editor.apply()
 | 
			
		||||
                AppColors.resetColors()
 | 
			
		||||
                requireActivity().recreate()
 | 
			
		||||
            }
 | 
			
		||||
            return super.onOptionsItemSelected(item)
 | 
			
		||||
@@ -197,17 +197,17 @@ class SettingsActivity : AppCompatActivity(),
 | 
			
		||||
            setPreferencesFromResource(R.xml.pref_links, rootKey)
 | 
			
		||||
 | 
			
		||||
            preferenceManager.findPreference<Preference>("trackerLink")?.onPreferenceClickListener = Preference.OnPreferenceClickListener {
 | 
			
		||||
                openUrl(Uri.parse(Config.trackerUrl))
 | 
			
		||||
                openUrl(Uri.parse(AppSettingsService.trackerUrl))
 | 
			
		||||
                true
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            preferenceManager.findPreference<Preference>("sourceLink")?.onPreferenceClickListener = Preference.OnPreferenceClickListener {
 | 
			
		||||
                openUrl(Uri.parse(Config.sourceUrl))
 | 
			
		||||
                openUrl(Uri.parse(AppSettingsService.sourceUrl))
 | 
			
		||||
                false
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            preferenceManager.findPreference<Preference>("translation")?.onPreferenceClickListener = Preference.OnPreferenceClickListener {
 | 
			
		||||
                openUrl(Uri.parse(Config.translationUrl))
 | 
			
		||||
                openUrl(Uri.parse(AppSettingsService.translationUrl))
 | 
			
		||||
                false
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -2,8 +2,8 @@ package bou.amine.apps.readerforselfossv2.android.themes
 | 
			
		||||
 | 
			
		||||
import android.app.Activity
 | 
			
		||||
import androidx.annotation.ColorInt
 | 
			
		||||
import androidx.preference.PreferenceManager
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.R
 | 
			
		||||
import com.russhwolf.settings.Settings
 | 
			
		||||
 | 
			
		||||
class AppColors(a: Activity) {
 | 
			
		||||
 | 
			
		||||
@@ -16,46 +16,57 @@ class AppColors(a: Activity) {
 | 
			
		||||
    val isDarkTheme: Boolean
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        val sharedPref = PreferenceManager.getDefaultSharedPreferences(a)
 | 
			
		||||
        val settings = Settings()
 | 
			
		||||
 | 
			
		||||
        colorPrimary =
 | 
			
		||||
                sharedPref.getInt(
 | 
			
		||||
                settings.getInt(
 | 
			
		||||
                    "color_primary",
 | 
			
		||||
                    a.resources.getColor(R.color.colorPrimary)
 | 
			
		||||
                )
 | 
			
		||||
        colorPrimaryDark =
 | 
			
		||||
                sharedPref.getInt(
 | 
			
		||||
                settings.getInt(
 | 
			
		||||
                    "color_primary_dark",
 | 
			
		||||
                    a.resources.getColor(R.color.colorPrimaryDark)
 | 
			
		||||
                )
 | 
			
		||||
        colorAccent =
 | 
			
		||||
                sharedPref.getInt(
 | 
			
		||||
                settings.getInt(
 | 
			
		||||
                    "color_accent",
 | 
			
		||||
                    a.resources.getColor(R.color.colorAccent)
 | 
			
		||||
                )
 | 
			
		||||
        colorAccentDark =
 | 
			
		||||
                sharedPref.getInt(
 | 
			
		||||
                settings.getInt(
 | 
			
		||||
                    "color_accent_dark",
 | 
			
		||||
                    a.resources.getColor(R.color.colorAccentDark)
 | 
			
		||||
                )
 | 
			
		||||
        isDarkTheme =
 | 
			
		||||
                sharedPref.getBoolean(
 | 
			
		||||
                settings.getBoolean(
 | 
			
		||||
                    "dark_theme",
 | 
			
		||||
                    false
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
        colorBackground = if (isDarkTheme) {
 | 
			
		||||
            a.setTheme(R.style.NoBarDark)
 | 
			
		||||
            R.color.darkBackground
 | 
			
		||||
            a.resources.getColor(R.color.darkBackground)
 | 
			
		||||
        } else {
 | 
			
		||||
            a.setTheme(R.style.NoBar)
 | 
			
		||||
            R.color.grey_50
 | 
			
		||||
            a.resources.getColor(R.color.grey_50)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        textColor = if (isDarkTheme) {
 | 
			
		||||
            R.color.white
 | 
			
		||||
            a.resources.getColor(R.color.white)
 | 
			
		||||
        } else {
 | 
			
		||||
            R.color.grey_900
 | 
			
		||||
            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,64 +0,0 @@
 | 
			
		||||
package bou.amine.apps.readerforselfossv2.android.utils
 | 
			
		||||
 | 
			
		||||
import android.app.Activity
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.content.SharedPreferences
 | 
			
		||||
import androidx.preference.PreferenceManager
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.LoginActivity
 | 
			
		||||
 | 
			
		||||
class Config(c: Context) {
 | 
			
		||||
 | 
			
		||||
    val settings: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(c)
 | 
			
		||||
 | 
			
		||||
    val baseUrl: String
 | 
			
		||||
        get() = settings.getString("url", "")!!
 | 
			
		||||
 | 
			
		||||
    val userLogin: String
 | 
			
		||||
        get() = settings.getString("login", "")!!
 | 
			
		||||
 | 
			
		||||
    val userPassword: String
 | 
			
		||||
        get() = settings.getString("password", "")!!
 | 
			
		||||
 | 
			
		||||
    val httpUserLogin: String
 | 
			
		||||
        get() = settings.getString("httpUserName", "")!!
 | 
			
		||||
 | 
			
		||||
    val httpUserPassword: String
 | 
			
		||||
        get() = settings.getString("httpPassword", "")!!
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        const val settingsName = "paramsselfoss"
 | 
			
		||||
 | 
			
		||||
        const val feedbackEmail = "aminecmi@gmail.com"
 | 
			
		||||
 | 
			
		||||
        const val translationUrl = "https://crwd.in/readerforselfoss"
 | 
			
		||||
 | 
			
		||||
        const val sourceUrl = "https://github.com/aminecmi/ReaderforSelfoss"
 | 
			
		||||
 | 
			
		||||
        const val trackerUrl = "https://github.com/aminecmi/ReaderforSelfoss/issues"
 | 
			
		||||
 | 
			
		||||
        const val syncChannelId = "sync-channel-id"
 | 
			
		||||
 | 
			
		||||
        const val newItemsChannelId = "new-items-channel-id"
 | 
			
		||||
 | 
			
		||||
        var apiVersion = 0
 | 
			
		||||
 | 
			
		||||
        /* Execute logout and clear all settings to default */
 | 
			
		||||
        fun logoutAndRedirect(
 | 
			
		||||
            c: Context,
 | 
			
		||||
            callingActivity: Activity,
 | 
			
		||||
            editor: SharedPreferences.Editor,
 | 
			
		||||
            baseUrlFail: Boolean = false
 | 
			
		||||
        ): Boolean {
 | 
			
		||||
            val settings = PreferenceManager.getDefaultSharedPreferences(c)
 | 
			
		||||
            settings.edit().clear().commit()
 | 
			
		||||
            val intent = Intent(c, LoginActivity::class.java)
 | 
			
		||||
            if (baseUrlFail) {
 | 
			
		||||
                intent.putExtra("baseUrlFail", baseUrlFail)
 | 
			
		||||
            }
 | 
			
		||||
            c.startActivity(intent)
 | 
			
		||||
            callingActivity.finish()
 | 
			
		||||
            return true
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,43 +0,0 @@
 | 
			
		||||
package bou.amine.apps.readerforselfossv2.android.utils
 | 
			
		||||
 | 
			
		||||
import okhttp3.OkHttpClient
 | 
			
		||||
import java.security.cert.CertificateException
 | 
			
		||||
import java.security.cert.X509Certificate
 | 
			
		||||
import javax.net.ssl.SSLContext
 | 
			
		||||
import javax.net.ssl.TrustManager
 | 
			
		||||
import javax.net.ssl.X509TrustManager
 | 
			
		||||
 | 
			
		||||
fun getUnsafeHttpClient(): OkHttpClient.Builder =
 | 
			
		||||
    try {
 | 
			
		||||
        // Create a trust manager that does not validate certificate chains
 | 
			
		||||
        val trustAllCerts = arrayOf<TrustManager>(object : X509TrustManager {
 | 
			
		||||
            override fun getAcceptedIssuers(): Array<X509Certificate> =
 | 
			
		||||
                arrayOf()
 | 
			
		||||
 | 
			
		||||
            @Throws(CertificateException::class)
 | 
			
		||||
            override fun checkClientTrusted(
 | 
			
		||||
                chain: Array<java.security.cert.X509Certificate>,
 | 
			
		||||
                authType: String
 | 
			
		||||
            ) {
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            @Throws(CertificateException::class)
 | 
			
		||||
            override fun checkServerTrusted(
 | 
			
		||||
                chain: Array<java.security.cert.X509Certificate>,
 | 
			
		||||
                authType: String
 | 
			
		||||
            ) {
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
 | 
			
		||||
        // Install the all-trusting trust manager
 | 
			
		||||
        val sslContext = SSLContext.getInstance("SSL")
 | 
			
		||||
        sslContext.init(null, trustAllCerts, java.security.SecureRandom())
 | 
			
		||||
 | 
			
		||||
        val sslSocketFactory = sslContext.socketFactory
 | 
			
		||||
 | 
			
		||||
        OkHttpClient.Builder()
 | 
			
		||||
            .sslSocketFactory(sslSocketFactory, trustAllCerts[0] as X509TrustManager)
 | 
			
		||||
            .hostnameVerifier { _, _ -> true }
 | 
			
		||||
    } catch (e: Exception) {
 | 
			
		||||
        throw RuntimeException(e)
 | 
			
		||||
    }
 | 
			
		||||
@@ -1,29 +0,0 @@
 | 
			
		||||
package bou.amine.apps.readerforselfossv2.android.utils
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.model.getSourceTitle
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.rest.SelfossModel
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.utils.DateUtils
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.utils.parseRelativeDate
 | 
			
		||||
 | 
			
		||||
fun String.toTextDrawableString(c: Context): String {
 | 
			
		||||
    val textDrawable = StringBuilder()
 | 
			
		||||
    for (s in this.split(" ".toRegex()).filter { it.isNotEmpty() }.toTypedArray()) {
 | 
			
		||||
        try {
 | 
			
		||||
            textDrawable.append(s[0])
 | 
			
		||||
        } catch (e: StringIndexOutOfBoundsException) {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return textDrawable.toString()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fun SelfossModel.Item.sourceAndDateText(dateUtils: DateUtils): String {
 | 
			
		||||
    val formattedDate = parseRelativeDate(dateUtils)
 | 
			
		||||
 | 
			
		||||
    return getSourceTitle() + formattedDate
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fun SelfossModel.Item.toggleStar(): SelfossModel.Item {
 | 
			
		||||
    this.starred = !this.starred
 | 
			
		||||
    return this
 | 
			
		||||
}
 | 
			
		||||
@@ -10,18 +10,16 @@ import android.net.Uri
 | 
			
		||||
import android.os.Build
 | 
			
		||||
import android.text.Spannable
 | 
			
		||||
import android.text.style.ClickableSpan
 | 
			
		||||
import androidx.browser.customtabs.CustomTabsIntent
 | 
			
		||||
import android.util.Patterns
 | 
			
		||||
import android.view.MotionEvent
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.widget.TextView
 | 
			
		||||
import android.widget.Toast
 | 
			
		||||
import androidx.browser.customtabs.CustomTabsIntent
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.R
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.ReaderActivity
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.model.getLinkDecoded
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.utils.customtabs.CustomTabActivityHelper
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.rest.SelfossModel
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.service.SearchService
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.model.SelfossModel
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.utils.toStringUriWithHttp
 | 
			
		||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
 | 
			
		||||
 | 
			
		||||
@@ -79,12 +77,10 @@ fun Context.openItemUrlInternally(
 | 
			
		||||
    linkDecoded: String,
 | 
			
		||||
    customTabsIntent: CustomTabsIntent,
 | 
			
		||||
    articleViewer: Boolean,
 | 
			
		||||
    app: Activity,
 | 
			
		||||
    searchService: SearchService
 | 
			
		||||
    app: Activity
 | 
			
		||||
) {
 | 
			
		||||
    if (articleViewer) {
 | 
			
		||||
        ReaderActivity.allItems = allItems
 | 
			
		||||
        searchService.position = currentItem
 | 
			
		||||
        val intent = Intent(this, ReaderActivity::class.java)
 | 
			
		||||
        intent.putExtra("currentItem", currentItem)
 | 
			
		||||
        app.startActivity(intent)
 | 
			
		||||
@@ -123,8 +119,7 @@ fun Context.openItemUrl(
 | 
			
		||||
    customTabsIntent: CustomTabsIntent,
 | 
			
		||||
    internalBrowser: Boolean,
 | 
			
		||||
    articleViewer: Boolean,
 | 
			
		||||
    app: Activity,
 | 
			
		||||
    searchService: SearchService
 | 
			
		||||
    app: Activity
 | 
			
		||||
) {
 | 
			
		||||
 | 
			
		||||
    if (!linkDecoded.isUrlValid()) {
 | 
			
		||||
@@ -143,8 +138,7 @@ fun Context.openItemUrl(
 | 
			
		||||
                linkDecoded,
 | 
			
		||||
                customTabsIntent,
 | 
			
		||||
                articleViewer,
 | 
			
		||||
                app,
 | 
			
		||||
                searchService
 | 
			
		||||
                app
 | 
			
		||||
            )
 | 
			
		||||
        } else {
 | 
			
		||||
            this.openItemUrlInternalBrowser(
 | 
			
		||||
@@ -169,7 +163,7 @@ private fun openInBrowser(linkDecoded: String, app: Activity) {
 | 
			
		||||
fun String.isUrlValid(): Boolean =
 | 
			
		||||
    this.toHttpUrlOrNull() != null && Patterns.WEB_URL.matcher(this).matches()
 | 
			
		||||
 | 
			
		||||
fun String.isBaseUrlValid(ctx: Context): Boolean {
 | 
			
		||||
fun String.isBaseUrlInvalid(): Boolean {
 | 
			
		||||
    val baseUrl = this.toHttpUrlOrNull()
 | 
			
		||||
    var existsAndEndsWithSlash = false
 | 
			
		||||
    if (baseUrl != null) {
 | 
			
		||||
@@ -177,7 +171,7 @@ fun String.isBaseUrlValid(ctx: Context): Boolean {
 | 
			
		||||
        existsAndEndsWithSlash = "" == pathSegments[pathSegments.size - 1]
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return Patterns.WEB_URL.matcher(this).matches() && existsAndEndsWithSlash
 | 
			
		||||
    return !(Patterns.WEB_URL.matcher(this).matches() && existsAndEndsWithSlash)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fun Context.openInBrowserAsNewTask(i: SelfossModel.Item) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +0,0 @@
 | 
			
		||||
package bou.amine.apps.readerforselfossv2.android.utils
 | 
			
		||||
 | 
			
		||||
import android.content.res.Resources
 | 
			
		||||
 | 
			
		||||
val Int.toPx: Int
 | 
			
		||||
    get() = (this * Resources.getSystem().displayMetrics.density).toInt()
 | 
			
		||||
 | 
			
		||||
val Int.toDp: Int
 | 
			
		||||
    get() = (this / Resources.getSystem().displayMetrics.density).toInt()
 | 
			
		||||
@@ -7,15 +7,14 @@ import android.content.IntentFilter;
 | 
			
		||||
import android.content.pm.PackageManager;
 | 
			
		||||
import android.content.pm.ResolveInfo;
 | 
			
		||||
import android.net.Uri;
 | 
			
		||||
import androidx.browser.customtabs.CustomTabsService;
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.utils.customtabs.helpers.KeepAliveService;
 | 
			
		||||
 | 
			
		||||
@SuppressWarnings("ALL")
 | 
			
		||||
class CustomTabsHelper {
 | 
			
		||||
    private static final String TAG = "CustomTabsHelper";
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,10 @@
 | 
			
		||||
/* 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 androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
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) {
 | 
			
		||||
 
 | 
			
		||||
@@ -2,33 +2,26 @@ package bou.amine.apps.readerforselfossv2.android.utils.glide
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.graphics.Bitmap
 | 
			
		||||
import android.graphics.drawable.Drawable
 | 
			
		||||
import android.util.Base64
 | 
			
		||||
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory
 | 
			
		||||
import android.widget.ImageView
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.utils.Config
 | 
			
		||||
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory
 | 
			
		||||
import com.bumptech.glide.Glide
 | 
			
		||||
import com.bumptech.glide.RequestBuilder
 | 
			
		||||
import com.bumptech.glide.RequestManager
 | 
			
		||||
import com.bumptech.glide.load.model.GlideUrl
 | 
			
		||||
import com.bumptech.glide.load.model.LazyHeaders
 | 
			
		||||
import com.bumptech.glide.request.RequestOptions
 | 
			
		||||
import com.bumptech.glide.request.target.BitmapImageViewTarget
 | 
			
		||||
import java.io.ByteArrayInputStream
 | 
			
		||||
import java.io.ByteArrayOutputStream
 | 
			
		||||
import java.io.InputStream
 | 
			
		||||
 | 
			
		||||
fun Context.bitmapCenterCrop(config: Config, url: String, iv: ImageView) =
 | 
			
		||||
fun Context.bitmapCenterCrop(url: String, iv: ImageView) =
 | 
			
		||||
    Glide.with(this)
 | 
			
		||||
        .asBitmap()
 | 
			
		||||
        .loadMaybeBasicAuth(config, url)
 | 
			
		||||
        .load(url)
 | 
			
		||||
        .apply(RequestOptions.centerCropTransform())
 | 
			
		||||
        .into(iv)
 | 
			
		||||
 | 
			
		||||
fun Context.circularBitmapDrawable(config: Config, url: String, iv: ImageView) =
 | 
			
		||||
fun Context.circularBitmapDrawable(url: String, iv: ImageView) =
 | 
			
		||||
    Glide.with(this)
 | 
			
		||||
        .asBitmap()
 | 
			
		||||
        .loadMaybeBasicAuth(config, url)
 | 
			
		||||
        .load(url)
 | 
			
		||||
        .apply(RequestOptions.centerCropTransform())
 | 
			
		||||
        .into(object : BitmapImageViewTarget(iv) {
 | 
			
		||||
            override fun setResource(resource: Bitmap?) {
 | 
			
		||||
@@ -41,26 +34,6 @@ fun Context.circularBitmapDrawable(config: Config, url: String, iv: ImageView) =
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
 | 
			
		||||
fun RequestBuilder<Bitmap>.loadMaybeBasicAuth(config: Config, url: String): RequestBuilder<Bitmap> {
 | 
			
		||||
    val builder: LazyHeaders.Builder = LazyHeaders.Builder()
 | 
			
		||||
    if (config.httpUserLogin.isNotEmpty() || config.httpUserPassword.isNotEmpty()) {
 | 
			
		||||
        val basicAuth = "Basic " + Base64.encodeToString("${config.httpUserLogin}:${config.httpUserPassword}".toByteArray(), Base64.NO_WRAP)
 | 
			
		||||
        builder.addHeader("Authorization", basicAuth)
 | 
			
		||||
    }
 | 
			
		||||
    val glideUrl = GlideUrl(url, builder.build())
 | 
			
		||||
    return this.load(glideUrl)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fun RequestManager.loadMaybeBasicAuth(config: Config, url: String): RequestBuilder<Drawable> {
 | 
			
		||||
    val builder: LazyHeaders.Builder = LazyHeaders.Builder()
 | 
			
		||||
    if (config.httpUserLogin.isNotEmpty() || config.httpUserPassword.isNotEmpty()) {
 | 
			
		||||
        val basicAuth = "Basic " + Base64.encodeToString("${config.httpUserLogin}:${config.httpUserPassword}".toByteArray(), Base64.NO_WRAP)
 | 
			
		||||
        builder.addHeader("Authorization", basicAuth)
 | 
			
		||||
    }
 | 
			
		||||
    val glideUrl = GlideUrl(url, builder.build())
 | 
			
		||||
    return this.load(glideUrl)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fun getBitmapInputStream(bitmap:Bitmap,compressFormat: Bitmap.CompressFormat): InputStream {
 | 
			
		||||
    val byteArrayOutputStream = ByteArrayOutputStream()
 | 
			
		||||
    bitmap.compress(compressFormat, 80, byteArrayOutputStream)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,33 +0,0 @@
 | 
			
		||||
package bou.amine.apps.readerforselfossv2.android.utils.glide
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.utils.Config
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.utils.getUnsafeHttpClient
 | 
			
		||||
import com.bumptech.glide.Glide
 | 
			
		||||
import com.bumptech.glide.GlideBuilder
 | 
			
		||||
import com.bumptech.glide.Registry
 | 
			
		||||
import com.bumptech.glide.load.model.GlideUrl
 | 
			
		||||
import com.bumptech.glide.module.GlideModule
 | 
			
		||||
import java.io.InputStream
 | 
			
		||||
 | 
			
		||||
class SelfSignedGlideModule : GlideModule {
 | 
			
		||||
 | 
			
		||||
    override fun applyOptions(context: Context?, builder: GlideBuilder?) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun registerComponents(context: Context?, glide: Glide?, registry: Registry?) {
 | 
			
		||||
 | 
			
		||||
        if (context != null) {
 | 
			
		||||
            val pref = context?.getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
 | 
			
		||||
            if (pref.getBoolean("isSelfSignedCert", false)) {
 | 
			
		||||
                val client = getUnsafeHttpClient().build()
 | 
			
		||||
 | 
			
		||||
                registry?.append(
 | 
			
		||||
                    GlideUrl::class.java,
 | 
			
		||||
                    InputStream::class.java,
 | 
			
		||||
                    com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader.Factory(client)
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,52 +1,14 @@
 | 
			
		||||
package bou.amine.apps.readerforselfossv2.android.utils.network
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.graphics.Color
 | 
			
		||||
import android.net.ConnectivityManager
 | 
			
		||||
import android.net.NetworkCapabilities
 | 
			
		||||
import android.os.Build
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.widget.TextView
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.R
 | 
			
		||||
import com.google.android.material.snackbar.Snackbar
 | 
			
		||||
 | 
			
		||||
var snackBarShown = false
 | 
			
		||||
var view: View? = null
 | 
			
		||||
lateinit var s: Snackbar
 | 
			
		||||
 | 
			
		||||
fun Context.isNetworkAvailable(
 | 
			
		||||
    v: View? = null,
 | 
			
		||||
    overrideOffline: Boolean = false
 | 
			
		||||
): Boolean {
 | 
			
		||||
    val networkIsAccessible = isNetworkAccessible(this)
 | 
			
		||||
 | 
			
		||||
    if (v != null && (!networkIsAccessible || overrideOffline) && (!snackBarShown || v != view)) {
 | 
			
		||||
        view = v
 | 
			
		||||
        s = Snackbar
 | 
			
		||||
            .make(
 | 
			
		||||
                v,
 | 
			
		||||
                R.string.no_network_connectivity,
 | 
			
		||||
                Snackbar.LENGTH_INDEFINITE
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
        s.setAction(android.R.string.ok) {
 | 
			
		||||
            snackBarShown = false
 | 
			
		||||
            s.dismiss()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        val view = s.view
 | 
			
		||||
        val tv: TextView = view.findViewById(com.google.android.material.R.id.snackbar_text)
 | 
			
		||||
        tv.setTextColor(Color.WHITE)
 | 
			
		||||
        s.show()
 | 
			
		||||
        snackBarShown = true
 | 
			
		||||
    }
 | 
			
		||||
    if (snackBarShown && networkIsAccessible && !overrideOffline) {
 | 
			
		||||
        s.dismiss()
 | 
			
		||||
    }
 | 
			
		||||
    return if(overrideOffline) overrideOffline else networkIsAccessible
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
private fun isNetworkAccessible(context: Context): Boolean {
 | 
			
		||||
fun isNetworkAccessible(context: Context): Boolean {
 | 
			
		||||
    val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
 | 
			
		||||
 | 
			
		||||
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,72 +0,0 @@
 | 
			
		||||
package bou.amine.apps.readerforselfossv2.android.utils.persistence
 | 
			
		||||
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.model.getSourceTitle
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.model.getTitleDecoded
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.entities.AndroidItemEntity
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.entities.SourceEntity
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.persistence.entities.TagEntity
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.rest.SelfossModel
 | 
			
		||||
 | 
			
		||||
fun TagEntity.toView(): SelfossModel.Tag =
 | 
			
		||||
        SelfossModel.Tag(
 | 
			
		||||
            this.tag,
 | 
			
		||||
            this.color,
 | 
			
		||||
            this.unread
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
fun SourceEntity.toView(): SelfossModel.Source =
 | 
			
		||||
        SelfossModel.Source(
 | 
			
		||||
            this.id.toInt(),
 | 
			
		||||
            this.title,
 | 
			
		||||
            this.tags.split(","),
 | 
			
		||||
            this.spout,
 | 
			
		||||
            this.error,
 | 
			
		||||
            this.icon
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
fun SelfossModel.Source.toEntity(): SourceEntity =
 | 
			
		||||
        SourceEntity(
 | 
			
		||||
            this.id.toString(),
 | 
			
		||||
            this.getTitleDecoded(),
 | 
			
		||||
            this.tags.joinToString(","),
 | 
			
		||||
            this.spout,
 | 
			
		||||
            this.error,
 | 
			
		||||
            this.icon.orEmpty()
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
fun SelfossModel.Tag.toEntity(): TagEntity =
 | 
			
		||||
        TagEntity(
 | 
			
		||||
            this.tag,
 | 
			
		||||
            this.color,
 | 
			
		||||
            this.unread
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
fun AndroidItemEntity.toView(): SelfossModel.Item =
 | 
			
		||||
        SelfossModel.Item(
 | 
			
		||||
            this.id.toInt(),
 | 
			
		||||
            this.datetime,
 | 
			
		||||
            this.title,
 | 
			
		||||
            this.content,
 | 
			
		||||
            this.unread,
 | 
			
		||||
            this.starred,
 | 
			
		||||
            this.thumbnail,
 | 
			
		||||
            this.icon,
 | 
			
		||||
            this.link,
 | 
			
		||||
            this.sourcetitle,
 | 
			
		||||
            this.tags.split(",")
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
fun SelfossModel.Item.toEntity(): AndroidItemEntity =
 | 
			
		||||
    AndroidItemEntity(
 | 
			
		||||
        this.id.toString(),
 | 
			
		||||
        this.datetime,
 | 
			
		||||
        this.getTitleDecoded(),
 | 
			
		||||
        this.content,
 | 
			
		||||
        this.unread,
 | 
			
		||||
        this.starred,
 | 
			
		||||
        this.thumbnail,
 | 
			
		||||
        this.icon,
 | 
			
		||||
        this.link,
 | 
			
		||||
        this.getSourceTitle(),
 | 
			
		||||
        this.tags.joinToString(",")
 | 
			
		||||
    )
 | 
			
		||||
@@ -0,0 +1,30 @@
 | 
			
		||||
package bou.amine.apps.readerforselfossv2.android.viewmodel
 | 
			
		||||
 | 
			
		||||
import androidx.lifecycle.ViewModel
 | 
			
		||||
import androidx.lifecycle.viewModelScope
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.repository.Repository
 | 
			
		||||
import kotlinx.coroutines.flow.MutableSharedFlow
 | 
			
		||||
import kotlinx.coroutines.flow.asSharedFlow
 | 
			
		||||
import kotlinx.coroutines.launch
 | 
			
		||||
 | 
			
		||||
class AppViewModel(private val repository: Repository) : ViewModel() {
 | 
			
		||||
    private val _networkAvailableProvider = MutableSharedFlow<Boolean>()
 | 
			
		||||
    val networkAvailableProvider = _networkAvailableProvider.asSharedFlow()
 | 
			
		||||
    private var wasConnected = true
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        viewModelScope.launch {
 | 
			
		||||
            repository.isConnectionAvailable.collect { isConnected ->
 | 
			
		||||
                if (repository.connectionMonitored) {
 | 
			
		||||
                    if (isConnected && !wasConnected && repository.connectionMonitored) {
 | 
			
		||||
                        _networkAvailableProvider.emit(true)
 | 
			
		||||
                        wasConnected = true
 | 
			
		||||
                    } else if (!isConnected && wasConnected && repository.connectionMonitored){
 | 
			
		||||
                        _networkAvailableProvider.emit(false)
 | 
			
		||||
                        wasConnected = false
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 406 B  | 
@@ -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="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,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="M12,3c-4.97,0 -9,4.03 -9,9s4.03,9 9,9c0.83,0 1.5,-0.67 1.5,-1.5 0,-0.39 -0.15,-0.74 -0.39,-1.01 -0.23,-0.26 -0.38,-0.61 -0.38,-0.99 0,-0.83 0.67,-1.5 1.5,-1.5L16,16c2.76,0 5,-2.24 5,-5 0,-4.42 -4.03,-8 -9,-8zM6.5,12c-0.83,0 -1.5,-0.67 -1.5,-1.5S5.67,9 6.5,9 8,9.67 8,10.5 7.33,12 6.5,12zM9.5,8C8.67,8 8,7.33 8,6.5S8.67,5 9.5,5s1.5,0.67 1.5,1.5S10.33,8 9.5,8zM14.5,8c-0.83,0 -1.5,-0.67 -1.5,-1.5S13.67,5 14.5,5s1.5,0.67 1.5,1.5S15.33,8 14.5,8zM17.5,12c-0.83,0 -1.5,-0.67 -1.5,-1.5S16.67,9 17.5,9s1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5z"/>
 | 
			
		||||
</vector>
 | 
			
		||||
@@ -82,45 +82,6 @@
 | 
			
		||||
                    android:maxLines="1"
 | 
			
		||||
                    android:visibility="gone" />
 | 
			
		||||
 | 
			
		||||
                <com.google.android.material.switchmaterial.SwitchMaterial
 | 
			
		||||
                    android:id="@+id/withHttpLogin"
 | 
			
		||||
                    android:layout_width="match_parent"
 | 
			
		||||
                    android:layout_height="wrap_content"
 | 
			
		||||
                    android:layout_weight="1"
 | 
			
		||||
                    android:text="@string/withHttpLoginSwitch" />
 | 
			
		||||
 | 
			
		||||
                <EditText
 | 
			
		||||
                    android:id="@+id/httpLoginView"
 | 
			
		||||
                    android:layout_width="match_parent"
 | 
			
		||||
                    android:layout_height="wrap_content"
 | 
			
		||||
                    android:autofillHints="username"
 | 
			
		||||
                    android:hint="@string/prompt_http_login"
 | 
			
		||||
                    android:inputType="text"
 | 
			
		||||
                    android:visibility="gone" />
 | 
			
		||||
 | 
			
		||||
                <EditText
 | 
			
		||||
                    android:id="@+id/httpPasswordView"
 | 
			
		||||
                    android:layout_width="match_parent"
 | 
			
		||||
                    android:layout_height="wrap_content"
 | 
			
		||||
                    android:autofillHints="password"
 | 
			
		||||
                    android:hint="@string/prompt_http_password"
 | 
			
		||||
                    android:inputType="textPassword"
 | 
			
		||||
                    android:visibility="gone" />
 | 
			
		||||
 | 
			
		||||
                <com.google.android.material.switchmaterial.SwitchMaterial
 | 
			
		||||
                    android:id="@+id/withSelfhostedCert"
 | 
			
		||||
                    android:layout_width="match_parent"
 | 
			
		||||
                    android:layout_height="wrap_content"
 | 
			
		||||
                    android:text="@string/self_hosted_cert_switch" />
 | 
			
		||||
 | 
			
		||||
                <TextView
 | 
			
		||||
                    android:id="@+id/warningText"
 | 
			
		||||
                    android:layout_width="match_parent"
 | 
			
		||||
                    android:layout_height="wrap_content"
 | 
			
		||||
                    android:text="@string/self_signed_cert_warning"
 | 
			
		||||
                    android:textAppearance="@style/TextAppearance.AppCompat.Medium"
 | 
			
		||||
                    android:visibility="gone" />
 | 
			
		||||
 | 
			
		||||
                <Button
 | 
			
		||||
                    android:id="@+id/signInButton"
 | 
			
		||||
                    style="?android:textAppearanceSmall"
 | 
			
		||||
 
 | 
			
		||||
@@ -3,16 +3,13 @@
 | 
			
		||||
    <string name="app_name">"Lector per a Selfoss"</string>
 | 
			
		||||
    <string name="title_activity_login">"Inicia la sessió"</string>
 | 
			
		||||
    <string name="prompt_password">"Contrasenya"</string>
 | 
			
		||||
    <string name="prompt_http_password">"Contrasenya HTTP"</string>
 | 
			
		||||
    <string name="action_sign_in">"Vés-hi"</string>
 | 
			
		||||
    <string name="error_invalid_password">"La contrasenya és massa curta"</string>
 | 
			
		||||
    <string name="error_field_required">"Camp necessari"</string>
 | 
			
		||||
    <string name="prompt_url">"URL"</string>
 | 
			
		||||
    <string name="withLoginSwitch">"Autenticació (si és necessària)"</string>
 | 
			
		||||
    <string name="withHttpLoginSwitch">"Autenticació HTTP (si és necessària)"</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_http_login">"Nom d'usuari HTTP"</string>
 | 
			
		||||
    <string name="label_share">"Comparteix"</string>
 | 
			
		||||
    <string name="readAll">"Llegeix-ho tot"</string>
 | 
			
		||||
    <string name="action_disconnect">"Desconnecta't"</string>
 | 
			
		||||
@@ -26,9 +23,6 @@
 | 
			
		||||
    <string name="wrong_infos">"Torneu a comprovar la informació."</string>
 | 
			
		||||
    <string name="all_posts_not_read">"No s'han llegit totes les publicacions"</string>
 | 
			
		||||
    <string name="all_posts_read">"S'han llegit totes les publicacions"</string>
 | 
			
		||||
    <string name="cant_get_favs">"No es poden obtenir preferits"</string>
 | 
			
		||||
    <string name="cant_get_new_elements">"No es pot accedir als articles nous"</string>
 | 
			
		||||
    <string name="cant_get_read">"No es poden llegir els articles"</string>
 | 
			
		||||
    <string name="nothing_here">"No hi ha res"</string>
 | 
			
		||||
    <string name="tab_new">"Nou"</string>
 | 
			
		||||
    <string name="tab_read">"Tot"</string>
 | 
			
		||||
@@ -40,26 +34,15 @@
 | 
			
		||||
    <string name="addStringNoUrl">"Inicieu la sessió per afegir fonts."</string>
 | 
			
		||||
    <string name="cant_get_sources">"No es pot obtenir la llista de fonts."</string>
 | 
			
		||||
    <string name="cant_create_source">"No es pot crear la font."</string>
 | 
			
		||||
    <string name="cant_get_spouts">"No es pot obtenir la llista de canals."</string>
 | 
			
		||||
    <string name="cant_get_spouts_no_network">"Can't get spouts list because of a network issue."</string>
 | 
			
		||||
    <string name="cant_get_spouts">"Can't get spouts list. There may ben an api issue."</string>
 | 
			
		||||
    <string name="form_not_complete">"El formulari no està complet"</string>
 | 
			
		||||
    <string name="pref_header_links">"Enllaços"</string>
 | 
			
		||||
    <string name="issue_tracker_link">"Detector de problemes"</string>
 | 
			
		||||
    <string name="issue_tracker_summary">"Informa d'un error o pregunta sobre funcions noves"</string>
 | 
			
		||||
    <string name="warning_wrong_url">"ADVERTÈNCIA"</string>
 | 
			
		||||
    <string name="pref_switch_card_view_title">"Visualització de targeta"</string>
 | 
			
		||||
    <string name="cant_mark_favortie">"No es pot marcar l'article com a preferit"</string>
 | 
			
		||||
    <string name="cant_unmark_favortie">"No es pot treure l'element de preferits"</string>
 | 
			
		||||
    <string name="share">"Comparteix"</string>
 | 
			
		||||
    <string name="rating_prompt_title">"Us agrada l'aplicació?"</string>
 | 
			
		||||
    <string name="rating_prompt_yes">"Sí."</string>
 | 
			
		||||
    <string name="rating_prompt_no">"No gaire…"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_title">"Ens podeu dir per què?"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_yes">"D'acord."</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_no">"Ara no."</string>
 | 
			
		||||
    <string name="rating_prompt_rating_title">"Perfecte! Ens podeu puntuar a la Botiga?"</string>
 | 
			
		||||
    <string name="rating_prompt_rating_yes">"Sí."</string>
 | 
			
		||||
    <string name="rating_prompt_rating_no">"Ara no."</string>
 | 
			
		||||
    <string name="rating_prompt_thanks">"Gràcies. La vostra opinió ens ajuda a millorar l'aplicació."</string>
 | 
			
		||||
    <string name="switch_unread_count">"Mostra el recompte d'articles no llegits amb un distintiu a la barra inferior."</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>
 | 
			
		||||
@@ -82,17 +65,12 @@
 | 
			
		||||
    <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="source_code">Codi font</string>
 | 
			
		||||
    <string name="cant_mark_read">No es pot marcar l\'article com a llegit</string>
 | 
			
		||||
    <string name="cant_mark_unread">Can\'t mark article as unread</string>
 | 
			
		||||
    <string name="drawer_error_loading_tags">S\'ha produït un error en carregar les etiquetes</string>
 | 
			
		||||
    <string name="drawer_error_loading_sources">S\'ha produït un error en carregar les fonts</string>
 | 
			
		||||
    <string name="drawer_item_filters">Filtres</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="no_tags_loaded">No s\'ha carregat cap etiqueta</string>
 | 
			
		||||
    <string name="no_sources_loaded">No s\'ha carregat cap font</string>
 | 
			
		||||
    <string name="drawer_loading">S\'està carregant…</string>
 | 
			
		||||
    <string name="menu_home_search">Cerca</string>
 | 
			
		||||
    <string name="can_delete_source">No es pot suprimir la font</string>
 | 
			
		||||
@@ -100,16 +78,9 @@
 | 
			
		||||
    <string name="pref_header_theme">Temes</string>
 | 
			
		||||
    <string name="default_theme">Predeterminat</string>
 | 
			
		||||
    <string name="default_dark_theme">Predeterminat/Fosc</string>
 | 
			
		||||
    <string name="pref_header_debug">Depuració</string>
 | 
			
		||||
    <string name="self_hosted_cert_switch">Utilitzeu un certificat autoallotjat?</string>
 | 
			
		||||
    <string name="self_signed_cert_warning">Per raons de seguretat, els certificats autosignats no seran compatibles per defecte. En activar aquesta opció, sereu responsable de qualsevol problema de seguretat que es pugui produir.</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_hidden_tags">Etiquetes ocultes</string>
 | 
			
		||||
    <string name="summary_debug_identifier">Identificador de depuració</string>
 | 
			
		||||
    <string name="unique_id_to_clipboard">S\'ha copiat l\'identificador al porta-retalls</string>
 | 
			
		||||
    <string name="display_header_drawer_summary">Mostra una capçalera amb la instància URL de Selfoss al panell lateral.</string>
 | 
			
		||||
    <string name="display_header_drawer_title">Capçalera de menú</string>
 | 
			
		||||
    <string name="pref_general_infinite_loading_title">Carrega articles en desplaçar</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>
 | 
			
		||||
@@ -120,19 +91,12 @@
 | 
			
		||||
    <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="add_to_favs_reader">Afegeix als preferits</string>
 | 
			
		||||
    <string name="remove_to_favs_reader">Suprimeix dels preferits</string>
 | 
			
		||||
    <string name="pref_content_reader_font_size">Mida de la lletra del lector d’articles</string>
 | 
			
		||||
    <string name="pref_header_viewer">Visualitzador d\'articles</string>
 | 
			
		||||
    <string name="refresh_dialog_message">Aquesta acció actualitzarà la vostra instància de Selfoss.</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_off">No es marcaran els articles com a llegits en lliscar el dit d\'un article a l\'altre.</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept">Envia informes d\'error automàtics</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept_enabled">S\'enviaran informes d\'error automàticament</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept_disabled">Us preguntarem abans d\'enviar un informe d\'error.</string>
 | 
			
		||||
    <string name="pref_debug_crash_reports">Informes d\'error</string>
 | 
			
		||||
    <string name="pref_debug_debug_logs">Registre de depuració (s\'enviarà automàticament)</string>
 | 
			
		||||
    <string name="acra_login">Habilita el registre</string>
 | 
			
		||||
    <string name="drawer_item_hidden_tags">Etiquetes ocultes</string>
 | 
			
		||||
    <string name="unmark">Marca com no llegit</string>
 | 
			
		||||
    <string name="pref_header_offline">Sense connexió i memòria clau</string>
 | 
			
		||||
@@ -141,7 +105,8 @@
 | 
			
		||||
    <string name="pref_switch_items_caching">Guarda els elements per utilitzar-los sense connexió</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="no_network_connectivity">Sense connexió!</string>
 | 
			
		||||
    <string name="network_connectivity_lost">"Network connection lost"</string>
 | 
			
		||||
    <string name="network_connectivity_retrieved">"Network connection is now available"</string>
 | 
			
		||||
    <string name="pref_switch_periodic_refresh">Sincronitza els articles</string>
 | 
			
		||||
    <string name="pref_switch_periodic_refresh_off">Els articles no se sincronitzaran en segon pla</string>
 | 
			
		||||
    <string name="pref_switch_periodic_refresh_on">Els articles se sincronitzaran periòdicament</string>
 | 
			
		||||
 
 | 
			
		||||
@@ -3,16 +3,13 @@
 | 
			
		||||
    <string name="app_name">"Reader für selfoss"</string>
 | 
			
		||||
    <string name="title_activity_login">"Anmelden"</string>
 | 
			
		||||
    <string name="prompt_password">"Passwort"</string>
 | 
			
		||||
    <string name="prompt_http_password">"HTTP Passwort"</string>
 | 
			
		||||
    <string name="action_sign_in">"Fortfahren"</string>
 | 
			
		||||
    <string name="error_invalid_password">"Passwort ist nicht lang genug"</string>
 | 
			
		||||
    <string name="error_field_required">"Pflichtfeld"</string>
 | 
			
		||||
    <string name="prompt_url">"URL"</string>
 | 
			
		||||
    <string name="withLoginSwitch">"Anmeldung erforderlich?"</string>
 | 
			
		||||
    <string name="withHttpLoginSwitch">"HTTP Anmeldung erforderlich?"</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_http_login">"HTTP Benutzername"</string>
 | 
			
		||||
    <string name="label_share">"Teilen"</string>
 | 
			
		||||
    <string name="readAll">"Alle gelesen"</string>
 | 
			
		||||
    <string name="action_disconnect">"Verbindung trennen"</string>
 | 
			
		||||
@@ -26,9 +23,6 @@
 | 
			
		||||
    <string name="wrong_infos">"Überprüfe deine Angaben noch einmal."</string>
 | 
			
		||||
    <string name="all_posts_not_read">"Nicht alle Beiträge wurden gelesen"</string>
 | 
			
		||||
    <string name="all_posts_read">"Alle Beiträge wurden gelesen"</string>
 | 
			
		||||
    <string name="cant_get_favs">"Favoriten können nicht abgerufen werden"</string>
 | 
			
		||||
    <string name="cant_get_new_elements">"Neue Artikel können nicht abgerufen werden"</string>
 | 
			
		||||
    <string name="cant_get_read">"Gelese Artikel können nicht abgerufen werden"</string>
 | 
			
		||||
    <string name="nothing_here">"Keine Einträge vorhanden"</string>
 | 
			
		||||
    <string name="tab_new">"Neu"</string>
 | 
			
		||||
    <string name="tab_read">"Alle"</string>
 | 
			
		||||
@@ -40,26 +34,15 @@
 | 
			
		||||
    <string name="addStringNoUrl">"Melde dich an um Quellen hinzuzufügen."</string>
 | 
			
		||||
    <string name="cant_get_sources">"Quellen können nicht abgerufen werden."</string>
 | 
			
		||||
    <string name="cant_create_source">"Quelle kann nicht gespeichert werden."</string>
 | 
			
		||||
    <string name="cant_get_spouts">"Can't get spouts list."</string>
 | 
			
		||||
    <string name="cant_get_spouts_no_network">"Can't get spouts list because of a network issue."</string>
 | 
			
		||||
    <string name="cant_get_spouts">"Can't get spouts list. There may ben an api issue."</string>
 | 
			
		||||
    <string name="form_not_complete">"Das Formular ist nicht vollständig"</string>
 | 
			
		||||
    <string name="pref_header_links">"Links"</string>
 | 
			
		||||
    <string name="issue_tracker_link">"Issue Tracker"</string>
 | 
			
		||||
    <string name="issue_tracker_summary">"Melde einen Bug oder rege ein neues Feature an"</string>
 | 
			
		||||
    <string name="warning_wrong_url">"WARNUNG"</string>
 | 
			
		||||
    <string name="pref_switch_card_view_title">"Kachelansicht"</string>
 | 
			
		||||
    <string name="cant_mark_favortie">"Artikel kann nicht als Favorit markiert werden"</string>
 | 
			
		||||
    <string name="cant_unmark_favortie">"Eintrag kann nicht aus Favoriten entfernt werden"</string>
 | 
			
		||||
    <string name="share">"Teilen"</string>
 | 
			
		||||
    <string name="rating_prompt_title">"Gefällt Dir die App?"</string>
 | 
			
		||||
    <string name="rating_prompt_yes">"Ja!"</string>
 | 
			
		||||
    <string name="rating_prompt_no">"Nicht wirklich…"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_title">"Magst du uns sagen warum?"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_yes">"OK!"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_no">"Nicht jetzt."</string>
 | 
			
		||||
    <string name="rating_prompt_rating_title">"Wunderbar! Magst du uns im Play Store bewerten?"</string>
 | 
			
		||||
    <string name="rating_prompt_rating_yes">"Sicher!"</string>
 | 
			
		||||
    <string name="rating_prompt_rating_no">"Nicht jetzt."</string>
 | 
			
		||||
    <string name="rating_prompt_thanks">"Vielen Dank, dein Feedback hilft die App zu verbessern!"</string>
 | 
			
		||||
    <string name="switch_unread_count">"Zeige die Zahl ungelesener Artikel in der unteren Leiste."</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>
 | 
			
		||||
@@ -82,17 +65,12 @@
 | 
			
		||||
    <string name="card_height_on">Kartenhöhe passt sich Inhalt an</string>
 | 
			
		||||
    <string name="card_height_off">Kartenhöhe ist fix</string>
 | 
			
		||||
    <string name="source_code">Quellcode</string>
 | 
			
		||||
    <string name="cant_mark_read">Artikel kann nicht als gelesen markiert werden</string>
 | 
			
		||||
    <string name="cant_mark_unread">Can\'t mark article as unread</string>
 | 
			
		||||
    <string name="drawer_error_loading_tags">Fehler beim Laden der Tags…</string>
 | 
			
		||||
    <string name="drawer_error_loading_sources">Fehler beim Laden der Quellen…</string>
 | 
			
		||||
    <string name="drawer_item_filters">Filter</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="no_tags_loaded">No tags loaded</string>
 | 
			
		||||
    <string name="no_sources_loaded">Keine Quellen geladen</string>
 | 
			
		||||
    <string name="drawer_loading">Lade…</string>
 | 
			
		||||
    <string name="menu_home_search">Suche</string>
 | 
			
		||||
    <string name="can_delete_source">Can\'t delete the source…</string>
 | 
			
		||||
@@ -100,16 +78,9 @@
 | 
			
		||||
    <string name="pref_header_theme">Designs</string>
 | 
			
		||||
    <string name="default_theme">Standard</string>
 | 
			
		||||
    <string name="default_dark_theme">Standard (Dunkel)</string>
 | 
			
		||||
    <string name="pref_header_debug">Debug</string>
 | 
			
		||||
    <string name="self_hosted_cert_switch">Verwenden Sie einen selbst gehostetes Zertifikat?</string>
 | 
			
		||||
    <string name="self_signed_cert_warning">Due to security reasons, self signed certificates are not supported by default. By activating this, I\'ll not be responsible of any security problem you encounter.</string>
 | 
			
		||||
    <string name="pref_selfoss_category">selfoss API</string>
 | 
			
		||||
    <string name="pref_api_items_number_title">Loaded items number</string>
 | 
			
		||||
    <string name="pref_hidden_tags">Hidden Tags</string>
 | 
			
		||||
    <string name="summary_debug_identifier">Debug identifier</string>
 | 
			
		||||
    <string name="unique_id_to_clipboard">Identifier copied to your clipboard</string>
 | 
			
		||||
    <string name="display_header_drawer_summary">Display a header with the selfoss instance url on the lateral drawer.</string>
 | 
			
		||||
    <string name="display_header_drawer_title">Account header</string>
 | 
			
		||||
    <string name="pref_general_infinite_loading_title">Load more articles on scroll</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>
 | 
			
		||||
@@ -120,19 +91,12 @@
 | 
			
		||||
    <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="add_to_favs_reader">Zu Favoriten hinzufügen</string>
 | 
			
		||||
    <string name="remove_to_favs_reader">Aus Favoriten entfernen</string>
 | 
			
		||||
    <string name="pref_content_reader_font_size">Article reader content font size</string>
 | 
			
		||||
    <string name="pref_header_viewer">Article viewer</string>
 | 
			
		||||
    <string name="refresh_dialog_message">This will refresh your Selfoss instance.</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_off">Don\'t mark articles as read when swiping.</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept">Automatically send crash reports</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept_enabled">Fehlerberichte werden automatisch gesendet</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept_disabled">Will ask everytime when sending crash reports.</string>
 | 
			
		||||
    <string name="pref_debug_crash_reports">Fehlerberichte</string>
 | 
			
		||||
    <string name="pref_debug_debug_logs">Debug logging (these will be sent without a dialog)</string>
 | 
			
		||||
    <string name="acra_login">Protokollierung aktivieren</string>
 | 
			
		||||
    <string name="drawer_item_hidden_tags">Hidden Tags</string>
 | 
			
		||||
    <string name="unmark">Eintrag als ungelesen markieren</string>
 | 
			
		||||
    <string name="pref_header_offline">Offline and cache</string>
 | 
			
		||||
@@ -141,7 +105,8 @@
 | 
			
		||||
    <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_summary">Disable this if your server is receiving excessive amounts of database queries.</string>
 | 
			
		||||
    <string name="no_network_connectivity">Nicht verbunden !</string>
 | 
			
		||||
    <string name="network_connectivity_lost">"Die Netzwerkverbindung wurde unterbrochen"</string>
 | 
			
		||||
    <string name="network_connectivity_retrieved">"Netzwerkverbindung ist jetzt verfügbar"</string>
 | 
			
		||||
    <string name="pref_switch_periodic_refresh">Synchronisiere Artikel</string>
 | 
			
		||||
    <string name="pref_switch_periodic_refresh_off">Artikel werden nicht im Hintergrund synchronisiert</string>
 | 
			
		||||
    <string name="pref_switch_periodic_refresh_on">Die Artikel werden regelmäßig synchronisiert</string>
 | 
			
		||||
 
 | 
			
		||||
@@ -3,16 +3,13 @@
 | 
			
		||||
    <string name="app_name">"Lector para Selfoss"</string>
 | 
			
		||||
    <string name="title_activity_login">"Iniciar sesión"</string>
 | 
			
		||||
    <string name="prompt_password">"Contraseña"</string>
 | 
			
		||||
    <string name="prompt_http_password">"Contraseña HTTP"</string>
 | 
			
		||||
    <string name="action_sign_in">"Empezar"</string>
 | 
			
		||||
    <string name="error_invalid_password">"La contraseña no es suficientemente larga"</string>
 | 
			
		||||
    <string name="error_field_required">"Campo requerido"</string>
 | 
			
		||||
    <string name="prompt_url">"Url"</string>
 | 
			
		||||
    <string name="withLoginSwitch">"Inicio de sesión requerido ?"</string>
 | 
			
		||||
    <string name="withHttpLoginSwitch">"Inicio de sesión HTTP requerido ?"</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_http_login">"Nombre de usuario HTTP"</string>
 | 
			
		||||
    <string name="label_share">"Compartir"</string>
 | 
			
		||||
    <string name="readAll">"Leer todo"</string>
 | 
			
		||||
    <string name="action_disconnect">"Desconectar"</string>
 | 
			
		||||
@@ -26,9 +23,6 @@
 | 
			
		||||
    <string name="wrong_infos">"Revise sus datos de nuevo."</string>
 | 
			
		||||
    <string name="all_posts_not_read">"No todas las publicaciones fueron leídas"</string>
 | 
			
		||||
    <string name="all_posts_read">"Todas las publicaciones fueron leídas"</string>
 | 
			
		||||
    <string name="cant_get_favs">"No se pueden obtener favoritos"</string>
 | 
			
		||||
    <string name="cant_get_new_elements">"No puede recibir nuevos artículos"</string>
 | 
			
		||||
    <string name="cant_get_read">"No puede recibir artículos leídos"</string>
 | 
			
		||||
    <string name="nothing_here">"Nada aquí"</string>
 | 
			
		||||
    <string name="tab_new">"Nuevo"</string>
 | 
			
		||||
    <string name="tab_read">"Todo"</string>
 | 
			
		||||
@@ -40,26 +34,15 @@
 | 
			
		||||
    <string name="addStringNoUrl">"Iniciar sesión para añadir fuentes."</string>
 | 
			
		||||
    <string name="cant_get_sources">"No se puede obtener la lista de fuentes."</string>
 | 
			
		||||
    <string name="cant_create_source">"No se puede crear la fuente."</string>
 | 
			
		||||
    <string name="cant_get_spouts">"No se puede obtener la lista de fuentes."</string>
 | 
			
		||||
    <string name="cant_get_spouts_no_network">"Can't get spouts list because of a network issue."</string>
 | 
			
		||||
    <string name="cant_get_spouts">"Can't get spouts list. There may ben an api issue."</string>
 | 
			
		||||
    <string name="form_not_complete">"El formulario no está completo"</string>
 | 
			
		||||
    <string name="pref_header_links">"Enlaces"</string>
 | 
			
		||||
    <string name="issue_tracker_link">"Rastreador de Incidencias"</string>
 | 
			
		||||
    <string name="issue_tracker_summary">"Reportar un error o solicitar una nueva función"</string>
 | 
			
		||||
    <string name="warning_wrong_url">"ADVERTENCIA"</string>
 | 
			
		||||
    <string name="pref_switch_card_view_title">"Vista de la tarjeta"</string>
 | 
			
		||||
    <string name="cant_mark_favortie">"No puede marcar el artículo como favorito"</string>
 | 
			
		||||
    <string name="cant_unmark_favortie">"No se puede quitar el artículo de favoritos"</string>
 | 
			
		||||
    <string name="share">"Compartir"</string>
 | 
			
		||||
    <string name="rating_prompt_title">"¿Disfrutando la aplicación?"</string>
 | 
			
		||||
    <string name="rating_prompt_yes">"¡Sí!"</string>
 | 
			
		||||
    <string name="rating_prompt_no">"La verdad es que no…"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_title">"¿Puede decirnos por qué?"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_yes">"¡Vale!"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_no">"Ahora no."</string>
 | 
			
		||||
    <string name="rating_prompt_rating_title">"¡Excelente! ¿Puede valorarnos en la tienda?"</string>
 | 
			
		||||
    <string name="rating_prompt_rating_yes">"¡Claro!"</string>
 | 
			
		||||
    <string name="rating_prompt_rating_no">"No en este momento."</string>
 | 
			
		||||
    <string name="rating_prompt_thanks">"¡Gracias, sus comentarios ayudan a mejorar la aplicación!"</string>
 | 
			
		||||
    <string name="switch_unread_count">"Mostrar el recuento no leído como una insignia de la barra inferior."</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>
 | 
			
		||||
@@ -82,17 +65,12 @@
 | 
			
		||||
    <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="source_code">Código fuente</string>
 | 
			
		||||
    <string name="cant_mark_read">No puede marcar el artículo como leído</string>
 | 
			
		||||
    <string name="cant_mark_unread">No se puede marcar el artículo como no leído</string>
 | 
			
		||||
    <string name="drawer_error_loading_tags">Error al cargar etiquetas…</string>
 | 
			
		||||
    <string name="drawer_error_loading_sources">Error al cargar fuentes…</string>
 | 
			
		||||
    <string name="drawer_item_filters">Filtros</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="no_tags_loaded">No hay etiquetas cargadas</string>
 | 
			
		||||
    <string name="no_sources_loaded">No hay fuentes cargadas</string>
 | 
			
		||||
    <string name="drawer_loading">Cargando…</string>
 | 
			
		||||
    <string name="menu_home_search">Buscar</string>
 | 
			
		||||
    <string name="can_delete_source">No se puede eliminar la fuente…</string>
 | 
			
		||||
@@ -100,16 +78,9 @@
 | 
			
		||||
    <string name="pref_header_theme">Temas</string>
 | 
			
		||||
    <string name="default_theme">Predeterminado</string>
 | 
			
		||||
    <string name="default_dark_theme">Predeterminado/Oscuro</string>
 | 
			
		||||
    <string name="pref_header_debug">Depurar</string>
 | 
			
		||||
    <string name="self_hosted_cert_switch">Utilizando un certificado alojado propiamente ?</string>
 | 
			
		||||
    <string name="self_signed_cert_warning">Por razones de seguridad, los certificados propios no son compatibles por defecto. Activando esto, no seré responsable de cualquier problema de seguridad que encuentre.</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_hidden_tags">Etiquetas ocultas</string>
 | 
			
		||||
    <string name="summary_debug_identifier">Identificador de depuración</string>
 | 
			
		||||
    <string name="unique_id_to_clipboard">Identificador copiado a su portapapeles</string>
 | 
			
		||||
    <string name="display_header_drawer_summary">Mostrar una cabecera con la url de instancia de selfoss en el cajón lateral.</string>
 | 
			
		||||
    <string name="display_header_drawer_title">Cabecera de cuenta</string>
 | 
			
		||||
    <string name="pref_general_infinite_loading_title">Cargar más artículos en desplazamiento</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>
 | 
			
		||||
@@ -120,19 +91,12 @@
 | 
			
		||||
    <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="add_to_favs_reader">Añadir a Favoritos</string>
 | 
			
		||||
    <string name="remove_to_favs_reader">Eliminar de favoritos</string>
 | 
			
		||||
    <string name="pref_content_reader_font_size">Tamaño de la fuente del lector</string>
 | 
			
		||||
    <string name="pref_header_viewer">Visor de artículos</string>
 | 
			
		||||
    <string name="refresh_dialog_message">Esto actualizará su instancia de Selfoss.</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_off">No marcar artículos como leídos al deslizar con el dedo hacia los lados.</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept">Enviar automáticamente informe de fallos</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept_enabled">Se enviaran automáticamente los informes de fallos</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept_disabled">Le preguntará al enviar informes de fallos.</string>
 | 
			
		||||
    <string name="pref_debug_crash_reports">Informe de fallos</string>
 | 
			
		||||
    <string name="pref_debug_debug_logs">Registro de depuración (éstos se enviarán sin diálogo)</string>
 | 
			
		||||
    <string name="acra_login">Habilitar el registro</string>
 | 
			
		||||
    <string name="drawer_item_hidden_tags">Etiquetas ocultas</string>
 | 
			
		||||
    <string name="unmark">Marcar artículo como no leído</string>
 | 
			
		||||
    <string name="pref_header_offline">Sin conexión y caché</string>
 | 
			
		||||
@@ -141,7 +105,8 @@
 | 
			
		||||
    <string name="pref_switch_items_caching">Guardar elementos para uso sin conexión</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="no_network_connectivity">Sin conexión!</string>
 | 
			
		||||
    <string name="network_connectivity_lost">"Network connection lost"</string>
 | 
			
		||||
    <string name="network_connectivity_retrieved">"Network connection is now available"</string>
 | 
			
		||||
    <string name="pref_switch_periodic_refresh">Sincronizar artículos</string>
 | 
			
		||||
    <string name="pref_switch_periodic_refresh_off">Los artículos no se sincronizarán en segundo plano</string>
 | 
			
		||||
    <string name="pref_switch_periodic_refresh_on">Los artículos se sincronizarán periódicamente</string>
 | 
			
		||||
 
 | 
			
		||||
@@ -3,16 +3,13 @@
 | 
			
		||||
    <string name="app_name">"Reader for Selfoss"</string>
 | 
			
		||||
    <string name="title_activity_login">"Log in"</string>
 | 
			
		||||
    <string name="prompt_password">"Password"</string>
 | 
			
		||||
    <string name="prompt_http_password">"HTTP Password"</string>
 | 
			
		||||
    <string name="action_sign_in">"Go"</string>
 | 
			
		||||
    <string name="error_invalid_password">"Password not long enough"</string>
 | 
			
		||||
    <string name="error_field_required">"Field required"</string>
 | 
			
		||||
    <string name="prompt_url">"Url"</string>
 | 
			
		||||
    <string name="withLoginSwitch">"Login required ?"</string>
 | 
			
		||||
    <string name="withHttpLoginSwitch">"HTTP Login required ?"</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_http_login">"HTTP Username"</string>
 | 
			
		||||
    <string name="label_share">"Share"</string>
 | 
			
		||||
    <string name="readAll">"Read all"</string>
 | 
			
		||||
    <string name="action_disconnect">"Disconnect"</string>
 | 
			
		||||
@@ -26,9 +23,6 @@
 | 
			
		||||
    <string name="wrong_infos">"Check your details again."</string>
 | 
			
		||||
    <string name="all_posts_not_read">"All posts weren't read"</string>
 | 
			
		||||
    <string name="all_posts_read">"All posts were read"</string>
 | 
			
		||||
    <string name="cant_get_favs">"Can't get favorites"</string>
 | 
			
		||||
    <string name="cant_get_new_elements">"Can't get new articles"</string>
 | 
			
		||||
    <string name="cant_get_read">"Can't get read articles"</string>
 | 
			
		||||
    <string name="nothing_here">"Nothing here"</string>
 | 
			
		||||
    <string name="tab_new">"New"</string>
 | 
			
		||||
    <string name="tab_read">"All"</string>
 | 
			
		||||
@@ -40,26 +34,15 @@
 | 
			
		||||
    <string name="addStringNoUrl">"Log in to add sources."</string>
 | 
			
		||||
    <string name="cant_get_sources">"Can't get sources list."</string>
 | 
			
		||||
    <string name="cant_create_source">"Can't create source."</string>
 | 
			
		||||
    <string name="cant_get_spouts">"Can't get spouts list."</string>
 | 
			
		||||
    <string name="cant_get_spouts_no_network">"Can't get spouts list because of a network issue."</string>
 | 
			
		||||
    <string name="cant_get_spouts">"Can't get spouts list. There may ben an api issue."</string>
 | 
			
		||||
    <string name="form_not_complete">"The form is not complete"</string>
 | 
			
		||||
    <string name="pref_header_links">"Links"</string>
 | 
			
		||||
    <string name="issue_tracker_link">"Issue Tracker"</string>
 | 
			
		||||
    <string name="issue_tracker_summary">"Report a bug or ask for a new feature"</string>
 | 
			
		||||
    <string name="warning_wrong_url">"WARNING"</string>
 | 
			
		||||
    <string name="pref_switch_card_view_title">"Card View"</string>
 | 
			
		||||
    <string name="cant_mark_favortie">"Can't mark article as favorite"</string>
 | 
			
		||||
    <string name="cant_unmark_favortie">"Can't remove item from favorite"</string>
 | 
			
		||||
    <string name="share">"Share"</string>
 | 
			
		||||
    <string name="rating_prompt_title">"Enjoying the app ?"</string>
 | 
			
		||||
    <string name="rating_prompt_yes">"Yes !"</string>
 | 
			
		||||
    <string name="rating_prompt_no">"Not really …"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_title">"Can you tell us why ?"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_yes">"OK !"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_no">"Not now."</string>
 | 
			
		||||
    <string name="rating_prompt_rating_title">"Great ! Can you rate us on the Store ?"</string>
 | 
			
		||||
    <string name="rating_prompt_rating_yes">"Sure !"</string>
 | 
			
		||||
    <string name="rating_prompt_rating_no">"Not right now."</string>
 | 
			
		||||
    <string name="rating_prompt_thanks">"Thanks, your feedback help enhance the app !"</string>
 | 
			
		||||
    <string name="switch_unread_count">"Display the unread count as a badge for the bottom bar."</string>
 | 
			
		||||
    <string name="switch_unread_count_title">"Display unread count"</string>
 | 
			
		||||
    <string name="display_all_counts_title">"Display count for favorite and read"</string>
 | 
			
		||||
@@ -82,17 +65,12 @@
 | 
			
		||||
    <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="source_code">Source code</string>
 | 
			
		||||
    <string name="cant_mark_read">Can\'t mark article as read</string>
 | 
			
		||||
    <string name="cant_mark_unread">Can\'t mark article as unread</string>
 | 
			
		||||
    <string name="drawer_error_loading_tags">Error loading tags…</string>
 | 
			
		||||
    <string name="drawer_error_loading_sources">Error loading sources…</string>
 | 
			
		||||
    <string name="drawer_item_filters">Filters</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="no_tags_loaded">No tags loaded</string>
 | 
			
		||||
    <string name="no_sources_loaded">No sources loaded</string>
 | 
			
		||||
    <string name="drawer_loading">Loading …</string>
 | 
			
		||||
    <string name="menu_home_search">Search</string>
 | 
			
		||||
    <string name="can_delete_source">Can\'t delete the source…</string>
 | 
			
		||||
@@ -100,16 +78,9 @@
 | 
			
		||||
    <string name="pref_header_theme">Themes</string>
 | 
			
		||||
    <string name="default_theme">Default</string>
 | 
			
		||||
    <string name="default_dark_theme">Default/Dark</string>
 | 
			
		||||
    <string name="pref_header_debug">Debug</string>
 | 
			
		||||
    <string name="self_hosted_cert_switch">Using a self hosted certificate ?</string>
 | 
			
		||||
    <string name="self_signed_cert_warning">Due to security reasons, self signed certificates are not supported by default. By activating this, I\'ll not be responsible of any security problem you encounter.</string>
 | 
			
		||||
    <string name="pref_selfoss_category">Selfoss Api</string>
 | 
			
		||||
    <string name="pref_api_items_number_title">Loaded items number</string>
 | 
			
		||||
    <string name="pref_hidden_tags">Hidden Tags</string>
 | 
			
		||||
    <string name="summary_debug_identifier">Debug identifier</string>
 | 
			
		||||
    <string name="unique_id_to_clipboard">Identifier copied to your clipboard</string>
 | 
			
		||||
    <string name="display_header_drawer_summary">Display a header with the selfoss instance url on the lateral drawer.</string>
 | 
			
		||||
    <string name="display_header_drawer_title">Account header</string>
 | 
			
		||||
    <string name="pref_general_infinite_loading_title">Load more articles on scroll</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>
 | 
			
		||||
@@ -120,19 +91,12 @@
 | 
			
		||||
    <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="add_to_favs_reader">Add to favorites</string>
 | 
			
		||||
    <string name="remove_to_favs_reader">Remove from favorites</string>
 | 
			
		||||
    <string name="pref_content_reader_font_size">Article reader content font size</string>
 | 
			
		||||
    <string name="pref_header_viewer">Article viewer</string>
 | 
			
		||||
    <string name="refresh_dialog_message">This will refresh your Selfoss instance.</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_off">Don\'t mark articles as read when swiping.</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept">Automatically send crash reports</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept_enabled">Will send crash reports automatically</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept_disabled">Will ask everytime when sending crash reports.</string>
 | 
			
		||||
    <string name="pref_debug_crash_reports">Crash reports</string>
 | 
			
		||||
    <string name="pref_debug_debug_logs">Debug logging (these will be sent without a dialog)</string>
 | 
			
		||||
    <string name="acra_login">Enable logging</string>
 | 
			
		||||
    <string name="drawer_item_hidden_tags">Hidden Tags</string>
 | 
			
		||||
    <string name="unmark">Mark item as unread</string>
 | 
			
		||||
    <string name="pref_header_offline">Offline and cache</string>
 | 
			
		||||
@@ -141,7 +105,8 @@
 | 
			
		||||
    <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_summary">Disable this if your server is receiving excessive amounts of database queries.</string>
 | 
			
		||||
    <string name="no_network_connectivity">Not connected !</string>
 | 
			
		||||
    <string name="network_connectivity_lost">"Network connection lost"</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_off">Articles will not be synced in the background</string>
 | 
			
		||||
    <string name="pref_switch_periodic_refresh_on">Articles will periodically be synced</string>
 | 
			
		||||
 
 | 
			
		||||
@@ -3,16 +3,13 @@
 | 
			
		||||
    <string name="app_name">"Reader for Selfoss"</string>
 | 
			
		||||
    <string name="title_activity_login">"Login"</string>
 | 
			
		||||
    <string name="prompt_password">"Mot de passe"</string>
 | 
			
		||||
    <string name="prompt_http_password">"Mot de passe HTTP"</string>
 | 
			
		||||
    <string name="action_sign_in">"Valider"</string>
 | 
			
		||||
    <string name="error_invalid_password">"Mot de passe trop court"</string>
 | 
			
		||||
    <string name="error_field_required">"Champ requis"</string>
 | 
			
		||||
    <string name="prompt_url">"Url Selfoss"</string>
 | 
			
		||||
    <string name="withLoginSwitch">"Avec login ?"</string>
 | 
			
		||||
    <string name="withHttpLoginSwitch">"Avec login HTTP ?"</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_http_login">"Utilisateur HTTP"</string>
 | 
			
		||||
    <string name="label_share">"Partager"</string>
 | 
			
		||||
    <string name="readAll">"Tout lire"</string>
 | 
			
		||||
    <string name="action_disconnect">"Déconnecter"</string>
 | 
			
		||||
@@ -26,9 +23,6 @@
 | 
			
		||||
    <string name="wrong_infos">"Vérifiez vos informations."</string>
 | 
			
		||||
    <string name="all_posts_not_read">"Tous les posts n'ont pas été lus"</string>
 | 
			
		||||
    <string name="all_posts_read">"Tous les posts sont lus"</string>
 | 
			
		||||
    <string name="cant_get_favs">"Impossible de récupérer les éléments favoris."</string>
 | 
			
		||||
    <string name="cant_get_new_elements">"Impossible de récupérer les nouveaux éléments."</string>
 | 
			
		||||
    <string name="cant_get_read">"Impossible de récupérer les éléments lus."</string>
 | 
			
		||||
    <string name="nothing_here">"Il n'y a rien ici !"</string>
 | 
			
		||||
    <string name="tab_new">"Non lus"</string>
 | 
			
		||||
    <string name="tab_read">"Tous"</string>
 | 
			
		||||
@@ -40,26 +34,15 @@
 | 
			
		||||
    <string name="addStringNoUrl">"Identifiez-vous pour ajouter une source."</string>
 | 
			
		||||
    <string name="cant_get_sources">"Impossible de récupérer la liste des sources"</string>
 | 
			
		||||
    <string name="cant_create_source">"Impossible de créer la source."</string>
 | 
			
		||||
    <string name="cant_get_spouts">"Impossible de récupérer vos Spouts pour rajouter des sources"</string>
 | 
			
		||||
    <string name="cant_get_spouts_no_network">"Impossible d'obtenir la liste des spouts en raison d'un problème de réseau."</string>
 | 
			
		||||
    <string name="cant_get_spouts">"Impossible d'obtenir la liste des spouts. Cela pourrait venir de l'api."</string>
 | 
			
		||||
    <string name="form_not_complete">"Il manque des données. Terminez le formulaire."</string>
 | 
			
		||||
    <string name="pref_header_links">"Liens utiles"</string>
 | 
			
		||||
    <string name="issue_tracker_link">"Suivi des problèmes"</string>
 | 
			
		||||
    <string name="issue_tracker_summary">"Pour signaler un bug ou demander une nouvelle fonctionnalité"</string>
 | 
			
		||||
    <string name="warning_wrong_url">"ATTENTION"</string>
 | 
			
		||||
    <string name="pref_switch_card_view_title">"Card View"</string>
 | 
			
		||||
    <string name="cant_mark_favortie">"Impossible de marquer l'élément comme favoris"</string>
 | 
			
		||||
    <string name="cant_unmark_favortie">"Impossible de retirer l'élément des favoris"</string>
 | 
			
		||||
    <string name="pref_switch_card_view_title">"Vue en carte"</string>
 | 
			
		||||
    <string name="share">"Partager"</string>
 | 
			
		||||
    <string name="rating_prompt_title">"Vous aimez l'application ?"</string>
 | 
			
		||||
    <string name="rating_prompt_yes">"Oui."</string>
 | 
			
		||||
    <string name="rating_prompt_no">"Pas vraiment …"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_title">"Pouvez-vous nous dire pourquoi ?"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_yes">"Oui !"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_no">"Pas maintenant."</string>
 | 
			
		||||
    <string name="rating_prompt_rating_title">"Super ! Pouvez-vous nous noter sur le store ?"</string>
 | 
			
		||||
    <string name="rating_prompt_rating_yes">"D'accord !"</string>
 | 
			
		||||
    <string name="rating_prompt_rating_no">"Peut-être plus tard."</string>
 | 
			
		||||
    <string name="rating_prompt_thanks">"Merci, cela nous aide à améliorer l'application !"</string>
 | 
			
		||||
    <string name="switch_unread_count">"Afficher le nombre d'articles non lus sur la barre en bas de l'écran"</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>
 | 
			
		||||
@@ -82,17 +65,12 @@
 | 
			
		||||
    <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="source_code">Code source</string>
 | 
			
		||||
    <string name="cant_mark_read">Impossible de marquer l\'article comme lu</string>
 | 
			
		||||
    <string name="cant_mark_unread">Impossible de marquer l\'article comme non lu</string>
 | 
			
		||||
    <string name="drawer_error_loading_tags">Erreur lors du chargement des tags…</string>
 | 
			
		||||
    <string name="drawer_error_loading_sources">Erreur lors du chargement des sources…</string>
 | 
			
		||||
    <string name="drawer_item_filters">Filtres</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="no_tags_loaded">Pas de tags chargés</string>
 | 
			
		||||
    <string name="no_sources_loaded">Pas de sources chargés</string>
 | 
			
		||||
    <string name="drawer_loading">Chargement …</string>
 | 
			
		||||
    <string name="menu_home_search">Rechercher</string>
 | 
			
		||||
    <string name="can_delete_source">Impossible de supprimer la source…</string>
 | 
			
		||||
@@ -100,16 +78,9 @@
 | 
			
		||||
    <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_header_debug">Debug</string>
 | 
			
		||||
    <string name="self_hosted_cert_switch">Certificat auto-signé ?</string>
 | 
			
		||||
    <string name="self_signed_cert_warning">Pour des raisons de sécurité, les certificats auto-signés sont désactivés par défaut. En les activant, je ne serais pas responsable de quelconques problèmes de sécurité rencontrés.</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_hidden_tags">Tags Cachés</string>
 | 
			
		||||
    <string name="summary_debug_identifier">Identifiant de debug</string>
 | 
			
		||||
    <string name="unique_id_to_clipboard">Texte copié</string>
 | 
			
		||||
    <string name="display_header_drawer_summary">Afficher une entête avec l\'url de votre instance de Selfoss en haut du drawer lateral.</string>
 | 
			
		||||
    <string name="display_header_drawer_title">Entête de compte</string>
 | 
			
		||||
    <string name="pref_general_infinite_loading_title">Charger plus d\'articles au scroll</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>
 | 
			
		||||
@@ -120,19 +91,12 @@
 | 
			
		||||
    <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="add_to_favs_reader">Ajouter aux favoris</string>
 | 
			
		||||
    <string name="remove_to_favs_reader">Supprimer des favoris</string>
 | 
			
		||||
    <string name="pref_content_reader_font_size">Taille du texte du contenu du lecteur d\'articles</string>
 | 
			
		||||
    <string name="pref_header_viewer">Lecteur d\'articles</string>
 | 
			
		||||
    <string name="refresh_dialog_message">En validant, votre instance Selfoss sera mise à jour.</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_off">Ne pas marquer les articles comme lus à la navigation.</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept">Envoyer automatiquement les rapports d\'erreur</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept_enabled">Enverra automatiquement les rapports d\'erreur</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept_disabled">Demandera une confirmation à chaque incident.</string>
 | 
			
		||||
    <string name="pref_debug_crash_reports">Rapport d\'erreur</string>
 | 
			
		||||
    <string name="pref_debug_debug_logs">Log de debug (seront envoyés automatiquement)</string>
 | 
			
		||||
    <string name="acra_login">Activer les logs</string>
 | 
			
		||||
    <string name="drawer_item_hidden_tags">Tags Cachés</string>
 | 
			
		||||
    <string name="unmark">Marquer l\'article comme non lu</string>
 | 
			
		||||
    <string name="pref_header_offline">Hors ligne et cache</string>
 | 
			
		||||
@@ -141,7 +105,8 @@
 | 
			
		||||
    <string name="pref_switch_items_caching">Sauvegarder les articles pour une utilisation hors ligne</string>
 | 
			
		||||
    <string name="pref_switch_update_sources">Vérifier les nouvelles sources et tags</string>
 | 
			
		||||
    <string name="pref_switch_update_sources_summary">Désactivez cette option si votre serveur reçoit trop de requêtes.</string>
 | 
			
		||||
    <string name="no_network_connectivity">Hors connexion !</string>
 | 
			
		||||
    <string name="network_connectivity_lost">"Connexion au réseau perdue"</string>
 | 
			
		||||
    <string name="network_connectivity_retrieved">"Connexion réseau de nouveau disponible"</string>
 | 
			
		||||
    <string name="pref_switch_periodic_refresh">Synchroniser les articles</string>
 | 
			
		||||
    <string name="pref_switch_periodic_refresh_off">Les articles ne seront pas synchronisés en arrière plan</string>
 | 
			
		||||
    <string name="pref_switch_periodic_refresh_on">Articles seront périodiquement synchronisées</string>
 | 
			
		||||
 
 | 
			
		||||
@@ -3,16 +3,13 @@
 | 
			
		||||
    <string name="app_name">"Lector para selfoss"</string>
 | 
			
		||||
    <string name="title_activity_login">"Conectar"</string>
 | 
			
		||||
    <string name="prompt_password">"Contrasinal"</string>
 | 
			
		||||
    <string name="prompt_http_password">"Contrasinal HTTP"</string>
 | 
			
		||||
    <string name="action_sign_in">"Ir"</string>
 | 
			
		||||
    <string name="error_invalid_password">"O contrasinal non é suficientemente longo"</string>
 | 
			
		||||
    <string name="error_field_required">"Campo requirido"</string>
 | 
			
		||||
    <string name="prompt_url">"URL"</string>
 | 
			
		||||
    <string name="withLoginSwitch">"É preciso iniciar sesión?"</string>
 | 
			
		||||
    <string name="withHttpLoginSwitch">"É preciso iniciar sesión?"</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_http_login">"Nome de usuario HTTP"</string>
 | 
			
		||||
    <string name="label_share">"Compartir"</string>
 | 
			
		||||
    <string name="readAll">"Ler todos"</string>
 | 
			
		||||
    <string name="action_disconnect">"Desconectar"</string>
 | 
			
		||||
@@ -26,9 +23,6 @@
 | 
			
		||||
    <string name="wrong_infos">"Comprobar os teus detalles de novo."</string>
 | 
			
		||||
    <string name="all_posts_not_read">"Non se leron todas as publicacións"</string>
 | 
			
		||||
    <string name="all_posts_read">"Leronse todas as publicacións"</string>
 | 
			
		||||
    <string name="cant_get_favs">"Non se poden obter os favoritos"</string>
 | 
			
		||||
    <string name="cant_get_new_elements">"Non se poden recibir os novos artigos"</string>
 | 
			
		||||
    <string name="cant_get_read">"Non se poden recibir os artigos lidos"</string>
 | 
			
		||||
    <string name="nothing_here">"Non hai nada aquí"</string>
 | 
			
		||||
    <string name="tab_new">"Novo"</string>
 | 
			
		||||
    <string name="tab_read">"Todos"</string>
 | 
			
		||||
@@ -40,26 +34,15 @@
 | 
			
		||||
    <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_create_source">"Non se pode crear unha fonte."</string>
 | 
			
		||||
    <string name="cant_get_spouts">"Non se pode obter a lista de fontes."</string>
 | 
			
		||||
    <string name="cant_get_spouts_no_network">"Can't get spouts list because of a network issue."</string>
 | 
			
		||||
    <string name="cant_get_spouts">"Can't get spouts list. There may ben an api issue."</string>
 | 
			
		||||
    <string name="form_not_complete">"O formulario non está completo"</string>
 | 
			
		||||
    <string name="pref_header_links">"Ligazóns"</string>
 | 
			
		||||
    <string name="issue_tracker_link">"Rastrexador de Incidencias"</string>
 | 
			
		||||
    <string name="issue_tracker_summary">"Informar dun erro ou pedir unha nova característica"</string>
 | 
			
		||||
    <string name="warning_wrong_url">"AVISO"</string>
 | 
			
		||||
    <string name="pref_switch_card_view_title">"Vista de tarxeta"</string>
 | 
			
		||||
    <string name="cant_mark_favortie">"Non se pode marcar o artigo como favorito"</string>
 | 
			
		||||
    <string name="cant_unmark_favortie">"Non se pode eliminar o elemento dos favoritos"</string>
 | 
			
		||||
    <string name="share">"Compartir"</string>
 | 
			
		||||
    <string name="rating_prompt_title">"Estás gozando coa aplicación?"</string>
 | 
			
		||||
    <string name="rating_prompt_yes">"Si !"</string>
 | 
			
		||||
    <string name="rating_prompt_no">"Non moito …"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_title">"Podes dicirnos por qué?"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_yes">"Dacordo!"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_no">"Agora non."</string>
 | 
			
		||||
    <string name="rating_prompt_rating_title">"Xenial! Podes puntuarnos na tenda?"</string>
 | 
			
		||||
    <string name="rating_prompt_rating_yes">"Claro!"</string>
 | 
			
		||||
    <string name="rating_prompt_rating_no">"Agora mesmo non."</string>
 | 
			
		||||
    <string name="rating_prompt_thanks">"Grazas, a túa opinión axudanos a mellorar a aplicación!"</string>
 | 
			
		||||
    <string name="switch_unread_count">"Mostrar o reconto de artigos non lidos cunha insignia na barra inferior."</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>
 | 
			
		||||
@@ -82,17 +65,12 @@
 | 
			
		||||
    <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="source_code">Código fonte</string>
 | 
			
		||||
    <string name="cant_mark_read">Non se pode marcar o artigo como lido</string>
 | 
			
		||||
    <string name="cant_mark_unread">Non se pode marcar o artigo como non lido</string>
 | 
			
		||||
    <string name="drawer_error_loading_tags">Produciuse un erro ao cargar as etiquetas…</string>
 | 
			
		||||
    <string name="drawer_error_loading_sources">Produciuse un erro ao cargar as fontes…</string>
 | 
			
		||||
    <string name="drawer_item_filters">Filtros</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="no_tags_loaded">Non se cargou ningunha etiqueta</string>
 | 
			
		||||
    <string name="no_sources_loaded">Non se cargou ningunha fonte</string>
 | 
			
		||||
    <string name="drawer_loading">Cargando…</string>
 | 
			
		||||
    <string name="menu_home_search">Procurar</string>
 | 
			
		||||
    <string name="can_delete_source">Non se puido eliminar a fonte…</string>
 | 
			
		||||
@@ -100,16 +78,9 @@
 | 
			
		||||
    <string name="pref_header_theme">Temas</string>
 | 
			
		||||
    <string name="default_theme">Predeterminado</string>
 | 
			
		||||
    <string name="default_dark_theme">Predeterminado/Escuro</string>
 | 
			
		||||
    <string name="pref_header_debug">Depuración</string>
 | 
			
		||||
    <string name="self_hosted_cert_switch">Utilizas un certificado autoaloxado?</string>
 | 
			
		||||
    <string name="self_signed_cert_warning">Por razóns de seguridade, por defecto non se permiten os certificados autoasinados. Activando isto, non serei responsable de calquera problema de seguridade que atopes.</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_hidden_tags">Etiquetas ocultas</string>
 | 
			
		||||
    <string name="summary_debug_identifier">Identificador de depuración</string>
 | 
			
		||||
    <string name="unique_id_to_clipboard">Copiouse o identificador ao portapapeis</string>
 | 
			
		||||
    <string name="display_header_drawer_summary">Amosar unha cabeceira coa URL da instancia de Selfoss no panel lateral.</string>
 | 
			
		||||
    <string name="display_header_drawer_title">Cabeceira da conta</string>
 | 
			
		||||
    <string name="pref_general_infinite_loading_title">Cargar máis artigos ao desprazarse</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>
 | 
			
		||||
@@ -120,19 +91,12 @@
 | 
			
		||||
    <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="add_to_favs_reader">Engadir a favoritos</string>
 | 
			
		||||
    <string name="remove_to_favs_reader">Eliminar dos favoritos</string>
 | 
			
		||||
    <string name="pref_content_reader_font_size">Tamaño da fonte do lector</string>
 | 
			
		||||
    <string name="pref_header_viewer">Visor de artigos</string>
 | 
			
		||||
    <string name="refresh_dialog_message">Isto actualizará a súa instancia de Selfoss.</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_off">Non marcar artigos como lidos ao deslizar co dedo cara os lados.</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept">Enviar automáticamente informes de erros</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept_enabled">Enviaranse automáticamente os informes de erros</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept_disabled">Preguntarase cada vez pra enviar os informes de erros.</string>
 | 
			
		||||
    <string name="pref_debug_crash_reports">Informes de erros</string>
 | 
			
		||||
    <string name="pref_debug_debug_logs">Rexistro de depuración (Estes enviaranse automáticamente)</string>
 | 
			
		||||
    <string name="acra_login">Habilitar o rexistro</string>
 | 
			
		||||
    <string name="drawer_item_hidden_tags">Etiquetas ocultas</string>
 | 
			
		||||
    <string name="unmark">Marcar artículo como non lido</string>
 | 
			
		||||
    <string name="pref_header_offline">Sen conexión e caché</string>
 | 
			
		||||
@@ -141,7 +105,8 @@
 | 
			
		||||
    <string name="pref_switch_items_caching">Gardar elementos para uso sen conexión</string>
 | 
			
		||||
    <string name="pref_switch_update_sources">Comproba novas fontes e etiquetas</string>
 | 
			
		||||
    <string name="pref_switch_update_sources_summary">Deshabilita isto se o teu servidor está recibindo demasiadas peticións de base de datos.</string>
 | 
			
		||||
    <string name="no_network_connectivity">Non conectado!</string>
 | 
			
		||||
    <string name="network_connectivity_lost">"Perdeuse a conexión de rede"</string>
 | 
			
		||||
    <string name="network_connectivity_retrieved">"Conexión de rede xa dispoñíbel"</string>
 | 
			
		||||
    <string name="pref_switch_periodic_refresh">Sincronizar artigos</string>
 | 
			
		||||
    <string name="pref_switch_periodic_refresh_off">Os artigos non se sincronizarán coa aplicación de fondo</string>
 | 
			
		||||
    <string name="pref_switch_periodic_refresh_on">Os artigos sincronizaranse periódicamente</string>
 | 
			
		||||
 
 | 
			
		||||
@@ -3,16 +3,13 @@
 | 
			
		||||
    <string name="app_name">"Reader for Selfoss"</string>
 | 
			
		||||
    <string name="title_activity_login">"Masuk"</string>
 | 
			
		||||
    <string name="prompt_password">"Kata sandi"</string>
 | 
			
		||||
    <string name="prompt_http_password">"Kata sandi HTTP"</string>
 | 
			
		||||
    <string name="action_sign_in">"Mulai"</string>
 | 
			
		||||
    <string name="error_invalid_password">"Kata sandinya tidak cukup panjang"</string>
 | 
			
		||||
    <string name="error_field_required">"Kolom wajib diisi"</string>
 | 
			
		||||
    <string name="prompt_url">"URL"</string>
 | 
			
		||||
    <string name="withLoginSwitch">"Harus masuk?"</string>
 | 
			
		||||
    <string name="withHttpLoginSwitch">"Otentikasi HTTP diperlukan?"</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_http_login">"Nama pengguna HTTP"</string>
 | 
			
		||||
    <string name="label_share">"Bagikan"</string>
 | 
			
		||||
    <string name="readAll">"Baca semua"</string>
 | 
			
		||||
    <string name="action_disconnect">"Putuskan sambungan"</string>
 | 
			
		||||
@@ -26,9 +23,6 @@
 | 
			
		||||
    <string name="wrong_infos">"Periksa kembali detail Anda."</string>
 | 
			
		||||
    <string name="all_posts_not_read">"Semua pos belum dibaca"</string>
 | 
			
		||||
    <string name="all_posts_read">"Semua pos sudah dibaca"</string>
 | 
			
		||||
    <string name="cant_get_favs">"Gagal menuju favorit"</string>
 | 
			
		||||
    <string name="cant_get_new_elements">"Gagal ke artikel baru"</string>
 | 
			
		||||
    <string name="cant_get_read">"Gagal ke artikel yang dibaca"</string>
 | 
			
		||||
    <string name="nothing_here">"Tidak ada di sini"</string>
 | 
			
		||||
    <string name="tab_new">"Baru"</string>
 | 
			
		||||
    <string name="tab_read">"Semua"</string>
 | 
			
		||||
@@ -40,26 +34,15 @@
 | 
			
		||||
    <string name="addStringNoUrl">"Masuk untuk menambah sumber."</string>
 | 
			
		||||
    <string name="cant_get_sources">"Tidak bisa mendapatkan daftar sumber."</string>
 | 
			
		||||
    <string name="cant_create_source">"Tidak dapat membuat sumber."</string>
 | 
			
		||||
    <string name="cant_get_spouts">"Tidak bisa masuk ke daftar Spouts."</string>
 | 
			
		||||
    <string name="cant_get_spouts_no_network">"Can't get spouts list because of a network issue."</string>
 | 
			
		||||
    <string name="cant_get_spouts">"Can't get spouts list. There may ben an api issue."</string>
 | 
			
		||||
    <string name="form_not_complete">"Formulirnya belum selesai"</string>
 | 
			
		||||
    <string name="pref_header_links">"Tautan"</string>
 | 
			
		||||
    <string name="issue_tracker_link">"Pelacak Masalah"</string>
 | 
			
		||||
    <string name="issue_tracker_summary">"Laporkan bug atau meminta fitur baru"</string>
 | 
			
		||||
    <string name="warning_wrong_url">"PERINGATAN"</string>
 | 
			
		||||
    <string name="pref_switch_card_view_title">"Tampilan Kartu"</string>
 | 
			
		||||
    <string name="cant_mark_favortie">"Tidak dapat menandai artikel sebagai favorit"</string>
 | 
			
		||||
    <string name="cant_unmark_favortie">"Tidak dapat melepas item dari favorit"</string>
 | 
			
		||||
    <string name="share">"Bagikan"</string>
 | 
			
		||||
    <string name="rating_prompt_title">"Suka aplikasi ini?"</string>
 | 
			
		||||
    <string name="rating_prompt_yes">"Ya !"</string>
 | 
			
		||||
    <string name="rating_prompt_no">"Tidak suka …"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_title">"Bisakah Anda memberitahu kami alasannya?"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_yes">"Oke !"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_no">"Tidak sekarang."</string>
 | 
			
		||||
    <string name="rating_prompt_rating_title">"Bagus! Dapatkah Anda memberi nilai kami di Store ?"</string>
 | 
			
		||||
    <string name="rating_prompt_rating_yes">"Tentu saja !"</string>
 | 
			
		||||
    <string name="rating_prompt_rating_no">"Jangan sekarang."</string>
 | 
			
		||||
    <string name="rating_prompt_thanks">"Terima kasih, umpan balik Anda membantu pengembangan aplikasi !"</string>
 | 
			
		||||
    <string name="switch_unread_count">"Tampilkan jumlah item yang belum dibaca di bilah bawah."</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>
 | 
			
		||||
@@ -82,17 +65,12 @@
 | 
			
		||||
    <string name="card_height_on">Tinggi kartu akan disesuaikan dengan konten</string>
 | 
			
		||||
    <string name="card_height_off">Ukuran kartu akan tetap</string>
 | 
			
		||||
    <string name="source_code">Kode sumber</string>
 | 
			
		||||
    <string name="cant_mark_read">Tidak dapat menandai artikel sebagai telah dibaca</string>
 | 
			
		||||
    <string name="cant_mark_unread">Can\'t mark article as unread</string>
 | 
			
		||||
    <string name="drawer_error_loading_tags">Kesalahan saat memuat tag…</string>
 | 
			
		||||
    <string name="drawer_error_loading_sources">Kesalahan saat memuat sumber…</string>
 | 
			
		||||
    <string name="drawer_item_filters">Filter</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="no_tags_loaded">Tidak ada tag yang dimuat</string>
 | 
			
		||||
    <string name="no_sources_loaded">Tak ada sumber yang dimuat</string>
 | 
			
		||||
    <string name="drawer_loading">Memuat …</string>
 | 
			
		||||
    <string name="menu_home_search">Cari</string>
 | 
			
		||||
    <string name="can_delete_source">Tidak dapat menghapus sumber…</string>
 | 
			
		||||
@@ -100,16 +78,9 @@
 | 
			
		||||
    <string name="pref_header_theme">Tema</string>
 | 
			
		||||
    <string name="default_theme">Bawaan</string>
 | 
			
		||||
    <string name="default_dark_theme">Bawaan/Gelap</string>
 | 
			
		||||
    <string name="pref_header_debug">Debug</string>
 | 
			
		||||
    <string name="self_hosted_cert_switch">Sertifikat yang ditandatangani sendiri?</string>
 | 
			
		||||
    <string name="self_signed_cert_warning">Untuk alasan keamanan, sertifikat yang ditandatangani sendiri tidak didukung secara bawaan. Jika Anda mengaktifkan item ini, saya tidak akan bertanggung jawab atas masalah keamanan yang Anda hadapi.</string>
 | 
			
		||||
    <string name="pref_selfoss_category">Selfoss Api</string>
 | 
			
		||||
    <string name="pref_api_items_number_title">Item nomor dimuat</string>
 | 
			
		||||
    <string name="pref_hidden_tags">Hidden Tags</string>
 | 
			
		||||
    <string name="summary_debug_identifier">Identifikasi debug</string>
 | 
			
		||||
    <string name="unique_id_to_clipboard">Salin pengenal ke papan klip Anda</string>
 | 
			
		||||
    <string name="display_header_drawer_summary">Kop dengan alamat link Selfoss ditampilkan di laci lateral.</string>
 | 
			
		||||
    <string name="display_header_drawer_title">Kop akun</string>
 | 
			
		||||
    <string name="pref_general_infinite_loading_title">Muat lebih banyak artikel saat membalik halaman</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>
 | 
			
		||||
@@ -120,19 +91,12 @@
 | 
			
		||||
    <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="add_to_favs_reader">Add to favorites</string>
 | 
			
		||||
    <string name="remove_to_favs_reader">Remove from favorites</string>
 | 
			
		||||
    <string name="pref_content_reader_font_size">Article reader content font size</string>
 | 
			
		||||
    <string name="pref_header_viewer">Article viewer</string>
 | 
			
		||||
    <string name="refresh_dialog_message">This will refresh your Selfoss instance.</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_off">Don\'t mark articles as read when swiping.</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept">Automatically send crash reports</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept_enabled">Will send crash reports automatically</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept_disabled">Will ask everytime when sending crash reports.</string>
 | 
			
		||||
    <string name="pref_debug_crash_reports">Crash reports</string>
 | 
			
		||||
    <string name="pref_debug_debug_logs">Debug logging (these will be sent without a dialog)</string>
 | 
			
		||||
    <string name="acra_login">Enable logging</string>
 | 
			
		||||
    <string name="drawer_item_hidden_tags">Hidden Tags</string>
 | 
			
		||||
    <string name="unmark">Mark item as unread</string>
 | 
			
		||||
    <string name="pref_header_offline">Offline and cache</string>
 | 
			
		||||
@@ -141,7 +105,8 @@
 | 
			
		||||
    <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_summary">Disable this if your server is receiving excessive amounts of database queries.</string>
 | 
			
		||||
    <string name="no_network_connectivity">Not connected !</string>
 | 
			
		||||
    <string name="network_connectivity_lost">"Network connection lost"</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_off">Articles will not be synced in the background</string>
 | 
			
		||||
    <string name="pref_switch_periodic_refresh_on">Articles will periodically be synced</string>
 | 
			
		||||
 
 | 
			
		||||
@@ -3,16 +3,13 @@
 | 
			
		||||
    <string name="app_name">"Lettore RSS per Selfoss"</string>
 | 
			
		||||
    <string name="title_activity_login">"Accedi"</string>
 | 
			
		||||
    <string name="prompt_password">"Password"</string>
 | 
			
		||||
    <string name="prompt_http_password">"Password HTTP"</string>
 | 
			
		||||
    <string name="action_sign_in">"Vai"</string>
 | 
			
		||||
    <string name="error_invalid_password">"La password non è sufficientemente lunga"</string>
 | 
			
		||||
    <string name="error_field_required">"Campo obbligatorio"</string>
 | 
			
		||||
    <string name="prompt_url">"URL"</string>
 | 
			
		||||
    <string name="withLoginSwitch">"È richiesto l'accesso?"</string>
 | 
			
		||||
    <string name="withHttpLoginSwitch">"Accesso HTTP necessario?"</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_http_login">"Nome utente HTTP"</string>
 | 
			
		||||
    <string name="label_share">"Condividi"</string>
 | 
			
		||||
    <string name="readAll">"Segna tutte come lette"</string>
 | 
			
		||||
    <string name="action_disconnect">"Scollegati"</string>
 | 
			
		||||
@@ -26,9 +23,6 @@
 | 
			
		||||
    <string name="wrong_infos">"Controlla nuovamente i dati."</string>
 | 
			
		||||
    <string name="all_posts_not_read">"All posts weren't read"</string>
 | 
			
		||||
    <string name="all_posts_read">"Tutti i messaggi sono stati letti"</string>
 | 
			
		||||
    <string name="cant_get_favs">"Non è possibile ottenere i preferiti"</string>
 | 
			
		||||
    <string name="cant_get_new_elements">"Non è possibile ottenere nuovi articoli"</string>
 | 
			
		||||
    <string name="cant_get_read">"Can't get read articles"</string>
 | 
			
		||||
    <string name="nothing_here">"Non c'è niente qui"</string>
 | 
			
		||||
    <string name="tab_new">"Nuovi"</string>
 | 
			
		||||
    <string name="tab_read">"Tutti"</string>
 | 
			
		||||
@@ -40,26 +34,15 @@
 | 
			
		||||
    <string name="addStringNoUrl">"Autenticati per aggiungere fonti."</string>
 | 
			
		||||
    <string name="cant_get_sources">"Can't get sources list."</string>
 | 
			
		||||
    <string name="cant_create_source">"Can't create source."</string>
 | 
			
		||||
    <string name="cant_get_spouts">"Can't get spouts list."</string>
 | 
			
		||||
    <string name="cant_get_spouts_no_network">"Can't get spouts list because of a network issue."</string>
 | 
			
		||||
    <string name="cant_get_spouts">"Can't get spouts list. There may ben an api issue."</string>
 | 
			
		||||
    <string name="form_not_complete">"Il modulo non è completo"</string>
 | 
			
		||||
    <string name="pref_header_links">"Links"</string>
 | 
			
		||||
    <string name="issue_tracker_link">"Traccia problemi"</string>
 | 
			
		||||
    <string name="issue_tracker_summary">"Segnalare un bug o richiedere una nuova funzionalità"</string>
 | 
			
		||||
    <string name="warning_wrong_url">"ATTENZIONE"</string>
 | 
			
		||||
    <string name="pref_switch_card_view_title">"Visualizzazione a schede"</string>
 | 
			
		||||
    <string name="cant_mark_favortie">"Can't mark article as favorite"</string>
 | 
			
		||||
    <string name="cant_unmark_favortie">"Can't remove item from favorite"</string>
 | 
			
		||||
    <string name="share">"Share"</string>
 | 
			
		||||
    <string name="rating_prompt_title">"Enjoying the app ?"</string>
 | 
			
		||||
    <string name="rating_prompt_yes">"Yes !"</string>
 | 
			
		||||
    <string name="rating_prompt_no">"Not really …"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_title">"Can you tell us why ?"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_yes">"OK !"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_no">"Not now."</string>
 | 
			
		||||
    <string name="rating_prompt_rating_title">"Great ! Can you rate us on the Store ?"</string>
 | 
			
		||||
    <string name="rating_prompt_rating_yes">"Sure !"</string>
 | 
			
		||||
    <string name="rating_prompt_rating_no">"Not right now."</string>
 | 
			
		||||
    <string name="rating_prompt_thanks">"Thanks, your feedback help enhance the app !"</string>
 | 
			
		||||
    <string name="switch_unread_count">"Display the unread count as a badge for the bottom bar."</string>
 | 
			
		||||
    <string name="switch_unread_count_title">"Display unread count"</string>
 | 
			
		||||
    <string name="display_all_counts_title">"Display count for favorite and read"</string>
 | 
			
		||||
@@ -82,17 +65,12 @@
 | 
			
		||||
    <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="source_code">Codice sorgente</string>
 | 
			
		||||
    <string name="cant_mark_read">Impossibile contrassegnare l\'articolo come già letto</string>
 | 
			
		||||
    <string name="cant_mark_unread">Can\'t mark article as unread</string>
 | 
			
		||||
    <string name="drawer_error_loading_tags">Errore nel caricamento dei tag…</string>
 | 
			
		||||
    <string name="drawer_error_loading_sources">Errore nel caricamento delle fonti…</string>
 | 
			
		||||
    <string name="drawer_item_filters">Filtri</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="no_tags_loaded">Nessun tag caricato</string>
 | 
			
		||||
    <string name="no_sources_loaded">No sources loaded</string>
 | 
			
		||||
    <string name="drawer_loading">Caricamento…</string>
 | 
			
		||||
    <string name="menu_home_search">Cerca</string>
 | 
			
		||||
    <string name="can_delete_source">Non è possibile eliminare la fonte…</string>
 | 
			
		||||
@@ -100,16 +78,9 @@
 | 
			
		||||
    <string name="pref_header_theme">Temi</string>
 | 
			
		||||
    <string name="default_theme">Predefinito</string>
 | 
			
		||||
    <string name="default_dark_theme">Predefinito (Scuro)</string>
 | 
			
		||||
    <string name="pref_header_debug">Debug</string>
 | 
			
		||||
    <string name="self_hosted_cert_switch">Using a self hosted certificate ?</string>
 | 
			
		||||
    <string name="self_signed_cert_warning">Due to security reasons, self signed certificates are not supported by default. By activating this, I\'ll not be responsible of any security problem you encounter.</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_hidden_tags">Tag nascosti</string>
 | 
			
		||||
    <string name="summary_debug_identifier">Debug identifier</string>
 | 
			
		||||
    <string name="unique_id_to_clipboard">Identifier copied to your clipboard</string>
 | 
			
		||||
    <string name="display_header_drawer_summary">Display a header with the selfoss instance url on the lateral drawer.</string>
 | 
			
		||||
    <string name="display_header_drawer_title">Account header</string>
 | 
			
		||||
    <string name="pref_general_infinite_loading_title">Load more articles on scroll</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>
 | 
			
		||||
@@ -120,19 +91,12 @@
 | 
			
		||||
    <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="add_to_favs_reader">Add to favorites</string>
 | 
			
		||||
    <string name="remove_to_favs_reader">Remove from favorites</string>
 | 
			
		||||
    <string name="pref_content_reader_font_size">Article reader content font size</string>
 | 
			
		||||
    <string name="pref_header_viewer">Article viewer</string>
 | 
			
		||||
    <string name="refresh_dialog_message">This will refresh your Selfoss instance.</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_off">Don\'t mark articles as read when swiping.</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept">Automatically send crash reports</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept_enabled">Will send crash reports automatically</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept_disabled">Will ask everytime when sending crash reports.</string>
 | 
			
		||||
    <string name="pref_debug_crash_reports">Crash reports</string>
 | 
			
		||||
    <string name="pref_debug_debug_logs">Debug logging (these will be sent without a dialog)</string>
 | 
			
		||||
    <string name="acra_login">Enable logging</string>
 | 
			
		||||
    <string name="drawer_item_hidden_tags">Hidden Tags</string>
 | 
			
		||||
    <string name="unmark">Segna come non letto</string>
 | 
			
		||||
    <string name="pref_header_offline">Offline and cache</string>
 | 
			
		||||
@@ -141,7 +105,8 @@
 | 
			
		||||
    <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_summary">Disable this if your server is receiving excessive amounts of database queries.</string>
 | 
			
		||||
    <string name="no_network_connectivity">Not connected !</string>
 | 
			
		||||
    <string name="network_connectivity_lost">"Network connection lost"</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_off">Articles will not be synced in the background</string>
 | 
			
		||||
    <string name="pref_switch_periodic_refresh_on">Articles will periodically be synced</string>
 | 
			
		||||
 
 | 
			
		||||
@@ -3,16 +3,13 @@
 | 
			
		||||
    <string name="app_name">"Reader for Selfoss"</string>
 | 
			
		||||
    <string name="title_activity_login">"로그인"</string>
 | 
			
		||||
    <string name="prompt_password">"비밀번호"</string>
 | 
			
		||||
    <string name="prompt_http_password">"HTTP 암호"</string>
 | 
			
		||||
    <string name="action_sign_in">"Go"</string>
 | 
			
		||||
    <string name="error_invalid_password">"패스워드가 짧습니다."</string>
 | 
			
		||||
    <string name="error_field_required">"필수 항목"</string>
 | 
			
		||||
    <string name="prompt_url">"Url"</string>
 | 
			
		||||
    <string name="withLoginSwitch">"로그인이 필요합니까?"</string>
 | 
			
		||||
    <string name="withHttpLoginSwitch">"HTTP 로그인이 필요 합니까?"</string>
 | 
			
		||||
    <string name="login_url_problem">"죄송합니다. Url의 끝에 \"/\"를 추가할 필요가 있습니다."</string>
 | 
			
		||||
    <string name="prompt_login">"사용자 이름"</string>
 | 
			
		||||
    <string name="prompt_http_login">"HTTP 사용자 이름"</string>
 | 
			
		||||
    <string name="label_share">"공유"</string>
 | 
			
		||||
    <string name="readAll">"모두 읽기"</string>
 | 
			
		||||
    <string name="action_disconnect">"연결 해제"</string>
 | 
			
		||||
@@ -26,9 +23,6 @@
 | 
			
		||||
    <string name="wrong_infos">"세부 정보를 다시 확인하세요."</string>
 | 
			
		||||
    <string name="all_posts_not_read">"모든 게시물을 읽지 않았습니다."</string>
 | 
			
		||||
    <string name="all_posts_read">"모든 게시물을 읽었습니다."</string>
 | 
			
		||||
    <string name="cant_get_favs">"즐겨찾기를 가져올 수 없습니다."</string>
 | 
			
		||||
    <string name="cant_get_new_elements">"새로운 기사를 가져올 수 없습니다."</string>
 | 
			
		||||
    <string name="cant_get_read">"읽은 기사를 가져올 수 없습니다."</string>
 | 
			
		||||
    <string name="nothing_here">"비어있음"</string>
 | 
			
		||||
    <string name="tab_new">"새로운"</string>
 | 
			
		||||
    <string name="tab_read">"전체"</string>
 | 
			
		||||
@@ -40,26 +34,15 @@
 | 
			
		||||
    <string name="addStringNoUrl">"로그인 소스를 추가 해야 합니다."</string>
 | 
			
		||||
    <string name="cant_get_sources">"소스 리스트를 얻을 수 없습니다."</string>
 | 
			
		||||
    <string name="cant_create_source">"소스를 만들 수 없습니다."</string>
 | 
			
		||||
    <string name="cant_get_spouts">"Spouts 목록을 가져올 수 없습니다."</string>
 | 
			
		||||
    <string name="cant_get_spouts_no_network">"Can't get spouts list because of a network issue."</string>
 | 
			
		||||
    <string name="cant_get_spouts">"Can't get spouts list. There may ben an api issue."</string>
 | 
			
		||||
    <string name="form_not_complete">"양식이 완료되지 않았습니다."</string>
 | 
			
		||||
    <string name="pref_header_links">"링크"</string>
 | 
			
		||||
    <string name="issue_tracker_link">"이슈 트래커"</string>
 | 
			
		||||
    <string name="issue_tracker_summary">"버그를 보고 하거나 새기능에 대해 요청하세요."</string>
 | 
			
		||||
    <string name="warning_wrong_url">"경고"</string>
 | 
			
		||||
    <string name="pref_switch_card_view_title">"카드 형식 보기"</string>
 | 
			
		||||
    <string name="cant_mark_favortie">"좋아하는 문서를 마크할 수 없습니다."</string>
 | 
			
		||||
    <string name="cant_unmark_favortie">"좋아하는 항목에서 제거할 수 없습니다."</string>
 | 
			
		||||
    <string name="share">"공유"</string>
 | 
			
		||||
    <string name="rating_prompt_title">"이 앱에 만족하십니까?"</string>
 | 
			
		||||
    <string name="rating_prompt_yes">"예!"</string>
 | 
			
		||||
    <string name="rating_prompt_no">"설마..."</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_title">"이유를 우리에게 말해줄 수 있습니까?"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_yes">"OK!"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_no">"나중에"</string>
 | 
			
		||||
    <string name="rating_prompt_rating_title">"Great ! Can you rate us on the Store ?"</string>
 | 
			
		||||
    <string name="rating_prompt_rating_yes">"Sure !"</string>
 | 
			
		||||
    <string name="rating_prompt_rating_no">"Not right now."</string>
 | 
			
		||||
    <string name="rating_prompt_thanks">"Thanks, your feedback help enhance the app !"</string>
 | 
			
		||||
    <string name="switch_unread_count">"Display the unread count as a badge for the bottom bar."</string>
 | 
			
		||||
    <string name="switch_unread_count_title">"Display unread count"</string>
 | 
			
		||||
    <string name="display_all_counts_title">"Display count for favorite and read"</string>
 | 
			
		||||
@@ -82,17 +65,12 @@
 | 
			
		||||
    <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="source_code">Source code</string>
 | 
			
		||||
    <string name="cant_mark_read">Can\'t mark article as read</string>
 | 
			
		||||
    <string name="cant_mark_unread">Can\'t mark article as unread</string>
 | 
			
		||||
    <string name="drawer_error_loading_tags">Error loading tags…</string>
 | 
			
		||||
    <string name="drawer_error_loading_sources">Error loading sources…</string>
 | 
			
		||||
    <string name="drawer_item_filters">Filters</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="no_tags_loaded">No tags loaded</string>
 | 
			
		||||
    <string name="no_sources_loaded">No sources loaded</string>
 | 
			
		||||
    <string name="drawer_loading">Loading …</string>
 | 
			
		||||
    <string name="menu_home_search">Search</string>
 | 
			
		||||
    <string name="can_delete_source">Can\'t delete the source…</string>
 | 
			
		||||
@@ -100,16 +78,9 @@
 | 
			
		||||
    <string name="pref_header_theme">Themes</string>
 | 
			
		||||
    <string name="default_theme">Default</string>
 | 
			
		||||
    <string name="default_dark_theme">Default/Dark</string>
 | 
			
		||||
    <string name="pref_header_debug">Debug</string>
 | 
			
		||||
    <string name="self_hosted_cert_switch">Using a self hosted certificate ?</string>
 | 
			
		||||
    <string name="self_signed_cert_warning">Due to security reasons, self signed certificates are not supported by default. By activating this, I\'ll not be responsible of any security problem you encounter.</string>
 | 
			
		||||
    <string name="pref_selfoss_category">Selfoss Api</string>
 | 
			
		||||
    <string name="pref_api_items_number_title">Loaded items number</string>
 | 
			
		||||
    <string name="pref_hidden_tags">Hidden Tags</string>
 | 
			
		||||
    <string name="summary_debug_identifier">Debug identifier</string>
 | 
			
		||||
    <string name="unique_id_to_clipboard">Identifier copied to your clipboard</string>
 | 
			
		||||
    <string name="display_header_drawer_summary">Display a header with the selfoss instance url on the lateral drawer.</string>
 | 
			
		||||
    <string name="display_header_drawer_title">Account header</string>
 | 
			
		||||
    <string name="pref_general_infinite_loading_title">Load more articles on scroll</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>
 | 
			
		||||
@@ -120,19 +91,12 @@
 | 
			
		||||
    <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="add_to_favs_reader">Add to favorites</string>
 | 
			
		||||
    <string name="remove_to_favs_reader">Remove from favorites</string>
 | 
			
		||||
    <string name="pref_content_reader_font_size">Article reader content font size</string>
 | 
			
		||||
    <string name="pref_header_viewer">Article viewer</string>
 | 
			
		||||
    <string name="refresh_dialog_message">This will refresh your Selfoss instance.</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_off">Don\'t mark articles as read when swiping.</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept">Automatically send crash reports</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept_enabled">Will send crash reports automatically</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept_disabled">Will ask everytime when sending crash reports.</string>
 | 
			
		||||
    <string name="pref_debug_crash_reports">Crash reports</string>
 | 
			
		||||
    <string name="pref_debug_debug_logs">Debug logging (these will be sent without a dialog)</string>
 | 
			
		||||
    <string name="acra_login">Enable logging</string>
 | 
			
		||||
    <string name="drawer_item_hidden_tags">Hidden Tags</string>
 | 
			
		||||
    <string name="unmark">Mark item as unread</string>
 | 
			
		||||
    <string name="pref_header_offline">Offline and cache</string>
 | 
			
		||||
@@ -141,7 +105,8 @@
 | 
			
		||||
    <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_summary">Disable this if your server is receiving excessive amounts of database queries.</string>
 | 
			
		||||
    <string name="no_network_connectivity">Not connected !</string>
 | 
			
		||||
    <string name="network_connectivity_lost">"Network connection lost"</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_off">Articles will not be synced in the background</string>
 | 
			
		||||
    <string name="pref_switch_periodic_refresh_on">Articles will periodically be synced</string>
 | 
			
		||||
 
 | 
			
		||||
@@ -3,16 +3,13 @@
 | 
			
		||||
    <string name="app_name">"Selfoss Reader"</string>
 | 
			
		||||
    <string name="title_activity_login">"Inloggen"</string>
 | 
			
		||||
    <string name="prompt_password">"Wachtwoord"</string>
 | 
			
		||||
    <string name="prompt_http_password">"HTTP Wachtwoord"</string>
 | 
			
		||||
    <string name="action_sign_in">"Inloggen"</string>
 | 
			
		||||
    <string name="error_invalid_password">"Wachtwoord niet lang genoeg"</string>
 | 
			
		||||
    <string name="error_field_required">"Dit veld is verplicht"</string>
 | 
			
		||||
    <string name="prompt_url">"Selfoss server"</string>
 | 
			
		||||
    <string name="withLoginSwitch">"Authenticatie vereist?"</string>
 | 
			
		||||
    <string name="withHttpLoginSwitch">"HTTP Authenticatie vereist?"</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_http_login">"HTTP Gebruikersnaam"</string>
 | 
			
		||||
    <string name="label_share">"Delen"</string>
 | 
			
		||||
    <string name="readAll">"Alles lezen"</string>
 | 
			
		||||
    <string name="action_disconnect">"Verbinding verbreken"</string>
 | 
			
		||||
@@ -26,9 +23,6 @@
 | 
			
		||||
    <string name="wrong_infos">"Controleer de gegevens nogmaals."</string>
 | 
			
		||||
    <string name="all_posts_not_read">"Fout bij markeren als gelezen"</string>
 | 
			
		||||
    <string name="all_posts_read">"Alle artikelen gemarkeerd als gelezen"</string>
 | 
			
		||||
    <string name="cant_get_favs">"Ophalen favorieten mislukt"</string>
 | 
			
		||||
    <string name="cant_get_new_elements">"Ophalen nieuwe artikelen mislukt"</string>
 | 
			
		||||
    <string name="cant_get_read">"Ophalen reeds gelezen artikelen mislukt"</string>
 | 
			
		||||
    <string name="nothing_here">"Niets gevonden"</string>
 | 
			
		||||
    <string name="tab_new">"Nieuw"</string>
 | 
			
		||||
    <string name="tab_read">"Alle"</string>
 | 
			
		||||
@@ -40,26 +34,15 @@
 | 
			
		||||
    <string name="addStringNoUrl">"Login om bronnen toe te voegen"</string>
 | 
			
		||||
    <string name="cant_get_sources">"Kan de lijst met bronnen niet ophalen"</string>
 | 
			
		||||
    <string name="cant_create_source">"Kan bron niet creëeren"</string>
 | 
			
		||||
    <string name="cant_get_spouts">"Ophalen spouts mislukt"</string>
 | 
			
		||||
    <string name="cant_get_spouts_no_network">"Can't get spouts list because of a network issue."</string>
 | 
			
		||||
    <string name="cant_get_spouts">"Can't get spouts list. There may ben an api issue."</string>
 | 
			
		||||
    <string name="form_not_complete">"Formulier is niet volledig ingevuld"</string>
 | 
			
		||||
    <string name="pref_header_links">"Links"</string>
 | 
			
		||||
    <string name="issue_tracker_link">"Bug tracker"</string>
 | 
			
		||||
    <string name="issue_tracker_summary">"Rapporteer een probleem of dien een verzoek in"</string>
 | 
			
		||||
    <string name="warning_wrong_url">"WAARSCHUWING"</string>
 | 
			
		||||
    <string name="pref_switch_card_view_title">"Kaart weergave"</string>
 | 
			
		||||
    <string name="cant_mark_favortie">"Kan het artikel niet markeren als favoriet"</string>
 | 
			
		||||
    <string name="cant_unmark_favortie">"Kan het item niet verwijderen uit favorieten"</string>
 | 
			
		||||
    <string name="share">"Delen"</string>
 | 
			
		||||
    <string name="rating_prompt_title">"Bevalt deze app?"</string>
 | 
			
		||||
    <string name="rating_prompt_yes">"Ja!"</string>
 | 
			
		||||
    <string name="rating_prompt_no">"Niet echt…"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_title">"Kun je ons vertellen waarom?"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_yes">"OK!"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_no">"Niet nu."</string>
 | 
			
		||||
    <string name="rating_prompt_rating_title">"Fantastisch! Wil je een review achter laten in de Store?"</string>
 | 
			
		||||
    <string name="rating_prompt_rating_yes">"Vanzelfsprekend"</string>
 | 
			
		||||
    <string name="rating_prompt_rating_no">"Niet op dit moment"</string>
 | 
			
		||||
    <string name="rating_prompt_thanks">"Bedankt, jouw feedback helpt ons de app te verbeteren"</string>
 | 
			
		||||
    <string name="switch_unread_count">"Geef het aantal ongelezen artikelen weer in de balk onderaan"</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>
 | 
			
		||||
@@ -82,17 +65,12 @@
 | 
			
		||||
    <string name="card_height_on">Hoogte aanpassen aan de hand van kaartinhoud</string>
 | 
			
		||||
    <string name="card_height_off">Vaste hoogte</string>
 | 
			
		||||
    <string name="source_code">Broncode</string>
 | 
			
		||||
    <string name="cant_mark_read">Impossible de marquer l\'article comme lu</string>
 | 
			
		||||
    <string name="cant_mark_unread">Can\'t mark article as unread</string>
 | 
			
		||||
    <string name="drawer_error_loading_tags">Fout bij het laden van tags…</string>
 | 
			
		||||
    <string name="drawer_error_loading_sources">Fout bij laden van bronnen…</string>
 | 
			
		||||
    <string name="drawer_item_filters">Filters</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="no_tags_loaded">Geen tags geladen</string>
 | 
			
		||||
    <string name="no_sources_loaded">Geen bronnen geladen</string>
 | 
			
		||||
    <string name="drawer_loading">Bezig met laden …</string>
 | 
			
		||||
    <string name="menu_home_search">Zoeken</string>
 | 
			
		||||
    <string name="can_delete_source">Kan de bron niet verwijderen…</string>
 | 
			
		||||
@@ -100,16 +78,9 @@
 | 
			
		||||
    <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_header_debug">Fout opsporen</string>
 | 
			
		||||
    <string name="self_hosted_cert_switch">Gebruik een zelf gehost certificaat?</string>
 | 
			
		||||
    <string name="self_signed_cert_warning">Vanwege veiligheidsredenen worden zelfondertekende certificaten niet standaard ondersteund. Door dit te activeren, ben ik niet verantwoordelijk voor beveiligingsproblemen die u tegenkomt.</string>
 | 
			
		||||
    <string name="pref_selfoss_category">Selfoss Api</string>
 | 
			
		||||
    <string name="pref_api_items_number_title">Geladen items nummer</string>
 | 
			
		||||
    <string name="pref_hidden_tags">Hidden Tags</string>
 | 
			
		||||
    <string name="summary_debug_identifier">ID voor foutopsporing</string>
 | 
			
		||||
    <string name="unique_id_to_clipboard">ID naar uw klembord gekopieerd</string>
 | 
			
		||||
    <string name="display_header_drawer_summary">Laat een koptekst weergeven met de url van de selfoss instantie in de zijlade.</string>
 | 
			
		||||
    <string name="display_header_drawer_title">Account titel</string>
 | 
			
		||||
    <string name="pref_general_infinite_loading_title">Laad meer artikelen door te bladeren</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>
 | 
			
		||||
@@ -120,19 +91,12 @@
 | 
			
		||||
    <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="add_to_favs_reader">Add to favorites</string>
 | 
			
		||||
    <string name="remove_to_favs_reader">Remove from favorites</string>
 | 
			
		||||
    <string name="pref_content_reader_font_size">Article reader content font size</string>
 | 
			
		||||
    <string name="pref_header_viewer">Article viewer</string>
 | 
			
		||||
    <string name="refresh_dialog_message">This will refresh your Selfoss instance.</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_off">Don\'t mark articles as read when swiping.</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept">Automatically send crash reports</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept_enabled">Will send crash reports automatically</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept_disabled">Will ask everytime when sending crash reports.</string>
 | 
			
		||||
    <string name="pref_debug_crash_reports">Crash reports</string>
 | 
			
		||||
    <string name="pref_debug_debug_logs">Debug logging (these will be sent without a dialog)</string>
 | 
			
		||||
    <string name="acra_login">Enable logging</string>
 | 
			
		||||
    <string name="drawer_item_hidden_tags">Hidden Tags</string>
 | 
			
		||||
    <string name="unmark">Mark item as unread</string>
 | 
			
		||||
    <string name="pref_header_offline">Offline and cache</string>
 | 
			
		||||
@@ -141,7 +105,8 @@
 | 
			
		||||
    <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_summary">Disable this if your server is receiving excessive amounts of database queries.</string>
 | 
			
		||||
    <string name="no_network_connectivity">Not connected !</string>
 | 
			
		||||
    <string name="network_connectivity_lost">"Network connection lost"</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_off">Articles will not be synced in the background</string>
 | 
			
		||||
    <string name="pref_switch_periodic_refresh_on">Articles will periodically be synced</string>
 | 
			
		||||
 
 | 
			
		||||
@@ -3,16 +3,13 @@
 | 
			
		||||
    <string name="app_name">"Reader for Selfoss"</string>
 | 
			
		||||
    <string name="title_activity_login">"Entrar"</string>
 | 
			
		||||
    <string name="prompt_password">"Senha"</string>
 | 
			
		||||
    <string name="prompt_http_password">"Senha HTTP"</string>
 | 
			
		||||
    <string name="action_sign_in">"Vamos lá"</string>
 | 
			
		||||
    <string name="error_invalid_password">"Senha muito pequena"</string>
 | 
			
		||||
    <string name="error_field_required">"Campo obrigatório"</string>
 | 
			
		||||
    <string name="prompt_url">"Url"</string>
 | 
			
		||||
    <string name="withLoginSwitch">"É necessário o login ?"</string>
 | 
			
		||||
    <string name="withHttpLoginSwitch">"É necessário o login HTTP ?"</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_http_login">"Usuário HTTP"</string>
 | 
			
		||||
    <string name="label_share">"Compartilhar"</string>
 | 
			
		||||
    <string name="readAll">"Ler todos"</string>
 | 
			
		||||
    <string name="action_disconnect">"Desconectar"</string>
 | 
			
		||||
@@ -26,9 +23,6 @@
 | 
			
		||||
    <string name="wrong_infos">"Verifique os detalhes novamente."</string>
 | 
			
		||||
    <string name="all_posts_not_read">"Nenhum post foi lido"</string>
 | 
			
		||||
    <string name="all_posts_read">"Todos os posts foram lidos"</string>
 | 
			
		||||
    <string name="cant_get_favs">"Não consigo obter os favoritos"</string>
 | 
			
		||||
    <string name="cant_get_new_elements">"Não consigo obter novos artigos"</string>
 | 
			
		||||
    <string name="cant_get_read">"Não consigo ler artigos"</string>
 | 
			
		||||
    <string name="nothing_here">"Nada aqui"</string>
 | 
			
		||||
    <string name="tab_new">"Novo"</string>
 | 
			
		||||
    <string name="tab_read">"Todos"</string>
 | 
			
		||||
@@ -40,26 +34,15 @@
 | 
			
		||||
    <string name="addStringNoUrl">"Faça login para adicionar fontes."</string>
 | 
			
		||||
    <string name="cant_get_sources">"Não é possível obter a lista de fontes."</string>
 | 
			
		||||
    <string name="cant_create_source">"Não é possível criar fonte."</string>
 | 
			
		||||
    <string name="cant_get_spouts">"Não é possível obter a lista de spouts."</string>
 | 
			
		||||
    <string name="cant_get_spouts_no_network">"Can't get spouts list because of a network issue."</string>
 | 
			
		||||
    <string name="cant_get_spouts">"Can't get spouts list. There may ben an api issue."</string>
 | 
			
		||||
    <string name="form_not_complete">"O formulário não está completo"</string>
 | 
			
		||||
    <string name="pref_header_links">"Links"</string>
 | 
			
		||||
    <string name="issue_tracker_link">"Rastreador de problemas"</string>
 | 
			
		||||
    <string name="issue_tracker_summary">"Informe um erro ou peça um novo recurso"</string>
 | 
			
		||||
    <string name="warning_wrong_url">"ATENÇÃO"</string>
 | 
			
		||||
    <string name="pref_switch_card_view_title">"Card View"</string>
 | 
			
		||||
    <string name="cant_mark_favortie">"Não é possível marcar o artigo como favorito"</string>
 | 
			
		||||
    <string name="cant_unmark_favortie">"Não é possível remover o item do favorito"</string>
 | 
			
		||||
    <string name="share">"Compartilhar"</string>
 | 
			
		||||
    <string name="rating_prompt_title">"Aproveitando o app ?"</string>
 | 
			
		||||
    <string name="rating_prompt_yes">"Sim !"</string>
 | 
			
		||||
    <string name="rating_prompt_no">"Na verdade não …"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_title">"Você pode nos dizer o porquê ?"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_yes">"OK !"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_no">"Não agora."</string>
 | 
			
		||||
    <string name="rating_prompt_rating_title">"Ótimo ! Você pode nos avaliar na loja ?"</string>
 | 
			
		||||
    <string name="rating_prompt_rating_yes">"Com certeza !"</string>
 | 
			
		||||
    <string name="rating_prompt_rating_no">"Não agora."</string>
 | 
			
		||||
    <string name="rating_prompt_thanks">"Obrigado, seu comentário ajuda a melhorar o app !"</string>
 | 
			
		||||
    <string name="switch_unread_count">"Exibir a contagem de artigos não lidos como um badge na barra inferior."</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>
 | 
			
		||||
@@ -82,17 +65,12 @@
 | 
			
		||||
    <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="source_code">Código fonte</string>
 | 
			
		||||
    <string name="cant_mark_read">Não é possível marcar o artigo como lido</string>
 | 
			
		||||
    <string name="cant_mark_unread">Can\'t mark article as unread</string>
 | 
			
		||||
    <string name="drawer_error_loading_tags">Erro ao carregar as tags…</string>
 | 
			
		||||
    <string name="drawer_error_loading_sources">Erro ao carregar as fontes…</string>
 | 
			
		||||
    <string name="drawer_item_filters">Filtros</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="no_tags_loaded">Nenhuma tag carregada</string>
 | 
			
		||||
    <string name="no_sources_loaded">Nenhuma fonte carregada</string>
 | 
			
		||||
    <string name="drawer_loading">Carregando …</string>
 | 
			
		||||
    <string name="menu_home_search">Procurar</string>
 | 
			
		||||
    <string name="can_delete_source">Não foi possível apagar a fonte…</string>
 | 
			
		||||
@@ -100,16 +78,9 @@
 | 
			
		||||
    <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_header_debug">Depurar</string>
 | 
			
		||||
    <string name="self_hosted_cert_switch">Usando um certificado autônomo ?</string>
 | 
			
		||||
    <string name="self_signed_cert_warning">Por motivos de segurança, certificados autônomos não são suportados por padrão. Ao ativar, não serei responsável por qualquer problema de segurança que você encontre.</string>
 | 
			
		||||
    <string name="pref_selfoss_category">Selfoss Api</string>
 | 
			
		||||
    <string name="pref_api_items_number_title">Quantidade de itens carregados</string>
 | 
			
		||||
    <string name="pref_hidden_tags">Hidden Tags</string>
 | 
			
		||||
    <string name="summary_debug_identifier">Identificador de depuração</string>
 | 
			
		||||
    <string name="unique_id_to_clipboard">Identificador copiado para a área de transferência</string>
 | 
			
		||||
    <string name="display_header_drawer_summary">Exibir um cabeçalho com o URL da instância do Selfoss na barra lateral.</string>
 | 
			
		||||
    <string name="display_header_drawer_title">Cabeçalho da conta</string>
 | 
			
		||||
    <string name="pref_general_infinite_loading_title">Carregar mais artigos ao realizar o scroll</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>
 | 
			
		||||
@@ -120,19 +91,12 @@
 | 
			
		||||
    <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="add_to_favs_reader">Adicionar aos favoritos</string>
 | 
			
		||||
    <string name="remove_to_favs_reader">Remover dos favoritos</string>
 | 
			
		||||
    <string name="pref_content_reader_font_size">Tamanho da fonte do conteúdo do leitor de artigos</string>
 | 
			
		||||
    <string name="pref_header_viewer">Visualizador de artigos</string>
 | 
			
		||||
    <string name="refresh_dialog_message">Isso atualizará sua instância do Selfoss.</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_off">Não marca artigos como lido quando abrir.</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept">Envia relatórios de erros automaticamente</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept_enabled">Enviar relatórios de erro automaticamente</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept_disabled">Perguntar sempre, ao enviar relatórios de erro.</string>
 | 
			
		||||
    <string name="pref_debug_crash_reports">Relatório de erro</string>
 | 
			
		||||
    <string name="pref_debug_debug_logs">Log de depuração (Serão enviados sem uma caixa de diálogo)</string>
 | 
			
		||||
    <string name="acra_login">Ativar registro de erros</string>
 | 
			
		||||
    <string name="drawer_item_hidden_tags">Hidden Tags</string>
 | 
			
		||||
    <string name="unmark">Mark item as unread</string>
 | 
			
		||||
    <string name="pref_header_offline">Offline and cache</string>
 | 
			
		||||
@@ -141,7 +105,8 @@
 | 
			
		||||
    <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_summary">Disable this if your server is receiving excessive amounts of database queries.</string>
 | 
			
		||||
    <string name="no_network_connectivity">Not connected !</string>
 | 
			
		||||
    <string name="network_connectivity_lost">"Network connection lost"</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_off">Articles will not be synced in the background</string>
 | 
			
		||||
    <string name="pref_switch_periodic_refresh_on">Articles will periodically be synced</string>
 | 
			
		||||
 
 | 
			
		||||
@@ -3,16 +3,13 @@
 | 
			
		||||
    <string name="app_name">"Leitor para Selfoss"</string>
 | 
			
		||||
    <string name="title_activity_login">"Iniciar sessão"</string>
 | 
			
		||||
    <string name="prompt_password">"Palavra passe"</string>
 | 
			
		||||
    <string name="prompt_http_password">"Senha HTTP"</string>
 | 
			
		||||
    <string name="action_sign_in">"Ir"</string>
 | 
			
		||||
    <string name="error_invalid_password">"Senha não é longa o suficiente"</string>
 | 
			
		||||
    <string name="error_field_required">"Campo obrigatório"</string>
 | 
			
		||||
    <string name="prompt_url">"Url"</string>
 | 
			
		||||
    <string name="withLoginSwitch">"É necessário fazer login?"</string>
 | 
			
		||||
    <string name="withHttpLoginSwitch">"É necessário fazer login on HTTP?"</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_http_login">"Nome de utilizador HTTP"</string>
 | 
			
		||||
    <string name="label_share">"Compartilhar"</string>
 | 
			
		||||
    <string name="readAll">"Ler tudo"</string>
 | 
			
		||||
    <string name="action_disconnect">"Desligar"</string>
 | 
			
		||||
@@ -26,9 +23,6 @@
 | 
			
		||||
    <string name="wrong_infos">"Verifique seus dados novamente."</string>
 | 
			
		||||
    <string name="all_posts_not_read">"Todas as postagens não foram lidas"</string>
 | 
			
		||||
    <string name="all_posts_read">"Todas as postagens foram lidas"</string>
 | 
			
		||||
    <string name="cant_get_favs">"Não é possível obter favoritos"</string>
 | 
			
		||||
    <string name="cant_get_new_elements">"Não é possível obter novos artigos"</string>
 | 
			
		||||
    <string name="cant_get_read">"Não é possível ler artigos"</string>
 | 
			
		||||
    <string name="nothing_here">"Nada aqui"</string>
 | 
			
		||||
    <string name="tab_new">"Novo"</string>
 | 
			
		||||
    <string name="tab_read">"Tudo"</string>
 | 
			
		||||
@@ -40,26 +34,15 @@
 | 
			
		||||
    <string name="addStringNoUrl">"Logar para adicionar fontes."</string>
 | 
			
		||||
    <string name="cant_get_sources">"Não é possível obter a lista de fontes."</string>
 | 
			
		||||
    <string name="cant_create_source">"Não é possível criar a fonte."</string>
 | 
			
		||||
    <string name="cant_get_spouts">"Não é possível obter a lista de bicos."</string>
 | 
			
		||||
    <string name="cant_get_spouts_no_network">"Can't get spouts list because of a network issue."</string>
 | 
			
		||||
    <string name="cant_get_spouts">"Can't get spouts list. There may ben an api issue."</string>
 | 
			
		||||
    <string name="form_not_complete">"O formulário não está completo"</string>
 | 
			
		||||
    <string name="pref_header_links">"Links"</string>
 | 
			
		||||
    <string name="issue_tracker_link">"Rastreador de problemas"</string>
 | 
			
		||||
    <string name="issue_tracker_summary">"Relatar um bug ou pedir um novo recurso"</string>
 | 
			
		||||
    <string name="warning_wrong_url">"AVISO"</string>
 | 
			
		||||
    <string name="pref_switch_card_view_title">"Vista de cartão"</string>
 | 
			
		||||
    <string name="cant_mark_favortie">"Não é possível marcar o artigo como favorito"</string>
 | 
			
		||||
    <string name="cant_unmark_favortie">"Não pode remover o item do favorito"</string>
 | 
			
		||||
    <string name="share">"Compartilhar"</string>
 | 
			
		||||
    <string name="rating_prompt_title">"Gosta da aplicação?"</string>
 | 
			
		||||
    <string name="rating_prompt_yes">"Sim!"</string>
 | 
			
		||||
    <string name="rating_prompt_no">"Não realmente…"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_title">"Pode nos dizer por que?"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_yes">"Okey!"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_no">"Agora não."</string>
 | 
			
		||||
    <string name="rating_prompt_rating_title">"Legal! Você pode classificar-na loja?"</string>
 | 
			
		||||
    <string name="rating_prompt_rating_yes">"Claro!"</string>
 | 
			
		||||
    <string name="rating_prompt_rating_no">"Agora não."</string>
 | 
			
		||||
    <string name="rating_prompt_thanks">"Obrigado, seu feedback ajudar a realçar o app!"</string>
 | 
			
		||||
    <string name="switch_unread_count">"Exibir a contagem não lida como um emblema para a barra inferior."</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>
 | 
			
		||||
@@ -82,17 +65,12 @@
 | 
			
		||||
    <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="source_code">Código fonte</string>
 | 
			
		||||
    <string name="cant_mark_read">Não pode marcar o artigo como lido</string>
 | 
			
		||||
    <string name="cant_mark_unread">Can\'t mark article as unread</string>
 | 
			
		||||
    <string name="drawer_error_loading_tags">Erro ao carregar etiquetas…</string>
 | 
			
		||||
    <string name="drawer_error_loading_sources">Erro ao carregar fontes…</string>
 | 
			
		||||
    <string name="drawer_item_filters">Filtros</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="no_tags_loaded">Não tags carregado</string>
 | 
			
		||||
    <string name="no_sources_loaded">Não há fontes carregadas</string>
 | 
			
		||||
    <string name="drawer_loading">A carregar…</string>
 | 
			
		||||
    <string name="menu_home_search">Buscar</string>
 | 
			
		||||
    <string name="can_delete_source">Não é possível excluir a fonte…</string>
 | 
			
		||||
@@ -100,16 +78,9 @@
 | 
			
		||||
    <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_header_debug">Depurar</string>
 | 
			
		||||
    <string name="self_hosted_cert_switch">Usando um certificado hospedado?</string>
 | 
			
		||||
    <string name="self_signed_cert_warning">Devido a razões de segurança, auto certificados auto-assinados não são suportados por padrão. Ao activar isto, eu não vou ser responsável de qualquer problema de segurança que você encontrar.</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_hidden_tags">Hidden Tags</string>
 | 
			
		||||
    <string name="summary_debug_identifier">Depurar o identificador</string>
 | 
			
		||||
    <string name="unique_id_to_clipboard">Identificador de copiados para a área de transferência</string>
 | 
			
		||||
    <string name="display_header_drawer_summary">Exibir um cabeçalho com o url de instância de selfoss na gaveta lateral.</string>
 | 
			
		||||
    <string name="display_header_drawer_title">Cabeçalho de conta</string>
 | 
			
		||||
    <string name="pref_general_infinite_loading_title">Carregar mais artigos no pergaminho</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>
 | 
			
		||||
@@ -120,19 +91,12 @@
 | 
			
		||||
    <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="add_to_favs_reader">Add to favorites</string>
 | 
			
		||||
    <string name="remove_to_favs_reader">Remove from favorites</string>
 | 
			
		||||
    <string name="pref_content_reader_font_size">Article reader content font size</string>
 | 
			
		||||
    <string name="pref_header_viewer">Article viewer</string>
 | 
			
		||||
    <string name="refresh_dialog_message">This will refresh your Selfoss instance.</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_off">Don\'t mark articles as read when swiping.</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept">Automatically send crash reports</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept_enabled">Will send crash reports automatically</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept_disabled">Will ask everytime when sending crash reports.</string>
 | 
			
		||||
    <string name="pref_debug_crash_reports">Crash reports</string>
 | 
			
		||||
    <string name="pref_debug_debug_logs">Debug logging (these will be sent without a dialog)</string>
 | 
			
		||||
    <string name="acra_login">Enable logging</string>
 | 
			
		||||
    <string name="drawer_item_hidden_tags">Hidden Tags</string>
 | 
			
		||||
    <string name="unmark">Mark item as unread</string>
 | 
			
		||||
    <string name="pref_header_offline">Offline and cache</string>
 | 
			
		||||
@@ -141,7 +105,8 @@
 | 
			
		||||
    <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_summary">Disable this if your server is receiving excessive amounts of database queries.</string>
 | 
			
		||||
    <string name="no_network_connectivity">Not connected !</string>
 | 
			
		||||
    <string name="network_connectivity_lost">"Network connection lost"</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_off">Articles will not be synced in the background</string>
 | 
			
		||||
    <string name="pref_switch_periodic_refresh_on">Articles will periodically be synced</string>
 | 
			
		||||
 
 | 
			
		||||
@@ -3,16 +3,13 @@
 | 
			
		||||
    <string name="app_name">"Reader for Selfoss"</string>
 | 
			
		||||
    <string name="title_activity_login">"පිවිසෙන්න"</string>
 | 
			
		||||
    <string name="prompt_password">"මුර පදය"</string>
 | 
			
		||||
    <string name="prompt_http_password">"HTTP Password"</string>
 | 
			
		||||
    <string name="action_sign_in">"Go"</string>
 | 
			
		||||
    <string name="error_invalid_password">"Password not long enough"</string>
 | 
			
		||||
    <string name="error_field_required">"Field required"</string>
 | 
			
		||||
    <string name="prompt_url">"Url"</string>
 | 
			
		||||
    <string name="withLoginSwitch">"Login required ?"</string>
 | 
			
		||||
    <string name="withHttpLoginSwitch">"HTTP Login required ?"</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_http_login">"HTTP Username"</string>
 | 
			
		||||
    <string name="label_share">"Share"</string>
 | 
			
		||||
    <string name="readAll">"Read all"</string>
 | 
			
		||||
    <string name="action_disconnect">"Disconnect"</string>
 | 
			
		||||
@@ -26,9 +23,6 @@
 | 
			
		||||
    <string name="wrong_infos">"Check your details again."</string>
 | 
			
		||||
    <string name="all_posts_not_read">"All posts weren't read"</string>
 | 
			
		||||
    <string name="all_posts_read">"All posts were read"</string>
 | 
			
		||||
    <string name="cant_get_favs">"Can't get favorites"</string>
 | 
			
		||||
    <string name="cant_get_new_elements">"Can't get new articles"</string>
 | 
			
		||||
    <string name="cant_get_read">"Can't get read articles"</string>
 | 
			
		||||
    <string name="nothing_here">"Nothing here"</string>
 | 
			
		||||
    <string name="tab_new">"New"</string>
 | 
			
		||||
    <string name="tab_read">"සියල්ල"</string>
 | 
			
		||||
@@ -40,26 +34,15 @@
 | 
			
		||||
    <string name="addStringNoUrl">"Log in to add sources."</string>
 | 
			
		||||
    <string name="cant_get_sources">"Can't get sources list."</string>
 | 
			
		||||
    <string name="cant_create_source">"Can't create source."</string>
 | 
			
		||||
    <string name="cant_get_spouts">"Can't get spouts list."</string>
 | 
			
		||||
    <string name="cant_get_spouts_no_network">"Can't get spouts list because of a network issue."</string>
 | 
			
		||||
    <string name="cant_get_spouts">"Can't get spouts list. There may ben an api issue."</string>
 | 
			
		||||
    <string name="form_not_complete">"The form is not complete"</string>
 | 
			
		||||
    <string name="pref_header_links">"Links"</string>
 | 
			
		||||
    <string name="issue_tracker_link">"Issue Tracker"</string>
 | 
			
		||||
    <string name="issue_tracker_summary">"Report a bug or ask for a new feature"</string>
 | 
			
		||||
    <string name="warning_wrong_url">"WARNING"</string>
 | 
			
		||||
    <string name="pref_switch_card_view_title">"Card View"</string>
 | 
			
		||||
    <string name="cant_mark_favortie">"Can't mark article as favorite"</string>
 | 
			
		||||
    <string name="cant_unmark_favortie">"Can't remove item from favorite"</string>
 | 
			
		||||
    <string name="share">"Share"</string>
 | 
			
		||||
    <string name="rating_prompt_title">"Enjoying the app ?"</string>
 | 
			
		||||
    <string name="rating_prompt_yes">"Yes !"</string>
 | 
			
		||||
    <string name="rating_prompt_no">"Not really …"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_title">"Can you tell us why ?"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_yes">"OK !"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_no">"Not now."</string>
 | 
			
		||||
    <string name="rating_prompt_rating_title">"Great ! Can you rate us on the Store ?"</string>
 | 
			
		||||
    <string name="rating_prompt_rating_yes">"Sure !"</string>
 | 
			
		||||
    <string name="rating_prompt_rating_no">"Not right now."</string>
 | 
			
		||||
    <string name="rating_prompt_thanks">"Thanks, your feedback help enhance the app !"</string>
 | 
			
		||||
    <string name="switch_unread_count">"Display the unread count as a badge for the bottom bar."</string>
 | 
			
		||||
    <string name="switch_unread_count_title">"Display unread count"</string>
 | 
			
		||||
    <string name="display_all_counts_title">"Display count for favorite and read"</string>
 | 
			
		||||
@@ -82,17 +65,12 @@
 | 
			
		||||
    <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="source_code">Source code</string>
 | 
			
		||||
    <string name="cant_mark_read">Can\'t mark article as read</string>
 | 
			
		||||
    <string name="cant_mark_unread">Can\'t mark article as unread</string>
 | 
			
		||||
    <string name="drawer_error_loading_tags">Error loading tags…</string>
 | 
			
		||||
    <string name="drawer_error_loading_sources">Error loading sources…</string>
 | 
			
		||||
    <string name="drawer_item_filters">Filters</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="no_tags_loaded">No tags loaded</string>
 | 
			
		||||
    <string name="no_sources_loaded">No sources loaded</string>
 | 
			
		||||
    <string name="drawer_loading">Loading …</string>
 | 
			
		||||
    <string name="menu_home_search">Search</string>
 | 
			
		||||
    <string name="can_delete_source">Can\'t delete the source…</string>
 | 
			
		||||
@@ -100,16 +78,9 @@
 | 
			
		||||
    <string name="pref_header_theme">Themes</string>
 | 
			
		||||
    <string name="default_theme">Default</string>
 | 
			
		||||
    <string name="default_dark_theme">Default/Dark</string>
 | 
			
		||||
    <string name="pref_header_debug">Debug</string>
 | 
			
		||||
    <string name="self_hosted_cert_switch">Using a self hosted certificate ?</string>
 | 
			
		||||
    <string name="self_signed_cert_warning">Due to security reasons, self signed certificates are not supported by default. By activating this, I\'ll not be responsible of any security problem you encounter.</string>
 | 
			
		||||
    <string name="pref_selfoss_category">Selfoss Api</string>
 | 
			
		||||
    <string name="pref_api_items_number_title">Loaded items number</string>
 | 
			
		||||
    <string name="pref_hidden_tags">Hidden Tags</string>
 | 
			
		||||
    <string name="summary_debug_identifier">Debug identifier</string>
 | 
			
		||||
    <string name="unique_id_to_clipboard">Identifier copied to your clipboard</string>
 | 
			
		||||
    <string name="display_header_drawer_summary">Display a header with the selfoss instance url on the lateral drawer.</string>
 | 
			
		||||
    <string name="display_header_drawer_title">Account header</string>
 | 
			
		||||
    <string name="pref_general_infinite_loading_title">Load more articles on scroll</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>
 | 
			
		||||
@@ -120,19 +91,12 @@
 | 
			
		||||
    <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="add_to_favs_reader">Add to favorites</string>
 | 
			
		||||
    <string name="remove_to_favs_reader">Remove from favorites</string>
 | 
			
		||||
    <string name="pref_content_reader_font_size">Article reader content font size</string>
 | 
			
		||||
    <string name="pref_header_viewer">Article viewer</string>
 | 
			
		||||
    <string name="refresh_dialog_message">This will refresh your Selfoss instance.</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_off">Don\'t mark articles as read when swiping.</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept">Automatically send crash reports</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept_enabled">Will send crash reports automatically</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept_disabled">Will ask everytime when sending crash reports.</string>
 | 
			
		||||
    <string name="pref_debug_crash_reports">Crash reports</string>
 | 
			
		||||
    <string name="pref_debug_debug_logs">Debug logging (these will be sent without a dialog)</string>
 | 
			
		||||
    <string name="acra_login">Enable logging</string>
 | 
			
		||||
    <string name="drawer_item_hidden_tags">Hidden Tags</string>
 | 
			
		||||
    <string name="unmark">Mark item as unread</string>
 | 
			
		||||
    <string name="pref_header_offline">Offline and cache</string>
 | 
			
		||||
@@ -141,7 +105,8 @@
 | 
			
		||||
    <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_summary">Disable this if your server is receiving excessive amounts of database queries.</string>
 | 
			
		||||
    <string name="no_network_connectivity">Not connected !</string>
 | 
			
		||||
    <string name="network_connectivity_lost">"Network connection lost"</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_off">Articles will not be synced in the background</string>
 | 
			
		||||
    <string name="pref_switch_periodic_refresh_on">Articles will periodically be synced</string>
 | 
			
		||||
 
 | 
			
		||||
@@ -3,16 +3,13 @@
 | 
			
		||||
    <string name="app_name">"Selfoss için okuyucu"</string>
 | 
			
		||||
    <string name="title_activity_login">"Giriş"</string>
 | 
			
		||||
    <string name="prompt_password">"Şifre"</string>
 | 
			
		||||
    <string name="prompt_http_password">"HTTP şifresi"</string>
 | 
			
		||||
    <string name="action_sign_in">"Git"</string>
 | 
			
		||||
    <string name="error_invalid_password">"Parola yeterince uzun değil"</string>
 | 
			
		||||
    <string name="error_field_required">"Alan gereklidir"</string>
 | 
			
		||||
    <string name="prompt_url">"Url"</string>
 | 
			
		||||
    <string name="withLoginSwitch">"Kullanıcı Girişi Gerekli?"</string>
 | 
			
		||||
    <string name="withHttpLoginSwitch">"HTTP üyelik gerekmektedir?"</string>
 | 
			
		||||
    <string name="login_url_problem">"Oops. Url'nin sonuna \"/\" eklemek gerekebilir."</string>
 | 
			
		||||
    <string name="prompt_login">"Kullanıcı adı"</string>
 | 
			
		||||
    <string name="prompt_http_login">"HTTP kullanıcı adı"</string>
 | 
			
		||||
    <string name="label_share">"Paylaş"</string>
 | 
			
		||||
    <string name="readAll">"Tümünü oku"</string>
 | 
			
		||||
    <string name="action_disconnect">"Bağlantıyı kes"</string>
 | 
			
		||||
@@ -26,9 +23,6 @@
 | 
			
		||||
    <string name="wrong_infos">"Detaylarınızı tekrar kontrol edin."</string>
 | 
			
		||||
    <string name="all_posts_not_read">"Tüm mesajlar okunmadı"</string>
 | 
			
		||||
    <string name="all_posts_read">"Tüm mesajlar okundu"</string>
 | 
			
		||||
    <string name="cant_get_favs">"Sık ullanılanlara ulaşılamıyor"</string>
 | 
			
		||||
    <string name="cant_get_new_elements">"Yeni makalelere ulaşılamıyor"</string>
 | 
			
		||||
    <string name="cant_get_read">"Yeni makaleler okunamıyor"</string>
 | 
			
		||||
    <string name="nothing_here">"Burada hiçbir şey yok"</string>
 | 
			
		||||
    <string name="tab_new">"Yeni"</string>
 | 
			
		||||
    <string name="tab_read">"Tüm"</string>
 | 
			
		||||
@@ -40,26 +34,15 @@
 | 
			
		||||
    <string name="addStringNoUrl">"Kaynakları eklemek için giriş yapın."</string>
 | 
			
		||||
    <string name="cant_get_sources">"Kaynakları listesi alınamıyor."</string>
 | 
			
		||||
    <string name="cant_create_source">"Kaynak oluşturulamıyor."</string>
 | 
			
		||||
    <string name="cant_get_spouts">"Spouts listesine girilemiyor."</string>
 | 
			
		||||
    <string name="cant_get_spouts_no_network">"Can't get spouts list because of a network issue."</string>
 | 
			
		||||
    <string name="cant_get_spouts">"Can't get spouts list. There may ben an api issue."</string>
 | 
			
		||||
    <string name="form_not_complete">"Form tamamlanamadı"</string>
 | 
			
		||||
    <string name="pref_header_links">"Bağlantılar"</string>
 | 
			
		||||
    <string name="issue_tracker_link">"Sorun İzleyici"</string>
 | 
			
		||||
    <string name="issue_tracker_summary">"Bir hatayı bildir veya yeni bir özellik iste"</string>
 | 
			
		||||
    <string name="warning_wrong_url">"UYARI"</string>
 | 
			
		||||
    <string name="pref_switch_card_view_title">"Kart görünümü"</string>
 | 
			
		||||
    <string name="cant_mark_favortie">"Makale favori olarak işaretlenemez"</string>
 | 
			
		||||
    <string name="cant_unmark_favortie">"Nesne favorilerden kaldırılamıyor"</string>
 | 
			
		||||
    <string name="share">"Paylaş"</string>
 | 
			
		||||
    <string name="rating_prompt_title">"Uygulamayı sevdiniz mi?"</string>
 | 
			
		||||
    <string name="rating_prompt_yes">"Evet!"</string>
 | 
			
		||||
    <string name="rating_prompt_no">"Aslında değil…"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_title">"Nedenini bize söyleyebilir misiniz?"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_yes">"Tamam!"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_no">"Henüz değil."</string>
 | 
			
		||||
    <string name="rating_prompt_rating_title">"Harika ! Bizi mağzada oylayabilir misin?"</string>
 | 
			
		||||
    <string name="rating_prompt_rating_yes">"Tabii ki!"</string>
 | 
			
		||||
    <string name="rating_prompt_rating_no">"Şimdi değil."</string>
 | 
			
		||||
    <string name="rating_prompt_thanks">"Teşekkürler, geri dönüşünü uygulamayı geliştirmede yardımcı olur!"</string>
 | 
			
		||||
    <string name="switch_unread_count">"Okunmamış sayıyı, alt çubuk için bir rozet olarak görüntüleyin."</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>
 | 
			
		||||
@@ -82,17 +65,12 @@
 | 
			
		||||
    <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="source_code">Kaynak kodu</string>
 | 
			
		||||
    <string name="cant_mark_read">Makale favori olarak işaretlenemez</string>
 | 
			
		||||
    <string name="cant_mark_unread">Can\'t mark article as unread</string>
 | 
			
		||||
    <string name="drawer_error_loading_tags">Etiketler yükleme hatası…</string>
 | 
			
		||||
    <string name="drawer_error_loading_sources">Kaynaklar yüklenirken hata oluştu…</string>
 | 
			
		||||
    <string name="drawer_item_filters">Filtreler</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="no_tags_loaded">Yüklenen görüntü yok</string>
 | 
			
		||||
    <string name="no_sources_loaded">Yüklenen kaynak yok</string>
 | 
			
		||||
    <string name="drawer_loading">Yükleniyor…</string>
 | 
			
		||||
    <string name="menu_home_search">Ara</string>
 | 
			
		||||
    <string name="can_delete_source">Kaynak silinemiyor…</string>
 | 
			
		||||
@@ -100,16 +78,9 @@
 | 
			
		||||
    <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_header_debug">Hata ayıklama</string>
 | 
			
		||||
    <string name="self_hosted_cert_switch">Kendi kendine barındırılan bir sertifika mı kullanıyorsunuz?</string>
 | 
			
		||||
    <string name="self_signed_cert_warning">Güvenlik nedeniyle, kendinden imzalı sertifikalar varsayılan olarak desteklenmez. Bunu etkinleştirerek karşılaştığınız herhangi bir güvenlik sorununun sorumluluğunu almayacağım.</string>
 | 
			
		||||
    <string name="pref_selfoss_category">Selfoss Uygulaması</string>
 | 
			
		||||
    <string name="pref_api_items_number_title">Yüklenen öğe numarası</string>
 | 
			
		||||
    <string name="pref_hidden_tags">Hidden Tags</string>
 | 
			
		||||
    <string name="summary_debug_identifier">Hata ayıklama tanıtıcısı</string>
 | 
			
		||||
    <string name="unique_id_to_clipboard">Tanımlayıcı panonuza kopyalanır</string>
 | 
			
		||||
    <string name="display_header_drawer_summary">Selfoss örneği url\'li bir üstbilgi, yan çekmece üzerine gösterin.</string>
 | 
			
		||||
    <string name="display_header_drawer_title">Hesap başlığı</string>
 | 
			
		||||
    <string name="pref_general_infinite_loading_title">Kaydırma üzerine daha fazla makale yükleyin</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>
 | 
			
		||||
@@ -120,19 +91,12 @@
 | 
			
		||||
    <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="add_to_favs_reader">Add to favorites</string>
 | 
			
		||||
    <string name="remove_to_favs_reader">Remove from favorites</string>
 | 
			
		||||
    <string name="pref_content_reader_font_size">Article reader content font size</string>
 | 
			
		||||
    <string name="pref_header_viewer">Article viewer</string>
 | 
			
		||||
    <string name="refresh_dialog_message">This will refresh your Selfoss instance.</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_off">Don\'t mark articles as read when swiping.</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept">Automatically send crash reports</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept_enabled">Will send crash reports automatically</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept_disabled">Will ask everytime when sending crash reports.</string>
 | 
			
		||||
    <string name="pref_debug_crash_reports">Crash reports</string>
 | 
			
		||||
    <string name="pref_debug_debug_logs">Debug logging (these will be sent without a dialog)</string>
 | 
			
		||||
    <string name="acra_login">Enable logging</string>
 | 
			
		||||
    <string name="drawer_item_hidden_tags">Hidden Tags</string>
 | 
			
		||||
    <string name="unmark">Mark item as unread</string>
 | 
			
		||||
    <string name="pref_header_offline">Offline and cache</string>
 | 
			
		||||
@@ -141,7 +105,8 @@
 | 
			
		||||
    <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_summary">Disable this if your server is receiving excessive amounts of database queries.</string>
 | 
			
		||||
    <string name="no_network_connectivity">Not connected !</string>
 | 
			
		||||
    <string name="network_connectivity_lost">"Network connection lost"</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_off">Articles will not be synced in the background</string>
 | 
			
		||||
    <string name="pref_switch_periodic_refresh_on">Articles will periodically be synced</string>
 | 
			
		||||
 
 | 
			
		||||
@@ -3,16 +3,13 @@
 | 
			
		||||
    <string name="app_name">"Selfoss 阅读器"</string>
 | 
			
		||||
    <string name="title_activity_login">"登录"</string>
 | 
			
		||||
    <string name="prompt_password">"密码"</string>
 | 
			
		||||
    <string name="prompt_http_password">"HTTP 密码"</string>
 | 
			
		||||
    <string name="action_sign_in">"转至"</string>
 | 
			
		||||
    <string name="error_invalid_password">"密码不够长"</string>
 | 
			
		||||
    <string name="error_field_required">"必填字段"</string>
 | 
			
		||||
    <string name="prompt_url">"网址"</string>
 | 
			
		||||
    <string name="withLoginSwitch">"需要登录?"</string>
 | 
			
		||||
    <string name="withHttpLoginSwitch">"请先登录网站"</string>
 | 
			
		||||
    <string name="login_url_problem">"哎呀。您可能需要在网址的末尾添加一个 \"/\"。"</string>
 | 
			
		||||
    <string name="prompt_login">"用户名"</string>
 | 
			
		||||
    <string name="prompt_http_login">"HTTP 用户名"</string>
 | 
			
		||||
    <string name="label_share">"分享"</string>
 | 
			
		||||
    <string name="readAll">"全部阅读"</string>
 | 
			
		||||
    <string name="action_disconnect">"断开连接"</string>
 | 
			
		||||
@@ -26,9 +23,6 @@
 | 
			
		||||
    <string name="wrong_infos">"再次检查您的详细信息。"</string>
 | 
			
		||||
    <string name="all_posts_not_read">"所有帖子都未读"</string>
 | 
			
		||||
    <string name="all_posts_read">"所有帖子已读"</string>
 | 
			
		||||
    <string name="cant_get_favs">"无法获取收藏文件"</string>
 | 
			
		||||
    <string name="cant_get_new_elements">"无法获取新文章"</string>
 | 
			
		||||
    <string name="cant_get_read">"无法获取已读文章"</string>
 | 
			
		||||
    <string name="nothing_here">"暂无内容!"</string>
 | 
			
		||||
    <string name="tab_new">"新建"</string>
 | 
			
		||||
    <string name="tab_read">"所有"</string>
 | 
			
		||||
@@ -40,26 +34,15 @@
 | 
			
		||||
    <string name="addStringNoUrl">"登录以添加数据源。"</string>
 | 
			
		||||
    <string name="cant_get_sources">"无法获取数据列表。"</string>
 | 
			
		||||
    <string name="cant_create_source">"无法创建源数据。"</string>
 | 
			
		||||
    <string name="cant_get_spouts">"无法获取数据列表"</string>
 | 
			
		||||
    <string name="cant_get_spouts_no_network">"由于网络问题,无法获取 spouts 列表。"</string>
 | 
			
		||||
    <string name="cant_get_spouts">"无法获取 spouts 列表。可能有一个 api 问题。"</string>
 | 
			
		||||
    <string name="form_not_complete">"窗体未完成"</string>
 | 
			
		||||
    <string name="pref_header_links">"链接"</string>
 | 
			
		||||
    <string name="issue_tracker_link">"问题追踪器"</string>
 | 
			
		||||
    <string name="issue_tracker_summary">"报告错误或请求新功能"</string>
 | 
			
		||||
    <string name="warning_wrong_url">"警告"</string>
 | 
			
		||||
    <string name="pref_switch_card_view_title">"卡片视图"</string>
 | 
			
		||||
    <string name="cant_mark_favortie">"不能将文章标记为收藏"</string>
 | 
			
		||||
    <string name="cant_unmark_favortie">"无法从收藏中删除项目"</string>
 | 
			
		||||
    <string name="share">"共享"</string>
 | 
			
		||||
    <string name="rating_prompt_title">"喜欢这个应用吗?"</string>
 | 
			
		||||
    <string name="rating_prompt_yes">"是的!"</string>
 | 
			
		||||
    <string name="rating_prompt_no">"不大喜欢…"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_title">"能告诉我们为什么吗?"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_yes">"好的!"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_no">"以后再说。"</string>
 | 
			
		||||
    <string name="rating_prompt_rating_title">"太好了!你能在应用商店给我们打分吗?"</string>
 | 
			
		||||
    <string name="rating_prompt_rating_yes">"当然!"</string>
 | 
			
		||||
    <string name="rating_prompt_rating_no">"现在不行。"</string>
 | 
			
		||||
    <string name="rating_prompt_thanks">"谢谢,您的反馈有助于改进应用程序!"</string>
 | 
			
		||||
    <string name="switch_unread_count">"将未读数在底部显示为一个徽标。"</string>
 | 
			
		||||
    <string name="switch_unread_count_title">"显示未读数"</string>
 | 
			
		||||
    <string name="display_all_counts_title">"显示收藏和已读的计数"</string>
 | 
			
		||||
@@ -82,17 +65,12 @@
 | 
			
		||||
    <string name="card_height_on">卡片高度将根据内容调整</string>
 | 
			
		||||
    <string name="card_height_off">卡片高度将被固定</string>
 | 
			
		||||
    <string name="source_code">源代码</string>
 | 
			
		||||
    <string name="cant_mark_read">无法将文章标记为已读</string>
 | 
			
		||||
    <string name="cant_mark_unread">无法将文章标记为未读</string>
 | 
			
		||||
    <string name="drawer_error_loading_tags">加载标记时出错..。</string>
 | 
			
		||||
    <string name="drawer_error_loading_sources">加载源时出错..。</string>
 | 
			
		||||
    <string name="drawer_item_filters">搜索条件</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="no_tags_loaded">未加载标签</string>
 | 
			
		||||
    <string name="no_sources_loaded">未加载数据源</string>
 | 
			
		||||
    <string name="drawer_loading">正在载入…</string>
 | 
			
		||||
    <string name="menu_home_search">搜索</string>
 | 
			
		||||
    <string name="can_delete_source">无法删除数据源…</string>
 | 
			
		||||
@@ -100,16 +78,9 @@
 | 
			
		||||
    <string name="pref_header_theme">主题</string>
 | 
			
		||||
    <string name="default_theme">默认</string>
 | 
			
		||||
    <string name="default_dark_theme">默认值/暗</string>
 | 
			
		||||
    <string name="pref_header_debug">调试</string>
 | 
			
		||||
    <string name="self_hosted_cert_switch">使用自托管证书?</string>
 | 
			
		||||
    <string name="self_signed_cert_warning">出于安全考虑, 默认情况下不支持自签名证书。如果激活此项, 您遇到的任何安全问题我将概不负责。</string>
 | 
			
		||||
    <string name="pref_selfoss_category">塞尔福斯 Api</string>
 | 
			
		||||
    <string name="pref_api_items_number_title">已加载项目编号</string>
 | 
			
		||||
    <string name="pref_hidden_tags">隐藏标签</string>
 | 
			
		||||
    <string name="summary_debug_identifier">除错标识符</string>
 | 
			
		||||
    <string name="unique_id_to_clipboard">复制到你的剪贴板的标识符</string>
 | 
			
		||||
    <string name="display_header_drawer_summary">在侧边栏中显示带有 Selfoss 链接地址的页眉。</string>
 | 
			
		||||
    <string name="display_header_drawer_title">帐户页眉</string>
 | 
			
		||||
    <string name="pref_general_infinite_loading_title">翻页时载入更多文章</string>
 | 
			
		||||
    <string name="translation">翻译</string>
 | 
			
		||||
    <string name="cant_open_invalid_url">项目链接地址无效。我正在设法解决这个问题,以避免应用程序崩溃。</string>
 | 
			
		||||
@@ -120,19 +91,12 @@
 | 
			
		||||
    <string name="reader_action_share">分享</string>
 | 
			
		||||
    <string name="pref_switch_actions_pager_scroll_on">切换文章时将文章标记为已读。</string>
 | 
			
		||||
    <string name="add_to_favs_reader">添加到收藏</string>
 | 
			
		||||
    <string name="remove_to_favs_reader">从收藏中移除</string>
 | 
			
		||||
    <string name="pref_content_reader_font_size">文章阅读器内容字体大小</string>
 | 
			
		||||
    <string name="pref_header_viewer">文章查看器</string>
 | 
			
		||||
    <string name="refresh_dialog_message">这将刷新您的 Selfoss 实例。</string>
 | 
			
		||||
    <string name="markall_dialog_message">这将标记所有项目为已读。</string>
 | 
			
		||||
    <string name="pref_switch_actions_pager_scroll">滑动时标为已读</string>
 | 
			
		||||
    <string name="pref_switch_actions_pager_scroll_off">滑动时不标记文章为已读</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept">自动发送崩溃报告</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept_enabled">允许自动发送故障报告</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept_disabled">每次发送崩溃报告时都会询问。</string>
 | 
			
		||||
    <string name="pref_debug_crash_reports">崩溃报告</string>
 | 
			
		||||
    <string name="pref_debug_debug_logs">调试日志(这些日志将在没有对话框的情况下发送)</string>
 | 
			
		||||
    <string name="acra_login">启用日志记录</string>
 | 
			
		||||
    <string name="drawer_item_hidden_tags">隐藏标签</string>
 | 
			
		||||
    <string name="unmark">标记条目为未读</string>
 | 
			
		||||
    <string name="pref_header_offline">离线和缓存</string>
 | 
			
		||||
@@ -141,7 +105,8 @@
 | 
			
		||||
    <string name="pref_switch_items_caching">保存项目以便离线使用</string>
 | 
			
		||||
    <string name="pref_switch_update_sources">检查新来源和标签</string>
 | 
			
		||||
    <string name="pref_switch_update_sources_summary">如果你的服务器接收过多的数据库查询,请禁用此功能。</string>
 | 
			
		||||
    <string name="no_network_connectivity">未连接!</string>
 | 
			
		||||
    <string name="network_connectivity_lost">"网络连接丢失"</string>
 | 
			
		||||
    <string name="network_connectivity_retrieved">"网络连接现在可用"</string>
 | 
			
		||||
    <string name="pref_switch_periodic_refresh">同步文章</string>
 | 
			
		||||
    <string name="pref_switch_periodic_refresh_off">文章将不会在后台同步</string>
 | 
			
		||||
    <string name="pref_switch_periodic_refresh_on">将定期同步文章</string>
 | 
			
		||||
 
 | 
			
		||||
@@ -3,16 +3,13 @@
 | 
			
		||||
    <string name="app_name">"Selfoss 阅读器"</string>
 | 
			
		||||
    <string name="title_activity_login">"登录"</string>
 | 
			
		||||
    <string name="prompt_password">"密码"</string>
 | 
			
		||||
    <string name="prompt_http_password">"HTTP 密碼"</string>
 | 
			
		||||
    <string name="action_sign_in">"转至"</string>
 | 
			
		||||
    <string name="error_invalid_password">"密码不够长"</string>
 | 
			
		||||
    <string name="error_field_required">"欄位必填"</string>
 | 
			
		||||
    <string name="prompt_url">"网址"</string>
 | 
			
		||||
    <string name="withLoginSwitch">"需要登入?"</string>
 | 
			
		||||
    <string name="withHttpLoginSwitch">"请先登录网站"</string>
 | 
			
		||||
    <string name="login_url_problem">"哎呀。您可能需要在网址的末尾添加一个 \"/\"。"</string>
 | 
			
		||||
    <string name="prompt_login">"使用者名稱"</string>
 | 
			
		||||
    <string name="prompt_http_login">"HTTP 用户名"</string>
 | 
			
		||||
    <string name="label_share">"分享"</string>
 | 
			
		||||
    <string name="readAll">"全部阅读"</string>
 | 
			
		||||
    <string name="action_disconnect">"断开连接"</string>
 | 
			
		||||
@@ -26,9 +23,6 @@
 | 
			
		||||
    <string name="wrong_infos">"再次检查您的详细信息。"</string>
 | 
			
		||||
    <string name="all_posts_not_read">"所有帖子都未读"</string>
 | 
			
		||||
    <string name="all_posts_read">"所有帖子已读"</string>
 | 
			
		||||
    <string name="cant_get_favs">"无法获取收藏文件"</string>
 | 
			
		||||
    <string name="cant_get_new_elements">"无法获取新文章"</string>
 | 
			
		||||
    <string name="cant_get_read">"无法获取已读文章"</string>
 | 
			
		||||
    <string name="nothing_here">"暂无内容!"</string>
 | 
			
		||||
    <string name="tab_new">"新建"</string>
 | 
			
		||||
    <string name="tab_read">"所有"</string>
 | 
			
		||||
@@ -40,26 +34,15 @@
 | 
			
		||||
    <string name="addStringNoUrl">"登录以添加数据源。"</string>
 | 
			
		||||
    <string name="cant_get_sources">"无法获取数据列表。"</string>
 | 
			
		||||
    <string name="cant_create_source">"无法创建源数据。"</string>
 | 
			
		||||
    <string name="cant_get_spouts">"无法获取数据列表"</string>
 | 
			
		||||
    <string name="cant_get_spouts_no_network">"Can't get spouts list because of a network issue."</string>
 | 
			
		||||
    <string name="cant_get_spouts">"Can't get spouts list. There may ben an api issue."</string>
 | 
			
		||||
    <string name="form_not_complete">"窗体未完成"</string>
 | 
			
		||||
    <string name="pref_header_links">"链接"</string>
 | 
			
		||||
    <string name="issue_tracker_link">"问题追踪器"</string>
 | 
			
		||||
    <string name="issue_tracker_summary">"报告错误或请求新功能"</string>
 | 
			
		||||
    <string name="warning_wrong_url">"警告"</string>
 | 
			
		||||
    <string name="pref_switch_card_view_title">"卡片视图"</string>
 | 
			
		||||
    <string name="cant_mark_favortie">"不能将文章标记为收藏"</string>
 | 
			
		||||
    <string name="cant_unmark_favortie">"无法从收藏中删除项目"</string>
 | 
			
		||||
    <string name="share">"共享"</string>
 | 
			
		||||
    <string name="rating_prompt_title">"喜欢这个应用吗?"</string>
 | 
			
		||||
    <string name="rating_prompt_yes">"是的!"</string>
 | 
			
		||||
    <string name="rating_prompt_no">"不大喜欢…"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_title">"能告诉我们为什么吗?"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_yes">"好的!"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_no">"以后再说。"</string>
 | 
			
		||||
    <string name="rating_prompt_rating_title">"太好了!你能在应用商店给我们打分吗?"</string>
 | 
			
		||||
    <string name="rating_prompt_rating_yes">"当然!"</string>
 | 
			
		||||
    <string name="rating_prompt_rating_no">"现在不行。"</string>
 | 
			
		||||
    <string name="rating_prompt_thanks">"谢谢,您的反馈有助于改进应用程序!"</string>
 | 
			
		||||
    <string name="switch_unread_count">"将未读数在底部显示为一个徽标。"</string>
 | 
			
		||||
    <string name="switch_unread_count_title">"显示未读数"</string>
 | 
			
		||||
    <string name="display_all_counts_title">"显示收藏和已读的计数"</string>
 | 
			
		||||
@@ -82,17 +65,12 @@
 | 
			
		||||
    <string name="card_height_on">卡片高度将根据内容调整</string>
 | 
			
		||||
    <string name="card_height_off">卡片高度将被固定</string>
 | 
			
		||||
    <string name="source_code">源代码</string>
 | 
			
		||||
    <string name="cant_mark_read">无法将文章标记为已读</string>
 | 
			
		||||
    <string name="cant_mark_unread">Can\'t mark article as unread</string>
 | 
			
		||||
    <string name="drawer_error_loading_tags">加载标记时出错..。</string>
 | 
			
		||||
    <string name="drawer_error_loading_sources">加载源时出错..。</string>
 | 
			
		||||
    <string name="drawer_item_filters">搜索条件</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="no_tags_loaded">未加载标签</string>
 | 
			
		||||
    <string name="no_sources_loaded">未加载数据源</string>
 | 
			
		||||
    <string name="drawer_loading">正在载入…</string>
 | 
			
		||||
    <string name="menu_home_search">搜索</string>
 | 
			
		||||
    <string name="can_delete_source">无法删除数据源…</string>
 | 
			
		||||
@@ -100,16 +78,9 @@
 | 
			
		||||
    <string name="pref_header_theme">主题</string>
 | 
			
		||||
    <string name="default_theme">默认</string>
 | 
			
		||||
    <string name="default_dark_theme">默认值/暗</string>
 | 
			
		||||
    <string name="pref_header_debug">调试</string>
 | 
			
		||||
    <string name="self_hosted_cert_switch">使用自托管证书?</string>
 | 
			
		||||
    <string name="self_signed_cert_warning">出于安全考虑, 默认情况下不支持自签名证书。如果激活此项, 您遇到的任何安全问题我将概不负责。</string>
 | 
			
		||||
    <string name="pref_selfoss_category">塞尔福斯 Api</string>
 | 
			
		||||
    <string name="pref_api_items_number_title">已加载项目编号</string>
 | 
			
		||||
    <string name="pref_hidden_tags">Hidden Tags</string>
 | 
			
		||||
    <string name="summary_debug_identifier">除错标识符</string>
 | 
			
		||||
    <string name="unique_id_to_clipboard">复制到你的剪贴板的标识符</string>
 | 
			
		||||
    <string name="display_header_drawer_summary">在侧边栏中显示带有 Selfoss 链接地址的页眉。</string>
 | 
			
		||||
    <string name="display_header_drawer_title">帐户页眉</string>
 | 
			
		||||
    <string name="pref_general_infinite_loading_title">翻页时载入更多文章</string>
 | 
			
		||||
    <string name="translation">翻译</string>
 | 
			
		||||
    <string name="cant_open_invalid_url">项目链接地址无效。我正在设法解决这个问题,以避免应用程序崩溃。</string>
 | 
			
		||||
@@ -120,19 +91,12 @@
 | 
			
		||||
    <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="add_to_favs_reader">Add to favorites</string>
 | 
			
		||||
    <string name="remove_to_favs_reader">Remove from favorites</string>
 | 
			
		||||
    <string name="pref_content_reader_font_size">Article reader content font size</string>
 | 
			
		||||
    <string name="pref_header_viewer">Article viewer</string>
 | 
			
		||||
    <string name="refresh_dialog_message">This will refresh your Selfoss instance.</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_off">Don\'t mark articles as read when swiping.</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept">Automatically send crash reports</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept_enabled">Will send crash reports automatically</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept_disabled">Will ask everytime when sending crash reports.</string>
 | 
			
		||||
    <string name="pref_debug_crash_reports">Crash reports</string>
 | 
			
		||||
    <string name="pref_debug_debug_logs">Debug logging (these will be sent without a dialog)</string>
 | 
			
		||||
    <string name="acra_login">Enable logging</string>
 | 
			
		||||
    <string name="drawer_item_hidden_tags">Hidden Tags</string>
 | 
			
		||||
    <string name="unmark">Mark item as unread</string>
 | 
			
		||||
    <string name="pref_header_offline">Offline and cache</string>
 | 
			
		||||
@@ -141,7 +105,8 @@
 | 
			
		||||
    <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_summary">Disable this if your server is receiving excessive amounts of database queries.</string>
 | 
			
		||||
    <string name="no_network_connectivity">Not connected !</string>
 | 
			
		||||
    <string name="network_connectivity_lost">"Network connection lost"</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_off">Articles will not be synced in the background</string>
 | 
			
		||||
    <string name="pref_switch_periodic_refresh_on">Articles will periodically be synced</string>
 | 
			
		||||
 
 | 
			
		||||
@@ -11,14 +11,6 @@
 | 
			
		||||
    <color name="refresh_progress_1">@color/colorAccentDark</color>
 | 
			
		||||
    <color name="refresh_progress_2">@color/colorAccent</color>
 | 
			
		||||
    <color name="refresh_progress_3">@color/pink</color>
 | 
			
		||||
    <color name="background_grey">#FFe4e4e4</color>
 | 
			
		||||
 | 
			
		||||
    <color name="dark_webview">#FF303030</color>
 | 
			
		||||
    <color name="dark_webview_text">#FFFFFF</color>
 | 
			
		||||
    <color name="light_webview">#FFFFFF</color>
 | 
			
		||||
    <color name="light_webview_text">#212121</color>
 | 
			
		||||
 | 
			
		||||
    <color name="cardBackgroundColor">#FFFFFFFF</color>
 | 
			
		||||
    <color name="materialDrawerHeaderSelectionText">#212121</color>
 | 
			
		||||
    <color name="darkBackground">#303030</color>
 | 
			
		||||
</resources>
 | 
			
		||||
 
 | 
			
		||||
@@ -2,16 +2,13 @@
 | 
			
		||||
    <string name="app_name">"Reader for Selfoss"</string>
 | 
			
		||||
    <string name="title_activity_login">"Log in"</string>
 | 
			
		||||
    <string name="prompt_password">"Password"</string>
 | 
			
		||||
    <string name="prompt_http_password">"HTTP Password"</string>
 | 
			
		||||
    <string name="action_sign_in">"Go"</string>
 | 
			
		||||
    <string name="error_invalid_password">"Password not long enough"</string>
 | 
			
		||||
    <string name="error_field_required">"Field required"</string>
 | 
			
		||||
    <string name="prompt_url">"Url"</string>
 | 
			
		||||
    <string name="withLoginSwitch">"Login required ?"</string>
 | 
			
		||||
    <string name="withHttpLoginSwitch">"HTTP Login required ?"</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_http_login">"HTTP Username"</string>
 | 
			
		||||
    <string name="label_share">"Share"</string>
 | 
			
		||||
    <string name="readAll">"Read all"</string>
 | 
			
		||||
    <string name="action_disconnect">"Disconnect"</string>
 | 
			
		||||
@@ -25,9 +22,6 @@
 | 
			
		||||
    <string name="wrong_infos">"Check your details again."</string>
 | 
			
		||||
    <string name="all_posts_not_read">"All posts weren't read"</string>
 | 
			
		||||
    <string name="all_posts_read">"All posts were read"</string>
 | 
			
		||||
    <string name="cant_get_favs">"Can't get favorites"</string>
 | 
			
		||||
    <string name="cant_get_new_elements">"Can't get new articles"</string>
 | 
			
		||||
    <string name="cant_get_read">"Can't get read articles"</string>
 | 
			
		||||
    <string name="nothing_here">"Nothing here"</string>
 | 
			
		||||
    <string name="tab_new">"New"</string>
 | 
			
		||||
    <string name="tab_read">"All"</string>
 | 
			
		||||
@@ -39,26 +33,15 @@
 | 
			
		||||
    <string name="addStringNoUrl">"Log in to add sources."</string>
 | 
			
		||||
    <string name="cant_get_sources">"Can't get sources list."</string>
 | 
			
		||||
    <string name="cant_create_source">"Can't create source."</string>
 | 
			
		||||
    <string name="cant_get_spouts">"Can't get spouts list."</string>
 | 
			
		||||
    <string name="cant_get_spouts_no_network">"Can't get spouts list because of a network issue."</string>
 | 
			
		||||
    <string name="cant_get_spouts">"Can't get spouts list. There may ben an api issue."</string>
 | 
			
		||||
    <string name="form_not_complete">"The form is not complete"</string>
 | 
			
		||||
    <string name="pref_header_links">"Links"</string>
 | 
			
		||||
    <string name="issue_tracker_link">"Issue Tracker"</string>
 | 
			
		||||
    <string name="issue_tracker_summary">"Report a bug or ask for a new feature"</string>
 | 
			
		||||
    <string name="warning_wrong_url">"WARNING"</string>
 | 
			
		||||
    <string name="pref_switch_card_view_title">"Card View"</string>
 | 
			
		||||
    <string name="cant_mark_favortie">"Can't mark article as favorite"</string>
 | 
			
		||||
    <string name="cant_unmark_favortie">"Can't remove item from favorite"</string>
 | 
			
		||||
    <string name="share">"Share"</string>
 | 
			
		||||
    <string name="rating_prompt_title">"Enjoying the app ?"</string>
 | 
			
		||||
    <string name="rating_prompt_yes">"Yes !"</string>
 | 
			
		||||
    <string name="rating_prompt_no">"Not really …"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_title">"Can you tell us why ?"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_yes">"OK !"</string>
 | 
			
		||||
    <string name="rating_prompt_feedback_no">"Not now."</string>
 | 
			
		||||
    <string name="rating_prompt_rating_title">"Great ! Can you rate us on the Store ?"</string>
 | 
			
		||||
    <string name="rating_prompt_rating_yes">"Sure !"</string>
 | 
			
		||||
    <string name="rating_prompt_rating_no">"Not right now."</string>
 | 
			
		||||
    <string name="rating_prompt_thanks">"Thanks, your feedback help enhance the app !"</string>
 | 
			
		||||
    <string name="switch_unread_count">"Display the unread count as a badge for the bottom bar."</string>
 | 
			
		||||
    <string name="switch_unread_count_title">"Display unread count"</string>
 | 
			
		||||
    <string name="display_all_counts_title">"Display count for favorite and read"</string>
 | 
			
		||||
@@ -82,17 +65,12 @@
 | 
			
		||||
    <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="source_code">Source code</string>
 | 
			
		||||
    <string name="cant_mark_read">Can\'t mark article as read</string>
 | 
			
		||||
    <string name="cant_mark_unread">Can\'t mark article as unread</string>
 | 
			
		||||
    <string name="drawer_error_loading_tags">Error loading tags…</string>
 | 
			
		||||
    <string name="drawer_error_loading_sources">Error loading sources…</string>
 | 
			
		||||
    <string name="drawer_item_filters">Filters</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="no_tags_loaded">No tags loaded</string>
 | 
			
		||||
    <string name="no_sources_loaded">No sources loaded</string>
 | 
			
		||||
    <string name="drawer_loading">Loading …</string>
 | 
			
		||||
    <string name="menu_home_search">Search</string>
 | 
			
		||||
    <string name="can_delete_source">Can\'t delete the source…</string>
 | 
			
		||||
@@ -100,17 +78,9 @@
 | 
			
		||||
    <string name="pref_header_theme">Themes</string>
 | 
			
		||||
    <string name="default_theme">Default</string>
 | 
			
		||||
    <string name="default_dark_theme">Default/Dark</string>
 | 
			
		||||
    <string name="pref_header_debug">Debug</string>
 | 
			
		||||
    <string name="self_hosted_cert_switch">Using a self hosted certificate ?</string>
 | 
			
		||||
    <string name="self_signed_cert_warning">Due to security reasons, self signed certificates are not supported by default. By activating this, I\'ll not be responsible of any security problem you encounter.</string>
 | 
			
		||||
    <string name="pref_selfoss_category">Selfoss Api</string>
 | 
			
		||||
    <string name="pref_api_items_number_title">Loaded items number</string>
 | 
			
		||||
    <string name="pref_hidden_tags">Hidden Tags</string>
 | 
			
		||||
    <string name="summary_debug_identifier">Debug identifier</string>
 | 
			
		||||
    <string name="unique_id_to_clipboard">Identifier copied to your clipboard</string>
 | 
			
		||||
    <string
 | 
			
		||||
        name="display_header_drawer_summary">Display a header with the selfoss instance url on the lateral drawer.</string>
 | 
			
		||||
    <string name="display_header_drawer_title">Account header</string>
 | 
			
		||||
    <string name="pref_general_infinite_loading_title">Load more articles on scroll</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>
 | 
			
		||||
@@ -121,19 +91,12 @@
 | 
			
		||||
    <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="add_to_favs_reader">Add to favorites</string>
 | 
			
		||||
    <string name="remove_to_favs_reader">Remove from favorites</string>
 | 
			
		||||
    <string name="pref_content_reader_font_size">Article reader content font size</string>
 | 
			
		||||
    <string name="pref_header_viewer">Article viewer</string>
 | 
			
		||||
    <string name="refresh_dialog_message">This will refresh your Selfoss instance.</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_off">Don\'t mark articles as read when swiping.</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept">Automatically send crash reports</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept_enabled">Will send crash reports automatically</string>
 | 
			
		||||
    <string name="pref_acra_alwaysaccept_disabled">Will ask everytime when sending crash reports.</string>
 | 
			
		||||
    <string name="pref_debug_crash_reports">Crash reports</string>
 | 
			
		||||
    <string name="pref_debug_debug_logs">Debug logging (these will be sent without a dialog)</string>
 | 
			
		||||
    <string name="acra_login">Enable logging</string>
 | 
			
		||||
    <string name="drawer_item_hidden_tags">Hidden Tags</string>
 | 
			
		||||
    <string name="unmark">Mark item as unread</string>
 | 
			
		||||
    <string name="pref_header_offline">Offline and cache</string>
 | 
			
		||||
@@ -142,7 +105,8 @@
 | 
			
		||||
    <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_summary">Disable this if your server is receiving excessive amounts of database queries.</string>
 | 
			
		||||
    <string name="no_network_connectivity">Not connected !</string>
 | 
			
		||||
    <string name="network_connectivity_lost">"Network connection lost"</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_off">Articles will not be synced in the background</string>
 | 
			
		||||
    <string name="pref_switch_periodic_refresh_on">Articles will periodically be synced</string>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										17
									
								
								androidApp/src/main/res/xml/data_extraction_rules.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								androidApp/src/main/res/xml/data_extraction_rules.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<data-extraction-rules>
 | 
			
		||||
    <cloud-backup>
 | 
			
		||||
        <exclude domain="root" />
 | 
			
		||||
        <exclude domain="file" />
 | 
			
		||||
        <exclude domain="database" />
 | 
			
		||||
        <exclude domain="sharedpref" />
 | 
			
		||||
        <exclude domain="external" />
 | 
			
		||||
    </cloud-backup>
 | 
			
		||||
    <device-transfer>
 | 
			
		||||
        <exclude domain="root" />
 | 
			
		||||
        <exclude domain="file" />
 | 
			
		||||
        <exclude domain="database" />
 | 
			
		||||
        <exclude domain="sharedpref" />
 | 
			
		||||
        <exclude domain="external" />
 | 
			
		||||
    </device-transfer>
 | 
			
		||||
</data-extraction-rules>
 | 
			
		||||
@@ -60,12 +60,6 @@
 | 
			
		||||
        android:title="@string/pref_general_category_displaying">
 | 
			
		||||
 | 
			
		||||
    </PreferenceCategory>
 | 
			
		||||
    <SwitchPreference
 | 
			
		||||
        android:defaultValue="false"
 | 
			
		||||
        android:key="account_header_displaying"
 | 
			
		||||
        android:summary="@string/display_header_drawer_summary"
 | 
			
		||||
        android:title="@string/display_header_drawer_title"
 | 
			
		||||
        app:iconSpaceReserved="false"/>
 | 
			
		||||
    <SwitchPreference
 | 
			
		||||
        android:defaultValue="false"
 | 
			
		||||
        android:key="card_view_active"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +0,0 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
# You can pass --force as first parameter to force push and tag creation.
 | 
			
		||||
 | 
			
		||||
echo "Creating tag $@"
 | 
			
		||||
 | 
			
		||||
TAG="v$@"
 | 
			
		||||
git tag ${TAG}
 | 
			
		||||
 | 
			
		||||
echo "Pushing tag"
 | 
			
		||||
 | 
			
		||||
git push origin ${TAG}
 | 
			
		||||
@@ -6,10 +6,18 @@ buildscript {
 | 
			
		||||
    }
 | 
			
		||||
    dependencies {
 | 
			
		||||
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10")
 | 
			
		||||
        classpath("com.android.tools.build:gradle:7.2.0")
 | 
			
		||||
        classpath("com.android.tools.build:gradle:7.3.0")
 | 
			
		||||
 | 
			
		||||
        // sonarquve
 | 
			
		||||
        classpath("org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.4.0.2513")
 | 
			
		||||
 | 
			
		||||
        // SqlDelight
 | 
			
		||||
        classpath("com.squareup.sqldelight:gradle-plugin:1.5.3")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
apply(plugin = "org.sonarqube")
 | 
			
		||||
 | 
			
		||||
allprojects {
 | 
			
		||||
    repositories {
 | 
			
		||||
        google()
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
 | 
			
		||||
git fetch --tags -p
 | 
			
		||||
 | 
			
		||||
BASE_VERSION="1.7"
 | 
			
		||||
BASE_VERSION="1"
 | 
			
		||||
LAST_TAG=$(git tag -l | sort -V | tail -1)
 | 
			
		||||
 | 
			
		||||
INITIAL_VERSION="${BASE_VERSION//./}$(date '+%y%m%j')"
 | 
			
		||||
@@ -21,11 +21,11 @@ VERSION="${INITIAL_VERSION}${TODAYS_VERSION}"
 | 
			
		||||
 | 
			
		||||
PARAMS_EXCEPT_PUBLISH=$(echo $1 | sed 's/\-\-publish//')
 | 
			
		||||
 | 
			
		||||
./version.sh ${VERSION} ${PARAMS_EXCEPT_PUBLISH}
 | 
			
		||||
./version.sh ${VERSION} ${PARAMS_EXCEPT_PUBLISH} $@
 | 
			
		||||
 | 
			
		||||
if [[ "$@" == *'--publish'* ]]
 | 
			
		||||
then
 | 
			
		||||
    ./publish-version.sh ${VERSION}
 | 
			
		||||
    ./publish-version.sh ${VERSION} $@
 | 
			
		||||
else
 | 
			
		||||
    echo "Did not publish. If you wanted to do so, call the script with \"--publish\" or \"--publish-local\"."
 | 
			
		||||
fi
 | 
			
		||||
@@ -68,9 +68,9 @@ redirect_from: "/ReaderforSelfoss-multiplatform/"
 | 
			
		||||
            <div id="links">
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                <a class="github-button" href="https://github.com/aminecmi/readerforselfoss-multiplatform" data-size="large" aria-label="Star aminecmi/readerforselfoss-multiplatform on GitHub">Star</a>
 | 
			
		||||
                <a class="github-button" href="https://gitea.amine-louveau.fr/Louvorg/readerforselfoss-multiplatform" data-size="large" aria-label="Star aminecmi/readerforselfoss-multiplatform on GitHub">Star</a>
 | 
			
		||||
            </div>
 | 
			
		||||
            <meta itemprop="url" content="https://github.com/aminecmi/readerforselfoss-multiplatform">
 | 
			
		||||
            <meta itemprop="url" content="https://gitea.amine-louveau.fr/Louvorg/readerforselfoss-multiplatform">
 | 
			
		||||
            <meta itemprop="applicationCategory" content="News & Magazines">
 | 
			
		||||
        </div>
 | 
			
		||||
    </body>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1 @@
 | 
			
		||||
A new RSS reader for <a href="http://selfoss.aditu.de/">selfoss</a>.
 | 
			
		||||
 | 
			
		||||
It connects to your selfoss instance (works only with selfoss, and can't work without it), and you'll be able to read and manage all your RSS feeds.
 | 
			
		||||
 
 | 
			
		||||
@@ -18,3 +18,7 @@ kotlin.native.enableDependencyPropagation=false
 | 
			
		||||
android.useAndroidX=true
 | 
			
		||||
android.enableJetifier=true
 | 
			
		||||
kotlin.mpp.enableGranularSourceSetsMetadata=true
 | 
			
		||||
org.gradle.parallel=true
 | 
			
		||||
org.gradle.caching=true
 | 
			
		||||
ignoreGitVersion=false
 | 
			
		||||
pushCache=true
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
								
							@@ -1,6 +1,6 @@
 | 
			
		||||
#Wed Feb 09 17:05:19 CET 2022
 | 
			
		||||
distributionBase=GRADLE_USER_HOME
 | 
			
		||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
 | 
			
		||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
 | 
			
		||||
distributionPath=wrapper/dists
 | 
			
		||||
zipStorePath=wrapper/dists
 | 
			
		||||
zipStoreBase=GRADLE_USER_HOME
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										15
									
								
								publish-version.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										15
									
								
								publish-version.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
 | 
			
		||||
# NOTE: This is copy/pasted in jenkins
 | 
			
		||||
 | 
			
		||||
rm -f version.txt
 | 
			
		||||
printf "versionName=$1-github\nversionCode=$1" >> version.txt
 | 
			
		||||
 | 
			
		||||
if [[ "$@" == *'--from-ci'* ]]
 | 
			
		||||
then
 | 
			
		||||
        echo "File created. HANDLE IN CI"
 | 
			
		||||
else
 | 
			
		||||
  # You'll need to change server as your server and define a VERSION_PATH.
 | 
			
		||||
  scp version.txt server:$VERSION_PATH
 | 
			
		||||
  rm version.txt
 | 
			
		||||
fi
 | 
			
		||||
@@ -1,3 +1,5 @@
 | 
			
		||||
val pushCache: String by settings
 | 
			
		||||
 | 
			
		||||
pluginManagement {
 | 
			
		||||
    repositories {
 | 
			
		||||
        google()
 | 
			
		||||
@@ -6,6 +8,16 @@ pluginManagement {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
buildCache {
 | 
			
		||||
    remote<HttpBuildCache> {
 | 
			
		||||
        url = uri("http://18.0.0.7:3071/cache/")
 | 
			
		||||
        isAllowInsecureProtocol = true
 | 
			
		||||
        isAllowUntrustedServer = true
 | 
			
		||||
        isUseExpectContinue = true
 | 
			
		||||
        isPush = (pushCache == "true")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
rootProject.name = "ReaderForSelfossV2"
 | 
			
		||||
include(":androidApp")
 | 
			
		||||
include(":shared")
 | 
			
		||||
@@ -1,6 +1,14 @@
 | 
			
		||||
object SqlDelight {
 | 
			
		||||
    const val runtime = "com.squareup.sqldelight:runtime:1.5.3"
 | 
			
		||||
    const val android = "com.squareup.sqldelight:android-driver:1.5.3"
 | 
			
		||||
    const val native = "com.squareup.sqldelight:native-driver:1.5.3"
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
plugins {
 | 
			
		||||
    kotlin("multiplatform")
 | 
			
		||||
    id("com.android.library")
 | 
			
		||||
    id("com.squareup.sqldelight")
 | 
			
		||||
    kotlin("plugin.serialization") version "1.4.10"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -27,6 +35,21 @@ kotlin {
 | 
			
		||||
                implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0")
 | 
			
		||||
                implementation("io.ktor:ktor-client-auth:2.0.1")
 | 
			
		||||
                implementation("org.jsoup:jsoup:1.14.3")
 | 
			
		||||
 | 
			
		||||
                //Dependency Injection
 | 
			
		||||
                implementation("org.kodein.di:kodein-di:7.12.0")
 | 
			
		||||
 | 
			
		||||
                //Settings
 | 
			
		||||
                implementation("com.russhwolf:multiplatform-settings-no-arg:0.9")
 | 
			
		||||
 | 
			
		||||
                //Logging
 | 
			
		||||
                implementation("io.github.aakira:napier:2.6.1")
 | 
			
		||||
 | 
			
		||||
                // Network information
 | 
			
		||||
                implementation("com.github.ln-12:multiplatform-connectivity-status:1.3.0")
 | 
			
		||||
 | 
			
		||||
                // Sql
 | 
			
		||||
                implementation(SqlDelight.runtime)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        val commonTest by getting {
 | 
			
		||||
@@ -38,6 +61,9 @@ kotlin {
 | 
			
		||||
        val androidMain by getting {
 | 
			
		||||
            dependencies {
 | 
			
		||||
                implementation("io.ktor:ktor-client-android:2.0.1")
 | 
			
		||||
 | 
			
		||||
                // Sql
 | 
			
		||||
                implementation(SqlDelight.android)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        val androidTest by getting {
 | 
			
		||||
@@ -54,6 +80,11 @@ kotlin {
 | 
			
		||||
            iosX64Main.dependsOn(this)
 | 
			
		||||
            iosArm64Main.dependsOn(this)
 | 
			
		||||
            //iosSimulatorArm64Main.dependsOn(this)
 | 
			
		||||
 | 
			
		||||
            // Sql
 | 
			
		||||
            dependencies {
 | 
			
		||||
                implementation(SqlDelight.native)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        val iosX64Test by getting
 | 
			
		||||
        val iosArm64Test by getting
 | 
			
		||||
@@ -77,4 +108,17 @@ android {
 | 
			
		||||
        minSdk = 21
 | 
			
		||||
        targetSdk = 31
 | 
			
		||||
    }
 | 
			
		||||
    compileOptions {
 | 
			
		||||
        sourceCompatibility = JavaVersion.VERSION_1_8
 | 
			
		||||
        targetCompatibility = JavaVersion.VERSION_1_8
 | 
			
		||||
    }
 | 
			
		||||
    namespace = "bou.amine.apps.readerforselfossv2"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sqldelight {
 | 
			
		||||
    database("ReaderForSelfossDB") {
 | 
			
		||||
        packageName = "bou.amine.apps.readerforselfossv2.dao"
 | 
			
		||||
        sourceFolders = listOf("sqldelight")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,2 +1,2 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<manifest package="bou.amine.apps.readerforselfossv2" />
 | 
			
		||||
<manifest />
 | 
			
		||||
@@ -1,5 +0,0 @@
 | 
			
		||||
package bou.amine.apps.readerforselfossv2
 | 
			
		||||
 | 
			
		||||
actual class Platform actual constructor() {
 | 
			
		||||
    actual val platform: String = "Android ${android.os.Build.VERSION.SDK_INT}"
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,10 @@
 | 
			
		||||
package bou.amine.apps.readerforselfossv2.dao
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import com.squareup.sqldelight.android.AndroidSqliteDriver
 | 
			
		||||
import com.squareup.sqldelight.db.SqlDriver
 | 
			
		||||
 | 
			
		||||
actual class DriverFactory(private val context: Context) {
 | 
			
		||||
    actual fun createDriver(): SqlDriver {
 | 
			
		||||
        return AndroidSqliteDriver(ReaderForSelfossDB.Schema, context, "ReaderForSelfossV2-android.db")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,36 @@
 | 
			
		||||
package bou.amine.apps.readerforselfossv2.utils
 | 
			
		||||
 | 
			
		||||
import android.text.format.DateUtils
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
 | 
			
		||||
import java.time.Instant
 | 
			
		||||
import java.time.LocalDateTime
 | 
			
		||||
import java.time.OffsetDateTime
 | 
			
		||||
import java.time.ZoneOffset
 | 
			
		||||
import java.time.format.DateTimeFormatter
 | 
			
		||||
 | 
			
		||||
actual class DateUtils actual constructor(actual val appSettingsService: AppSettingsService) {
 | 
			
		||||
 | 
			
		||||
    actual fun parseDate(dateString: String): Long {
 | 
			
		||||
 | 
			
		||||
        val FORMATTERV1 = "yyyy-MM-dd HH:mm:ss"
 | 
			
		||||
 | 
			
		||||
        return if (appSettingsService.getApiVersion() >= 4) {
 | 
			
		||||
            OffsetDateTime.parse(dateString).toInstant().toEpochMilli()
 | 
			
		||||
        } else {
 | 
			
		||||
            LocalDateTime.parse(dateString, DateTimeFormatter.ofPattern(FORMATTERV1)).toInstant(
 | 
			
		||||
                ZoneOffset.UTC).toEpochMilli()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    actual fun parseRelativeDate(dateString: String): String {
 | 
			
		||||
 | 
			
		||||
        val date = parseDate(dateString)
 | 
			
		||||
 | 
			
		||||
        return " " + DateUtils.getRelativeTimeSpanString(
 | 
			
		||||
            date,
 | 
			
		||||
            Instant.now().toEpochMilli(),
 | 
			
		||||
            DateUtils.MINUTE_IN_MILLIS,
 | 
			
		||||
            DateUtils.FORMAT_ABBREV_RELATIVE
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user