Compare commits
	
		
			147 Commits
		
	
	
		
			8cbb225e6d
			...
			v122092572
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 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 | ||||
|   | ||||
							
								
								
									
										10
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								README.md
									
									
									
									
									
								
							| @@ -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") | ||||
| @@ -32,11 +34,19 @@ fun gitVersion(): String { | ||||
| } | ||||
|  | ||||
| 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" | ||||
|         } | ||||
| @@ -170,16 +174,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,22 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:tools="http://schemas.android.com/tools" | ||||
|     package="bou.amine.apps.readerforselfossv2.android"> | ||||
|  | ||||
|     <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 +72,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.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.isBaseUrlValid(this@AddSourceActivity)) { | ||||
|             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.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,16 +112,12 @@ 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() | ||||
|  | ||||
|         var cancel = false | ||||
|         var focusView: View? = null | ||||
| @@ -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>) { | ||||
| @@ -82,18 +77,15 @@ 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) | ||||
|         } | ||||
| @@ -101,9 +93,7 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte | ||||
|  | ||||
|     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,9 +267,9 @@ class ArticleFragment : Fragment() { | ||||
|     } | ||||
|  | ||||
|     private fun getContentFromMercury(customTabsIntent: CustomTabsIntent) { | ||||
|         if ((context != null && requireContext().isNetworkAvailable(null)) || context == null) { | ||||
|             binding.progressBar.visibility = View.VISIBLE | ||||
|             val parser = MercuryApi() | ||||
|         if (repository.isNetworkAvailable()) { | ||||
|         binding.progressBar.visibility = View.VISIBLE | ||||
|         val parser = MercuryApi() | ||||
|  | ||||
|             parser.parseUrl(url).enqueue( | ||||
|                 object : Callback<ParsedContent> { | ||||
| @@ -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( | ||||
|   | ||||
| @@ -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.2.2") | ||||
|  | ||||
|         // 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 | ||||
| @@ -55,7 +55,7 @@ redirect_from: "/ReaderforSelfoss-multiplatform/" | ||||
|  | ||||
|  | ||||
|         <script async defer src="https://buttons.github.io/buttons.js"></script> | ||||
|        | ||||
|  | ||||
|     </head> | ||||
|  | ||||
|     <body id="main"> | ||||
| @@ -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 | ||||
|   | ||||
							
								
								
									
										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,16 @@ android { | ||||
|         minSdk = 21 | ||||
|         targetSdk = 31 | ||||
|     } | ||||
| } | ||||
|     compileOptions { | ||||
|         sourceCompatibility = JavaVersion.VERSION_1_8 | ||||
|         targetCompatibility = JavaVersion.VERSION_1_8 | ||||
|     } | ||||
| } | ||||
|  | ||||
| sqldelight { | ||||
|     database("ReaderForSelfossDB") { | ||||
|         packageName = "bou.amine.apps.readerforselfossv2.dao" | ||||
|         sourceFolders = listOf("sqldelight") | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -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 | ||||
|         ) | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,50 @@ | ||||
| package bou.amine.apps.readerforselfossv2.utils | ||||
|  | ||||
| import android.net.Uri | ||||
| import android.text.Html | ||||
| import bou.amine.apps.readerforselfossv2.model.SelfossModel | ||||
| import org.jsoup.Jsoup | ||||
| import java.util.* | ||||
|  | ||||
| actual fun String.getHtmlDecoded(): String { | ||||
|     return Html.fromHtml(this).toString() | ||||
| } | ||||
|  | ||||
| actual fun SelfossModel.Item.getIcon(baseUrl: String): String { | ||||
|     return constructUrl(baseUrl, "favicons", icon) | ||||
| } | ||||
|  | ||||
| actual fun SelfossModel.Item.getThumbnail(baseUrl: String): String { | ||||
|     return constructUrl(baseUrl, "thumbnails", thumbnail) | ||||
| } | ||||
|  | ||||
| actual 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 | ||||
| } | ||||
|  | ||||
| actual fun SelfossModel.Source.getIcon(baseUrl: String): String { | ||||
|     return constructUrl(baseUrl, "favicons", icon) | ||||
| } | ||||
|  | ||||
| actual 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() | ||||
|     } | ||||
| } | ||||
| @@ -1,12 +0,0 @@ | ||||
| package bou.amine.apps.readerforselfossv2 | ||||
|  | ||||
| import org.junit.Assert.assertTrue | ||||
| import org.junit.Test | ||||
|  | ||||
| class AndroidGreetingTest { | ||||
|  | ||||
|     @Test | ||||
|     fun testExample() { | ||||
|         assertTrue("Check Android is mentioned", Greeting().greeting().contains("Android")) | ||||
|     } | ||||
| } | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user