Compare commits

...

87 Commits

Author SHA1 Message Date
caef522c8b Changelog. 2017-11-28 20:16:09 +01:00
40ea07de2e Last fix for the endless scroll. 2017-11-28 20:10:32 +01:00
7905e4aa12 Fixes #127. 2017-11-28 19:18:43 +01:00
64f4fd708a Merge pull request #126 from aminecmi/translate_master
New Crowdin translations
2017-11-28 19:17:01 +01:00
b46e4a018f New translations strings.xml (Chinese Simplified) 2017-11-28 06:21:12 +01:00
3e999a9be2 New translations strings.xml (Chinese Simplified) 2017-11-28 06:11:20 +01:00
f656d621e6 New translations strings.xml (Chinese Simplified) 2017-11-28 06:01:37 +01:00
951cc1e6bd New translations strings.xml (Chinese Simplified) 2017-11-27 10:42:33 +01:00
d8d4264f1b New translations strings.xml (Chinese Simplified) 2017-11-27 10:33:30 +01:00
014eeec2b9 New translations strings.xml (Chinese Simplified) 2017-11-27 08:10:29 +01:00
83837bddc3 New translations strings.xml (Chinese Simplified) 2017-11-27 07:51:23 +01:00
f97666db92 New translations strings.xml (Chinese Simplified) 2017-11-27 07:00:51 +01:00
ee08ea41a1 New translations strings.xml (Chinese Simplified) 2017-11-27 06:50:49 +01:00
4ca64610cb New translations strings.xml (Chinese Simplified) 2017-11-27 06:40:37 +01:00
4980145e46 New translations strings.xml (Chinese Simplified) 2017-11-27 05:50:32 +01:00
10cbc19a0c New translations strings.xml (Chinese Simplified) 2017-11-27 05:40:32 +01:00
15fba2b29b New translations strings.xml (Chinese Simplified) 2017-11-27 05:20:28 +01:00
096952f88c New translations strings.xml (Chinese Simplified) 2017-11-27 05:10:31 +01:00
0ea70c1922 New translations strings.xml (Chinese Simplified) 2017-11-27 05:00:30 +01:00
69ac2e2b44 Kotlin style guide. (#125) 2017-11-25 13:12:12 +01:00
68098f4d84 Fixes #124. 2017-11-24 19:49:03 +01:00
080d52893e Changelog. 2017-11-23 21:57:10 +01:00
b02334a8d4 New Crowdin translations (#123)
* New translations strings.xml (Afrikaans)

* New translations strings.xml (Japanese)

* New translations strings.xml (Ukrainian)

* New translations strings.xml (Turkish)

* New translations strings.xml (Swedish)

* New translations strings.xml (Spanish)

* New translations strings.xml (Serbian (Cyrillic))

* New translations strings.xml (Russian)

* New translations strings.xml (Romanian)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Portuguese)

* New translations strings.xml (Polish)

* New translations strings.xml (Norwegian)

* New translations strings.xml (Korean)

* New translations strings.xml (Italian)

* New translations strings.xml (Arabic)

* New translations strings.xml (Hungarian)

* New translations strings.xml (Hebrew)

* New translations strings.xml (Greek)

* New translations strings.xml (German)

* New translations strings.xml (French)

* New translations strings.xml (Finnish)

* New translations strings.xml (Dutch)

* New translations strings.xml (Danish)

* New translations strings.xml (Czech)

* New translations strings.xml (Chinese Traditional)

* New translations strings.xml (Catalan)

* New translations strings.xml (Vietnamese)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Portuguese)

* New translations strings.xml (Portuguese, Brazilian)
2017-11-23 21:55:57 +01:00
27118add22 Closes #118. 2017-11-23 21:29:45 +01:00
2a6f98a1e8 Should fix #119. 2017-11-23 21:27:01 +01:00
1f67f2fdee Fixes #121. 2017-11-21 19:05:14 +01:00
ebf4d294a8 Fixing infinite scroll trying to load more items when there are no more. 2017-11-20 21:08:13 +01:00
4a4dbacc95 Changelog. 2017-11-18 15:19:57 +01:00
687839b5f8 Infinite scroll should be working as expected. Fixes #116. 2017-11-18 15:09:44 +01:00
8fb339034f Fixed #117. 2017-11-16 19:37:19 +01:00
8e9fd9c985 Changelog. 2017-11-14 19:38:18 +01:00
72400f71c0 Changed color of links in the article viewer. 2017-11-14 19:36:23 +01:00
1151587951 Merge branch 'master' of github.com:aminecmi/ReaderforSelfoss 2017-11-14 19:23:12 +01:00
abcd500045 Fixed #114. 2017-11-14 19:22:43 +01:00
beda24e736 New Crowdin translations (#112)
* New translations strings.xml (Portuguese)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Portuguese)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Portuguese, Brazilian)
2017-11-14 11:15:47 +01:00
37b2c5c2df Fixed toolbar and fab behavior #113. 2017-11-13 19:35:14 +01:00
7b5246ebf1 Update. 2017-11-13 18:58:57 +01:00
d6d5e72f48 New Crowdin translations (#111)
* New translations strings.xml (Portuguese)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Portuguese)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Portuguese, Brazilian)
2017-11-12 17:38:39 +01:00
fa8e88d489 Changelog. 2017-11-12 17:28:04 +01:00
1ef2da9f76 Fixing tests. 2017-11-12 17:22:40 +01:00
1ebd894be7 Tests fixes. 2017-11-12 17:14:21 +01:00
a9c493d105 Changelog. 2017-11-12 17:08:30 +01:00
f833d73fab Closes #109. 2017-11-12 17:05:47 +01:00
9e6602f114 Hiding FABs on scroll. 2017-11-12 15:41:28 +01:00
3bdfef9f8b Added changelog and changed fab size. 2017-11-12 07:55:01 +01:00
6f7f475a6b Enhancements. Three first items of #108. 2017-11-12 07:51:11 +01:00
8fc5fab67b Merge branch 'master' of github.com:aminecmi/ReaderforSelfoss 2017-11-11 21:01:48 +01:00
6927e92396 New Crowdin translations (#105)
* New translations strings.xml (French)

* New translations strings.xml (Afrikaans)

* New translations strings.xml (Japanese)

* New translations strings.xml (Ukrainian)

* New translations strings.xml (Turkish)

* New translations strings.xml (Swedish)

* New translations strings.xml (Spanish)

* New translations strings.xml (Serbian (Cyrillic))

* New translations strings.xml (Russian)

* New translations strings.xml (Romanian)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Polish)

* New translations strings.xml (Norwegian)

* New translations strings.xml (Korean)

* New translations strings.xml (Italian)

* New translations strings.xml (Arabic)

* New translations strings.xml (Hungarian)

* New translations strings.xml (Hebrew)

* New translations strings.xml (Greek)

* New translations strings.xml (German)

* New translations strings.xml (French)

* New translations strings.xml (Finnish)

* New translations strings.xml (Dutch)

* New translations strings.xml (Danish)

* New translations strings.xml (Czech)

* New translations strings.xml (Chinese Traditional)

* New translations strings.xml (Catalan)

* New translations strings.xml (Vietnamese)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Portuguese)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Afrikaans)

* New translations strings.xml (Japanese)

* New translations strings.xml (Ukrainian)

* New translations strings.xml (Turkish)

* New translations strings.xml (Swedish)

* New translations strings.xml (Spanish)

* New translations strings.xml (Serbian (Cyrillic))

* New translations strings.xml (Russian)

* New translations strings.xml (Romanian)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Arabic)

* New translations strings.xml (Greek)

* New translations strings.xml (Portuguese)

* New translations strings.xml (Polish)

* New translations strings.xml (Norwegian)

* New translations strings.xml (Korean)

* New translations strings.xml (Italian)

* New translations strings.xml (Hungarian)

* New translations strings.xml (Hebrew)

* New translations strings.xml (German)

* New translations strings.xml (Catalan)

* New translations strings.xml (French)

* New translations strings.xml (Finnish)

* New translations strings.xml (Dutch)

* New translations strings.xml (Danish)

* New translations strings.xml (Czech)

* New translations strings.xml (Chinese Traditional)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Vietnamese)
2017-11-11 21:01:25 +01:00
c7470396d7 Changelog. 2017-11-11 20:55:31 +01:00
f21570e2e4 New Crowdin translations (#104)
* New translations strings.xml (French)

* New translations strings.xml (Afrikaans)

* New translations strings.xml (Japanese)

* New translations strings.xml (Ukrainian)

* New translations strings.xml (Turkish)

* New translations strings.xml (Swedish)

* New translations strings.xml (Spanish)

* New translations strings.xml (Serbian (Cyrillic))

* New translations strings.xml (Russian)

* New translations strings.xml (Romanian)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Polish)

* New translations strings.xml (Norwegian)

* New translations strings.xml (Korean)

* New translations strings.xml (Italian)

* New translations strings.xml (Arabic)

* New translations strings.xml (Hungarian)

* New translations strings.xml (Hebrew)

* New translations strings.xml (Greek)

* New translations strings.xml (German)

* New translations strings.xml (French)

* New translations strings.xml (Finnish)

* New translations strings.xml (Dutch)

* New translations strings.xml (Danish)

* New translations strings.xml (Czech)

* New translations strings.xml (Chinese Traditional)

* New translations strings.xml (Catalan)

* New translations strings.xml (Vietnamese)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Portuguese)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Afrikaans)

* New translations strings.xml (Japanese)

* New translations strings.xml (Ukrainian)

* New translations strings.xml (Turkish)

* New translations strings.xml (Swedish)

* New translations strings.xml (Spanish)

* New translations strings.xml (Serbian (Cyrillic))

* New translations strings.xml (Russian)

* New translations strings.xml (Romanian)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Arabic)

* New translations strings.xml (Greek)

* New translations strings.xml (Portuguese)

* New translations strings.xml (Polish)

* New translations strings.xml (Norwegian)

* New translations strings.xml (Korean)

* New translations strings.xml (Italian)

* New translations strings.xml (Hungarian)

* New translations strings.xml (Hebrew)

* New translations strings.xml (German)

* New translations strings.xml (Catalan)

* New translations strings.xml (French)

* New translations strings.xml (Finnish)

* New translations strings.xml (Dutch)

* New translations strings.xml (Danish)

* New translations strings.xml (Czech)

* New translations strings.xml (Chinese Traditional)
2017-11-11 20:53:15 +01:00
51f406e20c New action bar. Closes #103. 2017-11-11 20:39:56 +01:00
9e3fde744e Changed to Textview to disaply the simple content from the API. 2017-11-11 16:50:17 +01:00
ccf406ae68 Update CONTRIBUTING.md 2017-11-11 14:47:40 +01:00
bc78d1e079 Changelog and updated target sdk. 2017-11-11 14:35:13 +01:00
d151eb261e Updates to make the build work. 2017-11-11 14:28:06 +01:00
0856598cd9 Changelog. 2017-11-11 08:44:18 +01:00
f0563efc62 Fixed #98. Using kotlin implementation for the drawer. Using the new style code. 2017-11-11 07:58:29 +01:00
84dfa9a8a5 New Crowdin translations (#100)
* New translations strings.xml (French)

* New translations strings.xml (Afrikaans)

* New translations strings.xml (Japanese)

* New translations strings.xml (Ukrainian)

* New translations strings.xml (Turkish)

* New translations strings.xml (Swedish)

* New translations strings.xml (Spanish)

* New translations strings.xml (Serbian (Cyrillic))

* New translations strings.xml (Russian)

* New translations strings.xml (Romanian)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Polish)

* New translations strings.xml (Norwegian)

* New translations strings.xml (Korean)

* New translations strings.xml (Italian)

* New translations strings.xml (Arabic)

* New translations strings.xml (Hungarian)

* New translations strings.xml (Hebrew)

* New translations strings.xml (Greek)

* New translations strings.xml (German)

* New translations strings.xml (French)

* New translations strings.xml (Finnish)

* New translations strings.xml (Dutch)

* New translations strings.xml (Danish)

* New translations strings.xml (Czech)

* New translations strings.xml (Chinese Traditional)

* New translations strings.xml (Catalan)

* New translations strings.xml (Vietnamese)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Portuguese)

* New translations strings.xml (Portuguese, Brazilian)
2017-11-08 11:36:41 +01:00
8e25489cca Update CHANGELOG.md 2017-11-08 11:24:48 +01:00
198f95e1ca Update CHANGELOG.md 2017-11-08 11:24:40 +01:00
7e02fe89ea New Crowdin translations (#97)
* New translations strings.xml (French)

* New translations strings.xml (Afrikaans)

* New translations strings.xml (Japanese)

* New translations strings.xml (Ukrainian)

* New translations strings.xml (Turkish)

* New translations strings.xml (Swedish)

* New translations strings.xml (Spanish)

* New translations strings.xml (Serbian (Cyrillic))

* New translations strings.xml (Russian)

* New translations strings.xml (Romanian)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Polish)

* New translations strings.xml (Norwegian)

* New translations strings.xml (Korean)

* New translations strings.xml (Italian)

* New translations strings.xml (Arabic)

* New translations strings.xml (Hungarian)

* New translations strings.xml (Hebrew)

* New translations strings.xml (Greek)

* New translations strings.xml (German)

* New translations strings.xml (French)

* New translations strings.xml (Finnish)

* New translations strings.xml (Dutch)

* New translations strings.xml (Danish)

* New translations strings.xml (Czech)

* New translations strings.xml (Chinese Traditional)

* New translations strings.xml (Catalan)

* New translations strings.xml (Vietnamese)
2017-11-04 11:57:30 +01:00
819356412c Optimizing imports. 2017-11-04 11:43:09 +01:00
deb789bc1b Some code cleaning. 2017-11-04 11:33:22 +01:00
133ba74548 Fixed changelog. 2017-11-04 10:59:13 +01:00
1461e32643 Update README.md 2017-11-02 10:11:19 +01:00
f400c3d9ac New translations strings.xml (French) (#96) 2017-11-02 09:42:22 +01:00
7e595a4f74 Reverted last commit 2017-11-02 09:39:46 +01:00
18c9c499b2 Delete crowdin.yml 2017-11-02 09:36:25 +01:00
24ae115ed4 New translations strings.xml (French) (#95) 2017-11-01 19:54:56 +01:00
7f345558cd Changelog. 2017-11-01 19:48:06 +01:00
57177cc910 Loading more on swipe. 2017-11-01 19:46:13 +01:00
cea258bc21 Fixes #45. User may need to reselect the theme. 2017-11-01 19:06:36 +01:00
ed9b1c8ba7 Only reporting the issue if there is an issue. 2017-11-01 18:13:54 +01:00
5a79fd89e9 Realy fixed the api call this time. 2017-10-29 21:11:03 +01:00
42a130db08 Changelog. 2017-10-29 20:18:35 +01:00
320a8d19de New translations strings.xml (French) (#94) 2017-10-29 20:14:52 +01:00
5721506007 Maybe fixed issue with marking items. 2017-10-29 20:10:02 +01:00
803e8cb2f4 Revert "This is causing bugs for Xperia XZ Premium device on pre-launch report."
This reverts commit 98492fd0c0.
2017-10-29 13:52:43 +01:00
98492fd0c0 This is causing bugs for Xperia XZ Premium device on pre-launch report. 2017-10-29 13:31:31 +01:00
0b07178577 Removed codebeat. 2017-10-29 12:57:54 +01:00
07e545079c Fixes full height cards problem. 2017-10-29 12:55:03 +01:00
95d64dc5e8 New Crowdin translations (#93)
* New translations strings.xml (Afrikaans)

* New translations strings.xml (Japanese)

* New translations strings.xml (Ukrainian)

* New translations strings.xml (Turkish)

* New translations strings.xml (Swedish)

* New translations strings.xml (Spanish)

* New translations strings.xml (Serbian (Cyrillic))

* New translations strings.xml (Russian)

* New translations strings.xml (Romanian)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Arabic)

* New translations strings.xml (Greek)

* New translations strings.xml (Polish)

* New translations strings.xml (Norwegian)

* New translations strings.xml (Korean)

* New translations strings.xml (Italian)

* New translations strings.xml (Hungarian)

* New translations strings.xml (Hebrew)

* New translations strings.xml (German)

* New translations strings.xml (Catalan)

* New translations strings.xml (French)

* New translations strings.xml (Finnish)

* New translations strings.xml (Dutch)

* New translations strings.xml (Danish)

* New translations strings.xml (Czech)

* New translations strings.xml (Chinese Traditional)

* New translations strings.xml (Vietnamese)
2017-10-27 19:56:04 +02:00
abe546dcda test fixes. 2017-10-27 19:13:57 +02:00
e6f367acaf Cleaning code to make them work ? 2017-10-27 18:51:30 +02:00
a9b61853b9 Updates and more. 2017-10-27 18:48:22 +02:00
5afc04a630 New Crowdin translations (#89)
* New translations strings.xml (Afrikaans)

* New translations strings.xml (Japanese)

* New translations strings.xml (Ukrainian)

* New translations strings.xml (Turkish)

* New translations strings.xml (Swedish)

* New translations strings.xml (Spanish)

* New translations strings.xml (Serbian (Cyrillic))

* New translations strings.xml (Russian)

* New translations strings.xml (Romanian)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Polish)

* New translations strings.xml (Norwegian)

* New translations strings.xml (Korean)

* New translations strings.xml (Italian)

* New translations strings.xml (Arabic)

* New translations strings.xml (Hungarian)

* New translations strings.xml (Hebrew)

* New translations strings.xml (Greek)

* New translations strings.xml (German)

* New translations strings.xml (French)

* New translations strings.xml (Finnish)

* New translations strings.xml (Dutch)

* New translations strings.xml (Danish)

* New translations strings.xml (Czech)

* New translations strings.xml (Chinese Traditional)

* New translations strings.xml (Catalan)

* New translations strings.xml (Vietnamese)
2017-10-23 18:47:16 +02:00
1da4cc2782 Fixes #86. 2017-10-23 18:29:44 +02:00
117 changed files with 3128 additions and 2335 deletions

View File

@ -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 report bugs, request missing features, suggest enhancements and changes to existing ones. You also can improve the README with useful tips that could help the other users. There are many ways to contribute to this project, you could 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/labels/help%20wanted) or [develop new things](https://github.com/aminecmi/ReaderforSelfoss/issues) 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)
### What I can't help you with. ### What I can't help you with.
@ -31,7 +31,7 @@ Always check if the web version of your instance is working.
* Please ask before starting to work on an issue. I may be working on it, or someone else could be doing so. * 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. * 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. * Your code must be simple and clear enough to avoid using comments to explain what it does.
* Follow the used coding style [the official one](https://kotlinlang.org/docs/reference/coding-conventions.html) ([some idoms for reference](http://kotlinlang.org/docs/reference/idioms.html)) with more to come. * Follow the used coding style [the android koding style](https://android.github.io/kotlin-guides/style.html) ([some idoms for reference](http://kotlinlang.org/docs/reference/idioms.html)) with more to come.
* Try as much as possible to write a test for your feature, and if you do so, run it, and make it work. * Try as much as possible to write a test for your feature, and if you do so, run it, and make it work.
* Always check your changes and discard the ones that are irrelevant to your feature or bugfix. * Always check your changes and discard the ones that are irrelevant to your feature or bugfix.
* Have meaningful commit messages. * Have meaningful commit messages.
@ -48,12 +48,13 @@ You'll have to:
- Configure fabric and add your `apiKey` and `apiSecret` in the `fabric.properties` file. - Configure fabric and add your `apiKey` and `apiSecret` in the `fabric.properties` file.
- Create a firebase project and add the `google-services.json` to the `app/` folder. - Create a firebase project and add the `google-services.json` to the `app/` folder.
- Define the following some parameters either in `~/.gradle/gradle.properties` or as gradle parameters (see the examples) - Define some parameters either in `~/.gradle/gradle.properties` or as gradle parameters (see the examples)
- mercuryApiKey: A [Mercury](https://mercury.postlight.com/web-parser/) web parser api key for the internal browser - mercuryApiKey: A [Mercury](https://mercury.postlight.com/web-parser/) web parser api key for the internal browser
- feedbackEmail: An email to receive users feedback. - feedbackEmail: An email to receive users feedback.
- sourceUrl: an url to the source code, used in the settings. **It can be empty.** - sourceUrl: an url to the source code, used in the settings. **It can be empty.**
- trackerUrl: an url to the tracker, used in the settings. **It can be empty.** - trackerUrl: an url to the tracker, used in the settings. **It can be empty.**
- githubToken: a github token used to report issues from within the app. [Details here](https://github.com/heinrichreimer/android-issue-reporter#how-to-create-a-bot-key). **It can be empty.**
- appLoginUrl, appLoginUsername and appLoginPassword: url, username and password of a selfoss instance. **These are only used for tests. They can be empty if you don't test API calls.** - appLoginUrl, appLoginUsername and appLoginPassword: url, username and password of a selfoss instance. **These are only used for tests. They can be empty if you don't test API calls.**
### Examples: ### Examples:
@ -67,10 +68,11 @@ mercuryApiKey="LONGAPIKEY"
feedbackEmail="EMAIL" feedbackEmail="EMAIL"
sourceUrl="URLSOURCE" # It can be empty. sourceUrl="URLSOURCE" # It can be empty.
trackerUrl="URLTRACKER" # It can be empty. trackerUrl="URLTRACKER" # It can be empty.
githubToken="GITHUBTOKEN" # It can be empty or use https://github.com/heinrichreimer/android-issue-reporter#how-to-create-a-bot-key to generate one
``` ```
#### As gradle parameters #### As gradle parameters
``` ```
./gradlew .... -P appLoginUrl="URL" -P appLoginUsername="LOGIN" -P appLoginPassword="PASS" -P mercuryApiKey="LONGAPIKEY" -P feedbackEmail="EMAIL" -P sourceUrl="URLSOURCE" -P trackerUrl="URLTRACKER" ./gradlew .... -P appLoginUrl="URL" -P appLoginUsername="LOGIN" -P appLoginPassword="PASS" -P mercuryApiKey="LONGAPIKEY" -P feedbackEmail="EMAIL" -P sourceUrl="URLSOURCE" -P trackerUrl="URLTRACKER" -P githubToken="GITHUBTOKEN"
``` ```

View File

@ -1,3 +1,111 @@
**1.5.4.18**
- Typo fix.
- The real last infinite scroll bug fix.
- Simplified Chinese translation !
**1.5.4.17**
- Fixed the last bug with infinite scroll.
**1.5.4.16**
- Fixing list view displaying issues.
- Endless scroll is not in beta anymore.
**1.5.4.15**
- Fixed an issue with the sources list.
**1.5.4.14**
- Fixing infinite scroll trying to load more items when there are no more.
**1.5.4.13**
- Displaying the right number of items.
- Fixing infinite scroll remaining issues. Should be stable enough.
**1.5.4.12**
- Fixed fab and toolbar issue (#113)
- Fixed links clickable (#114)
- Changed the link colors in the article viewer
**1.5.4.11**
- Hiding FABs on scroll.
- Closing #109 (code cleaning)
- Hiding fabs on scroll (#101)
**1.5.4.10**
- Displaying a loader when "reading more" in the article viewer.
- Displaying the thumbnail instead of icon on the article viewer.
- Scrolling to top when loading content with the "read more" button.
**1.5.4.09**
- Using the kotlin wrapper for the material drawer (see #98 for more details).
- Updated support libraries
- Changed the Floating Action Button to the support library version.
- New reader activity action bar #103.
**1.5.4.08**
- Thanks @jrafaelsantana for translating the whole app in Brazilian Portuguese.
**1.5.4.07**
- Loading more items on swipe too.
- Fixed popup menu style. User may need to reselect the theme.
- Disabled reporting marking items as read if there isn't an issue.
**1.5.4.05/06**
- Translation fix.
**1.5.4.04**
- Fixing an issue with marking items as read (something related to an old version of selfoss).
**1.5.4.03**
- Trying to fix some issue with pre-launch reports. Reverted because it seems to be related to the dev console side.
**1.5.4.02**
- Fixing full height cards issue.
**1.5.4.01**
- Removed the "apk downloaded from outside of playstore" message.
- Versions update.
- HTML viewer version update. It should fix an issue with images.
- Some code cleaning.
**1.5.4.00**
- Added issue reporting from within the app.
**1.5.3.06** **1.5.3.06**
- Fixed infinite scroll not working. - Fixed infinite scroll not working.

View File

@ -4,7 +4,7 @@
[![Build Status](http://jenkins.amine-bou.fr/job/ReaderForSelfoss/badge/icon)](http://jenkins.amine-bou.fr/job/ReaderForSelfoss/) [![Build Status](http://jenkins.amine-bou.fr/job/ReaderForSelfoss/badge/icon)](http://jenkins.amine-bou.fr/job/ReaderForSelfoss/)
[![codebeat badge](https://codebeat.co/badges/bce66c0f-fd28-4341-a159-3b6dd22ac854)](https://codebeat.co/projects/github-com-aminecmi-readerforselfoss-master) [![Code Triagers Badge](https://www.codetriage.com/aminecmi/readerforselfoss/badges/users.svg)](https://www.codetriage.com/aminecmi/readerforselfoss) [![Code Triagers Badge](https://www.codetriage.com/aminecmi/readerforselfoss/badges/users.svg)](https://www.codetriage.com/aminecmi/readerforselfoss)
This is the repo of [Reader For Selfoss](https://play.google.com/store/apps/details?id=apps.amine.bou.readerforselfoss&hl=en). This is the repo of [Reader For Selfoss](https://play.google.com/store/apps/details?id=apps.amine.bou.readerforselfoss&hl=en).
@ -22,3 +22,5 @@ Check the [Contribution guide](https://github.com/aminecmi/ReaderforSelfoss/blob
- [Check what changed](https://github.com/aminecmi/ReaderforSelfoss/blob/master/CHANGELOG.md) - [Check what changed](https://github.com/aminecmi/ReaderforSelfoss/blob/master/CHANGELOG.md)
- [See what I'm doing](https://github.com/aminecmi/ReaderforSelfoss/projects/1) - [See what I'm doing](https://github.com/aminecmi/ReaderforSelfoss/projects/1)
- [Create an issue, or request a new feature](https://github.com/aminecmi/ReaderforSelfoss/issues) - [Create an issue, or request a new feature](https://github.com/aminecmi/ReaderforSelfoss/issues)
- [Help translation the app](https://crowdin.com/project/readerforselfoss)
- [Ask for help](https://gitter.im/amine-bou/ReaderForSelfoss)

View File

@ -31,6 +31,8 @@ apply plugin: 'io.fabric'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
repositories { repositories {
maven { maven {
url 'https://maven.fabric.io/public' url 'https://maven.fabric.io/public'
@ -38,12 +40,12 @@ repositories {
} }
android { android {
compileSdkVersion 26 compileSdkVersion 27
buildToolsVersion '26.0.2' buildToolsVersion '27.0.0'
defaultConfig { defaultConfig {
applicationId "apps.amine.bou.readerforselfoss" applicationId "apps.amine.bou.readerforselfoss"
minSdkVersion 16 minSdkVersion 16
targetSdkVersion 26 targetSdkVersion 27
versionCode versionCodeFromGit() versionCode versionCodeFromGit()
versionName versionNameFromGit() versionName versionNameFromGit()
@ -63,6 +65,7 @@ android {
buildConfigField "String", "SOURCE_URL", sourceUrl buildConfigField "String", "SOURCE_URL", sourceUrl
buildConfigField "String", "TRACKER_URL", trackerUrl buildConfigField "String", "TRACKER_URL", trackerUrl
buildConfigField "String", "TRANSLATION_URL", translationUrl buildConfigField "String", "TRANSLATION_URL", translationUrl
buildConfigField "String", "GITHUB_TOKEN", githubToken
} }
buildTypes { buildTypes {
release { release {
@ -94,31 +97,31 @@ android {
dependencies { dependencies {
// Testing // Testing
androidTestCompile 'com.android.support.test.espresso:espresso-core:3.0.0' androidTestCompile 'com.android.support.test.espresso:espresso-core:3.0.1'
androidTestCompile 'com.android.support.test:runner:1.0.0' androidTestCompile 'com.android.support.test:runner:1.0.1'
// Espresso-contrib for DatePicker, RecyclerView, Drawer actions, Accessibility checks, CountingIdlingResource // Espresso-contrib for DatePicker, RecyclerView, Drawer actions, Accessibility checks, CountingIdlingResource
androidTestCompile 'com.android.support.test.espresso:espresso-contrib:3.0.0' androidTestCompile 'com.android.support.test.espresso:espresso-contrib:3.0.1'
// Espresso-intents for validation and stubbing of Intents // Espresso-intents for validation and stubbing of Intents
androidTestCompile 'com.android.support.test.espresso:espresso-intents:3.0.0' androidTestCompile 'com.android.support.test.espresso:espresso-intents:3.0.1'
compile fileTree(dir: 'libs', include: ['*.jar']) compile fileTree(dir: 'libs', include: ['*.jar'])
compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
// Android Support // Android Support
compile 'com.android.support:appcompat-v7:26.0.1' compile 'com.android.support:appcompat-v7:27.0.0'
compile 'com.android.support:design:26.0.1' compile 'com.android.support:design:27.0.0'
compile 'com.android.support:recyclerview-v7:26.0.1' compile 'com.android.support:recyclerview-v7:27.0.0'
compile 'com.android.support:support-v4:26.0.1' compile 'com.android.support:support-v4:27.0.0'
compile 'com.android.support:support-vector-drawable:26.0.1' compile 'com.android.support:support-vector-drawable:27.0.0'
compile 'com.android.support:customtabs:26.0.1' compile 'com.android.support:customtabs:27.0.0'
compile 'com.android.support:cardview-v7:26.0.1' compile 'com.android.support:cardview-v7:27.0.0'
compile 'com.android.support.constraint:constraint-layout:1.0.2' compile 'com.android.support.constraint:constraint-layout:1.0.2'
// Firebase + crashlytics // Firebase + crashlytics
compile 'com.google.firebase:firebase-core:11.2.0' compile 'com.google.firebase:firebase-core:11.4.2'
compile 'com.google.firebase:firebase-config:11.2.0' compile 'com.google.firebase:firebase-config:11.4.2'
compile 'com.google.firebase:firebase-invites:11.2.0' compile 'com.google.firebase:firebase-invites:11.4.2'
compile('com.crashlytics.sdk.android:crashlytics:2.7.1@aar') { compile('com.crashlytics.sdk.android:crashlytics:2.7.1@aar') {
transitive = true; transitive = true;
} }
@ -130,7 +133,7 @@ dependencies {
compile 'agency.tango.android:material-intro-screen:0.0.5' compile 'agency.tango.android:material-intro-screen:0.0.5'
// About // About
compile('com.mikepenz:aboutlibraries:5.9.7@aar') { compile('com.mikepenz:aboutlibraries:6.0.0@aar') {
transitive = true transitive = true
} }
@ -142,10 +145,9 @@ dependencies {
// Material-ish things // Material-ish things
compile 'com.ashokvarma.android:bottom-navigation-bar:2.0.3' compile 'com.ashokvarma.android:bottom-navigation-bar:2.0.3'
compile 'com.melnykov:floatingactionbutton:1.3.0'
compile 'com.github.jd-alexander:LikeButton:0.2.1' compile 'com.github.jd-alexander:LikeButton:0.2.1'
compile 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1' compile 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1'
compile 'org.sufficientlysecure:html-textview:3.3' compile 'org.sufficientlysecure:html-textview:3.5'
// glide // glide
compile 'com.github.bumptech.glide:glide:4.1.1' compile 'com.github.bumptech.glide:glide:4.1.1'
@ -158,14 +160,16 @@ dependencies {
compile 'com.klinkerapps:drag-dismiss-activity:1.5.0' compile 'com.klinkerapps:drag-dismiss-activity:1.5.0'
// Drawer // Drawer
compile('com.mikepenz:materialdrawer:5.9.5@aar') { implementation 'co.zsmb:materialdrawer-kt:1.2.1'
transitive = true
}
compile 'com.anupcowkur:reservoir:3.1.0' compile 'com.anupcowkur:reservoir:3.1.0'
// Themes // Themes
compile 'com.52inc:scoops:1.0.0' compile 'com.52inc:scoops:1.0.0'
// Github issues reporter
compile 'com.heinrichreimersoftware:android-issue-reporter:1.3.1'
compile 'com.github.rubensousa:floatingtoolbar:1.5.1'
} }
apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.gms.google-services'
@ -210,6 +214,7 @@ def initAppForSecretPropertiesIfNeeded() {
entry(key: "sourceUrl", value: System.getProperty("sourceUrl")) entry(key: "sourceUrl", value: System.getProperty("sourceUrl"))
entry(key: "trackerUrl", value: System.getProperty("trackerUrl")) entry(key: "trackerUrl", value: System.getProperty("trackerUrl"))
entry(key: "translationUrl", value: System.getProperty("translationUrl")) entry(key: "translationUrl", value: System.getProperty("translationUrl"))
entry(key: "githubToken", value: System.getProperty("githubToken"))
} }
} }
} }

View File

@ -1,4 +1,3 @@
package apps.amine.bou.readerforselfoss package apps.amine.bou.readerforselfoss
// TODO: test source adding // TODO: test source adding

View File

@ -5,29 +5,33 @@ import android.content.Intent
import android.support.test.InstrumentationRegistry import android.support.test.InstrumentationRegistry
import android.support.test.espresso.Espresso.onView import android.support.test.espresso.Espresso.onView
import android.support.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu import android.support.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu
import android.support.test.espresso.action.ViewActions.* import android.support.test.espresso.action.ViewActions.click
import android.support.test.espresso.action.ViewActions.closeSoftKeyboard
import android.support.test.espresso.action.ViewActions.pressBack
import android.support.test.espresso.action.ViewActions.pressKey
import android.support.test.espresso.action.ViewActions.typeText
import android.support.test.espresso.assertion.ViewAssertions.matches import android.support.test.espresso.assertion.ViewAssertions.matches
import android.support.test.espresso.contrib.DrawerActions import android.support.test.espresso.contrib.DrawerActions
import android.support.test.espresso.intent.Intents import android.support.test.espresso.intent.Intents
import android.support.test.espresso.intent.Intents.intended import android.support.test.espresso.intent.Intents.intended
import android.support.test.espresso.intent.Intents.times import android.support.test.espresso.intent.Intents.times
import android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent import android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent
import android.support.test.espresso.matcher.ViewMatchers.* import android.support.test.espresso.matcher.ViewMatchers.isDisplayed
import android.support.test.espresso.matcher.ViewMatchers.isRoot
import android.support.test.espresso.matcher.ViewMatchers.withContentDescription
import android.support.test.espresso.matcher.ViewMatchers.withId
import android.support.test.espresso.matcher.ViewMatchers.withText
import android.support.test.rule.ActivityTestRule import android.support.test.rule.ActivityTestRule
import android.support.test.runner.AndroidJUnit4 import android.support.test.runner.AndroidJUnit4
import android.view.KeyEvent import android.view.KeyEvent
import apps.amine.bou.readerforselfoss.utils.Config
import com.mikepenz.aboutlibraries.ui.LibsActivity import com.heinrichreimersoftware.androidissuereporter.IssueReporterLauncher
import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import apps.amine.bou.readerforselfoss.settings.SettingsActivity
import apps.amine.bou.readerforselfoss.utils.Config
import org.junit.After
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
class HomeActivityEspressoTest { class HomeActivityEspressoTest {
lateinit var context: Context lateinit var context: Context
@ -68,13 +72,14 @@ class HomeActivityEspressoTest {
onView(withId(R.id.search_bar)).check(matches(isDisplayed())) 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(withId(R.id.search_src_text)).perform(
typeText("android"),
pressKey(KeyEvent.KEYCODE_SEARCH),
closeSoftKeyboard()
)
onView(withContentDescription(R.string.abc_toolbar_collapse_description)).perform(click()) onView(withContentDescription(R.string.abc_toolbar_collapse_description)).perform(click())
onView(withMenu(id = R.id.readAll, titleId = R.string.readAll)).perform(click())
openActionBarOverflowOrOptionsMenu(context) openActionBarOverflowOrOptionsMenu(context)
onView(withMenu(id = R.id.refresh, titleId = R.string.menu_home_refresh)) onView(withMenu(id = R.id.refresh, titleId = R.string.menu_home_refresh))
@ -85,10 +90,6 @@ class HomeActivityEspressoTest {
onView(withText(R.string.action_disconnect)).perform(click()) onView(withText(R.string.action_disconnect)).perform(click())
intended(hasComponent(LoginActivity::class.java.name), times(1)) intended(hasComponent(LoginActivity::class.java.name), times(1))
//onView(isRoot()).perform(pressBack())
} }
@Test @Test
@ -98,8 +99,9 @@ class HomeActivityEspressoTest {
onView(withId(R.id.material_drawer_layout)).perform(DrawerActions.open()) onView(withId(R.id.material_drawer_layout)).perform(DrawerActions.open())
onView(withText(R.string.action_about)).perform(click()) onView(withText(R.string.drawer_report_bug)).perform(click())
intended(hasComponent(LibsActivity::class.java.name)) intended(hasComponent(IssueReporterLauncher.Activity::class.java.name))
onView(isRoot()).perform(pressBack())
onView(isRoot()).perform(pressBack()) onView(isRoot()).perform(pressBack())
intended(hasComponent(HomeActivity::class.java.name)) intended(hasComponent(HomeActivity::class.java.name))
@ -107,11 +109,6 @@ class HomeActivityEspressoTest {
onView(withId(R.id.material_drawer_layout)).perform(DrawerActions.open()) onView(withId(R.id.material_drawer_layout)).perform(DrawerActions.open())
onView(withText(R.string.drawer_action_clear)).perform(click()) onView(withText(R.string.drawer_action_clear)).perform(click())
// bug
//onView(withText(R.string.title_activity_settings)).perform(scrollTo(), click())
//intended(hasComponent(SettingsActivity::class.java.name))
} }
// TODO: test articles opening and actions for cards and lists // TODO: test articles opening and actions for cards and lists

View File

@ -1,7 +1,5 @@
package apps.amine.bou.readerforselfoss package apps.amine.bou.readerforselfoss
import java.util.*
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.support.test.InstrumentationRegistry.getInstrumentation import android.support.test.InstrumentationRegistry.getInstrumentation
@ -11,22 +9,19 @@ import android.support.test.espresso.assertion.ViewAssertions.matches
import android.support.test.espresso.intent.Intents import android.support.test.espresso.intent.Intents
import android.support.test.espresso.intent.Intents.intended import android.support.test.espresso.intent.Intents.intended
import android.support.test.espresso.intent.Intents.times import android.support.test.espresso.intent.Intents.times
import android.support.test.espresso.intent.matcher.IntentMatchers.* import android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent
import android.support.test.espresso.intent.matcher.UriMatchers.hasHost import android.support.test.espresso.matcher.ViewMatchers.isDisplayed
import android.support.test.espresso.matcher.ViewMatchers.* import android.support.test.espresso.matcher.ViewMatchers.withId
import android.support.test.espresso.matcher.ViewMatchers.withText
import android.support.test.rule.ActivityTestRule import android.support.test.rule.ActivityTestRule
import android.support.test.runner.AndroidJUnit4 import android.support.test.runner.AndroidJUnit4
import apps.amine.bou.readerforselfoss.utils.Config
import org.hamcrest.Matchers.allOf import org.junit.After
import org.hamcrest.Matchers.equalTo
import org.junit.Before import org.junit.Before
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import java.util.*
import apps.amine.bou.readerforselfoss.utils.Config
import org.junit.After
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
class IntroActivityEspressoTest { class IntroActivityEspressoTest {
@ -46,7 +41,7 @@ class IntroActivityEspressoTest {
Intents.init() Intents.init()
} }
/*@Test @Test
fun nextEachTimes() { fun nextEachTimes() {
rule.launchActivity(Intent()) rule.launchActivity(Intent())
@ -60,8 +55,7 @@ class IntroActivityEspressoTest {
intended(hasComponent(IntroActivity::class.java.name), times(1)) intended(hasComponent(IntroActivity::class.java.name), times(1))
intended(hasComponent(LoginActivity::class.java.name), times(1)) intended(hasComponent(LoginActivity::class.java.name), times(1))
}
}*/
@Test @Test
fun nextBackRandomTimes() { fun nextBackRandomTimes() {
@ -75,7 +69,7 @@ class IntroActivityEspressoTest {
onView(withText(R.string.intro_hello_title)).check(matches(isDisplayed())) onView(withText(R.string.intro_hello_title)).check(matches(isDisplayed()))
onView(withId(R.id.button_next)).perform(click()) onView(withId(R.id.button_next)).perform(click())
repeat(random) {_ -> repeat(random) { _ ->
onView(withText(R.string.intro_needs_selfoss_message)).check(matches(isDisplayed())) onView(withText(R.string.intro_needs_selfoss_message)).check(matches(isDisplayed()))
onView(withId(R.id.button_next)).perform(click()) onView(withId(R.id.button_next)).perform(click())
onView(withText(R.string.intro_all_set_message)).check(matches(isDisplayed())) onView(withText(R.string.intro_all_set_message)).check(matches(isDisplayed()))
@ -88,30 +82,6 @@ class IntroActivityEspressoTest {
intended(hasComponent(IntroActivity::class.java.name), times(1)) intended(hasComponent(IntroActivity::class.java.name), times(1))
intended(hasComponent(LoginActivity::class.java.name), times(1)) intended(hasComponent(LoginActivity::class.java.name), times(1))
}
@Test
fun clickSelfossUrl() {
rule.launchActivity(Intent())
onView(withText(R.string.intro_hello_title)).check(matches(isDisplayed()))
onView(withId(R.id.button_next)).perform(click())
onView(withId(R.id.button_message)).perform(click())
intended(
allOf(
hasData(
hasHost(
equalTo("selfoss.aditu.de")
)
),
hasAction(Intent.ACTION_VIEW)
)
)
} }
@After @After

View File

@ -5,37 +5,40 @@ import android.content.Intent
import android.support.test.InstrumentationRegistry import android.support.test.InstrumentationRegistry
import android.support.test.espresso.Espresso.onView import android.support.test.espresso.Espresso.onView
import android.support.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu import android.support.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu
import android.support.test.espresso.action.ViewActions.* import android.support.test.espresso.action.ViewActions.click
import android.support.test.espresso.action.ViewActions.closeSoftKeyboard
import android.support.test.espresso.action.ViewActions.pressBack
import android.support.test.espresso.action.ViewActions.typeText
import android.support.test.espresso.assertion.ViewAssertions.matches import android.support.test.espresso.assertion.ViewAssertions.matches
import android.support.test.espresso.intent.Intents import android.support.test.espresso.intent.Intents
import android.support.test.espresso.intent.Intents.intended import android.support.test.espresso.intent.Intents.intended
import android.support.test.espresso.intent.Intents.times import android.support.test.espresso.intent.Intents.times
import android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent import android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent
import android.support.test.espresso.matcher.ViewMatchers import android.support.test.espresso.matcher.ViewMatchers
import android.support.test.espresso.matcher.ViewMatchers.* import android.support.test.espresso.matcher.ViewMatchers.isRoot
import android.support.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
import android.support.test.espresso.matcher.ViewMatchers.withId
import android.support.test.espresso.matcher.ViewMatchers.withText
import android.support.test.rule.ActivityTestRule import android.support.test.rule.ActivityTestRule
import android.support.test.runner.AndroidJUnit4 import android.support.test.runner.AndroidJUnit4
import apps.amine.bou.readerforselfoss.utils.Config
import com.mikepenz.aboutlibraries.ui.LibsActivity import com.mikepenz.aboutlibraries.ui.LibsActivity
import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import apps.amine.bou.readerforselfoss.utils.Config
import org.junit.After
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
class LoginActivityEspressoTest { class LoginActivityEspressoTest {
@Rule @JvmField @Rule @JvmField
val rule = ActivityTestRule(LoginActivity::class.java, true, false) val rule = ActivityTestRule(LoginActivity::class.java, true, false)
lateinit var context: Context private lateinit var context: Context
lateinit var url: String private lateinit var url: String
lateinit var username: String private lateinit var username: String
lateinit var password: String private lateinit var password: String
@Before @Before
fun setUp() { fun setUp() {
@ -69,20 +72,18 @@ class LoginActivityEspressoTest {
onView(isRoot()).perform(pressBack()) onView(isRoot()).perform(pressBack())
intended(hasComponent(LoginActivity::class.java.name)) intended(hasComponent(LoginActivity::class.java.name))
} }
@Test @Test
fun wrongLoginUrl() { fun wrongLoginUrl() {
rule.launchActivity(Intent()) rule.launchActivity(Intent())
onView(withId(R.id.login_progress)) onView(withId(R.id.loginProgress))
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE))) .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)))
onView(withId(R.id.url)).perform(click()).perform(typeText("WRONGURL")) onView(withId(R.id.urlView)).perform(click()).perform(typeText("WRONGURL"))
onView(withId(R.id.email_sign_in_button)).perform(click()) onView(withId(R.id.signInButton)).perform(click())
onView(withId(R.id.urlLayout)).check(matches(isHintOrErrorEnabled())) onView(withId(R.id.urlLayout)).check(matches(isHintOrErrorEnabled()))
} }
@ -94,26 +95,29 @@ class LoginActivityEspressoTest {
rule.launchActivity(Intent()) rule.launchActivity(Intent())
onView(withId(R.id.url)).perform(click()).perform(typeText(url), closeSoftKeyboard()) onView(withId(R.id.urlView)).perform(click()).perform(typeText(url), closeSoftKeyboard())
onView(withId(R.id.withLogin)).perform(click()) onView(withId(R.id.withLogin)).perform(click())
onView(withId(R.id.email_sign_in_button)).perform(click()) onView(withId(R.id.signInButton)).perform(click())
onView(withId(R.id.loginLayout)).check(matches(isHintOrErrorEnabled())) onView(withId(R.id.loginLayout)).check(matches(isHintOrErrorEnabled()))
onView(withId(R.id.passwordLayout)).check(matches(isHintOrErrorEnabled())) onView(withId(R.id.passwordLayout)).check(matches(isHintOrErrorEnabled()))
onView(withId(R.id.login)).perform(click()).perform(typeText(username), closeSoftKeyboard()) onView(withId(R.id.loginView)).perform(click()).perform(
typeText(username),
closeSoftKeyboard()
)
onView(withId(R.id.passwordLayout)).check(matches(isHintOrErrorEnabled())) onView(withId(R.id.passwordLayout)).check(matches(isHintOrErrorEnabled()))
onView(withId(R.id.email_sign_in_button)).perform(click()) onView(withId(R.id.signInButton)).perform(click())
onView(withId(R.id.passwordLayout)).check( onView(withId(R.id.passwordLayout)).check(
matches( matches(
isHintOrErrorEnabled()) isHintOrErrorEnabled()
)
) )
} }
@Test @Test
@ -121,20 +125,25 @@ class LoginActivityEspressoTest {
rule.launchActivity(Intent()) rule.launchActivity(Intent())
onView(withId(R.id.url)).perform(click()).perform(typeText(url), closeSoftKeyboard()) onView(withId(R.id.urlView)).perform(click()).perform(typeText(url), closeSoftKeyboard())
onView(withId(R.id.withLogin)).perform(click()) onView(withId(R.id.withLogin)).perform(click())
onView(withId(R.id.login)).perform(click()).perform(typeText(username), closeSoftKeyboard()) onView(withId(R.id.loginView)).perform(click()).perform(
typeText(username),
closeSoftKeyboard()
)
onView(withId(R.id.password)).perform(click()).perform(typeText("WRONGPASS"), closeSoftKeyboard()) onView(withId(R.id.passwordView)).perform(click()).perform(
typeText("WRONGPASS"),
closeSoftKeyboard()
)
onView(withId(R.id.email_sign_in_button)).perform(click()) onView(withId(R.id.signInButton)).perform(click())
onView(withId(R.id.urlLayout)).check(matches(isHintOrErrorEnabled())) onView(withId(R.id.urlLayout)).check(matches(isHintOrErrorEnabled()))
onView(withId(R.id.loginLayout)).check(matches(isHintOrErrorEnabled())) onView(withId(R.id.loginLayout)).check(matches(isHintOrErrorEnabled()))
onView(withId(R.id.passwordLayout)).check(matches(isHintOrErrorEnabled())) onView(withId(R.id.passwordLayout)).check(matches(isHintOrErrorEnabled()))
} }
@Test @Test
@ -142,23 +151,27 @@ class LoginActivityEspressoTest {
rule.launchActivity(Intent()) rule.launchActivity(Intent())
onView(withId(R.id.url)).perform(click()).perform(typeText(url), closeSoftKeyboard()) onView(withId(R.id.urlView)).perform(click()).perform(typeText(url), closeSoftKeyboard())
onView(withId(R.id.withLogin)).perform(click()) onView(withId(R.id.withLogin)).perform(click())
onView(withId(R.id.login)).perform(click()).perform(typeText(username), closeSoftKeyboard()) onView(withId(R.id.loginView)).perform(click()).perform(
typeText(username),
closeSoftKeyboard()
)
onView(withId(R.id.password)).perform(click()).perform(typeText(password), closeSoftKeyboard()) onView(withId(R.id.passwordView)).perform(click()).perform(
typeText(password),
closeSoftKeyboard()
)
onView(withId(R.id.email_sign_in_button)).perform(click()) onView(withId(R.id.signInButton)).perform(click())
intended(hasComponent(HomeActivity::class.java.name)) intended(hasComponent(HomeActivity::class.java.name))
} }
@After @After
fun releaseIntents() { fun releaseIntents() {
Intents.release() Intents.release()
} }
} }

View File

@ -17,7 +17,6 @@ import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
class MainActivityEspressoTest { class MainActivityEspressoTest {
@ -48,7 +47,6 @@ class MainActivityEspressoTest {
intended(hasComponent(MainActivity::class.java.name)) intended(hasComponent(MainActivity::class.java.name))
intended(hasComponent(IntroActivity::class.java.name)) intended(hasComponent(IntroActivity::class.java.name))
intended(hasComponent(LoginActivity::class.java.name), times(0)) intended(hasComponent(LoginActivity::class.java.name), times(0))
} }
@Test @Test
@ -61,13 +59,10 @@ class MainActivityEspressoTest {
intended(hasComponent(MainActivity::class.java.name)) intended(hasComponent(MainActivity::class.java.name))
intended(hasComponent(LoginActivity::class.java.name)) intended(hasComponent(LoginActivity::class.java.name))
intended(hasComponent(IntroActivity::class.java.name), times(0)) intended(hasComponent(IntroActivity::class.java.name), times(0))
} }
@After @After
fun releaseIntents() { fun releaseIntents() {
Intents.release() Intents.release()
} }
} }

View File

@ -1,19 +1,17 @@
package apps.amine.bou.readerforselfoss package apps.amine.bou.readerforselfoss
import android.view.View
import android.support.design.widget.TextInputLayout import android.support.design.widget.TextInputLayout
import android.support.test.espresso.matcher.ViewMatchers import android.support.test.espresso.matcher.ViewMatchers
import android.view.View
import org.hamcrest.Description import org.hamcrest.Description
import org.hamcrest.Matcher import org.hamcrest.Matcher
import org.hamcrest.TypeSafeMatcher
import org.hamcrest.Matchers import org.hamcrest.Matchers
import org.hamcrest.TypeSafeMatcher
fun isHintOrErrorEnabled(): Matcher<View> = fun isHintOrErrorEnabled(): Matcher<View> =
object : TypeSafeMatcher<View>() { object : TypeSafeMatcher<View>() {
override fun describeTo(description: Description?) {} override fun describeTo(description: Description?) {
}
override fun matchesSafely(item: View?): Boolean { override fun matchesSafely(item: View?): Boolean {
if (item !is TextInputLayout) { if (item !is TextInputLayout) {

View File

@ -65,8 +65,7 @@
</intent-filter> </intent-filter>
</activity> </activity>
<activity <activity
android:name=".ReaderActivity" android:name=".ReaderActivity">
android:theme="@style/DragDismissTheme">
</activity> </activity>
<meta-data <meta-data

View File

@ -5,21 +5,24 @@ import android.os.Bundle
import android.preference.PreferenceManager import android.preference.PreferenceManager
import android.support.constraint.ConstraintLayout import android.support.constraint.ConstraintLayout
import android.support.v7.app.AppCompatActivity import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.Toolbar
import android.view.View import android.view.View
import android.widget.* import android.widget.AdapterView
import android.widget.ArrayAdapter
import retrofit2.Call import android.widget.EditText
import retrofit2.Callback import android.widget.ProgressBar
import retrofit2.Response import android.widget.Spinner
import android.widget.TextView
import android.widget.Toast
import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
import apps.amine.bou.readerforselfoss.api.selfoss.Spout import apps.amine.bou.readerforselfoss.api.selfoss.Spout
import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse
import apps.amine.bou.readerforselfoss.utils.Config import apps.amine.bou.readerforselfoss.utils.Config
import apps.amine.bou.readerforselfoss.utils.isBaseUrlValid import apps.amine.bou.readerforselfoss.utils.isBaseUrlValid
import com.ftinc.scoop.Scoop import com.ftinc.scoop.Scoop
import kotlinx.android.synthetic.main.activity_add_source.*
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
class AddSourceActivity : AppCompatActivity() { class AddSourceActivity : AppCompatActivity() {
@ -29,40 +32,48 @@ class AddSourceActivity : AppCompatActivity() {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
Scoop.getInstance().apply(this) Scoop.getInstance().apply(this)
setContentView(R.layout.activity_add_source) setContentView(R.layout.activity_add_source)
val toolbar: Toolbar = findViewById(R.id.toolbar)
setSupportActionBar(toolbar) setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setDisplayShowHomeEnabled(true) supportActionBar?.setDisplayShowHomeEnabled(true)
val mProgress: ProgressBar = findViewById(R.id.progress)
val mForm: ConstraintLayout = findViewById(R.id.formContainer)
val mNameInput: EditText = findViewById(R.id.nameInput)
val mSourceUri: EditText = findViewById(R.id.sourceUri)
val mTags: EditText = findViewById(R.id.tags)
val mSpoutsSpinner: Spinner = findViewById(R.id.spoutsSpinner)
val mSaveBtn: Button = findViewById(R.id.saveBtn)
var api: SelfossApi? = null var api: SelfossApi? = null
try { try {
val prefs = PreferenceManager.getDefaultSharedPreferences(this) val prefs = PreferenceManager.getDefaultSharedPreferences(this)
api = SelfossApi(this, this@AddSourceActivity, prefs.getBoolean("isSelfSignedCert", false), prefs.getBoolean("should_log_everything", false)) api = SelfossApi(
this,
this@AddSourceActivity,
prefs.getBoolean("isSelfSignedCert", false),
prefs.getBoolean("should_log_everything", false)
)
} catch (e: IllegalArgumentException) { } catch (e: IllegalArgumentException) {
mustLoginToAddSource() mustLoginToAddSource()
} }
val intent = intent maybeGetDetailsFromIntentSharing(intent, sourceUri, nameInput)
if (Intent.ACTION_SEND == intent.action && "text/plain" == intent.type) {
mSourceUri.setText(intent.getStringExtra(Intent.EXTRA_TEXT)) saveBtn.setOnClickListener {
mNameInput.setText(intent.getStringExtra(Intent.EXTRA_TITLE)) handleSaveSource(tags, nameInput.text.toString(), sourceUri.text.toString(), api!!)
} }
mSaveBtn.setOnClickListener { val config = Config(this)
handleSaveSource(mTags, mNameInput.text.toString(), mSourceUri.text.toString(), api!!)
if (config.baseUrl.isEmpty() || !config.baseUrl.isBaseUrlValid()) {
mustLoginToAddSource()
} else {
handleSpoutsSpinner(spoutsSpinner, api, progress, formContainer)
}
} }
private fun handleSpoutsSpinner(
spoutsSpinner: Spinner,
api: SelfossApi?,
mProgress: ProgressBar,
formContainer: ConstraintLayout
) {
val spoutsKV = HashMap<String, String>() val spoutsKV = HashMap<String, String>()
mSpoutsSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { spoutsSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(adapterView: AdapterView<*>, view: View, i: Int, l: Long) { override fun onItemSelected(adapterView: AdapterView<*>, view: View, i: Int, l: Long) {
val spoutName = (view as TextView).text.toString() val spoutName = (view as TextView).text.toString()
mSpoutsValue = spoutsKV[spoutName] mSpoutsValue = spoutsKV[spoutName]
@ -73,15 +84,12 @@ class AddSourceActivity : AppCompatActivity() {
} }
} }
val config = Config(this)
if (config.baseUrl.isEmpty() || !config.baseUrl.isBaseUrlValid()) {
mustLoginToAddSource()
} else {
var items: Map<String, Spout> var items: Map<String, Spout>
api!!.spouts().enqueue(object : Callback<Map<String, Spout>> { api!!.spouts().enqueue(object : Callback<Map<String, Spout>> {
override fun onResponse(call: Call<Map<String, Spout>>, response: Response<Map<String, Spout>>) { override fun onResponse(
call: Call<Map<String, Spout>>,
response: Response<Map<String, Spout>>
) {
if (response.body() != null) { if (response.body() != null) {
items = response.body()!! items = response.body()!!
@ -91,16 +99,16 @@ class AddSourceActivity : AppCompatActivity() {
} }
mProgress.visibility = View.GONE mProgress.visibility = View.GONE
mForm.visibility = View.VISIBLE formContainer.visibility = View.VISIBLE
val spinnerArrayAdapter = val spinnerArrayAdapter =
ArrayAdapter( ArrayAdapter(
this@AddSourceActivity, this@AddSourceActivity,
android.R.layout.simple_spinner_item, android.R.layout.simple_spinner_item,
itemsStrings) itemsStrings
)
spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
mSpoutsSpinner.adapter = spinnerArrayAdapter spoutsSpinner.adapter = spinnerArrayAdapter
} else { } else {
handleProblemWithSpouts() handleProblemWithSpouts()
} }
@ -111,11 +119,25 @@ class AddSourceActivity : AppCompatActivity() {
} }
private fun handleProblemWithSpouts() { private fun handleProblemWithSpouts() {
Toast.makeText(this@AddSourceActivity, R.string.cant_get_spouts, Toast.LENGTH_SHORT).show() Toast.makeText(
this@AddSourceActivity,
R.string.cant_get_spouts,
Toast.LENGTH_SHORT
).show()
mProgress.visibility = View.GONE mProgress.visibility = View.GONE
} }
}) })
} }
private fun maybeGetDetailsFromIntentSharing(
intent: Intent,
sourceUri: EditText,
nameInput: EditText
) {
if (Intent.ACTION_SEND == intent.action && "text/plain" == intent.type) {
sourceUri.setText(intent.getStringExtra(Intent.EXTRA_TEXT))
nameInput.setText(intent.getStringExtra(Intent.EXTRA_TITLE))
}
} }
private fun mustLoginToAddSource() { private fun mustLoginToAddSource() {
@ -125,28 +147,41 @@ class AddSourceActivity : AppCompatActivity() {
finish() finish()
} }
private fun handleSaveSource(mTags: EditText, title: String, url: String, api: SelfossApi) { private fun handleSaveSource(tags: EditText, title: String, url: String, api: SelfossApi) {
if (title.isEmpty() || url.isEmpty() || mSpoutsValue == null || mSpoutsValue!!.isEmpty()) { val sourceDetailsAvailable = title.isEmpty() || url.isEmpty() || mSpoutsValue == null || mSpoutsValue!!.isEmpty()
if (sourceDetailsAvailable) {
Toast.makeText(this, R.string.form_not_complete, Toast.LENGTH_SHORT).show() Toast.makeText(this, R.string.form_not_complete, Toast.LENGTH_SHORT).show()
} else { } else {
api.createSource( api.createSource(
title, title,
url, url,
mSpoutsValue!!, mSpoutsValue!!,
mTags.text.toString(), tags.text.toString(),
"" ""
).enqueue(object : Callback<SuccessResponse> { ).enqueue(object : Callback<SuccessResponse> {
override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) { override fun onResponse(
call: Call<SuccessResponse>,
response: Response<SuccessResponse>
) {
if (response.body() != null && response.body()!!.isSuccess) { if (response.body() != null && response.body()!!.isSuccess) {
finish() finish()
} else { } else {
Toast.makeText(this@AddSourceActivity, R.string.cant_create_source, Toast.LENGTH_SHORT).show() Toast.makeText(
this@AddSourceActivity,
R.string.cant_create_source,
Toast.LENGTH_SHORT
).show()
} }
} }
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) { override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
Toast.makeText(this@AddSourceActivity, R.string.cant_create_source, Toast.LENGTH_SHORT).show() Toast.makeText(
this@AddSourceActivity,
R.string.cant_create_source,
Toast.LENGTH_SHORT
).show()
} }
}) })
} }

View File

@ -1,16 +1,14 @@
package apps.amine.bou.readerforselfoss package apps.amine.bou.readerforselfoss
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.preference.PreferenceManager
import android.view.View
import agency.tango.materialintroscreen.MaterialIntroActivity import agency.tango.materialintroscreen.MaterialIntroActivity
import agency.tango.materialintroscreen.MessageButtonBehaviour import agency.tango.materialintroscreen.MessageButtonBehaviour
import agency.tango.materialintroscreen.SlideFragmentBuilder import agency.tango.materialintroscreen.SlideFragmentBuilder
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.preference.PreferenceManager
import android.support.v7.app.AppCompatDelegate import android.support.v7.app.AppCompatDelegate
import android.view.View
class IntroActivity : MaterialIntroActivity() { class IntroActivity : MaterialIntroActivity() {
@ -19,33 +17,44 @@ class IntroActivity : MaterialIntroActivity() {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true) AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
addSlide(SlideFragmentBuilder() addSlide(
SlideFragmentBuilder()
.backgroundColor(R.color.colorPrimary) .backgroundColor(R.color.colorPrimary)
.buttonsColor(R.color.colorAccent) .buttonsColor(R.color.colorAccent)
.image(R.drawable.web_hi_res_512) .image(R.drawable.web_hi_res_512)
.title(getString(R.string.intro_hello_title)) .title(getString(R.string.intro_hello_title))
.description(getString(R.string.intro_hello_message)) .description(getString(R.string.intro_hello_message))
.build()) .build()
)
addSlide(SlideFragmentBuilder() addSlide(
SlideFragmentBuilder()
.backgroundColor(R.color.colorAccent) .backgroundColor(R.color.colorAccent)
.buttonsColor(R.color.colorPrimary) .buttonsColor(R.color.colorPrimary)
.image(R.drawable.ic_info_outline_white_48px) .image(R.drawable.ic_info_outline_white_48px)
.title(getString(R.string.intro_needs_selfoss_title)) .title(getString(R.string.intro_needs_selfoss_title))
.description(getString(R.string.intro_needs_selfoss_message)) .description(getString(R.string.intro_needs_selfoss_message))
.build(), .build(),
MessageButtonBehaviour(View.OnClickListener { MessageButtonBehaviour(
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse("https://selfoss.aditu.de")) View.OnClickListener {
val browserIntent = Intent(
Intent.ACTION_VIEW,
Uri.parse("https://selfoss.aditu.de")
)
startActivity(browserIntent) startActivity(browserIntent)
}, getString(R.string.intro_needs_selfoss_link))) }, getString(R.string.intro_needs_selfoss_link)
)
)
addSlide(SlideFragmentBuilder() addSlide(
SlideFragmentBuilder()
.backgroundColor(R.color.colorPrimaryDark) .backgroundColor(R.color.colorPrimaryDark)
.buttonsColor(R.color.colorAccentDark) .buttonsColor(R.color.colorAccentDark)
.image(R.drawable.ic_thumb_up_white_48px) .image(R.drawable.ic_thumb_up_white_48px)
.title(getString(R.string.intro_all_set_title)) .title(getString(R.string.intro_all_set_title))
.description(getString(R.string.intro_all_set_message)) .description(getString(R.string.intro_all_set_message))
.build()) .build()
)
} }
override fun onFinish() { override fun onFinish() {

View File

@ -6,31 +6,29 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.Bundle import android.os.Bundle
import android.support.design.widget.TextInputLayout
import android.support.v7.app.AlertDialog import android.support.v7.app.AlertDialog
import android.support.v7.app.AppCompatActivity import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.Toolbar
import android.text.TextUtils import android.text.TextUtils
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.view.inputmethod.EditorInfo import android.view.inputmethod.EditorInfo
import android.widget.* import android.widget.TextView
import android.widget.Toast
import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse
import apps.amine.bou.readerforselfoss.utils.Config import apps.amine.bou.readerforselfoss.utils.Config
import apps.amine.bou.readerforselfoss.utils.checkAndDisplayStoreApk
import apps.amine.bou.readerforselfoss.utils.isBaseUrlValid import apps.amine.bou.readerforselfoss.utils.isBaseUrlValid
import com.crashlytics.android.Crashlytics import com.crashlytics.android.Crashlytics
import com.ftinc.scoop.Scoop import com.ftinc.scoop.Scoop
import com.google.firebase.analytics.FirebaseAnalytics import com.google.firebase.analytics.FirebaseAnalytics
import com.mikepenz.aboutlibraries.Libs import com.mikepenz.aboutlibraries.Libs
import com.mikepenz.aboutlibraries.LibsBuilder import com.mikepenz.aboutlibraries.LibsBuilder
import kotlinx.android.synthetic.main.activity_login.*
import retrofit2.Call import retrofit2.Call
import retrofit2.Callback import retrofit2.Callback
import retrofit2.Response import retrofit2.Response
class LoginActivity : AppCompatActivity() { class LoginActivity : AppCompatActivity() {
private var inValidCount: Int = 0 private var inValidCount: Int = 0
@ -40,27 +38,74 @@ class LoginActivity : AppCompatActivity() {
private lateinit var settings: SharedPreferences private lateinit var settings: SharedPreferences
private lateinit var editor: SharedPreferences.Editor private lateinit var editor: SharedPreferences.Editor
private lateinit var mFirebaseAnalytics: FirebaseAnalytics private lateinit var firebaseAnalytics: FirebaseAnalytics
private lateinit var mUrlView: EditText
private lateinit var mLoginView: TextView
private lateinit var mHTTPLoginView: TextView
private lateinit var mProgressView: View
private lateinit var mPasswordView: EditText
private lateinit var mHTTPPasswordView: EditText
private lateinit var mLoginFormView: View
private lateinit var userIdentifier: String private lateinit var userIdentifier: String
private var logErrors: Boolean = false private var logErrors: Boolean = false
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
Scoop.getInstance().apply(this) Scoop.getInstance().apply(this)
setContentView(R.layout.activity_login) setContentView(R.layout.activity_login)
val toolbar: Toolbar = findViewById(R.id.toolbar)
setSupportActionBar(toolbar) setSupportActionBar(toolbar)
handleBaseUrlFail()
settings = getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
userIdentifier = settings.getString("unique_id", "")
logErrors = settings.getBoolean("login_debug", false)
editor = settings.edit()
if (settings.getString("url", "").isNotEmpty()) {
goToMain()
}
firebaseAnalytics = FirebaseAnalytics.getInstance(this)
handleActions()
}
private fun handleActions() {
withSelfhostedCert.setOnCheckedChangeListener { _, b ->
isWithSelfSignedCert = !isWithSelfSignedCert
val visi: Int = if (b) View.VISIBLE else View.GONE
warningText.visibility = visi
}
passwordView.setOnEditorActionListener(
TextView.OnEditorActionListener { _, id, _ ->
if (id == R.id.loginView || id == EditorInfo.IME_NULL) {
attemptLogin()
return@OnEditorActionListener true
}
false
}
)
signInButton.setOnClickListener { attemptLogin() }
withLogin.setOnCheckedChangeListener { _, b ->
isWithLogin = !isWithLogin
val visi: Int = if (b) View.VISIBLE else View.GONE
loginLayout.visibility = visi
passwordLayout.visibility = visi
}
withHttpLogin.setOnCheckedChangeListener { _, b ->
isWithHTTPLogin = !isWithHTTPLogin
val visi: Int = if (b) View.VISIBLE else View.GONE
httpLoginInput.visibility = visi
httpPasswordInput.visibility = visi
}
}
private fun handleBaseUrlFail() {
if (intent.getBooleanExtra("baseUrlFail", false)) { if (intent.getBooleanExtra("baseUrlFail", false)) {
val alertDialog = AlertDialog.Builder(this).create() val alertDialog = AlertDialog.Builder(this).create()
alertDialog.setTitle(getString(R.string.warning_wrong_url)) alertDialog.setTitle(getString(R.string.warning_wrong_url))
@ -68,74 +113,10 @@ class LoginActivity : AppCompatActivity() {
alertDialog.setButton( alertDialog.setButton(
AlertDialog.BUTTON_NEUTRAL, AlertDialog.BUTTON_NEUTRAL,
"OK", "OK",
{ dialog, _ -> dialog.dismiss() }) { dialog, _ -> dialog.dismiss() }
)
alertDialog.show() alertDialog.show()
} }
settings = getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
userIdentifier = settings.getString("unique_id", "")
logErrors = settings.getBoolean("loging_debug", false)
editor = settings.edit()
if (settings.getString("url", "").isNotEmpty()) {
goToMain()
} else {
this@LoginActivity.checkAndDisplayStoreApk()
}
mFirebaseAnalytics = FirebaseAnalytics.getInstance(this)
mUrlView = findViewById(R.id.url)
mLoginView = findViewById(R.id.login)
mHTTPLoginView = findViewById(R.id.httpLogin)
mPasswordView = findViewById(R.id.password)
mHTTPPasswordView = findViewById(R.id.httpPassword)
mLoginFormView = findViewById(R.id.login_form)
mProgressView = findViewById(R.id.login_progress)
val mSwitch: Switch = findViewById(R.id.withLogin)
val mHTTPSwitch: Switch = findViewById(R.id.withHttpLogin)
val mLoginLayout: TextInputLayout = findViewById(R.id.loginLayout)
val mHTTPLoginLayout: TextInputLayout = findViewById(R.id.httpLoginInput)
val mPasswordLayout: TextInputLayout = findViewById(R.id.passwordLayout)
val mHTTPPasswordLayout: TextInputLayout = findViewById(R.id.httpPasswordInput)
val mEmailSignInButton: Button = findViewById(R.id.email_sign_in_button)
val selfHostedSwitch: Switch = findViewById(R.id.withSelfhostedCert)
val warningTextview: TextView = findViewById(R.id.warningText)
selfHostedSwitch.setOnCheckedChangeListener {_, b ->
isWithSelfSignedCert = !isWithSelfSignedCert
val visi: Int = if (b) View.VISIBLE else View.GONE
warningTextview.visibility = visi
}
mPasswordView.setOnEditorActionListener(TextView.OnEditorActionListener { _, id, _ ->
if (id == R.id.login || id == EditorInfo.IME_NULL) {
attemptLogin()
return@OnEditorActionListener true
}
false
})
mEmailSignInButton.setOnClickListener { attemptLogin() }
mSwitch.setOnCheckedChangeListener { _, b ->
isWithLogin = !isWithLogin
val visi: Int = if (b) View.VISIBLE else View.GONE
mLoginLayout.visibility = visi
mPasswordLayout.visibility = visi
}
mHTTPSwitch.setOnCheckedChangeListener { _, b ->
isWithHTTPLogin = !isWithHTTPLogin
val visi: Int = if (b) View.VISIBLE else View.GONE
mHTTPLoginLayout.visibility = visi
mHTTPPasswordLayout.visibility = visi
}
} }
private fun goToMain() { private fun goToMain() {
@ -147,25 +128,25 @@ class LoginActivity : AppCompatActivity() {
private fun attemptLogin() { private fun attemptLogin() {
// Reset errors. // Reset errors.
mUrlView.error = null urlView.error = null
mLoginView.error = null loginView.error = null
mHTTPLoginView.error = null httpLoginView.error = null
mPasswordView.error = null passwordView.error = null
mHTTPPasswordView.error = null httpPasswordView.error = null
// Store values at the time of the login attempt. // Store values at the time of the login attempt.
val url = mUrlView.text.toString() val url = urlView.text.toString()
val login = mLoginView.text.toString() val login = loginView.text.toString()
val httpLogin = mHTTPLoginView.text.toString() val httpLogin = httpLoginView.text.toString()
val password = mPasswordView.text.toString() val password = passwordView.text.toString()
val httpPassword = mHTTPPasswordView.text.toString() val httpPassword = httpPasswordView.text.toString()
var cancel = false var cancel = false
var focusView: View? = null var focusView: View? = null
if (!url.isBaseUrlValid()) { if (!url.isBaseUrlValid()) {
mUrlView.error = getString(R.string.login_url_problem) urlView.error = getString(R.string.login_url_problem)
focusView = mUrlView focusView = urlView
cancel = true cancel = true
inValidCount++ inValidCount++
if (inValidCount == 3) { if (inValidCount == 3) {
@ -175,7 +156,8 @@ class LoginActivity : AppCompatActivity() {
alertDialog.setButton( alertDialog.setButton(
AlertDialog.BUTTON_NEUTRAL, AlertDialog.BUTTON_NEUTRAL,
"OK", "OK",
{ dialog, _ -> dialog.dismiss() }) { dialog, _ -> dialog.dismiss() }
)
alertDialog.show() alertDialog.show()
inValidCount = 0 inValidCount = 0
} }
@ -183,14 +165,14 @@ class LoginActivity : AppCompatActivity() {
if (isWithLogin || isWithHTTPLogin) { if (isWithLogin || isWithHTTPLogin) {
if (TextUtils.isEmpty(password)) { if (TextUtils.isEmpty(password)) {
mPasswordView.error = getString(R.string.error_invalid_password) passwordView.error = getString(R.string.error_invalid_password)
focusView = mPasswordView focusView = passwordView
cancel = true cancel = true
} }
if (TextUtils.isEmpty(login)) { if (TextUtils.isEmpty(login)) {
mLoginView.error = getString(R.string.error_field_required) loginView.error = getString(R.string.error_field_required)
focusView = mLoginView focusView = loginView
cancel = true cancel = true
} }
} }
@ -208,7 +190,12 @@ class LoginActivity : AppCompatActivity() {
editor.putBoolean("isSelfSignedCert", isWithSelfSignedCert) editor.putBoolean("isSelfSignedCert", isWithSelfSignedCert)
editor.apply() editor.apply()
val api = SelfossApi(this, this@LoginActivity, isWithSelfSignedCert, isWithSelfSignedCert) val api = SelfossApi(
this,
this@LoginActivity,
isWithSelfSignedCert,
isWithSelfSignedCert
)
api.login().enqueue(object : Callback<SuccessResponse> { api.login().enqueue(object : Callback<SuccessResponse> {
private fun preferenceError(t: Throwable) { private fun preferenceError(t: Throwable) {
editor.remove("url") editor.remove("url")
@ -217,23 +204,30 @@ class LoginActivity : AppCompatActivity() {
editor.remove("password") editor.remove("password")
editor.remove("httpPassword") editor.remove("httpPassword")
editor.apply() editor.apply()
mUrlView.error = getString(R.string.wrong_infos) urlView.error = getString(R.string.wrong_infos)
mLoginView.error = getString(R.string.wrong_infos) loginView.error = getString(R.string.wrong_infos)
mPasswordView.error = getString(R.string.wrong_infos) passwordView.error = getString(R.string.wrong_infos)
mHTTPLoginView.error = getString(R.string.wrong_infos) httpLoginView.error = getString(R.string.wrong_infos)
mHTTPPasswordView.error = getString(R.string.wrong_infos) httpPasswordView.error = getString(R.string.wrong_infos)
if (logErrors) { if (logErrors) {
Crashlytics.setUserIdentifier(userIdentifier) Crashlytics.setUserIdentifier(userIdentifier)
Crashlytics.log(100, "LOGIN_DEBUG_ERRROR", t.message) Crashlytics.log(100, "LOGIN_DEBUG_ERRROR", t.message)
Crashlytics.logException(t) Crashlytics.logException(t)
Toast.makeText(this@LoginActivity, t.message, Toast.LENGTH_LONG).show() Toast.makeText(
this@LoginActivity,
t.message,
Toast.LENGTH_LONG
).show()
} }
showProgress(false) showProgress(false)
} }
override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) { override fun onResponse(
call: Call<SuccessResponse>,
response: Response<SuccessResponse>
) {
if (response.body() != null && response.body()!!.isSuccess) { if (response.body() != null && response.body()!!.isSuccess) {
mFirebaseAnalytics.logEvent(FirebaseAnalytics.Event.LOGIN, Bundle()) firebaseAnalytics.logEvent(FirebaseAnalytics.Event.LOGIN, Bundle())
goToMain() goToMain()
} else { } else {
preferenceError(Exception("No response body...")) preferenceError(Exception("No response body..."))
@ -247,40 +241,39 @@ class LoginActivity : AppCompatActivity() {
} }
} }
/**
* Shows the progress UI and hides the login form.
*/
private fun showProgress(show: Boolean) { private fun showProgress(show: Boolean) {
val shortAnimTime = resources.getInteger(android.R.integer.config_shortAnimTime) val shortAnimTime = resources.getInteger(android.R.integer.config_shortAnimTime)
mLoginFormView.visibility = if (show) View.GONE else View.VISIBLE loginForm.visibility = if (show) View.GONE else View.VISIBLE
mLoginFormView loginForm
.animate() .animate()
.setDuration(shortAnimTime.toLong()) .setDuration(shortAnimTime.toLong())
.alpha( .alpha(
if (show) 0F else 1F if (show) 0F else 1F
).setListener(object : AnimatorListenerAdapter() { ).setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) { override fun onAnimationEnd(animation: Animator) {
mLoginFormView.visibility = if (show) View.GONE else View.VISIBLE loginForm.visibility = if (show) View.GONE else View.VISIBLE
} }
}) }
)
mProgressView.visibility = if (show) View.VISIBLE else View.GONE loginProgress.visibility = if (show) View.VISIBLE else View.GONE
mProgressView loginProgress
.animate() .animate()
.setDuration(shortAnimTime.toLong()) .setDuration(shortAnimTime.toLong())
.alpha( .alpha(
if (show) 1F else 0F if (show) 1F else 0F
).setListener(object : AnimatorListenerAdapter() { ).setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) { override fun onAnimationEnd(animation: Animator) {
mProgressView.visibility = if (show) View.VISIBLE else View.GONE loginProgress.visibility = if (show) View.VISIBLE else View.GONE
} }
}) }
)
} }
override fun onCreateOptionsMenu(menu: Menu): Boolean { override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.login_menu, menu) menuInflater.inflate(R.menu.login_menu, menu)
menu.findItem(R.id.loging_debug).isChecked = logErrors menu.findItem(R.id.login_debug).isChecked = logErrors
return true return true
} }
@ -294,11 +287,11 @@ class LoginActivity : AppCompatActivity() {
.start(this) .start(this)
return true return true
} }
R.id.loging_debug -> { R.id.login_debug -> {
val newState = !item.isChecked val newState = !item.isChecked
item.isChecked = newState item.isChecked = newState
logErrors = newState logErrors = newState
editor.putBoolean("loging_debug", newState) editor.putBoolean("login_debug", newState)
editor.apply() editor.apply()
return true return true
} }

View File

@ -5,15 +5,16 @@ import android.os.Bundle
import android.preference.PreferenceManager import android.preference.PreferenceManager
import android.support.v7.app.AppCompatActivity import android.support.v7.app.AppCompatActivity
class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main) setContentView(R.layout.activity_main)
if (PreferenceManager.getDefaultSharedPreferences(baseContext).getBoolean("firstStart", true)) { if (PreferenceManager.getDefaultSharedPreferences(baseContext).getBoolean(
"firstStart",
true
)) {
val i = Intent(this@MainActivity, IntroActivity::class.java) val i = Intent(this@MainActivity, IntroActivity::class.java)
startActivity(i) startActivity(i)
} else { } else {
@ -22,6 +23,5 @@ class MainActivity : AppCompatActivity() {
} }
finish() finish()
} }
} }

View File

@ -21,9 +21,6 @@ import io.fabric.sdk.android.Fabric
import java.io.IOException import java.io.IOException
import java.util.UUID.randomUUID import java.util.UUID.randomUUID
class MyApp : MultiDexApplication() { class MyApp : MultiDexApplication() {
override fun onCreate() { override fun onCreate() {
@ -46,7 +43,6 @@ class MyApp : MultiDexApplication() {
initTheme() initTheme()
tryToHandleBug() tryToHandleBug()
} }
private fun initAmplify() { private fun initAmplify() {
@ -66,11 +62,15 @@ class MyApp : MultiDexApplication() {
private fun initDrawerImageLoader() { private fun initDrawerImageLoader() {
DrawerImageLoader.init(object : AbstractDrawerImageLoader() { DrawerImageLoader.init(object : AbstractDrawerImageLoader() {
override fun set(imageView: ImageView?, uri: Uri?, placeholder: Drawable?, tag: String?) { override fun set(
imageView: ImageView?,
uri: Uri?,
placeholder: Drawable?,
tag: String?
) {
Glide.with(imageView?.context) Glide.with(imageView?.context)
.load(uri) .load(uri)
.apply(RequestOptions.fitCenterTransform() .apply(RequestOptions.fitCenterTransform().placeholder(placeholder))
.placeholder(placeholder))
.into(imageView) .into(imageView)
} }
@ -108,11 +108,13 @@ class MyApp : MultiDexApplication() {
val oldHandler = Thread.getDefaultUncaughtExceptionHandler() val oldHandler = Thread.getDefaultUncaughtExceptionHandler()
Thread.setDefaultUncaughtExceptionHandler { thread, e -> Thread.setDefaultUncaughtExceptionHandler { thread, e ->
if (e is java.lang.NoClassDefFoundError && e.stackTrace.asList().any { it.toString().contains("android.view.ViewDebug") }) if (e is java.lang.NoClassDefFoundError && e.stackTrace.asList().any {
it.toString().contains("android.view.ViewDebug")
}) {
Unit Unit
else } else {
oldHandler.uncaughtException(thread, e) oldHandler.uncaughtException(thread, e)
} }
}
} }
} }

View File

@ -1,106 +1,204 @@
package apps.amine.bou.readerforselfoss package apps.amine.bou.readerforselfoss
import android.content.SharedPreferences
import android.os.Bundle import android.os.Bundle
import android.preference.PreferenceManager import android.preference.PreferenceManager
import android.view.LayoutInflater import android.support.customtabs.CustomTabsIntent
import android.support.design.widget.FloatingActionButton
import android.support.v4.widget.NestedScrollView
import android.support.v7.app.AppCompatActivity
import android.text.Html
import android.text.method.LinkMovementMethod
import android.view.MenuItem
import android.view.View import android.view.View
import android.view.ViewGroup
import android.widget.ImageButton
import android.widget.ImageView
import android.widget.TextView
import apps.amine.bou.readerforselfoss.api.mercury.MercuryApi import apps.amine.bou.readerforselfoss.api.mercury.MercuryApi
import apps.amine.bou.readerforselfoss.api.mercury.ParsedContent import apps.amine.bou.readerforselfoss.api.mercury.ParsedContent
import apps.amine.bou.readerforselfoss.utils.buildCustomTabsIntent import apps.amine.bou.readerforselfoss.utils.buildCustomTabsIntent
import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper
import apps.amine.bou.readerforselfoss.utils.isEmptyOrNullOrNullString
import apps.amine.bou.readerforselfoss.utils.openItemUrl import apps.amine.bou.readerforselfoss.utils.openItemUrl
import apps.amine.bou.readerforselfoss.utils.shareLink import apps.amine.bou.readerforselfoss.utils.shareLink
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions import com.bumptech.glide.request.RequestOptions
import com.crashlytics.android.Crashlytics
import com.ftinc.scoop.Scoop import com.ftinc.scoop.Scoop
import com.github.rubensousa.floatingtoolbar.FloatingToolbar
import kotlinx.android.synthetic.main.activity_reader.*
import org.sufficientlysecure.htmltextview.HtmlHttpImageGetter import org.sufficientlysecure.htmltextview.HtmlHttpImageGetter
import org.sufficientlysecure.htmltextview.HtmlTextView
import retrofit2.Call import retrofit2.Call
import retrofit2.Callback import retrofit2.Callback
import retrofit2.Response import retrofit2.Response
import xyz.klinker.android.drag_dismiss.activity.DragDismissActivity
class ReaderActivity : AppCompatActivity() {
class ReaderActivity : DragDismissActivity() {
private lateinit var mCustomTabActivityHelper: CustomTabActivityHelper private lateinit var mCustomTabActivityHelper: CustomTabActivityHelper
//private lateinit var content: HtmlTextView
override fun onStart() { private lateinit var url: String
super.onStart() private lateinit var contentText: String
mCustomTabActivityHelper.bindCustomTabsService(this) private lateinit var contentSource: String
} private lateinit var contentImage: String
private lateinit var contentTitle: String
private lateinit var fab: FloatingActionButton
override fun onStop() { override fun onStop() {
super.onStop() super.onStop()
mCustomTabActivityHelper.unbindCustomTabsService(this) mCustomTabActivityHelper.unbindCustomTabsService(this)
} }
override fun onCreateContent(inflater: LayoutInflater, parent: ViewGroup, savedInstanceState: Bundle?): View { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Scoop.getInstance().apply(this) Scoop.getInstance().apply(this)
val v = inflater.inflate(R.layout.activity_reader, parent, false) setContentView(R.layout.activity_reader)
showProgressBar()
val prefs = PreferenceManager.getDefaultSharedPreferences(this)
val image: ImageView = v.findViewById(R.id.imageView) url = intent.getStringExtra("url")
val source: TextView = v.findViewById(R.id.source) contentText = intent.getStringExtra("content")
val title: TextView = v.findViewById(R.id.title) contentTitle = intent.getStringExtra("title")
val content: HtmlTextView = v.findViewById(R.id.content) contentImage = intent.getStringExtra("image")
val url = intent.getStringExtra("url") contentSource = intent.getStringExtra("source")
val parser = MercuryApi(BuildConfig.MERCURY_KEY, prefs.getBoolean("should_log_everything", false))
val browserBtn: ImageButton = v.findViewById(R.id.browserBtn)
val shareBtn: ImageButton = v.findViewById(R.id.shareBtn)
fab = findViewById(R.id.fab)
val mFloatingToolbar: FloatingToolbar = findViewById(R.id.floatingToolbar)
mFloatingToolbar.attachFab(fab)
val customTabsIntent = this@ReaderActivity.buildCustomTabsIntent() val customTabsIntent = this@ReaderActivity.buildCustomTabsIntent()
mCustomTabActivityHelper = CustomTabActivityHelper() mCustomTabActivityHelper = CustomTabActivityHelper()
mCustomTabActivityHelper.bindCustomTabsService(this) mCustomTabActivityHelper.bindCustomTabsService(this)
val prefs = PreferenceManager.getDefaultSharedPreferences(this)
mFloatingToolbar.setClickListener(object : FloatingToolbar.ItemClickListener {
override fun onItemClick(item: MenuItem) {
when (item.itemId) {
R.id.more_action -> getContentFromMercury(customTabsIntent, prefs)
R.id.share_action -> this@ReaderActivity.shareLink(url)
R.id.open_action -> this@ReaderActivity.openItemUrl(
url,
contentText,
contentImage,
contentTitle,
contentSource,
customTabsIntent,
false,
false,
this@ReaderActivity
)
else -> Unit
}
}
override fun onItemLongClick(item: MenuItem?) {
}
})
if (contentText.isEmptyOrNullOrNullString()) {
getContentFromMercury(customTabsIntent, prefs)
} else {
source.text = contentSource
titleView.text = contentTitle
tryToHandleHtml(contentText, customTabsIntent, prefs)
if (!contentImage.isEmptyOrNullOrNullString()) {
imageView.visibility = View.VISIBLE
Glide
.with(baseContext)
.asBitmap()
.load(contentImage)
.apply(RequestOptions.fitCenterTransform())
.into(imageView)
} else {
imageView.visibility = View.GONE
}
}
nestedScrollView.setOnScrollChangeListener(
NestedScrollView.OnScrollChangeListener { _, _, scrollY, _, oldScrollY ->
if (scrollY > oldScrollY) {
fab.hide()
} else {
if (mFloatingToolbar.isShowing) mFloatingToolbar.hide() else fab.show()
}
}
)
content.movementMethod = LinkMovementMethod.getInstance()
}
private fun getContentFromMercury(
customTabsIntent: CustomTabsIntent,
prefs: SharedPreferences
) {
progressBar.visibility = View.VISIBLE
val parser = MercuryApi(
BuildConfig.MERCURY_KEY,
prefs.getBoolean("should_log_everything", false)
)
parser.parseUrl(url).enqueue(object : Callback<ParsedContent> { parser.parseUrl(url).enqueue(object : Callback<ParsedContent> {
override fun onResponse(call: Call<ParsedContent>, response: Response<ParsedContent>) { override fun onResponse(
call: Call<ParsedContent>,
response: Response<ParsedContent>
) {
if (response.body() != null && response.body()!!.content != null && response.body()!!.content.isNotEmpty()) { if (response.body() != null && response.body()!!.content != null && response.body()!!.content.isNotEmpty()) {
source.text = response.body()!!.domain source.text = response.body()!!.domain
title.text = response.body()!!.title titleView.text = response.body()!!.title
this@ReaderActivity.url = response.body()!!.url
if (response.body()!!.content != null && !response.body()!!.content.isEmpty()) { if (response.body()!!.content != null && !response.body()!!.content.isEmpty()) {
try { tryToHandleHtml(response.body()!!.content, customTabsIntent, prefs)
content.setHtml(response.body()!!.content, HtmlHttpImageGetter(content, null, true))
} catch (e: IndexOutOfBoundsException) {
openInBrowserAfterFailing()
} }
}
if (response.body()!!.lead_image_url != null && !response.body()!!.lead_image_url.isEmpty()) if (response.body()!!.lead_image_url != null && !response.body()!!.lead_image_url.isEmpty()) {
imageView.visibility = View.VISIBLE
Glide Glide
.with(baseContext) .with(baseContext)
.asBitmap() .asBitmap()
.load(response.body()!!.lead_image_url) .load(response.body()!!.lead_image_url)
.apply(RequestOptions.fitCenterTransform()) .apply(RequestOptions.fitCenterTransform())
.into(image) .into(imageView)
} else {
shareBtn.setOnClickListener { imageView.visibility = View.GONE
this@ReaderActivity.shareLink(response.body()!!.url)
} }
browserBtn.setOnClickListener { nestedScrollView.scrollTo(0, 0)
this@ReaderActivity.openItemUrl(
response.body()!!.url, progressBar.visibility = View.GONE
customTabsIntent, } else {
false, openInBrowserAfterFailing(customTabsIntent)
false, }
this@ReaderActivity)
} }
hideProgressBar() override fun onFailure(
} else openInBrowserAfterFailing() call: Call<ParsedContent>,
t: Throwable
) = openInBrowserAfterFailing(customTabsIntent)
})
} }
override fun onFailure(call: Call<ParsedContent>, t: Throwable) = openInBrowserAfterFailing() private fun tryToHandleHtml(
c: String,
customTabsIntent: CustomTabsIntent,
prefs: SharedPreferences
) {
try {
content.text = Html.fromHtml(c, HtmlHttpImageGetter(content, null, true), null)
private fun openInBrowserAfterFailing() { //content.setHtml(response.body()!!.content, HtmlHttpImageGetter(content, null, true))
} catch (e: Exception) {
Crashlytics.setUserIdentifier(prefs.getString("unique_id", ""))
Crashlytics.log(100, "CANT_TRANSFORM_TO_HTML", e.message)
Crashlytics.logException(e)
openInBrowserAfterFailing(customTabsIntent)
}
}
private fun openInBrowserAfterFailing(customTabsIntent: CustomTabsIntent) {
progressBar.visibility = View.GONE
this@ReaderActivity.openItemUrl( this@ReaderActivity.openItemUrl(
url, url,
contentText,
contentImage,
contentTitle,
contentSource,
customTabsIntent, customTabsIntent,
true, true,
false, false,
@ -108,7 +206,4 @@ class ReaderActivity : DragDismissActivity() {
) )
finish() finish()
} }
})
return v
}
} }

View File

@ -5,20 +5,15 @@ import android.os.Bundle
import android.preference.PreferenceManager import android.preference.PreferenceManager
import android.support.v7.app.AppCompatActivity import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.LinearLayoutManager import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.support.v7.widget.Toolbar
import android.widget.Toast import android.widget.Toast
import com.melnykov.fab.FloatingActionButton
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import apps.amine.bou.readerforselfoss.adapters.SourcesListAdapter import apps.amine.bou.readerforselfoss.adapters.SourcesListAdapter
import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
import apps.amine.bou.readerforselfoss.api.selfoss.Sources import apps.amine.bou.readerforselfoss.api.selfoss.Sources
import com.ftinc.scoop.Scoop import com.ftinc.scoop.Scoop
import kotlinx.android.synthetic.main.activity_sources.*
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
class SourcesActivity : AppCompatActivity() { class SourcesActivity : AppCompatActivity() {
@ -26,44 +21,64 @@ class SourcesActivity : AppCompatActivity() {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
Scoop.getInstance().apply(this) Scoop.getInstance().apply(this)
setContentView(R.layout.activity_sources) setContentView(R.layout.activity_sources)
val toolbar: Toolbar = findViewById(R.id.toolbar)
setSupportActionBar(toolbar) setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setDisplayShowHomeEnabled(true) supportActionBar?.setDisplayShowHomeEnabled(true)
} }
override fun onStop() {
super.onStop()
recyclerView.clearOnScrollListeners()
}
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
val mFab: FloatingActionButton = findViewById(R.id.fab)
val mRecyclerView: RecyclerView = findViewById(R.id.activity_sources)
val mLayoutManager = LinearLayoutManager(this) val mLayoutManager = LinearLayoutManager(this)
val prefs = PreferenceManager.getDefaultSharedPreferences(this) val prefs = PreferenceManager.getDefaultSharedPreferences(this)
val api = SelfossApi(this, this@SourcesActivity, prefs.getBoolean("isSelfSignedCert", false), prefs.getBoolean("should_log_everything", false)) val api = SelfossApi(
this,
this@SourcesActivity,
prefs.getBoolean("isSelfSignedCert", false),
prefs.getBoolean("should_log_everything", false)
)
var items: ArrayList<Sources> = ArrayList() var items: ArrayList<Sources> = ArrayList()
mFab.attachToRecyclerView(mRecyclerView) recyclerView.setHasFixedSize(true)
mRecyclerView.setHasFixedSize(true) recyclerView.layoutManager = mLayoutManager
mRecyclerView.layoutManager = mLayoutManager
api.sources.enqueue(object : Callback<List<Sources>> { api.sources.enqueue(object : Callback<List<Sources>> {
override fun onResponse(call: Call<List<Sources>>, response: Response<List<Sources>>) { override fun onResponse(
call: Call<List<Sources>>,
response: Response<List<Sources>>
) {
if (response.body() != null && response.body()!!.isNotEmpty()) { if (response.body() != null && response.body()!!.isNotEmpty()) {
items = response.body() as ArrayList<Sources> items = response.body() as ArrayList<Sources>
} }
val mAdapter = SourcesListAdapter(this@SourcesActivity, items, api) val mAdapter = SourcesListAdapter(this@SourcesActivity, items, api)
mRecyclerView.adapter = mAdapter recyclerView.adapter = mAdapter
mAdapter.notifyDataSetChanged() mAdapter.notifyDataSetChanged()
if (items.isEmpty()) Toast.makeText(this@SourcesActivity, R.string.nothing_here, Toast.LENGTH_SHORT).show() if (items.isEmpty()) {
Toast.makeText(
this@SourcesActivity,
R.string.nothing_here,
Toast.LENGTH_SHORT
).show()
}
} }
override fun onFailure(call: Call<List<Sources>>, t: Throwable) { override fun onFailure(call: Call<List<Sources>>, t: Throwable) {
Toast.makeText(this@SourcesActivity, R.string.cant_get_sources, Toast.LENGTH_SHORT).show() Toast.makeText(
this@SourcesActivity,
R.string.cant_get_sources,
Toast.LENGTH_SHORT
).show()
} }
}) })
mFab.setOnClickListener { fab.setOnClickListener {
startActivity(Intent(this@SourcesActivity, AddSourceActivity::class.java)) startActivity(Intent(this@SourcesActivity, AddSourceActivity::class.java))
} }
} }

View File

@ -3,42 +3,43 @@ package apps.amine.bou.readerforselfoss.adapters
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
import android.graphics.Color import android.graphics.Color
import android.support.constraint.ConstraintLayout
import android.support.design.widget.Snackbar import android.support.design.widget.Snackbar
import android.support.v7.widget.CardView import android.support.v7.widget.CardView
import android.support.v7.widget.RecyclerView import android.support.v7.widget.RecyclerView
import android.text.Html import android.text.Html
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageButton
import android.widget.ImageView
import android.widget.ImageView.ScaleType import android.widget.ImageView.ScaleType
import android.widget.TextView import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import com.amulyakhare.textdrawable.TextDrawable
import com.amulyakhare.textdrawable.util.ColorGenerator
import com.bumptech.glide.Glide
import com.like.LikeButton
import com.like.OnLikeListener
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import apps.amine.bou.readerforselfoss.R import apps.amine.bou.readerforselfoss.R
import apps.amine.bou.readerforselfoss.api.selfoss.Item import apps.amine.bou.readerforselfoss.api.selfoss.Item
import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse
import apps.amine.bou.readerforselfoss.themes.AppColors import apps.amine.bou.readerforselfoss.themes.AppColors
import apps.amine.bou.readerforselfoss.utils.* import apps.amine.bou.readerforselfoss.utils.buildCustomTabsIntent
import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper
import apps.amine.bou.readerforselfoss.utils.glide.bitmapCenterCrop import apps.amine.bou.readerforselfoss.utils.glide.bitmapCenterCrop
import apps.amine.bou.readerforselfoss.utils.glide.bitmapFitCenter
import apps.amine.bou.readerforselfoss.utils.glide.circularBitmapDrawable import apps.amine.bou.readerforselfoss.utils.glide.circularBitmapDrawable
import apps.amine.bou.readerforselfoss.utils.openInBrowserAsNewTask
import apps.amine.bou.readerforselfoss.utils.openItemUrl
import apps.amine.bou.readerforselfoss.utils.shareLink
import apps.amine.bou.readerforselfoss.utils.sourceAndDateText
import apps.amine.bou.readerforselfoss.utils.succeeded
import apps.amine.bou.readerforselfoss.utils.toTextDrawableString
import com.amulyakhare.textdrawable.TextDrawable
import com.amulyakhare.textdrawable.util.ColorGenerator
import com.bumptech.glide.Glide
import com.crashlytics.android.Crashlytics import com.crashlytics.android.Crashlytics
import kotlin.collections.ArrayList import com.like.LikeButton
import com.like.OnLikeListener
import kotlinx.android.synthetic.main.card_item.view.*
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
class ItemCardAdapter(private val app: Activity, class ItemCardAdapter(
private val app: Activity,
private val items: ArrayList<Item>, private val items: ArrayList<Item>,
private val api: SelfossApi, private val api: SelfossApi,
private val helper: CustomTabActivityHelper, private val helper: CustomTabActivityHelper,
@ -47,12 +48,13 @@ class ItemCardAdapter(private val app: Activity,
private val fullHeightCards: Boolean, private val fullHeightCards: Boolean,
private val appColors: AppColors, private val appColors: AppColors,
val debugReadingItems: Boolean, val debugReadingItems: Boolean,
val userIdentifier: String) : RecyclerView.Adapter<ItemCardAdapter.ViewHolder>() { val userIdentifier: String
) : RecyclerView.Adapter<ItemCardAdapter.ViewHolder>() {
private val c: Context = app.baseContext private val c: Context = app.baseContext
private val generator: ColorGenerator = ColorGenerator.MATERIAL private val generator: ColorGenerator = ColorGenerator.MATERIAL
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val v = LayoutInflater.from(c).inflate(R.layout.card_item, parent, false) as ConstraintLayout val v = LayoutInflater.from(c).inflate(R.layout.card_item, parent, false) as CardView
return ViewHolder(v) return ViewHolder(v)
} }
@ -60,23 +62,18 @@ class ItemCardAdapter(private val app: Activity,
val itm = items[position] val itm = items[position]
holder.saveBtn.isLiked = itm.starred holder.mView.favButton.isLiked = itm.starred
holder.title.text = Html.fromHtml(itm.title) holder.mView.title.text = Html.fromHtml(itm.title)
holder.sourceTitleAndDate.text = itm.sourceAndDateText() holder.mView.sourceTitleAndDate.text = itm.sourceAndDateText()
if (itm.getThumbnail(c).isEmpty()) { if (itm.getThumbnail(c).isEmpty()) {
Glide.with(c).clear(holder.itemImage) Glide.with(c).clear(holder.mView.itemImage)
holder.itemImage.setImageDrawable(null) holder.mView.itemImage.setImageDrawable(null)
} else { } else {
if (fullHeightCards) { c.bitmapCenterCrop(itm.getThumbnail(c), holder.mView.itemImage)
c.bitmapFitCenter(itm.getThumbnail(c), holder.itemImage)
} else {
c.bitmapCenterCrop(itm.getThumbnail(c), holder.itemImage)
}
} }
val fHolder = holder
if (itm.getIcon(c).isEmpty()) { if (itm.getIcon(c).isEmpty()) {
val color = generator.getColor(itm.sourcetitle) val color = generator.getColor(itm.sourcetitle)
@ -85,12 +82,12 @@ class ItemCardAdapter(private val app: Activity,
.builder() .builder()
.round() .round()
.build(itm.sourcetitle.toTextDrawableString(), color) .build(itm.sourcetitle.toTextDrawableString(), color)
holder.sourceImage.setImageDrawable(drawable) holder.mView.sourceImage.setImageDrawable(drawable)
} else { } else {
c.circularBitmapDrawable(itm.getIcon(c), holder.sourceImage) c.circularBitmapDrawable(itm.getIcon(c), holder.mView.sourceImage)
} }
holder.saveBtn.isLiked = itm.starred holder.mView.favButton.isLiked = itm.starred
} }
override fun getItemCount(): Int { override fun getItemCount(): Int {
@ -99,13 +96,21 @@ class ItemCardAdapter(private val app: Activity,
private fun doUnmark(i: Item, position: Int) { private fun doUnmark(i: Item, position: Int) {
val s = Snackbar val s = Snackbar
.make(app.findViewById(R.id.coordLayout), R.string.marked_as_read, Snackbar.LENGTH_LONG) .make(
app.findViewById(R.id.coordLayout),
R.string.marked_as_read,
Snackbar.LENGTH_LONG
)
.setAction(R.string.undo_string) { .setAction(R.string.undo_string) {
items.add(position, i) items.add(position, i)
notifyItemInserted(position) notifyItemInserted(position)
api.unmarkItem(i.id).enqueue(object : Callback<SuccessResponse> { api.unmarkItem(i.id).enqueue(object : Callback<SuccessResponse> {
override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) {} override fun onResponse(
call: Call<SuccessResponse>,
response: Response<SuccessResponse>
) {
}
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) { override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
items.remove(i) items.remove(i)
@ -129,8 +134,11 @@ class ItemCardAdapter(private val app: Activity,
notifyItemRemoved(position) notifyItemRemoved(position)
api.markItem(i.id).enqueue(object : Callback<SuccessResponse> { api.markItem(i.id).enqueue(object : Callback<SuccessResponse> {
override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) { override fun onResponse(
if (debugReadingItems) { call: Call<SuccessResponse>,
response: Response<SuccessResponse>
) {
if (!response.succeeded() && debugReadingItems) {
val message = val message =
"message: ${response.message()} " + "message: ${response.message()} " +
"response isSuccess: ${response.isSuccessful} " + "response isSuccess: ${response.isSuccessful} " +
@ -155,52 +163,51 @@ class ItemCardAdapter(private val app: Activity,
Crashlytics.logException(t) Crashlytics.logException(t)
Toast.makeText(c, t.message, Toast.LENGTH_LONG).show() Toast.makeText(c, t.message, Toast.LENGTH_LONG).show()
} }
Toast.makeText(app, app.getString(R.string.cant_mark_read), Toast.LENGTH_SHORT).show() Toast.makeText(
app,
app.getString(R.string.cant_mark_read),
Toast.LENGTH_SHORT
).show()
items.add(i) items.add(i)
notifyItemInserted(position) notifyItemInserted(position)
} }
}) })
} }
inner class ViewHolder(val mView: ConstraintLayout) : RecyclerView.ViewHolder(mView) { inner class ViewHolder(val mView: CardView) : RecyclerView.ViewHolder(mView) {
lateinit var saveBtn: LikeButton
lateinit var browserBtn: ImageButton
lateinit var shareBtn: ImageButton
lateinit var itemImage: ImageView
lateinit var sourceImage: ImageView
lateinit var title: TextView
lateinit var sourceTitleAndDate: TextView
init { init {
(mView.findViewById<CardView>(R.id.card)).setCardBackgroundColor(appColors.cardBackground) mView.setCardBackgroundColor(appColors.cardBackground)
handleClickListeners() handleClickListeners()
handleCustomTabActions() handleCustomTabActions()
} }
private fun handleClickListeners() { private fun handleClickListeners() {
sourceImage = mView.findViewById(R.id.sourceImage)
itemImage = mView.findViewById(R.id.itemImage)
title = mView.findViewById(R.id.title)
sourceTitleAndDate = mView.findViewById(R.id.sourceTitleAndDate)
saveBtn = mView.findViewById(R.id.favButton)
shareBtn = mView.findViewById(R.id.shareBtn)
browserBtn = mView.findViewById(R.id.browserBtn)
if (!fullHeightCards) { if (!fullHeightCards) {
itemImage.maxHeight = c.resources.getDimension(R.dimen.card_image_max_height).toInt() mView.itemImage.maxHeight = c.resources.getDimension(R.dimen.card_image_max_height).toInt()
itemImage.scaleType = ScaleType.CENTER_CROP mView.itemImage.scaleType = ScaleType.CENTER_CROP
} }
saveBtn.setOnLikeListener(object : OnLikeListener { mView.favButton.setOnLikeListener(object : OnLikeListener {
override fun liked(likeButton: LikeButton) { override fun liked(likeButton: LikeButton) {
val (id) = items[adapterPosition] val (id) = items[adapterPosition]
api.starrItem(id).enqueue(object : Callback<SuccessResponse> { api.starrItem(id).enqueue(object : Callback<SuccessResponse> {
override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) {} override fun onResponse(
call: Call<SuccessResponse>,
response: Response<SuccessResponse>
) {
}
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) { override fun onFailure(
saveBtn.isLiked = false call: Call<SuccessResponse>,
Toast.makeText(c, R.string.cant_mark_favortie, Toast.LENGTH_SHORT).show() t: Throwable
) {
mView.favButton.isLiked = false
Toast.makeText(
c,
R.string.cant_mark_favortie,
Toast.LENGTH_SHORT
).show()
} }
}) })
} }
@ -208,22 +215,33 @@ class ItemCardAdapter(private val app: Activity,
override fun unLiked(likeButton: LikeButton) { override fun unLiked(likeButton: LikeButton) {
val (id) = items[adapterPosition] val (id) = items[adapterPosition]
api.unstarrItem(id).enqueue(object : Callback<SuccessResponse> { api.unstarrItem(id).enqueue(object : Callback<SuccessResponse> {
override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) {} override fun onResponse(
call: Call<SuccessResponse>,
response: Response<SuccessResponse>
) {
}
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) { override fun onFailure(
saveBtn.isLiked = true call: Call<SuccessResponse>,
Toast.makeText(c, R.string.cant_unmark_favortie, Toast.LENGTH_SHORT).show() t: Throwable
) {
mView.favButton.isLiked = true
Toast.makeText(
c,
R.string.cant_unmark_favortie,
Toast.LENGTH_SHORT
).show()
} }
}) })
} }
}) })
shareBtn.setOnClickListener { mView.shareBtn.setOnClickListener {
c.shareLink(items[adapterPosition].getLinkDecoded()) c.shareLink(items[adapterPosition].getLinkDecoded())
} }
browserBtn.setOnClickListener { mView.browserBtn.setOnClickListener {
c.openInBrowser(items[adapterPosition]) c.openInBrowserAsNewTask(items[adapterPosition])
} }
} }
@ -232,11 +250,17 @@ class ItemCardAdapter(private val app: Activity,
helper.bindCustomTabsService(app) helper.bindCustomTabsService(app)
mView.setOnClickListener { mView.setOnClickListener {
c.openItemUrl(items[adapterPosition].getLinkDecoded(), c.openItemUrl(
items[adapterPosition].getLinkDecoded(),
items[adapterPosition].content,
items[adapterPosition].getThumbnail(c),
items[adapterPosition].title,
items[adapterPosition].sourceAndDateText(),
customTabsIntent, customTabsIntent,
internalBrowser, internalBrowser,
articleViewer, articleViewer,
app) app
)
} }
} }
} }

View File

@ -1,6 +1,5 @@
package apps.amine.bou.readerforselfoss.adapters package apps.amine.bou.readerforselfoss.adapters
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
import android.graphics.Color import android.graphics.Color
@ -12,30 +11,35 @@ import android.util.TypedValue
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.* import android.widget.TextView
import android.widget.Toast
import com.amulyakhare.textdrawable.TextDrawable
import com.amulyakhare.textdrawable.util.ColorGenerator
import com.like.LikeButton
import com.like.OnLikeListener
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import java.util.*
import apps.amine.bou.readerforselfoss.R import apps.amine.bou.readerforselfoss.R
import apps.amine.bou.readerforselfoss.api.selfoss.Item import apps.amine.bou.readerforselfoss.api.selfoss.Item
import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse
import apps.amine.bou.readerforselfoss.utils.* import apps.amine.bou.readerforselfoss.utils.buildCustomTabsIntent
import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper
import apps.amine.bou.readerforselfoss.utils.glide.bitmapCenterCrop import apps.amine.bou.readerforselfoss.utils.glide.bitmapCenterCrop
import apps.amine.bou.readerforselfoss.utils.glide.circularBitmapDrawable import apps.amine.bou.readerforselfoss.utils.glide.circularBitmapDrawable
import apps.amine.bou.readerforselfoss.utils.openInBrowserAsNewTask
import apps.amine.bou.readerforselfoss.utils.openItemUrl
import apps.amine.bou.readerforselfoss.utils.shareLink
import apps.amine.bou.readerforselfoss.utils.sourceAndDateText
import apps.amine.bou.readerforselfoss.utils.succeeded
import com.amulyakhare.textdrawable.TextDrawable
import com.amulyakhare.textdrawable.util.ColorGenerator
import com.crashlytics.android.Crashlytics import com.crashlytics.android.Crashlytics
import com.like.LikeButton
import com.like.OnLikeListener
import kotlinx.android.synthetic.main.list_item.view.*
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import java.util.*
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
class ItemListAdapter(
class ItemListAdapter(private val app: Activity, private val app: Activity,
private val items: ArrayList<Item>, private val items: ArrayList<Item>,
private val api: SelfossApi, private val api: SelfossApi,
private val helper: CustomTabActivityHelper, private val helper: CustomTabActivityHelper,
@ -43,13 +47,18 @@ class ItemListAdapter(private val app: Activity,
private val internalBrowser: Boolean, private val internalBrowser: Boolean,
private val articleViewer: Boolean, private val articleViewer: Boolean,
val debugReadingItems: Boolean, val debugReadingItems: Boolean,
val userIdentifier: String) : RecyclerView.Adapter<ItemListAdapter.ViewHolder>() { val userIdentifier: String
) : RecyclerView.Adapter<ItemListAdapter.ViewHolder>() {
private val generator: ColorGenerator = ColorGenerator.MATERIAL private val generator: ColorGenerator = ColorGenerator.MATERIAL
private val c: Context = app.baseContext private val c: Context = app.baseContext
private val bars: ArrayList<Boolean> = ArrayList(Collections.nCopies(items.size + 1, false)) private val bars: ArrayList<Boolean> = ArrayList(Collections.nCopies(items.size + 1, false))
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val v = LayoutInflater.from(c).inflate(R.layout.list_item, parent, false) as ConstraintLayout val v = LayoutInflater.from(c).inflate(
R.layout.list_item,
parent,
false
) as ConstraintLayout
return ViewHolder(v) return ViewHolder(v)
} }
@ -57,27 +66,29 @@ class ItemListAdapter(private val app: Activity,
val itm = items[position] val itm = items[position]
holder.saveBtn.isLiked = itm.starred holder.mView.favButton.isLiked = itm.starred
holder.title.text = Html.fromHtml(itm.title) holder.mView.title.text = Html.fromHtml(itm.title)
holder.sourceTitleAndDate.text = itm.sourceAndDateText() holder.mView.sourceTitleAndDate.text = itm.sourceAndDateText()
if (itm.getThumbnail(c).isEmpty()) { if (itm.getThumbnail(c).isEmpty()) {
val sizeInInt = 46 val sizeInInt = 46
val sizeInDp = TypedValue.applyDimension( val sizeInDp = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, sizeInInt.toFloat(), c.resources TypedValue.COMPLEX_UNIT_DIP, sizeInInt.toFloat(), c.resources
.displayMetrics).toInt() .displayMetrics
).toInt()
val marginInInt = 16 val marginInInt = 16
val marginInDp = TypedValue.applyDimension( val marginInDp = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, marginInInt.toFloat(), c.resources TypedValue.COMPLEX_UNIT_DIP, marginInInt.toFloat(), c.resources
.displayMetrics).toInt() .displayMetrics
).toInt()
val params = holder.sourceImage.layoutParams as ViewGroup.MarginLayoutParams val params = holder.mView.itemImage.layoutParams as ViewGroup.MarginLayoutParams
params.height = sizeInDp params.height = sizeInDp
params.width = sizeInDp params.width = sizeInDp
params.setMargins(marginInDp, 0, 0, 0) params.setMargins(marginInDp, 0, 0, 0)
holder.sourceImage.layoutParams = params holder.mView.itemImage.layoutParams = params
if (itm.getIcon(c).isEmpty()) { if (itm.getIcon(c).isEmpty()) {
val color = generator.getColor(itm.sourcetitle) val color = generator.getColor(itm.sourcetitle)
@ -89,31 +100,42 @@ class ItemListAdapter(private val app: Activity,
val builder = TextDrawable.builder().round() val builder = TextDrawable.builder().round()
val drawable = builder.build(textDrawable.toString(), color) val drawable = builder.build(textDrawable.toString(), color)
holder.sourceImage.setImageDrawable(drawable) holder.mView.itemImage.setImageDrawable(drawable)
} else { } else {
c.circularBitmapDrawable(itm.getIcon(c), holder.sourceImage) c.circularBitmapDrawable(itm.getIcon(c), holder.mView.itemImage)
} }
} else { } else {
c.bitmapCenterCrop(itm.getThumbnail(c), holder.sourceImage) c.bitmapCenterCrop(itm.getThumbnail(c), holder.mView.itemImage)
} }
if (bars[position]) holder.actionBar.visibility = View.VISIBLE else holder.actionBar.visibility = View.GONE if (bars[position]) {
holder.mView.actionBar.visibility = View.VISIBLE
} else {
holder.mView.actionBar.visibility = View.GONE
}
holder.saveBtn.isLiked = itm.starred holder.mView.favButton.isLiked = itm.starred
} }
override fun getItemCount(): Int = items.size override fun getItemCount(): Int = items.size
private fun doUnmark(i: Item, position: Int) { private fun doUnmark(i: Item, position: Int) {
val s = Snackbar val s = Snackbar
.make(app.findViewById(R.id.coordLayout), R.string.marked_as_read, Snackbar.LENGTH_LONG) .make(
app.findViewById(R.id.coordLayout),
R.string.marked_as_read,
Snackbar.LENGTH_LONG
)
.setAction(R.string.undo_string) { .setAction(R.string.undo_string) {
items.add(position, i) items.add(position, i)
notifyItemInserted(position) notifyItemInserted(position)
api.unmarkItem(i.id).enqueue(object : Callback<SuccessResponse> { api.unmarkItem(i.id).enqueue(object : Callback<SuccessResponse> {
override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) {} override fun onResponse(
call: Call<SuccessResponse>,
response: Response<SuccessResponse>
) {
}
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) { override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
items.remove(i) items.remove(i)
@ -137,8 +159,11 @@ class ItemListAdapter(private val app: Activity,
notifyItemRemoved(position) notifyItemRemoved(position)
api.markItem(i.id).enqueue(object : Callback<SuccessResponse> { api.markItem(i.id).enqueue(object : Callback<SuccessResponse> {
override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) { override fun onResponse(
if (debugReadingItems) { call: Call<SuccessResponse>,
response: Response<SuccessResponse>
) {
if (!response.succeeded() && debugReadingItems) {
val message = val message =
"message: ${response.message()} " + "message: ${response.message()} " +
"response isSuccess: ${response.isSuccessful} " + "response isSuccess: ${response.isSuccessful} " +
@ -153,7 +178,6 @@ class ItemListAdapter(private val app: Activity,
Toast.makeText(c, message, Toast.LENGTH_LONG).show() Toast.makeText(c, message, Toast.LENGTH_LONG).show()
} }
doUnmark(i, position) doUnmark(i, position)
} }
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) { override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
@ -163,22 +187,18 @@ class ItemListAdapter(private val app: Activity,
Crashlytics.logException(t) Crashlytics.logException(t)
Toast.makeText(c, t.message, Toast.LENGTH_LONG).show() Toast.makeText(c, t.message, Toast.LENGTH_LONG).show()
} }
Toast.makeText(app, app.getString(R.string.cant_mark_read), Toast.LENGTH_SHORT).show() Toast.makeText(
app,
app.getString(R.string.cant_mark_read),
Toast.LENGTH_SHORT
).show()
items.add(i) items.add(i)
notifyItemInserted(position) notifyItemInserted(position)
} }
}) })
} }
inner class ViewHolder(val mView: ConstraintLayout) : RecyclerView.ViewHolder(mView) { inner class ViewHolder(val mView: ConstraintLayout) : RecyclerView.ViewHolder(mView) {
lateinit var saveBtn: LikeButton
lateinit var browserBtn: ImageButton
lateinit var shareBtn: ImageButton
lateinit var actionBar: RelativeLayout
lateinit var sourceImage: ImageView
lateinit var title: TextView
lateinit var sourceTitleAndDate: TextView
init { init {
handleClickListeners() handleClickListeners()
@ -186,24 +206,27 @@ class ItemListAdapter(private val app: Activity,
} }
private fun handleClickListeners() { private fun handleClickListeners() {
actionBar = mView.findViewById(R.id.actionBar)
sourceImage = mView.findViewById(R.id.itemImage)
title = mView.findViewById(R.id.title)
sourceTitleAndDate = mView.findViewById(R.id.sourceTitleAndDate)
saveBtn = mView.findViewById(R.id.favButton)
shareBtn = mView.findViewById(R.id.shareBtn)
browserBtn = mView.findViewById(R.id.browserBtn)
mView.favButton.setOnLikeListener(object : OnLikeListener {
saveBtn.setOnLikeListener(object : OnLikeListener {
override fun liked(likeButton: LikeButton) { override fun liked(likeButton: LikeButton) {
val (id) = items[adapterPosition] val (id) = items[adapterPosition]
api.starrItem(id).enqueue(object : Callback<SuccessResponse> { api.starrItem(id).enqueue(object : Callback<SuccessResponse> {
override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) {} override fun onResponse(
call: Call<SuccessResponse>,
response: Response<SuccessResponse>
) {
}
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) { override fun onFailure(
saveBtn.isLiked = false call: Call<SuccessResponse>,
Toast.makeText(c, R.string.cant_mark_favortie, Toast.LENGTH_SHORT).show() t: Throwable
) {
mView.favButton.isLiked = false
Toast.makeText(
c,
R.string.cant_mark_favortie,
Toast.LENGTH_SHORT
).show()
} }
}) })
} }
@ -211,27 +234,37 @@ class ItemListAdapter(private val app: Activity,
override fun unLiked(likeButton: LikeButton) { override fun unLiked(likeButton: LikeButton) {
val (id) = items[adapterPosition] val (id) = items[adapterPosition]
api.unstarrItem(id).enqueue(object : Callback<SuccessResponse> { api.unstarrItem(id).enqueue(object : Callback<SuccessResponse> {
override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) {} override fun onResponse(
call: Call<SuccessResponse>,
response: Response<SuccessResponse>
) {
}
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) { override fun onFailure(
saveBtn.isLiked = true call: Call<SuccessResponse>,
Toast.makeText(c, R.string.cant_unmark_favortie, Toast.LENGTH_SHORT).show() t: Throwable
) {
mView.favButton.isLiked = true
Toast.makeText(
c,
R.string.cant_unmark_favortie,
Toast.LENGTH_SHORT
).show()
} }
}) })
} }
}) })
shareBtn.setOnClickListener { mView.shareBtn.setOnClickListener {
c.shareLink(items[adapterPosition].getLinkDecoded()) c.shareLink(items[adapterPosition].getLinkDecoded())
} }
browserBtn.setOnClickListener { mView.browserBtn.setOnClickListener {
c.openInBrowser(items[adapterPosition]) c.openInBrowserAsNewTask(items[adapterPosition])
} }
} }
private fun handleCustomTabActions() { private fun handleCustomTabActions() {
val customTabsIntent = c.buildCustomTabsIntent() val customTabsIntent = c.buildCustomTabsIntent()
helper.bindCustomTabsService(app) helper.bindCustomTabsService(app)
@ -239,11 +272,17 @@ class ItemListAdapter(private val app: Activity,
if (!clickBehavior) { if (!clickBehavior) {
mView.setOnClickListener { mView.setOnClickListener {
c.openItemUrl(items[adapterPosition].getLinkDecoded(), c.openItemUrl(
items[adapterPosition].getLinkDecoded(),
items[adapterPosition].content,
items[adapterPosition].getThumbnail(c),
items[adapterPosition].title,
items[adapterPosition].sourceAndDateText(),
customTabsIntent, customTabsIntent,
internalBrowser, internalBrowser,
articleViewer, articleViewer,
app) app
)
} }
mView.setOnLongClickListener { mView.setOnLongClickListener {
actionBarShowHide() actionBarShowHide()
@ -252,11 +291,17 @@ class ItemListAdapter(private val app: Activity,
} else { } else {
mView.setOnClickListener { actionBarShowHide() } mView.setOnClickListener { actionBarShowHide() }
mView.setOnLongClickListener { mView.setOnLongClickListener {
c.openItemUrl(items[adapterPosition].getLinkDecoded(), c.openItemUrl(
items[adapterPosition].getLinkDecoded(),
items[adapterPosition].content,
items[adapterPosition].getThumbnail(c),
items[adapterPosition].title,
items[adapterPosition].sourceAndDateText(),
customTabsIntent, customTabsIntent,
internalBrowser, internalBrowser,
articleViewer, articleViewer,
app) app
)
true true
} }
} }
@ -264,7 +309,11 @@ class ItemListAdapter(private val app: Activity,
private fun actionBarShowHide() { private fun actionBarShowHide() {
bars[adapterPosition] = true bars[adapterPosition] = true
if (actionBar.visibility == View.GONE) actionBar.visibility = View.VISIBLE else actionBar.visibility = View.GONE if (mView.actionBar.visibility == View.GONE) {
mView.actionBar.visibility = View.VISIBLE
} else {
mView.actionBar.visibility = View.GONE
}
} }
} }
} }

View File

@ -7,32 +7,34 @@ import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.Button import android.widget.Button
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import com.amulyakhare.textdrawable.TextDrawable
import com.amulyakhare.textdrawable.util.ColorGenerator
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import apps.amine.bou.readerforselfoss.R import apps.amine.bou.readerforselfoss.R
import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
import apps.amine.bou.readerforselfoss.api.selfoss.Sources import apps.amine.bou.readerforselfoss.api.selfoss.Sources
import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse
import apps.amine.bou.readerforselfoss.utils.glide.circularBitmapDrawable import apps.amine.bou.readerforselfoss.utils.glide.circularBitmapDrawable
import apps.amine.bou.readerforselfoss.utils.toTextDrawableString import apps.amine.bou.readerforselfoss.utils.toTextDrawableString
import com.amulyakhare.textdrawable.TextDrawable
import com.amulyakhare.textdrawable.util.ColorGenerator
import kotlinx.android.synthetic.main.source_list_item.view.*
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
class SourcesListAdapter(
class SourcesListAdapter(private val app: Activity, private val app: Activity,
private val items: ArrayList<Sources>, private val items: ArrayList<Sources>,
private val api: SelfossApi) : RecyclerView.Adapter<SourcesListAdapter.ViewHolder>() { private val api: SelfossApi
) : RecyclerView.Adapter<SourcesListAdapter.ViewHolder>() {
private val c: Context = app.baseContext private val c: Context = app.baseContext
private val generator: ColorGenerator = ColorGenerator.MATERIAL private val generator: ColorGenerator = ColorGenerator.MATERIAL
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val v = LayoutInflater.from(c).inflate(R.layout.source_list_item, parent, false) as ConstraintLayout val v = LayoutInflater.from(c).inflate(
R.layout.source_list_item,
parent,
false
) as ConstraintLayout
return ViewHolder(v) return ViewHolder(v)
} }
@ -47,53 +49,55 @@ class SourcesListAdapter(private val app: Activity,
.builder() .builder()
.round() .round()
.build(itm.title.toTextDrawableString(), color) .build(itm.title.toTextDrawableString(), color)
holder.sourceImage.setImageDrawable(drawable) holder.mView.itemImage.setImageDrawable(drawable)
} else { } else {
c.circularBitmapDrawable(itm.getIcon(c), holder.sourceImage) c.circularBitmapDrawable(itm.getIcon(c), holder.mView.itemImage)
} }
holder.sourceTitle.text = itm.title holder.mView.sourceTitle.text = itm.title
} }
override fun getItemCount(): Int { override fun getItemCount(): Int = items.size
return items.size
}
inner class ViewHolder(internal val mView: ConstraintLayout) : RecyclerView.ViewHolder(mView) { inner class ViewHolder(internal val mView: ConstraintLayout) : RecyclerView.ViewHolder(mView) {
lateinit var sourceImage: ImageView
lateinit var sourceTitle: TextView
init { init {
handleClickListeners() handleClickListeners()
} }
private fun handleClickListeners() { private fun handleClickListeners() {
sourceImage = mView.findViewById(R.id.itemImage)
sourceTitle = mView.findViewById(R.id.sourceTitle)
val deleteBtn: Button = mView.findViewById(R.id.deleteBtn) val deleteBtn: Button = mView.findViewById(R.id.deleteBtn)
deleteBtn.setOnClickListener { deleteBtn.setOnClickListener {
val (id) = items[adapterPosition] val (id) = items[adapterPosition]
api.deleteSource(id).enqueue(object : Callback<SuccessResponse> { api.deleteSource(id).enqueue(object : Callback<SuccessResponse> {
override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) { override fun onResponse(
call: Call<SuccessResponse>,
response: Response<SuccessResponse>
) {
if (response.body() != null && response.body()!!.isSuccess) { if (response.body() != null && response.body()!!.isSuccess) {
items.removeAt(adapterPosition) items.removeAt(adapterPosition)
notifyItemRemoved(adapterPosition) notifyItemRemoved(adapterPosition)
notifyItemRangeChanged(adapterPosition, itemCount) notifyItemRangeChanged(adapterPosition, itemCount)
} else { } else {
Toast.makeText(app, R.string.can_delete_source, Toast.LENGTH_SHORT).show() Toast.makeText(
app,
R.string.can_delete_source,
Toast.LENGTH_SHORT
).show()
} }
} }
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) { override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
Toast.makeText(app, R.string.can_delete_source, Toast.LENGTH_SHORT).show() Toast.makeText(
app,
R.string.can_delete_source,
Toast.LENGTH_SHORT
).show()
} }
}) })
} }
} }
} }
} }

View File

@ -7,18 +7,17 @@ import retrofit2.Call
import retrofit2.Retrofit import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory import retrofit2.converter.gson.GsonConverterFactory
class MercuryApi(private val key: String, shouldLog: Boolean) { class MercuryApi(private val key: String, shouldLog: Boolean) {
private val service: MercuryService private val service: MercuryService
init { init {
val interceptor = HttpLoggingInterceptor() val interceptor = HttpLoggingInterceptor()
interceptor.level = if (shouldLog) interceptor.level = if (shouldLog) {
HttpLoggingInterceptor.Level.BODY HttpLoggingInterceptor.Level.BODY
else } else {
HttpLoggingInterceptor.Level.NONE HttpLoggingInterceptor.Level.NONE
}
val client = OkHttpClient.Builder().addInterceptor(interceptor).build() val client = OkHttpClient.Builder().addInterceptor(interceptor).build()
val gson = GsonBuilder() val gson = GsonBuilder()

View File

@ -4,8 +4,8 @@ import android.os.Parcel
import android.os.Parcelable import android.os.Parcelable
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
class ParsedContent(
class ParsedContent(@SerializedName("title") val title: String, @SerializedName("title") val title: String,
@SerializedName("content") val content: String, @SerializedName("content") val content: String,
@SerializedName("date_published") val date_published: String, @SerializedName("date_published") val date_published: String,
@SerializedName("lead_image_url") val lead_image_url: String, @SerializedName("lead_image_url") val lead_image_url: String,
@ -15,10 +15,12 @@ class ParsedContent(@SerializedName("title") val title: String,
@SerializedName("excerpt") val excerpt: String, @SerializedName("excerpt") val excerpt: String,
@SerializedName("total_pages") val total_pages: Int, @SerializedName("total_pages") val total_pages: Int,
@SerializedName("rendered_pages") val rendered_pages: Int, @SerializedName("rendered_pages") val rendered_pages: Int,
@SerializedName("next_page_url") val next_page_url: String) : Parcelable { @SerializedName("next_page_url") val next_page_url: String
) : Parcelable {
companion object { companion object {
@JvmField val CREATOR: Parcelable.Creator<ParsedContent> = object : Parcelable.Creator<ParsedContent> { @JvmField
val CREATOR: Parcelable.Creator<ParsedContent> = object : Parcelable.Creator<ParsedContent> {
override fun createFromParcel(source: Parcel): ParsedContent = ParsedContent(source) override fun createFromParcel(source: Parcel): ParsedContent = ParsedContent(source)
override fun newArray(size: Int): Array<ParsedContent?> = arrayOfNulls(size) override fun newArray(size: Int): Array<ParsedContent?> = arrayOfNulls(size)
} }

View File

@ -1,13 +1,10 @@
package apps.amine.bou.readerforselfoss.api.mercury package apps.amine.bou.readerforselfoss.api.mercury
import retrofit2.Call import retrofit2.Call
import retrofit2.http.GET import retrofit2.http.GET
import retrofit2.http.Header import retrofit2.http.Header
import retrofit2.http.Query import retrofit2.http.Query
interface MercuryService { interface MercuryService {
@GET("parser") @GET("parser")
fun parseUrl(@Query("url") url: String, @Header("x-api-key") key: String): Call<ParsedContent> fun parseUrl(@Query("url") url: String, @Header("x-api-key") key: String): Call<ParsedContent>

View File

@ -1,18 +1,19 @@
package apps.amine.bou.readerforselfoss.api.selfoss package apps.amine.bou.readerforselfoss.api.selfoss
import java.lang.reflect.Type
import com.google.gson.JsonParseException
import com.google.gson.JsonDeserializationContext import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonElement
import com.google.gson.JsonDeserializer import com.google.gson.JsonDeserializer
import com.google.gson.JsonElement
import com.google.gson.JsonParseException
import java.lang.reflect.Type
internal class BooleanTypeAdapter : JsonDeserializer<Boolean> { internal class BooleanTypeAdapter : JsonDeserializer<Boolean> {
@Throws(JsonParseException::class) @Throws(JsonParseException::class)
override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): Boolean? = override fun deserialize(
json: JsonElement,
typeOfT: Type,
context: JsonDeserializationContext
): Boolean? =
try { try {
json.asInt == 1 json.asInt == 1
} catch (e: Exception) { } catch (e: Exception) {

View File

@ -2,8 +2,8 @@ package apps.amine.bou.readerforselfoss.api.selfoss
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
import java.util.concurrent.ConcurrentHashMap import apps.amine.bou.readerforselfoss.utils.Config
import apps.amine.bou.readerforselfoss.utils.getUnsafeHttpClient
import com.burgstaller.okhttp.AuthenticationCacheInterceptor import com.burgstaller.okhttp.AuthenticationCacheInterceptor
import com.burgstaller.okhttp.CachingAuthenticatorDecorator import com.burgstaller.okhttp.CachingAuthenticatorDecorator
import com.burgstaller.okhttp.DispatchingAuthenticator import com.burgstaller.okhttp.DispatchingAuthenticator
@ -13,19 +13,18 @@ import com.burgstaller.okhttp.digest.Credentials
import com.burgstaller.okhttp.digest.DigestAuthenticator import com.burgstaller.okhttp.digest.DigestAuthenticator
import com.google.gson.GsonBuilder import com.google.gson.GsonBuilder
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Call import retrofit2.Call
import retrofit2.Retrofit import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.ConcurrentHashMap
import apps.amine.bou.readerforselfoss.utils.Config class SelfossApi(
import apps.amine.bou.readerforselfoss.utils.getUnsafeHttpClient c: Context,
import okhttp3.logging.HttpLoggingInterceptor callingActivity: Activity,
isWithSelfSignedCert: Boolean,
shouldLog: Boolean
) {
// codebeat:disable[ARITY,TOO_MANY_FUNCTIONS]
class SelfossApi(c: Context, callingActivity: Activity, isWithSelfSignedCert: Boolean, shouldLog: Boolean) {
private lateinit var service: SelfossService private lateinit var service: SelfossService
private val config: Config = Config(c) private val config: Config = Config(c)
@ -54,7 +53,6 @@ class SelfossApi(c: Context, callingActivity: Activity, isWithSelfSignedCert: Bo
.addInterceptor(AuthenticationCacheInterceptor(authCache)) .addInterceptor(AuthenticationCacheInterceptor(authCache))
} }
init { init {
userName = config.userLogin userName = config.userLogin
password = config.userPassword password = config.userPassword
@ -73,10 +71,11 @@ class SelfossApi(c: Context, callingActivity: Activity, isWithSelfSignedCert: Bo
val logging = HttpLoggingInterceptor() val logging = HttpLoggingInterceptor()
logging.level = if (shouldLog) logging.level = if (shouldLog) {
HttpLoggingInterceptor.Level.BODY HttpLoggingInterceptor.Level.BODY
else } else {
HttpLoggingInterceptor.Level.NONE HttpLoggingInterceptor.Level.NONE
}
val httpClient = authenticator.getHttpClien(isWithSelfSignedCert) val httpClient = authenticator.getHttpClien(isWithSelfSignedCert)
@ -99,16 +98,41 @@ class SelfossApi(c: Context, callingActivity: Activity, isWithSelfSignedCert: Bo
fun login(): Call<SuccessResponse> = fun login(): Call<SuccessResponse> =
service.loginToSelfoss(config.userLogin, config.userPassword) service.loginToSelfoss(config.userLogin, config.userPassword)
fun readItems(tag: String?, sourceId: Long?, search: String?, itemsNumber: Int, offset: Int): Call<List<Item>> = fun readItems(
tag: String?,
sourceId: Long?,
search: String?,
itemsNumber: Int,
offset: Int
): Call<List<Item>> =
getItems("read", tag, sourceId, search, itemsNumber, offset) getItems("read", tag, sourceId, search, itemsNumber, offset)
fun newItems(tag: String?, sourceId: Long?, search: String?, itemsNumber: Int, offset: Int): Call<List<Item>> = fun newItems(
tag: String?,
sourceId: Long?,
search: String?,
itemsNumber: Int,
offset: Int
): Call<List<Item>> =
getItems("unread", tag, sourceId, search, itemsNumber, offset) getItems("unread", tag, sourceId, search, itemsNumber, offset)
fun starredItems(tag: String?, sourceId: Long?, search: String?, itemsNumber: Int, offset: Int): Call<List<Item>> = fun starredItems(
tag: String?,
sourceId: Long?,
search: String?,
itemsNumber: Int,
offset: Int
): Call<List<Item>> =
getItems("starred", tag, sourceId, search, itemsNumber, offset) getItems("starred", tag, sourceId, search, itemsNumber, offset)
private fun getItems(type: String, tag: String?, sourceId: Long?, search: String?, items: Int, offset: Int): Call<List<Item>> = private fun getItems(
type: String,
tag: String?,
sourceId: Long?,
search: String?,
items: Int,
offset: Int
): Call<List<Item>> =
service.getItems(type, tag, sourceId, search, userName, password, items, offset) service.getItems(type, tag, sourceId, search, userName, password, items, offset)
fun markItem(itemId: String): Call<SuccessResponse> = fun markItem(itemId: String): Call<SuccessResponse> =
@ -144,9 +168,12 @@ class SelfossApi(c: Context, callingActivity: Activity, isWithSelfSignedCert: Bo
fun spouts(): Call<Map<String, Spout>> = fun spouts(): Call<Map<String, Spout>> =
service.spouts(userName, password) service.spouts(userName, password)
fun createSource(title: String, url: String, spout: String, tags: String, filter: String): Call<SuccessResponse> = fun createSource(
title: String,
url: String,
spout: String,
tags: String,
filter: String
): Call<SuccessResponse> =
service.createSource(title, url, spout, tags, filter, userName, password) service.createSource(title, url, spout, tags, filter, userName, password)
} }
// codebeat:enable[ARITY,TOO_MANY_FUNCTIONS]

View File

@ -9,58 +9,69 @@ import apps.amine.bou.readerforselfoss.utils.Config
import apps.amine.bou.readerforselfoss.utils.isEmptyOrNullOrNullString import apps.amine.bou.readerforselfoss.utils.isEmptyOrNullOrNullString
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
private fun constructUrl(config: Config?, path: String, file: String): String { private fun constructUrl(config: Config?, path: String, file: String): String {
val baseUriBuilder = Uri.parse(config!!.baseUrl).buildUpon() val baseUriBuilder = Uri.parse(config!!.baseUrl).buildUpon()
baseUriBuilder.appendPath(path).appendPath(file) baseUriBuilder.appendPath(path).appendPath(file)
return if (file.isEmptyOrNullOrNullString()) "" return if (file.isEmptyOrNullOrNullString()) {
else baseUriBuilder.toString() ""
} else {
baseUriBuilder.toString()
}
} }
data class Tag(
data class Tag(@SerializedName("tag") val tag: String, @SerializedName("tag") val tag: String,
@SerializedName("color") val color: String, @SerializedName("color") val color: String,
@SerializedName("unread") val unread: Int) @SerializedName("unread") val unread: Int
)
class SuccessResponse(@SerializedName("success") val success: Boolean) { class SuccessResponse(@SerializedName("success") val success: Boolean) {
val isSuccess: Boolean val isSuccess: Boolean
get() = success get() = success
} }
class Stats(@SerializedName("total") val total: Int, class Stats(
@SerializedName("total") val total: Int,
@SerializedName("unread") val unread: Int, @SerializedName("unread") val unread: Int,
@SerializedName("starred") val starred: Int) @SerializedName("starred") val starred: Int
)
data class Spout(@SerializedName("name") val name: String, data class Spout(
@SerializedName("description") val description: String) @SerializedName("name") val name: String,
@SerializedName("description") val description: String
)
data class Sources(@SerializedName("id") val id: String, data class Sources(
@SerializedName("id") val id: String,
@SerializedName("title") val title: String, @SerializedName("title") val title: String,
@SerializedName("tags") val tags: String, @SerializedName("tags") val tags: String,
@SerializedName("spout") val spout: String, @SerializedName("spout") val spout: String,
@SerializedName("error") val error: String, @SerializedName("error") val error: String,
@SerializedName("icon") val icon: String) { @SerializedName("icon") val icon: String
) {
var config: Config? = null var config: Config? = null
fun getIcon(app: Context): String { fun getIcon(app: Context): String {
if (config == null) { if (config == null) {
config = Config(app) config = Config(app)
} }
return constructUrl(config,"favicons", icon) return constructUrl(config, "favicons", icon)
} }
} }
data class Item(@SerializedName("id") val id: String, data class Item(
@SerializedName("id") val id: String,
@SerializedName("datetime") val datetime: String, @SerializedName("datetime") val datetime: String,
@SerializedName("title") val title: String, @SerializedName("title") val title: String,
@SerializedName("content") val content: String,
@SerializedName("unread") val unread: Boolean, @SerializedName("unread") val unread: Boolean,
@SerializedName("starred") val starred: Boolean, @SerializedName("starred") val starred: Boolean,
@SerializedName("thumbnail") val thumbnail: String, @SerializedName("thumbnail") val thumbnail: String,
@SerializedName("icon") val icon: String, @SerializedName("icon") val icon: String,
@SerializedName("link") val link: String, @SerializedName("link") val link: String,
@SerializedName("sourcetitle") val sourcetitle: String) : Parcelable { @SerializedName("sourcetitle") val sourcetitle: String
) : Parcelable {
var config: Config? = null var config: Config? = null
@ -75,6 +86,7 @@ data class Item(@SerializedName("id") val id: String,
id = source.readString(), id = source.readString(),
datetime = source.readString(), datetime = source.readString(),
title = source.readString(), title = source.readString(),
content = source.readString(),
unread = 0.toByte() != source.readByte(), unread = 0.toByte() != source.readByte(),
starred = 0.toByte() != source.readByte(), starred = 0.toByte() != source.readByte(),
thumbnail = source.readString(), thumbnail = source.readString(),
@ -89,6 +101,7 @@ data class Item(@SerializedName("id") val id: String,
dest.writeString(id) dest.writeString(id)
dest.writeString(datetime) dest.writeString(datetime)
dest.writeString(title) dest.writeString(title)
dest.writeString(content)
dest.writeByte((if (unread) 1 else 0)) dest.writeByte((if (unread) 1 else 0))
dest.writeByte((if (starred) 1 else 0)) dest.writeByte((if (starred) 1 else 0))
dest.writeString(thumbnail) dest.writeString(thumbnail)
@ -136,5 +149,4 @@ data class Item(@SerializedName("id") val id: String,
return stringUrl return stringUrl
} }
} }

View File

@ -5,93 +5,114 @@ import retrofit2.http.DELETE
import retrofit2.http.Field import retrofit2.http.Field
import retrofit2.http.FormUrlEncoded import retrofit2.http.FormUrlEncoded
import retrofit2.http.GET import retrofit2.http.GET
import retrofit2.http.Headers
import retrofit2.http.POST import retrofit2.http.POST
import retrofit2.http.Path import retrofit2.http.Path
import retrofit2.http.Query import retrofit2.http.Query
// codebeat:disable[ARITY]
internal interface SelfossService { internal interface SelfossService {
@GET("login") @GET("login")
fun loginToSelfoss(@Query("username") username: String, @Query("password") password: String): Call<SuccessResponse> fun loginToSelfoss(@Query("username") username: String, @Query("password") password: String): Call<SuccessResponse>
@GET("items") @GET("items")
fun getItems(@Query("type") type: String, fun getItems(
@Query("type") type: String,
@Query("tag") tag: String?, @Query("tag") tag: String?,
@Query("source") source: Long?, @Query("source") source: Long?,
@Query("search") search: String?, @Query("search") search: String?,
@Query("username") username: String, @Query("username") username: String,
@Query("password") password: String, @Query("password") password: String,
@Query("items") items: Int, @Query("items") items: Int,
@Query("offset") offset: Int): Call<List<Item>> @Query("offset") offset: Int
): Call<List<Item>>
@Headers("Content-Type: application/x-www-form-urlencoded")
@POST("mark/{id}") @POST("mark/{id}")
fun markAsRead(@Path("id") id: String, fun markAsRead(
@Path("id") id: String,
@Query("username") username: String, @Query("username") username: String,
@Query("password") password: String): Call<SuccessResponse> @Query("password") password: String
): Call<SuccessResponse>
@Headers("Content-Type: application/x-www-form-urlencoded")
@POST("unmark/{id}") @POST("unmark/{id}")
fun unmarkAsRead(@Path("id") id: String, fun unmarkAsRead(
@Path("id") id: String,
@Query("username") username: String, @Query("username") username: String,
@Query("password") password: String): Call<SuccessResponse> @Query("password") password: String
): Call<SuccessResponse>
@FormUrlEncoded @FormUrlEncoded
@POST("mark") @POST("mark")
fun markAllAsRead(@Field("ids[]") ids: List<String>, fun markAllAsRead(
@Field("ids[]") ids: List<String>,
@Query("username") username: String, @Query("username") username: String,
@Query("password") password: String): Call<SuccessResponse> @Query("password") password: String
): Call<SuccessResponse>
@Headers("Content-Type: application/x-www-form-urlencoded")
@POST("starr/{id}") @POST("starr/{id}")
fun starr(@Path("id") id: String, fun starr(
@Path("id") id: String,
@Query("username") username: String, @Query("username") username: String,
@Query("password") password: String): Call<SuccessResponse> @Query("password") password: String
): Call<SuccessResponse>
@Headers("Content-Type: application/x-www-form-urlencoded")
@POST("unstarr/{id}") @POST("unstarr/{id}")
fun unstarr(@Path("id") id: String, fun unstarr(
@Path("id") id: String,
@Query("username") username: String, @Query("username") username: String,
@Query("password") password: String): Call<SuccessResponse> @Query("password") password: String
): Call<SuccessResponse>
@GET("stats") @GET("stats")
fun stats(@Query("username") username: String, fun stats(
@Query("password") password: String): Call<Stats> @Query("username") username: String,
@Query("password") password: String
): Call<Stats>
@GET("tags") @GET("tags")
fun tags(@Query("username") username: String, fun tags(
@Query("password") password: String): Call<List<Tag>> @Query("username") username: String,
@Query("password") password: String
): Call<List<Tag>>
@GET("update") @GET("update")
fun update(@Query("username") username: String, fun update(
@Query("password") password: String): Call<String> @Query("username") username: String,
@Query("password") password: String
): Call<String>
@GET("sources/spouts") @GET("sources/spouts")
fun spouts(@Query("username") username: String, fun spouts(
@Query("password") password: String): Call<Map<String, Spout>> @Query("username") username: String,
@Query("password") password: String
): Call<Map<String, Spout>>
@GET("sources/list") @GET("sources/list")
fun sources(@Query("username") username: String, fun sources(
@Query("password") password: String): Call<List<Sources>> @Query("username") username: String,
@Query("password") password: String
): Call<List<Sources>>
@DELETE("source/{id}") @DELETE("source/{id}")
fun deleteSource(@Path("id") id: String, fun deleteSource(
@Path("id") id: String,
@Query("username") username: String, @Query("username") username: String,
@Query("password") password: String): Call<SuccessResponse> @Query("password") password: String
): Call<SuccessResponse>
@FormUrlEncoded @FormUrlEncoded
@POST("source") @POST("source")
fun createSource(@Field("title") title: String, fun createSource(
@Field("title") title: String,
@Field("url") url: String, @Field("url") url: String,
@Field("spout") spout: String, @Field("spout") spout: String,
@Field("tags") tags: String, @Field("tags") tags: String,
@Field("filter") filter: String, @Field("filter") filter: String,
@Query("username") username: String, @Query("username") username: String,
@Query("password") password: String): Call<SuccessResponse> @Query("password") password: String
): Call<SuccessResponse>
} }
// codebeat:disable[ARITY]

View File

@ -24,7 +24,7 @@ import com.ftinc.scoop.Scoop;
* A {@link PreferenceActivity} which implements and proxies the necessary calls * A {@link PreferenceActivity} which implements and proxies the necessary calls
* to be used with AppCompat. * to be used with AppCompat.
*/ */
public abstract class AppCompatPreferenceActivity extends PreferenceActivity { public abstract class AppCompatPreferenceActivity extends PreferenceActivity { //NOSONAR
private AppCompatDelegate mDelegate; private AppCompatDelegate mDelegate;
@ -116,6 +116,7 @@ public abstract class AppCompatPreferenceActivity extends PreferenceActivity {
getDelegate().onDestroy(); getDelegate().onDestroy();
} }
@Override
public void invalidateOptionsMenu() { public void invalidateOptionsMenu() {
getDelegate().invalidateOptionsMenu(); getDelegate().invalidateOptionsMenu();
} }

View File

@ -1,6 +1,8 @@
package apps.amine.bou.readerforselfoss.settings; package apps.amine.bou.readerforselfoss.settings;
import java.util.List;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.content.ClipData; import android.content.ClipData;
import android.content.ClipboardManager; import android.content.ClipboardManager;
@ -16,17 +18,15 @@ import android.preference.Preference;
import android.preference.Preference.OnPreferenceChangeListener; import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.Preference.OnPreferenceClickListener; import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceActivity; import android.preference.PreferenceActivity;
import android.preference.SwitchPreference;
import android.support.v7.app.ActionBar;
import android.preference.PreferenceFragment; import android.preference.PreferenceFragment;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.preference.SwitchPreference;
import android.support.v7.app.ActionBar;
import android.text.InputFilter; import android.text.InputFilter;
import android.text.Spanned; import android.text.Spanned;
import android.view.MenuItem; import android.view.MenuItem;
import android.widget.Toast; import android.widget.Toast;
import java.util.List;
import apps.amine.bou.readerforselfoss.BuildConfig; import apps.amine.bou.readerforselfoss.BuildConfig;
import apps.amine.bou.readerforselfoss.R; import apps.amine.bou.readerforselfoss.R;
import apps.amine.bou.readerforselfoss.utils.Config; import apps.amine.bou.readerforselfoss.utils.Config;
@ -44,7 +44,7 @@ import com.ftinc.scoop.ui.ScoopSettingsActivity;
* href="http://developer.android.com/guide/topics/ui/settings.html">Settings * href="http://developer.android.com/guide/topics/ui/settings.html">Settings
* API Guide</a> for more information on developing a Settings UI. * API Guide</a> for more information on developing a Settings UI.
*/ */
public class SettingsActivity extends AppCompatPreferenceActivity { public class SettingsActivity extends AppCompatPreferenceActivity { //NOSONAR
/** /**
* A preference value change listener that updates the preference's summary * A preference value change listener that updates the preference's summary
* to reflect its new value. * to reflect its new value.
@ -126,6 +126,7 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
* This method stops fragment injection in malicious applications. * This method stops fragment injection in malicious applications.
* Make sure to deny any unknown fragments here. * Make sure to deny any unknown fragments here.
*/ */
@Override
protected boolean isValidFragment(String fragmentName) { protected boolean isValidFragment(String fragmentName) {
return PreferenceFragment.class.getName().equals(fragmentName) return PreferenceFragment.class.getName().equals(fragmentName)
|| GeneralPreferenceFragment.class.getName().equals(fragmentName) || GeneralPreferenceFragment.class.getName().equals(fragmentName)
@ -166,7 +167,9 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
int input = Integer.parseInt(dest.toString() + source.toString()); int input = Integer.parseInt(dest.toString() + source.toString());
if (input <= 200 && input >0) if (input <= 200 && input >0)
return null; return null;
} catch (NumberFormatException nfe) { } } catch (NumberFormatException nfe) {
Toast.makeText(getActivity(), R.string.items_number_should_be_number, Toast.LENGTH_LONG).show();
}
return ""; return "";
} }
} }

View File

@ -6,7 +6,6 @@ import android.support.annotation.ColorInt
import android.util.TypedValue import android.util.TypedValue
import apps.amine.bou.readerforselfoss.R import apps.amine.bou.readerforselfoss.R
class AppColors(a: Activity) { class AppColors(a: Activity) {
@ColorInt val accent: Int @ColorInt val accent: Int
@ColorInt val dark: Int @ColorInt val dark: Int
@ -20,7 +19,7 @@ class AppColors(a: Activity) {
val method = wrapper!!.getMethod("getThemeResId") val method = wrapper!!.getMethod("getThemeResId")
method.isAccessible = true method.isAccessible = true
isDarkTheme = when(method.invoke(a.baseContext)) { isDarkTheme = when (method.invoke(a.baseContext)) {
R.style.NoBarTealOrangeDark, R.style.NoBarTealOrangeDark,
R.style.NoBarDark, R.style.NoBarDark,
R.style.NoBarBlueAmberDark, R.style.NoBarBlueAmberDark,

View File

@ -0,0 +1,7 @@
package apps.amine.bou.readerforselfoss.utils
import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse
import retrofit2.Response
fun Response<SuccessResponse>.succeeded(): Boolean =
this.code() === 200 && this.body() != null && this.body()!!.isSuccess

View File

@ -5,41 +5,17 @@ import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import android.net.Uri import android.net.Uri
import android.support.v7.app.AlertDialog import android.support.v7.app.AlertDialog
import android.text.TextUtils
import com.google.firebase.remoteconfig.FirebaseRemoteConfig
import apps.amine.bou.readerforselfoss.BuildConfig
import apps.amine.bou.readerforselfoss.R import apps.amine.bou.readerforselfoss.R
import apps.amine.bou.readerforselfoss.api.selfoss.Item import com.google.firebase.remoteconfig.FirebaseRemoteConfig
fun Context.checkAndDisplayStoreApk() = {
fun isStoreVersion(): Boolean =
try {
val installer = this.packageManager
.getInstallerPackageName(this.packageName)
!TextUtils.isEmpty(installer)
} catch (e: Throwable) {
false
}
if (!isStoreVersion() && !BuildConfig.GITHUB_VERSION) {
val alertDialog = AlertDialog.Builder(this).create()
alertDialog.setTitle(getString(R.string.warning_version))
alertDialog.setMessage(getString(R.string.text_version))
alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK",
{ dialog, _ -> dialog.dismiss() })
alertDialog.show()
} else Unit
}
fun String?.isEmptyOrNullOrNullString(): Boolean = fun String?.isEmptyOrNullOrNullString(): Boolean =
this == null || this == "null" || this.isEmpty() this == null || this == "null" || this.isEmpty()
fun Context.checkApkVersion(settings: SharedPreferences, fun Context.checkApkVersion(
settings: SharedPreferences,
editor: SharedPreferences.Editor, editor: SharedPreferences.Editor,
mFirebaseRemoteConfig: FirebaseRemoteConfig) = { mFirebaseRemoteConfig: FirebaseRemoteConfig
) = {
fun isThereAnUpdate() { fun isThereAnUpdate() {
val APK_LINK = "github_apk" val APK_LINK = "github_apk"
@ -49,21 +25,25 @@ fun Context.checkApkVersion(settings: SharedPreferences,
val alertDialog = AlertDialog.Builder(this).create() val alertDialog = AlertDialog.Builder(this).create()
alertDialog.setTitle(getString(R.string.new_apk_available_title)) alertDialog.setTitle(getString(R.string.new_apk_available_title))
alertDialog.setMessage(getString(R.string.new_apk_available_message)) alertDialog.setMessage(getString(R.string.new_apk_available_message))
alertDialog.setButton(AlertDialog.BUTTON_POSITIVE, getString(R.string.new_apk_available_get)) { _, _ -> alertDialog.setButton(
AlertDialog.BUTTON_POSITIVE,
getString(R.string.new_apk_available_get)
) { _, _ ->
editor.putString(APK_LINK, apkLink) editor.putString(APK_LINK, apkLink)
editor.apply() editor.apply()
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(apkLink)) val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(apkLink))
startActivity(browserIntent) startActivity(browserIntent)
} }
alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, getString(R.string.new_apk_available_no), alertDialog.setButton(
AlertDialog.BUTTON_NEUTRAL, getString(R.string.new_apk_available_no),
{ dialog, _ -> { dialog, _ ->
editor.putString(APK_LINK, apkLink) editor.putString(APK_LINK, apkLink)
editor.apply() editor.apply()
dialog.dismiss() dialog.dismiss()
}) }
)
alertDialog.show() alertDialog.show()
} }
} }
mFirebaseRemoteConfig.fetch(43200) mFirebaseRemoteConfig.fetch(43200)
@ -87,11 +67,12 @@ fun String.longHash(): Long {
return h return h
} }
fun String.toStringUriWithHttp() = fun String.toStringUriWithHttp(): String =
if (!this.startsWith("https://") && !this.startsWith("http://")) if (!this.startsWith("https://") && !this.startsWith("http://")) {
"http://" + this "http://" + this
else } else {
this this
}
fun Context.shareLink(itemUrl: String) { fun Context.shareLink(itemUrl: String) {
val sendIntent = Intent() val sendIntent = Intent()
@ -99,12 +80,10 @@ fun Context.shareLink(itemUrl: String) {
sendIntent.action = Intent.ACTION_SEND sendIntent.action = Intent.ACTION_SEND
sendIntent.putExtra(Intent.EXTRA_TEXT, itemUrl.toStringUriWithHttp()) sendIntent.putExtra(Intent.EXTRA_TEXT, itemUrl.toStringUriWithHttp())
sendIntent.type = "text/plain" sendIntent.type = "text/plain"
startActivity(Intent.createChooser(sendIntent, getString(R.string.share)).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)) startActivity(
} Intent.createChooser(
sendIntent,
fun Context.openInBrowser(i: Item) { getString(R.string.share)
val intent = Intent(Intent.ACTION_VIEW) ).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK )
intent.data = Uri.parse(i.getLinkDecoded().toStringUriWithHttp())
startActivity(intent)
} }

View File

@ -6,7 +6,6 @@ import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import apps.amine.bou.readerforselfoss.LoginActivity import apps.amine.bou.readerforselfoss.LoginActivity
class Config(c: Context) { class Config(c: Context) {
val settings: SharedPreferences = c.getSharedPreferences(settingsName, Context.MODE_PRIVATE) val settings: SharedPreferences = c.getSharedPreferences(settingsName, Context.MODE_PRIVATE)
@ -26,21 +25,23 @@ class Config(c: Context) {
val httpUserPassword: String val httpUserPassword: String
get() = settings.getString("httpPassword", "") get() = settings.getString("httpPassword", "")
companion object { companion object {
val settingsName = "paramsselfoss" val settingsName = "paramsselfoss"
fun logoutAndRedirect(c: Context, fun logoutAndRedirect(
c: Context,
callingActivity: Activity, callingActivity: Activity,
editor: SharedPreferences.Editor, editor: SharedPreferences.Editor,
baseUrlFail: Boolean = false): Boolean { baseUrlFail: Boolean = false
): Boolean {
editor.remove("url") editor.remove("url")
editor.remove("login") editor.remove("login")
editor.remove("password") editor.remove("password")
editor.apply() editor.apply()
val intent = Intent(c, LoginActivity::class.java) val intent = Intent(c, LoginActivity::class.java)
if (baseUrlFail) if (baseUrlFail) {
intent.putExtra("baseUrlFail", baseUrlFail) intent.putExtra("baseUrlFail", baseUrlFail)
}
c.startActivity(intent) c.startActivity(intent)
callingActivity.finish() callingActivity.finish()
return true return true

View File

@ -15,13 +15,18 @@ fun getUnsafeHttpClient() =
arrayOf() arrayOf()
@Throws(CertificateException::class) @Throws(CertificateException::class)
override fun checkClientTrusted(chain: Array<java.security.cert.X509Certificate>, authType: String) { override fun checkClientTrusted(
chain: Array<java.security.cert.X509Certificate>,
authType: String
) {
} }
@Throws(CertificateException::class) @Throws(CertificateException::class)
override fun checkServerTrusted(chain: Array<java.security.cert.X509Certificate>, authType: String) { override fun checkServerTrusted(
chain: Array<java.security.cert.X509Certificate>,
authType: String
) {
} }
}) })
// Install the all-trusting trust manager // Install the all-trusting trust manager
@ -33,7 +38,6 @@ fun getUnsafeHttpClient() =
OkHttpClient.Builder() OkHttpClient.Builder()
.sslSocketFactory(sslSocketFactory, trustAllCerts[0] as X509TrustManager) .sslSocketFactory(sslSocketFactory, trustAllCerts[0] as X509TrustManager)
.hostnameVerifier { _, _ -> true } .hostnameVerifier { _, _ -> true }
} catch (e: Exception) { } catch (e: Exception) {
throw RuntimeException(e) throw RuntimeException(e)
} }

View File

@ -6,7 +6,6 @@ import java.text.ParseException
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
fun String.toTextDrawableString(): String { fun String.toTextDrawableString(): String {
val textDrawable = StringBuilder() val textDrawable = StringBuilder()
for (s in this.split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()) { for (s in this.split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()) {

View File

@ -11,17 +11,20 @@ import android.util.Patterns
import android.widget.Toast import android.widget.Toast
import apps.amine.bou.readerforselfoss.R import apps.amine.bou.readerforselfoss.R
import apps.amine.bou.readerforselfoss.ReaderActivity import apps.amine.bou.readerforselfoss.ReaderActivity
import apps.amine.bou.readerforselfoss.api.selfoss.Item
import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper
import okhttp3.HttpUrl import okhttp3.HttpUrl
import xyz.klinker.android.drag_dismiss.DragDismissIntentBuilder
fun Context.buildCustomTabsIntent(): CustomTabsIntent { fun Context.buildCustomTabsIntent(): CustomTabsIntent {
val actionIntent = Intent(Intent.ACTION_SEND) val actionIntent = Intent(Intent.ACTION_SEND)
actionIntent.type = "text/plain" actionIntent.type = "text/plain"
val createPendingShareIntent: PendingIntent = PendingIntent.getActivity(this, 0, actionIntent, 0) val createPendingShareIntent: PendingIntent = PendingIntent.getActivity(
this,
0,
actionIntent,
0
)
val intentBuilder = CustomTabsIntent.Builder() val intentBuilder = CustomTabsIntent.Builder()
@ -31,50 +34,62 @@ fun Context.buildCustomTabsIntent(): CustomTabsIntent {
intentBuilder.setShowTitle(true) intentBuilder.setShowTitle(true)
intentBuilder.setStartAnimations(this, intentBuilder.setStartAnimations(
this,
R.anim.slide_in_right, R.anim.slide_in_right,
R.anim.slide_out_left) R.anim.slide_out_left
intentBuilder.setExitAnimations(this, )
intentBuilder.setExitAnimations(
this,
android.R.anim.slide_in_left, android.R.anim.slide_in_left,
android.R.anim.slide_out_right) android.R.anim.slide_out_right
)
val closeicon = BitmapFactory.decodeResource(resources, R.drawable.ic_close_white_24dp) val closeicon = BitmapFactory.decodeResource(resources, R.drawable.ic_close_white_24dp)
intentBuilder.setCloseButtonIcon(closeicon) intentBuilder.setCloseButtonIcon(closeicon)
val shareLabel = this.getString(R.string.label_share) val shareLabel = this.getString(R.string.label_share)
val icon = BitmapFactory.decodeResource(resources, val icon = BitmapFactory.decodeResource(
R.drawable.ic_share_white_24dp) resources,
R.drawable.ic_share_white_24dp
)
intentBuilder.setActionButton(icon, shareLabel, createPendingShareIntent) intentBuilder.setActionButton(icon, shareLabel, createPendingShareIntent)
return intentBuilder.build() return intentBuilder.build()
} }
fun Context.openItemUrl(linkDecoded: String, fun Context.openItemUrlInternally(
linkDecoded: String,
content: String,
image: String,
title: String,
source: String,
customTabsIntent: CustomTabsIntent, customTabsIntent: CustomTabsIntent,
internalBrowser: Boolean,
articleViewer: Boolean, articleViewer: Boolean,
app: Activity) { app: Activity
) {
if (!linkDecoded.isUrlValid()) {
Toast.makeText(this, this.getString(R.string.cant_open_invalid_url), Toast.LENGTH_LONG).show()
} else {
if (!internalBrowser) {
openInBrowser(linkDecoded, app)
} else {
if (articleViewer) { if (articleViewer) {
val intent = Intent(this, ReaderActivity::class.java) val intent = Intent(this, ReaderActivity::class.java)
DragDismissIntentBuilder(this) /*DragDismissIntentBuilder(this)
.setFullscreenOnTablets(true) // defaults to false, tablets will have padding on each side .setFullscreenOnTablets(true) // defaults to false, tablets will have padding on each side
.setDragElasticity(DragDismissIntentBuilder.DragElasticity.NORMAL) // Larger elasticities will make it easier to dismiss. .setDragElasticity(DragDismissIntentBuilder.DragElasticity.NORMAL) // Larger elasticities will make it easier to dismiss.
.setDrawUnderStatusBar(true) .setDrawUnderStatusBar(true)
.build(intent) .build(intent)*/
intent.putExtra("url", linkDecoded) intent.putExtra("url", linkDecoded)
intent.putExtra("content", content)
intent.putExtra("title", title)
intent.putExtra("image", image)
intent.putExtra("source", source)
app.startActivity(intent) app.startActivity(intent)
} else { } else {
try { try {
CustomTabActivityHelper.openCustomTab(app, customTabsIntent, Uri.parse(linkDecoded) CustomTabActivityHelper.openCustomTab(
app,
customTabsIntent,
Uri.parse(linkDecoded)
) { _, uri -> ) { _, uri ->
val intent = Intent(Intent.ACTION_VIEW, uri) val intent = Intent(Intent.ACTION_VIEW, uri)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
@ -84,6 +99,40 @@ fun Context.openItemUrl(linkDecoded: String,
openInBrowser(linkDecoded, app) openInBrowser(linkDecoded, app)
} }
} }
}
fun Context.openItemUrl(
linkDecoded: String,
content: String,
image: String,
title: String,
source: String,
customTabsIntent: CustomTabsIntent,
internalBrowser: Boolean,
articleViewer: Boolean,
app: Activity
) {
if (!linkDecoded.isUrlValid()) {
Toast.makeText(
this,
this.getString(R.string.cant_open_invalid_url),
Toast.LENGTH_LONG
).show()
} else {
if (!internalBrowser) {
openInBrowser(linkDecoded, app)
} else {
this.openItemUrlInternally(
linkDecoded,
content,
image,
title,
source,
customTabsIntent,
articleViewer,
app
)
} }
} }
} }
@ -107,3 +156,10 @@ fun String.isBaseUrlValid(): Boolean {
return Patterns.WEB_URL.matcher(this).matches() && existsAndEndsWithSlash return Patterns.WEB_URL.matcher(this).matches() && existsAndEndsWithSlash
} }
fun Context.openInBrowserAsNewTask(i: Item) {
val intent = Intent(Intent.ACTION_VIEW)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
intent.data = Uri.parse(i.getLinkDecoded().toStringUriWithHttp())
startActivity(intent)
}

View File

@ -0,0 +1,53 @@
package apps.amine.bou.readerforselfoss.utils
import android.content.Context
import android.support.design.widget.CoordinatorLayout
import android.support.design.widget.FloatingActionButton
import android.util.AttributeSet
import android.view.View
class ScrollAwareFABBehavior(
context: Context,
attrs: AttributeSet
) : CoordinatorLayout.Behavior<FloatingActionButton>() {
override fun onStartNestedScroll(
coordinatorLayout: CoordinatorLayout,
child: FloatingActionButton,
directTargetChild: View,
target: View,
nestedScrollAxes: Int
): Boolean {
return true
}
override fun onNestedScroll(
coordinatorLayout: CoordinatorLayout,
child: FloatingActionButton,
target: View,
dxConsumed: Int,
dyConsumed: Int,
dxUnconsumed: Int,
dyUnconsumed: Int
) {
super.onNestedScroll(
coordinatorLayout,
child,
target,
dxConsumed,
dyConsumed,
dxUnconsumed,
dyUnconsumed
)
if (dyConsumed > 0 && child.visibility == View.VISIBLE) {
child.hide(object : FloatingActionButton.OnVisibilityChangedListener() {
override fun onHidden(fab: FloatingActionButton?) {
super.onHidden(fab)
fab!!.visibility = View.INVISIBLE
}
})
} else if (dyConsumed < 0 && child.visibility != View.VISIBLE) {
child.show()
}
}
}

View File

@ -2,7 +2,6 @@ package apps.amine.bou.readerforselfoss.utils.bottombar
import com.ashokvarma.bottomnavigation.TextBadgeItem import com.ashokvarma.bottomnavigation.TextBadgeItem
fun TextBadgeItem.removeBadge(): TextBadgeItem { fun TextBadgeItem.removeBadge(): TextBadgeItem {
this.setText("") this.setText("")
this.hide() this.hide()
@ -10,7 +9,4 @@ fun TextBadgeItem.removeBadge(): TextBadgeItem {
} }
fun TextBadgeItem.maybeShow(): TextBadgeItem = fun TextBadgeItem.maybeShow(): TextBadgeItem =
if (this.isHidden) if (this.isHidden) this.show() else this
this.show()
else
this

View File

@ -1,5 +1,8 @@
package apps.amine.bou.readerforselfoss.utils.customtabs; package apps.amine.bou.readerforselfoss.utils.customtabs;
import java.util.List;
import android.app.Activity; import android.app.Activity;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
@ -8,8 +11,6 @@ import android.support.customtabs.CustomTabsIntent;
import android.support.customtabs.CustomTabsServiceConnection; import android.support.customtabs.CustomTabsServiceConnection;
import android.support.customtabs.CustomTabsSession; import android.support.customtabs.CustomTabsSession;
import java.util.List;
/** /**
* This is a helper class to manage the connection to the Custom Tabs Service. * This is a helper class to manage the connection to the Custom Tabs Service.
*/ */

View File

@ -1,5 +1,9 @@
package apps.amine.bou.readerforselfoss.utils.customtabs; package apps.amine.bou.readerforselfoss.utils.customtabs;
import java.util.ArrayList;
import java.util.List;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
@ -9,10 +13,8 @@ import android.net.Uri;
import android.support.customtabs.CustomTabsService; import android.support.customtabs.CustomTabsService;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import apps.amine.bou.readerforselfoss.utils.customtabs.helpers.KeepAliveService;
import java.util.ArrayList; import apps.amine.bou.readerforselfoss.utils.customtabs.helpers.KeepAliveService;
import java.util.List;
@SuppressWarnings("ALL") @SuppressWarnings("ALL")
class CustomTabsHelper { class CustomTabsHelper {
@ -101,7 +103,7 @@ class CustomTabsHelper {
List<ResolveInfo> handlers = pm.queryIntentActivities( List<ResolveInfo> handlers = pm.queryIntentActivities(
intent, intent,
PackageManager.GET_RESOLVED_FILTER); PackageManager.GET_RESOLVED_FILTER);
if (handlers == null || handlers.size() == 0) { if (handlers == null || handlers.isEmpty()) {
return false; return false;
} }
for (ResolveInfo resolveInfo : handlers) { for (ResolveInfo resolveInfo : handlers) {

View File

@ -1,11 +1,12 @@
package apps.amine.bou.readerforselfoss.utils.customtabs; package apps.amine.bou.readerforselfoss.utils.customtabs;
import java.lang.ref.WeakReference;
import android.content.ComponentName; import android.content.ComponentName;
import android.support.customtabs.CustomTabsClient; import android.support.customtabs.CustomTabsClient;
import android.support.customtabs.CustomTabsServiceConnection; import android.support.customtabs.CustomTabsServiceConnection;
import java.lang.ref.WeakReference;
/** /**
* Implementation for the CustomTabsServiceConnection that avoids leaking the * Implementation for the CustomTabsServiceConnection that avoids leaking the
* ServiceConnectionCallback * ServiceConnectionCallback

View File

@ -8,8 +8,6 @@ import android.widget.TextView
import apps.amine.bou.readerforselfoss.R import apps.amine.bou.readerforselfoss.R
open class CustomBaseViewHolder(var view: View) : RecyclerView.ViewHolder(view) { open class CustomBaseViewHolder(var view: View) : RecyclerView.ViewHolder(view) {
var icon: ImageView = view.findViewById(R.id.material_drawer_icon) var icon: ImageView = view.findViewById(R.id.material_drawer_icon)
var name: TextView = view.findViewById(R.id.material_drawer_name) var name: TextView = view.findViewById(R.id.material_drawer_name)

View File

@ -15,8 +15,6 @@ import com.mikepenz.materialdrawer.util.DrawerImageLoader
import com.mikepenz.materialdrawer.util.DrawerUIUtils import com.mikepenz.materialdrawer.util.DrawerUIUtils
import com.mikepenz.materialize.util.UIUtils import com.mikepenz.materialize.util.UIUtils
abstract class CustomUrlBasePrimaryDrawerItem<T, VH : RecyclerView.ViewHolder> : BaseDrawerItem<T, VH>() { abstract class CustomUrlBasePrimaryDrawerItem<T, VH : RecyclerView.ViewHolder> : BaseDrawerItem<T, VH>() {
fun withIcon(url: String): T { fun withIcon(url: String): T {
this.icon = ImageHolder(url) this.icon = ImageHolder(url)
@ -77,7 +75,10 @@ abstract class CustomUrlBasePrimaryDrawerItem<T, VH : RecyclerView.ViewHolder> :
val selectedIconColor = getSelectedIconColor(ctx) val selectedIconColor = getSelectedIconColor(ctx)
//set the background for the item //set the background for the item
UIUtils.setBackground(viewHolder.view, UIUtils.getSelectableBackground(ctx, selectedColor, true)) UIUtils.setBackground(
viewHolder.view,
UIUtils.getSelectableBackground(ctx, selectedColor, true)
)
//set the text for the name //set the text for the name
StringHolder.applyTo(this.getName(), viewHolder.name) StringHolder.applyTo(this.getName(), viewHolder.name)
//set the text for the description or hide //set the text for the description or hide
@ -86,8 +87,11 @@ abstract class CustomUrlBasePrimaryDrawerItem<T, VH : RecyclerView.ViewHolder> :
//set the colors for textViews //set the colors for textViews
viewHolder.name.setTextColor(getTextColorStateList(color, selectedTextColor)) viewHolder.name.setTextColor(getTextColorStateList(color, selectedTextColor))
//set the description text color //set the description text color
ColorHolder.applyToOr(descriptionTextColor, ColorHolder.applyToOr(
viewHolder.description, getTextColorStateList(color, selectedTextColor)) descriptionTextColor,
viewHolder.description,
getTextColorStateList(color, selectedTextColor)
)
//define the typeface for our textViews //define the typeface for our textViews
if (getTypeface() != null) { if (getTypeface() != null) {

View File

@ -5,15 +5,11 @@ import android.support.annotation.LayoutRes
import android.support.annotation.StringRes import android.support.annotation.StringRes
import android.view.View import android.view.View
import android.widget.TextView import android.widget.TextView
import apps.amine.bou.readerforselfoss.R
import com.mikepenz.materialdrawer.holder.BadgeStyle import com.mikepenz.materialdrawer.holder.BadgeStyle
import com.mikepenz.materialdrawer.holder.StringHolder import com.mikepenz.materialdrawer.holder.StringHolder
import com.mikepenz.materialdrawer.model.interfaces.ColorfulBadgeable import com.mikepenz.materialdrawer.model.interfaces.ColorfulBadgeable
import apps.amine.bou.readerforselfoss.R
class CustomUrlPrimaryDrawerItem : CustomUrlBasePrimaryDrawerItem<CustomUrlPrimaryDrawerItem, CustomUrlPrimaryDrawerItem.ViewHolder>(), ColorfulBadgeable<CustomUrlPrimaryDrawerItem> { class CustomUrlPrimaryDrawerItem : CustomUrlBasePrimaryDrawerItem<CustomUrlPrimaryDrawerItem, CustomUrlPrimaryDrawerItem.ViewHolder>(), ColorfulBadgeable<CustomUrlPrimaryDrawerItem> {
protected var mBadge: StringHolder = StringHolder("") protected var mBadge: StringHolder = StringHolder("")
protected var mBadgeStyle = BadgeStyle() protected var mBadgeStyle = BadgeStyle()
@ -67,7 +63,10 @@ class CustomUrlPrimaryDrawerItem : CustomUrlBasePrimaryDrawerItem<CustomUrlPrima
val badgeVisible = StringHolder.applyToOrHide(mBadge, viewHolder.badge) val badgeVisible = StringHolder.applyToOrHide(mBadge, viewHolder.badge)
//style the badge if it is visible //style the badge if it is visible
if (badgeVisible) { if (badgeVisible) {
mBadgeStyle.style(viewHolder.badge, getTextColorStateList(getColor(ctx), getSelectedTextColor(ctx))) mBadgeStyle.style(
viewHolder.badge,
getTextColorStateList(getColor(ctx), getSelectedTextColor(ctx))
)
viewHolder.badgeContainer.visibility = View.VISIBLE viewHolder.badgeContainer.visibility = View.VISIBLE
} else { } else {
viewHolder.badgeContainer.visibility = View.GONE viewHolder.badgeContainer.visibility = View.GONE
@ -89,6 +88,5 @@ class CustomUrlPrimaryDrawerItem : CustomUrlBasePrimaryDrawerItem<CustomUrlPrima
class ViewHolder(view: View) : CustomBaseViewHolder(view) { class ViewHolder(view: View) : CustomBaseViewHolder(view) {
val badgeContainer: View = view.findViewById(R.id.material_drawer_badge_container) val badgeContainer: View = view.findViewById(R.id.material_drawer_badge_container)
val badge: TextView = view.findViewById(R.id.material_drawer_badge) val badge: TextView = view.findViewById(R.id.material_drawer_badge)
} }
} }

View File

@ -8,21 +8,31 @@ import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.request.target.BitmapImageViewTarget import com.bumptech.glide.request.target.BitmapImageViewTarget
fun Context.bitmapCenterCrop(url: String, iv: ImageView) = fun Context.bitmapCenterCrop(url: String, iv: ImageView) =
Glide.with(this).asBitmap().load(url).apply(RequestOptions.centerCropTransform()).into(iv) Glide.with(this)
.asBitmap()
.load(url)
.apply(RequestOptions.centerCropTransform())
.into(iv)
fun Context.bitmapFitCenter(url: String, iv: ImageView) = fun Context.bitmapFitCenter(url: String, iv: ImageView) =
Glide.with(this).asBitmap().load(url).apply(RequestOptions.fitCenterTransform()).into(iv) Glide.with(this)
.asBitmap()
.load(url)
.apply(RequestOptions.fitCenterTransform())
.into(iv)
fun Context.circularBitmapDrawable(url: String, iv: ImageView) = fun Context.circularBitmapDrawable(url: String, iv: ImageView) =
Glide.with(this) Glide.with(this)
.asBitmap() .asBitmap()
.load(url) .load(url)
.apply(RequestOptions.centerCropTransform()). .apply(RequestOptions.centerCropTransform())
into(object : BitmapImageViewTarget(iv) { .into(object : BitmapImageViewTarget(iv) {
override fun setResource(resource: Bitmap?) { override fun setResource(resource: Bitmap?) {
val circularBitmapDrawable = RoundedBitmapDrawableFactory.create(resources, resource) val circularBitmapDrawable = RoundedBitmapDrawableFactory.create(
resources,
resource
)
circularBitmapDrawable.isCircular = true circularBitmapDrawable.isCircular = true
iv.setImageDrawable(circularBitmapDrawable) iv.setImageDrawable(circularBitmapDrawable)
} }

View File

@ -6,14 +6,14 @@ import apps.amine.bou.readerforselfoss.utils.getUnsafeHttpClient
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.GlideBuilder import com.bumptech.glide.GlideBuilder
import com.bumptech.glide.Registry import com.bumptech.glide.Registry
import com.bumptech.glide.module.GlideModule
import com.bumptech.glide.load.model.GlideUrl import com.bumptech.glide.load.model.GlideUrl
import com.bumptech.glide.module.GlideModule
import java.io.InputStream import java.io.InputStream
class SelfSignedGlideModule : GlideModule { class SelfSignedGlideModule : GlideModule {
override fun applyOptions(context: Context?, builder: GlideBuilder?) {} override fun applyOptions(context: Context?, builder: GlideBuilder?) {
}
override fun registerComponents(context: Context?, glide: Glide?, registry: Registry?) { override fun registerComponents(context: Context?, glide: Glide?, registry: Registry?) {
@ -22,11 +22,12 @@ class SelfSignedGlideModule : GlideModule {
if (pref.getBoolean("isSelfSignedCert", false)) { if (pref.getBoolean("isSelfSignedCert", false)) {
val client = getUnsafeHttpClient().build() val client = getUnsafeHttpClient().build()
registry?.append(GlideUrl::class.java, InputStream::class.java, registry?.append(
com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader.Factory(client)) GlideUrl::class.java,
} InputStream::class.java,
com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader.Factory(client)
)
}
} }
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 434 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 307 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 542 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 263 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 768 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 500 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 296 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 408 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -15,7 +15,8 @@
android:id="@+id/toolbar" android:id="@+id/toolbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" android:layout_height="?attr/actionBarSize"
app:theme="@style/ToolBarStyle" /> app:theme="@style/ToolBarStyle"
app:popupTheme="?attr/toolbarPopupTheme" />
</android.support.design.widget.AppBarLayout> </android.support.design.widget.AppBarLayout>

View File

@ -9,7 +9,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"> xmlns:app="http://schemas.android.com/apk/res-auto">
<com.github.stkent.amplify.prompt.DefaultLayoutPromptView <com.github.stkent.amplify.prompt.DefaultLayoutPromptView
android:id="@+id/prompt_view" android:id="@+id/promptView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:prompt_view_user_opinion_question_title="@string/rating_prompt_title" app:prompt_view_user_opinion_question_title="@string/rating_prompt_title"
@ -34,7 +34,7 @@
android:id="@+id/coordLayout" android:id="@+id/coordLayout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_below="@id/prompt_view"> android:layout_below="@id/promptView">
<android.support.design.widget.CoordinatorLayout <android.support.design.widget.CoordinatorLayout
android:id="@+id/intern_coordLayout" android:id="@+id/intern_coordLayout"
@ -51,10 +51,11 @@
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar <android.support.v7.widget.Toolbar
android:id="@+id/toolbar" android:id="@+id/toolBar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" android:layout_height="?attr/actionBarSize"
app:theme="@style/ToolBarStyle" /> app:theme="@style/ToolBarStyle"
app:popupTheme="?attr/toolbarPopupTheme" />
</android.support.design.widget.AppBarLayout> </android.support.design.widget.AppBarLayout>
@ -88,7 +89,7 @@
android:background="@color/transparent" android:background="@color/transparent"
android:visibility="gone" /> android:visibility="gone" />
<android.support.v7.widget.RecyclerView <android.support.v7.widget.RecyclerView
android:id="@+id/my_recycler_view" android:id="@+id/recyclerView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@color/transparent" android:background="@color/transparent"

View File

@ -14,7 +14,8 @@
android:id="@+id/toolbar" android:id="@+id/toolbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" android:layout_height="?attr/actionBarSize"
app:theme="@style/ToolBarStyle" /> app:theme="@style/ToolBarStyle"
app:popupTheme="?attr/toolbarPopupTheme" />
</android.support.design.widget.AppBarLayout> </android.support.design.widget.AppBarLayout>
<LinearLayout <LinearLayout
@ -27,7 +28,7 @@
android:paddingTop="@dimen/activity_vertical_margin"> android:paddingTop="@dimen/activity_vertical_margin">
<!-- Login progress --> <!-- Login progress -->
<ProgressBar <ProgressBar
android:id="@+id/login_progress" android:id="@+id/loginProgress"
style="?android:attr/progressBarStyleLarge" style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -35,7 +36,7 @@
android:visibility="gone"/> android:visibility="gone"/>
<ScrollView <ScrollView
android:id="@+id/login_form" android:id="@+id/loginForm"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
@ -51,15 +52,13 @@
> >
<EditText <EditText
android:id="@+id/url" android:id="@+id/urlView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:hint="@string/prompt_url" android:hint="@string/prompt_url"
android:imeActionId="@+id/login"
android:inputType="textUri"
android:imeOptions="actionUnspecified" android:imeOptions="actionUnspecified"
android:maxLines="1" android:inputType="textUri"
/> android:maxLines="1" />
</android.support.design.widget.TextInputLayout> </android.support.design.widget.TextInputLayout>
@ -77,13 +76,12 @@
android:visibility="gone"> android:visibility="gone">
<AutoCompleteTextView <AutoCompleteTextView
android:id="@+id/login" android:id="@+id/loginView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:hint="@string/prompt_login" android:hint="@string/prompt_login"
android:inputType="text" android:inputType="text"
android:maxLines="1" android:maxLines="1" />
/>
</android.support.design.widget.TextInputLayout> </android.support.design.widget.TextInputLayout>
@ -94,13 +92,12 @@
android:visibility="gone"> android:visibility="gone">
<EditText <EditText
android:id="@+id/password" android:id="@+id/passwordView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:hint="@string/prompt_password" android:hint="@string/prompt_password"
android:inputType="textPassword" android:inputType="textPassword"
android:maxLines="1" android:maxLines="1" />
/>
</android.support.design.widget.TextInputLayout> </android.support.design.widget.TextInputLayout>
@ -118,7 +115,7 @@
android:visibility="gone"> android:visibility="gone">
<EditText <EditText
android:id="@+id/httpLogin" android:id="@+id/httpLoginView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:hint="@string/prompt_http_login" /> android:hint="@string/prompt_http_login" />
@ -131,11 +128,11 @@
android:visibility="gone"> android:visibility="gone">
<EditText <EditText
android:id="@+id/httpPassword" android:id="@+id/httpPasswordView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:inputType="textPassword" android:hint="@string/prompt_http_password"
android:hint="@string/prompt_http_password" /> android:inputType="textPassword" />
</android.support.design.widget.TextInputLayout> </android.support.design.widget.TextInputLayout>
<Switch <Switch
@ -153,7 +150,7 @@
android:visibility="gone" /> android:visibility="gone" />
<Button <Button
android:id="@+id/email_sign_in_button" android:id="@+id/signInButton"
style="?android:textAppearanceSmall" style="?android:textAppearanceSmall"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View File

@ -1,12 +1,18 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout <android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent">
tools:context="apps.amine.bou.readerforselfoss.ReaderActivity"
android:background="?android:attr/windowBackground"> <android.support.v4.widget.NestedScrollView
android:id="@+id/nestedScrollView"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView <ImageView
android:id="@+id/imageView" android:id="@+id/imageView"
@ -35,7 +41,7 @@
app:layout_constraintTop_toBottomOf="@+id/imageView" /> app:layout_constraintTop_toBottomOf="@+id/imageView" />
<TextView <TextView
android:id="@+id/title" android:id="@+id/titleView"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="16dp" android:layout_marginEnd="16dp"
@ -50,7 +56,7 @@
app:layout_constraintRight_toRightOf="parent" app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/source" /> app:layout_constraintTop_toBottomOf="@+id/source" />
<org.sufficientlysecure.htmltextview.HtmlTextView <TextView
android:id="@+id/content" android:id="@+id/content"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -63,64 +69,80 @@
app:layout_constraintHorizontal_bias="0.0" app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/title" app:layout_constraintTop_toBottomOf="@+id/titleView"
tools:text="Some text @android:string/fingerprint_icon_content_description" /> android:textColorLink="?attr/colorAccent"/>
<android.support.constraint.ConstraintLayout <!--<org.sufficientlysecure.htmltextview.HtmlTextView
android:layout_width="match_parent" android:id="@+id/content"
android:layout_height="35dp" android:layout_width="0dp"
android:layout_marginBottom="0dp" android:layout_height="wrap_content"
android:layout_marginEnd="0dp"
android:layout_marginRight="16dp"
android:layout_marginTop="16dp"
android:background="#BBBBBB"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/content"
app:layout_constraintVertical_bias="1.0">
<ImageButton
android:id="@+id/browserBtn"
android:layout_width="35dp"
android:layout_height="35dp"
android:layout_centerVertical="true"
android:layout_marginEnd="16dp" android:layout_marginEnd="16dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp" android:layout_marginRight="16dp"
android:layout_toLeftOf="@+id/shareBtn" android:layout_marginStart="16dp"
android:layout_toStartOf="@+id/shareBtn" android:layout_marginTop="24dp"
android:adjustViewBounds="true" android:paddingBottom="48dp"
android:background="@android:color/transparent" app:layout_constraintHorizontal_bias="0.0"
android:elevation="5dp" app:layout_constraintLeft_toLeftOf="parent"
android:padding="4dp" app:layout_constraintRight_toRightOf="parent"
android:scaleType="centerCrop" app:layout_constraintTop_toBottomOf="@+id/titleView" />-->
android:src="@drawable/ic_open_in_browser_black_24dp"
android:tint="@android:color/black"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/shareBtn"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageButton
android:id="@+id/shareBtn"
android:layout_width="35dp"
android:layout_height="35dp"
android:adjustViewBounds="true"
android:background="@android:color/transparent"
android:elevation="5dp"
android:padding="4dp"
android:scaleType="centerCrop"
android:src="@drawable/ic_share_black_24dp"
android:tint="@android:color/black"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/browserBtn"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout> </android.support.constraint.ConstraintLayout>
</android.support.constraint.ConstraintLayout> </android.support.v4.widget.NestedScrollView>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_gravity="end|bottom|right">
<com.github.rubensousa.floatingtoolbar.FloatingToolbar
android:id="@+id/floatingToolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:layout_gravity="bottom"
app:floatingItemBackground="?attr/colorAccent"
app:floatingMenu="@menu/reader_toolbar" />
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_gravity="end|bottom|right"
android:layout_marginBottom="16dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:src="@drawable/ic_add"
app:backgroundTint="?attr/colorAccent"
app:fabSize="mini"
app:rippleColor="?attr/colorAccentDark" />
</FrameLayout>
<FrameLayout
android:id="@+id/progressBar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
android:animateLayoutChanges="true"
android:alpha="0.8"
android:background="@color/black"
android:clickable="false">
<ProgressBar
style="?android:attr/progressBarStyleLarge"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:progressTint="?attr/colorAccent" />
</FrameLayout>
</android.support.design.widget.CoordinatorLayout>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout <android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
@ -16,28 +16,25 @@
android:id="@+id/toolbar" android:id="@+id/toolbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" android:layout_height="?attr/actionBarSize"
app:theme="@style/ToolBarStyle" /> app:theme="@style/ToolBarStyle"
app:popupTheme="?attr/toolbarPopupTheme" />
</android.support.design.widget.AppBarLayout> </android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView <android.support.v7.widget.RecyclerView
android:id="@+id/activity_sources" android:id="@+id/recyclerView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:scrollbars="vertical" android:scrollbars="vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior"> app:layout_behavior="@string/appbar_scrolling_view_behavior">
</android.support.v7.widget.RecyclerView> </android.support.v7.widget.RecyclerView>
<com.melnykov.fab.FloatingActionButton <android.support.design.widget.FloatingActionButton
android:id="@+id/fab" android:id="@+id/fab"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="end|bottom|right" android:layout_gravity="end|bottom|right"
android:src="@drawable/ic_add_black_24dp" android:src="@drawable/ic_add"
android:tint="?android:textColorPrimary"
fab:fab_colorNormal="?attr/colorAccent"
fab:fab_colorPressed="?attr/colorAccentDark"
fab:fab_colorRipple="@color/pink"
android:paddingBottom="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingTop="@dimen/activity_vertical_margin" android:paddingTop="@dimen/activity_vertical_margin"
android:layout_alignParentBottom="true" android:layout_alignParentBottom="true"
@ -45,5 +42,6 @@
android:layout_alignParentEnd="true" android:layout_alignParentEnd="true"
android:layout_marginBottom="16dp" android:layout_marginBottom="16dp"
android:layout_marginEnd="16dp" android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"/> android:layout_marginRight="16dp"
</RelativeLayout> app:layout_behavior="apps.amine.bou.readerforselfoss.utils.ScrollAwareFABBehavior" />
</android.support.design.widget.CoordinatorLayout>

View File

@ -1,65 +1,58 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.CardView
android:id="@+id/card"
xmlns:card_view="http://schemas.android.com/apk/res-auto" xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="0dp" xmlns:tools="http://schemas.android.com/tools"
app:layout_constraintRight_toRightOf="parent" android:id="@+id/card"
app:layout_constraintLeft_toLeftOf="parent" android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="8dp"
app:layout_constraintHorizontal_bias="0.62" app:layout_constraintHorizontal_bias="0.62"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
card_view:cardElevation="2dp" card_view:cardElevation="2dp"
card_view:cardUseCompatPadding="true" card_view:cardUseCompatPadding="true"
android:layout_height="wrap_content" card_view:layout_constraintBottom_toBottomOf="parent">
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp">
<android.support.constraint.ConstraintLayout <android.support.constraint.ConstraintLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<ImageView <ImageView
android:id="@+id/itemImage"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:srcCompat="@drawable/background_splash"
android:id="@+id/itemImage"
android:scaleType="fitCenter"
android:adjustViewBounds="true" android:adjustViewBounds="true"
android:cropToPadding="true" android:cropToPadding="true"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintLeft_toLeftOf="parent"
android:layout_marginTop="0dp"
android:layout_marginRight="0dp"
app:layout_constraintRight_toRightOf="parent" app:layout_constraintRight_toRightOf="parent"
android:layout_marginLeft="0dp" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent" /> app:srcCompat="@drawable/background_splash"
card_view:layout_constraintBottom_toTopOf="@+id/constraintLayout" />
<android.support.constraint.ConstraintLayout <android.support.constraint.ConstraintLayout
android:id="@+id/constraintLayout"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/itemImage"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
> app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/itemImage">
<ImageView <ImageView
android:layout_height="40dp"
app:srcCompat="@drawable/background_splash"
android:id="@+id/sourceImage" android:id="@+id/sourceImage"
app:layout_constraintLeft_toLeftOf="parent" android:layout_width="40dp"
android:layout_marginStart="8dp" android:layout_height="40dp"
android:layout_marginLeft="8dp" android:layout_marginLeft="8dp"
app:layout_constraintTop_toTopOf="parent" android:layout_marginStart="8dp"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:layout_width="40dp" /> app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/background_splash" />
<TextView <TextView
android:id="@+id/title" android:id="@+id/title"
@ -79,40 +72,40 @@
tools:text="Titre" /> tools:text="Titre" />
<TextView <TextView
android:id="@+id/sourceTitleAndDate"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:id="@+id/sourceTitleAndDate"
android:textSize="14sp"
tools:text="Google Actualité Il y a 5h"
android:textAlignment="viewStart"
app:layout_constraintTop_toBottomOf="@+id/title"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:gravity="start"
android:textAlignment="viewStart"
android:textSize="14sp"
app:layout_constraintLeft_toLeftOf="@+id/title" app:layout_constraintLeft_toLeftOf="@+id/title"
android:gravity="start" /> app:layout_constraintTop_toBottomOf="@+id/title"
tools:text="Google Actualité Il y a 5h" />
<RelativeLayout <RelativeLayout
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/sourceTitleAndDate"
android:layout_marginTop="16dp" android:layout_marginTop="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"> app:layout_constraintTop_toBottomOf="@+id/sourceTitleAndDate">
<com.like.LikeButton <com.like.LikeButton
app:icon_type="heart"
app:icon_size="22dp"
android:id="@+id/favButton" android:id="@+id/favButton"
android:layout_width="35dp" android:layout_width="35dp"
android:layout_height="35dp" android:layout_height="35dp"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:layout_alignParentRight="true" android:layout_marginEnd="8dp"
android:layout_alignParentEnd="true" android:layout_marginRight="8dp"
android:elevation="5dp" android:elevation="5dp"
android:padding="4dp" android:padding="4dp"
android:layout_marginRight="8dp" app:icon_size="22dp"
android:layout_marginEnd="8dp"/> app:icon_type="heart" />
<ImageButton <ImageButton
android:id="@+id/shareBtn" android:id="@+id/shareBtn"
@ -153,5 +146,4 @@
</android.support.constraint.ConstraintLayout> </android.support.constraint.ConstraintLayout>
</android.support.constraint.ConstraintLayout> </android.support.constraint.ConstraintLayout>
</android.support.v7.widget.CardView> </android.support.v7.widget.CardView>
</android.support.constraint.ConstraintLayout>

View File

@ -1,55 +1,66 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:minHeight="88dp"> android:minHeight="88dp">
<android.support.constraint.Guideline
android:id="@+id/guideline4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_begin="99dp" />
<ImageView <ImageView
android:id="@+id/itemImage" android:id="@+id/itemImage"
android:layout_width="88dp" android:layout_width="88dp"
android:layout_height="88dp" android:layout_height="88dp"
android:src="@color/about_libraries_accent" app:layout_constraintBottom_toTopOf="@+id/guideline4"
app:layout_constraintBottom_toTopOf="@+id/actionBar" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintTop_toTopOf="parent"
/>
<TextView <TextView
android:id="@+id/title" android:id="@+id/title"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="16dp" android:layout_marginEnd="16dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginStart="16dp" android:layout_marginStart="16dp"
android:layout_marginTop="16dp" android:layout_marginTop="16dp"
android:fontFamily="sans-serif" android:fontFamily="sans-serif"
android:gravity="start" android:gravity="start"
android:maxLines="3"
android:ellipsize="end"
android:textAlignment="viewStart" android:textAlignment="viewStart"
android:textAllCaps="false" android:textAllCaps="false"
android:textSize="16sp" android:textSize="16sp"
android:textStyle="bold" android:textStyle="bold"
app:layout_constraintBottom_toTopOf="@+id/sourceTitleAndDate"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0" app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintLeft_toRightOf="@+id/itemImage" app:layout_constraintStart_toEndOf="@+id/itemImage"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0"
tools:text="Titre" /> tools:text="Titre" />
<TextView <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/sourceTitleAndDate" android:id="@+id/sourceTitleAndDate"
android:textSize="14sp" android:layout_width="0dp"
tools:text="Google Actualité Il y a 5h" android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"
android:gravity="start"
android:textAlignment="viewStart" android:textAlignment="viewStart"
app:layout_constraintTop_toBottomOf="@+id/title" android:textSize="14sp"
android:layout_marginTop="8dp" app:layout_constraintBottom_toTopOf="@+id/guideline4"
app:layout_constraintLeft_toLeftOf="@+id/title" app:layout_constraintEnd_toEndOf="parent"
android:gravity="start" /> app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toEndOf="@+id/itemImage"
tools:text="Google Actualité Il y a 5h" />
<RelativeLayout <RelativeLayout
android:id="@+id/actionBar" android:id="@+id/actionBar"
@ -58,9 +69,11 @@
android:background="#BBBBBB" android:background="#BBBBBB"
android:visibility="gone" android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintRight_toRightOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/sourceTitleAndDate"> app:layout_constraintTop_toTopOf="@+id/guideline4"
app:layout_constraintVertical_bias="1.0"
tools:visibility="visible">
<com.like.LikeButton <com.like.LikeButton
android:id="@+id/favButton" android:id="@+id/favButton"
@ -68,7 +81,6 @@
android:layout_height="35dp" android:layout_height="35dp"
android:layout_alignParentEnd="true" android:layout_alignParentEnd="true"
android:layout_alignParentRight="true" android:layout_alignParentRight="true"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:layout_marginEnd="8dp" android:layout_marginEnd="8dp"
android:layout_marginRight="8dp" android:layout_marginRight="8dp"
@ -110,7 +122,7 @@
android:padding="4dp" android:padding="4dp"
android:scaleType="centerCrop" android:scaleType="centerCrop"
android:src="@drawable/ic_open_in_browser_black_24dp" /> android:src="@drawable/ic_open_in_browser_black_24dp" />
</RelativeLayout> </RelativeLayout>
</android.support.constraint.ConstraintLayout> </android.support.constraint.ConstraintLayout>

View File

@ -9,6 +9,7 @@
android:id="@+id/toolbar" android:id="@+id/toolbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" android:layout_height="?attr/actionBarSize"
app:theme="@style/ToolBarStyle" /> app:theme="@style/ToolBarStyle"
app:popupTheme="?attr/toolbarPopupTheme" />
</android.support.design.widget.AppBarLayout> </android.support.design.widget.AppBarLayout>

View File

@ -1,11 +0,0 @@
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Switch
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true" />
</RelativeLayout>

View File

@ -5,14 +5,14 @@
<item android:id="@+id/action_search" <item android:id="@+id/action_search"
android:title="@string/menu_home_search" android:title="@string/menu_home_search"
android:icon="@drawable/ic_action_search" android:icon="@drawable/ic_action_search"
app:showAsAction="always|collapseActionView" app:showAsAction="ifRoom|collapseActionView"
app:actionViewClass="android.support.v7.widget.SearchView" /> app:actionViewClass="android.support.v7.widget.SearchView" />
<item android:id="@+id/readAll" <item android:id="@+id/readAll"
android:icon="@drawable/ic_done_all_white_24dp" android:icon="@drawable/ic_done_all_white_24dp"
android:title="@string/readAll" android:title="@string/readAll"
android:orderInCategory="1" android:orderInCategory="1"
app:showAsAction="always"/> app:showAsAction="ifRoom"/>
<item <item
android:id="@+id/refresh" android:id="@+id/refresh"

View File

@ -3,7 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"> xmlns:app="http://schemas.android.com/apk/res-auto">
<item <item
android:id="@+id/loging_debug" android:id="@+id/login_debug"
android:checkable="true" android:checkable="true"
android:checked="false" android:checked="false"
android:icon="@drawable/ic_bug_report" android:icon="@drawable/ic_bug_report"

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/more_action"
android:icon="@drawable/ic_chrome_reader_mode"
android:title="@string/reader_action_more"
app:showAsAction="ifRoom" />
<item
android:id="@+id/open_action"
android:icon="@drawable/ic_open_in_browser"
android:iconTint="@color/white"
android:title="@string/reader_action_open"
app:showAsAction="ifRoom" />
<item
android:id="@+id/share_action"
android:icon="@drawable/ic_share_white_24dp"
android:title="@string/reader_action_share"
app:showAsAction="ifRoom" />
</menu>

View File

@ -46,9 +46,7 @@
<string name="pref_header_links">"Links"</string> <string name="pref_header_links">"Links"</string>
<string name="issue_tracker_link">"Issue Tracker"</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="issue_tracker_summary">"Report a bug or ask for a new feature"</string>
<string name="warning_version">"WARNING"</string>
<string name="warning_wrong_url">"WARNING"</string> <string name="warning_wrong_url">"WARNING"</string>
<string name="text_version">"You seem to be using a version of the app that doesn't come from the store. The app could have been tampered with. I will not be responsible if it causes any damage to your device. Consider using the ReaderForSelfoss app from the Play Store."</string>
<string name="pref_switch_card_view_title">"Card View"</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_mark_favortie">"Can't mark article as favorite"</string>
<string name="cant_unmark_favortie">"Can't remove item from favorite"</string> <string name="cant_unmark_favortie">"Can't remove item from favorite"</string>
@ -77,7 +75,7 @@
<string name="prefer_article_viewer_title">"Use the article viewer"</string> <string name="prefer_article_viewer_title">"Use the article viewer"</string>
<string name="prefer_article_viewer_on">"Will use the article viewer instead of the internal browser"</string> <string name="prefer_article_viewer_on">"Will use the article viewer instead of the internal browser"</string>
<string name="prefer_article_viewer_off">"Will use the internal browser instead of the article viewer"</string> <string name="prefer_article_viewer_off">"Will use the internal browser instead of the article viewer"</string>
<string name="pref_general_category_links">"Link handeling"</string> <string name="pref_general_category_links">"Link handling"</string>
<string name="pref_general_category_displaying">"Displaying"</string> <string name="pref_general_category_displaying">"Displaying"</string>
<string name="pref_general_category_actions">"Actions"</string> <string name="pref_general_category_actions">"Actions"</string>
<string name="pref_switch_card_view_on">"The articles will be displayed as cards"</string> <string name="pref_switch_card_view_on">"The articles will be displayed as cards"</string>
@ -116,7 +114,7 @@
<string name="no_sources_loaded">No sources loaded</string> <string name="no_sources_loaded">No sources loaded</string>
<string name="drawer_loading">Loading …</string> <string name="drawer_loading">Loading …</string>
<string name="menu_home_search">Search</string> <string name="menu_home_search">Search</string>
<string name="can_delete_source">Can\'t delete the source...</string> <string name="can_delete_source">Can\'t delete the source</string>
<string name="base_url_error">There was an issue when trying to communicate with your Selfoss Instance. If the issue persists, please get in touch with me.</string> <string name="base_url_error">There was an issue when trying to communicate with your Selfoss Instance. If the issue persists, please get in touch with me.</string>
<string name="pref_header_theme">Themes</string> <string name="pref_header_theme">Themes</string>
<string name="default_theme">Default</string> <string name="default_theme">Default</string>
@ -152,7 +150,12 @@
<string name="login_everything_title">Logging every api calls</string> <string name="login_everything_title">Logging every api calls</string>
<string name="login_everything_on">This will log every api call for debug purpose.</string> <string name="login_everything_on">This will log every api call for debug purpose.</string>
<string name="login_everything_off">No api call will be logged</string> <string name="login_everything_off">No api call will be logged</string>
<string name="pref_general_infinite_loading_title">(BETA) Load more articles on scroll</string> <string name="pref_general_infinite_loading_title">Load more articles on scroll</string>
<string name="translation">Translation</string> <string name="translation">Translation</string>
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string> <string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
<string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

View File

@ -46,9 +46,7 @@
<string name="pref_header_links">"Links"</string> <string name="pref_header_links">"Links"</string>
<string name="issue_tracker_link">"Issue Tracker"</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="issue_tracker_summary">"Report a bug or ask for a new feature"</string>
<string name="warning_version">"WARNING"</string>
<string name="warning_wrong_url">"WARNING"</string> <string name="warning_wrong_url">"WARNING"</string>
<string name="text_version">"You seem to be using a version of the app that doesn't come from the store. The app could have been tampered with. I will not be responsible if it causes any damage to your device. Consider using the ReaderForSelfoss app from the Play Store."</string>
<string name="pref_switch_card_view_title">"Card View"</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_mark_favortie">"Can't mark article as favorite"</string>
<string name="cant_unmark_favortie">"Can't remove item from favorite"</string> <string name="cant_unmark_favortie">"Can't remove item from favorite"</string>
@ -77,7 +75,7 @@
<string name="prefer_article_viewer_title">"Use the article viewer"</string> <string name="prefer_article_viewer_title">"Use the article viewer"</string>
<string name="prefer_article_viewer_on">"Will use the article viewer instead of the internal browser"</string> <string name="prefer_article_viewer_on">"Will use the article viewer instead of the internal browser"</string>
<string name="prefer_article_viewer_off">"Will use the internal browser instead of the article viewer"</string> <string name="prefer_article_viewer_off">"Will use the internal browser instead of the article viewer"</string>
<string name="pref_general_category_links">"Link handeling"</string> <string name="pref_general_category_links">"Link handling"</string>
<string name="pref_general_category_displaying">"Displaying"</string> <string name="pref_general_category_displaying">"Displaying"</string>
<string name="pref_general_category_actions">"Actions"</string> <string name="pref_general_category_actions">"Actions"</string>
<string name="pref_switch_card_view_on">"The articles will be displayed as cards"</string> <string name="pref_switch_card_view_on">"The articles will be displayed as cards"</string>
@ -116,7 +114,7 @@
<string name="no_sources_loaded">No sources loaded</string> <string name="no_sources_loaded">No sources loaded</string>
<string name="drawer_loading">Loading …</string> <string name="drawer_loading">Loading …</string>
<string name="menu_home_search">Search</string> <string name="menu_home_search">Search</string>
<string name="can_delete_source">Can\'t delete the source...</string> <string name="can_delete_source">Can\'t delete the source</string>
<string name="base_url_error">There was an issue when trying to communicate with your Selfoss Instance. If the issue persists, please get in touch with me.</string> <string name="base_url_error">There was an issue when trying to communicate with your Selfoss Instance. If the issue persists, please get in touch with me.</string>
<string name="pref_header_theme">Themes</string> <string name="pref_header_theme">Themes</string>
<string name="default_theme">Default</string> <string name="default_theme">Default</string>
@ -152,7 +150,12 @@
<string name="login_everything_title">Logging every api calls</string> <string name="login_everything_title">Logging every api calls</string>
<string name="login_everything_on">This will log every api call for debug purpose.</string> <string name="login_everything_on">This will log every api call for debug purpose.</string>
<string name="login_everything_off">No api call will be logged</string> <string name="login_everything_off">No api call will be logged</string>
<string name="pref_general_infinite_loading_title">(BETA) Load more articles on scroll</string> <string name="pref_general_infinite_loading_title">Load more articles on scroll</string>
<string name="translation">Translation</string> <string name="translation">Translation</string>
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string> <string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
<string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

View File

@ -46,9 +46,7 @@
<string name="pref_header_links">"Links"</string> <string name="pref_header_links">"Links"</string>
<string name="issue_tracker_link">"Issue Tracker"</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="issue_tracker_summary">"Report a bug or ask for a new feature"</string>
<string name="warning_version">"WARNING"</string>
<string name="warning_wrong_url">"WARNING"</string> <string name="warning_wrong_url">"WARNING"</string>
<string name="text_version">"You seem to be using a version of the app that doesn't come from the store. The app could have been tampered with. I will not be responsible if it causes any damage to your device. Consider using the ReaderForSelfoss app from the Play Store."</string>
<string name="pref_switch_card_view_title">"Card View"</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_mark_favortie">"Can't mark article as favorite"</string>
<string name="cant_unmark_favortie">"Can't remove item from favorite"</string> <string name="cant_unmark_favortie">"Can't remove item from favorite"</string>
@ -77,7 +75,7 @@
<string name="prefer_article_viewer_title">"Use the article viewer"</string> <string name="prefer_article_viewer_title">"Use the article viewer"</string>
<string name="prefer_article_viewer_on">"Will use the article viewer instead of the internal browser"</string> <string name="prefer_article_viewer_on">"Will use the article viewer instead of the internal browser"</string>
<string name="prefer_article_viewer_off">"Will use the internal browser instead of the article viewer"</string> <string name="prefer_article_viewer_off">"Will use the internal browser instead of the article viewer"</string>
<string name="pref_general_category_links">"Link handeling"</string> <string name="pref_general_category_links">"Link handling"</string>
<string name="pref_general_category_displaying">"Displaying"</string> <string name="pref_general_category_displaying">"Displaying"</string>
<string name="pref_general_category_actions">"Actions"</string> <string name="pref_general_category_actions">"Actions"</string>
<string name="pref_switch_card_view_on">"The articles will be displayed as cards"</string> <string name="pref_switch_card_view_on">"The articles will be displayed as cards"</string>
@ -116,7 +114,7 @@
<string name="no_sources_loaded">No sources loaded</string> <string name="no_sources_loaded">No sources loaded</string>
<string name="drawer_loading">Loading …</string> <string name="drawer_loading">Loading …</string>
<string name="menu_home_search">Search</string> <string name="menu_home_search">Search</string>
<string name="can_delete_source">Can\'t delete the source...</string> <string name="can_delete_source">Can\'t delete the source</string>
<string name="base_url_error">There was an issue when trying to communicate with your Selfoss Instance. If the issue persists, please get in touch with me.</string> <string name="base_url_error">There was an issue when trying to communicate with your Selfoss Instance. If the issue persists, please get in touch with me.</string>
<string name="pref_header_theme">Themes</string> <string name="pref_header_theme">Themes</string>
<string name="default_theme">Default</string> <string name="default_theme">Default</string>
@ -152,7 +150,12 @@
<string name="login_everything_title">Logging every api calls</string> <string name="login_everything_title">Logging every api calls</string>
<string name="login_everything_on">This will log every api call for debug purpose.</string> <string name="login_everything_on">This will log every api call for debug purpose.</string>
<string name="login_everything_off">No api call will be logged</string> <string name="login_everything_off">No api call will be logged</string>
<string name="pref_general_infinite_loading_title">(BETA) Load more articles on scroll</string> <string name="pref_general_infinite_loading_title">Load more articles on scroll</string>
<string name="translation">Translation</string> <string name="translation">Translation</string>
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string> <string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
<string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

View File

@ -46,9 +46,7 @@
<string name="pref_header_links">"Links"</string> <string name="pref_header_links">"Links"</string>
<string name="issue_tracker_link">"Issue Tracker"</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="issue_tracker_summary">"Report a bug or ask for a new feature"</string>
<string name="warning_version">"WARNING"</string>
<string name="warning_wrong_url">"WARNING"</string> <string name="warning_wrong_url">"WARNING"</string>
<string name="text_version">"You seem to be using a version of the app that doesn't come from the store. The app could have been tampered with. I will not be responsible if it causes any damage to your device. Consider using the ReaderForSelfoss app from the Play Store."</string>
<string name="pref_switch_card_view_title">"Card View"</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_mark_favortie">"Can't mark article as favorite"</string>
<string name="cant_unmark_favortie">"Can't remove item from favorite"</string> <string name="cant_unmark_favortie">"Can't remove item from favorite"</string>
@ -77,7 +75,7 @@
<string name="prefer_article_viewer_title">"Use the article viewer"</string> <string name="prefer_article_viewer_title">"Use the article viewer"</string>
<string name="prefer_article_viewer_on">"Will use the article viewer instead of the internal browser"</string> <string name="prefer_article_viewer_on">"Will use the article viewer instead of the internal browser"</string>
<string name="prefer_article_viewer_off">"Will use the internal browser instead of the article viewer"</string> <string name="prefer_article_viewer_off">"Will use the internal browser instead of the article viewer"</string>
<string name="pref_general_category_links">"Link handeling"</string> <string name="pref_general_category_links">"Link handling"</string>
<string name="pref_general_category_displaying">"Displaying"</string> <string name="pref_general_category_displaying">"Displaying"</string>
<string name="pref_general_category_actions">"Actions"</string> <string name="pref_general_category_actions">"Actions"</string>
<string name="pref_switch_card_view_on">"The articles will be displayed as cards"</string> <string name="pref_switch_card_view_on">"The articles will be displayed as cards"</string>
@ -116,7 +114,7 @@
<string name="no_sources_loaded">No sources loaded</string> <string name="no_sources_loaded">No sources loaded</string>
<string name="drawer_loading">Loading …</string> <string name="drawer_loading">Loading …</string>
<string name="menu_home_search">Search</string> <string name="menu_home_search">Search</string>
<string name="can_delete_source">Can\'t delete the source...</string> <string name="can_delete_source">Can\'t delete the source</string>
<string name="base_url_error">There was an issue when trying to communicate with your Selfoss Instance. If the issue persists, please get in touch with me.</string> <string name="base_url_error">There was an issue when trying to communicate with your Selfoss Instance. If the issue persists, please get in touch with me.</string>
<string name="pref_header_theme">Themes</string> <string name="pref_header_theme">Themes</string>
<string name="default_theme">Default</string> <string name="default_theme">Default</string>
@ -152,7 +150,12 @@
<string name="login_everything_title">Logging every api calls</string> <string name="login_everything_title">Logging every api calls</string>
<string name="login_everything_on">This will log every api call for debug purpose.</string> <string name="login_everything_on">This will log every api call for debug purpose.</string>
<string name="login_everything_off">No api call will be logged</string> <string name="login_everything_off">No api call will be logged</string>
<string name="pref_general_infinite_loading_title">(BETA) Load more articles on scroll</string> <string name="pref_general_infinite_loading_title">Load more articles on scroll</string>
<string name="translation">Translation</string> <string name="translation">Translation</string>
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string> <string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
<string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

View File

@ -46,9 +46,7 @@
<string name="pref_header_links">"Links"</string> <string name="pref_header_links">"Links"</string>
<string name="issue_tracker_link">"Issue Tracker"</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="issue_tracker_summary">"Report a bug or ask for a new feature"</string>
<string name="warning_version">"WARNING"</string>
<string name="warning_wrong_url">"WARNING"</string> <string name="warning_wrong_url">"WARNING"</string>
<string name="text_version">"You seem to be using a version of the app that doesn't come from the store. The app could have been tampered with. I will not be responsible if it causes any damage to your device. Consider using the ReaderForSelfoss app from the Play Store."</string>
<string name="pref_switch_card_view_title">"Card View"</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_mark_favortie">"Can't mark article as favorite"</string>
<string name="cant_unmark_favortie">"Can't remove item from favorite"</string> <string name="cant_unmark_favortie">"Can't remove item from favorite"</string>
@ -77,7 +75,7 @@
<string name="prefer_article_viewer_title">"Use the article viewer"</string> <string name="prefer_article_viewer_title">"Use the article viewer"</string>
<string name="prefer_article_viewer_on">"Will use the article viewer instead of the internal browser"</string> <string name="prefer_article_viewer_on">"Will use the article viewer instead of the internal browser"</string>
<string name="prefer_article_viewer_off">"Will use the internal browser instead of the article viewer"</string> <string name="prefer_article_viewer_off">"Will use the internal browser instead of the article viewer"</string>
<string name="pref_general_category_links">"Link handeling"</string> <string name="pref_general_category_links">"Link handling"</string>
<string name="pref_general_category_displaying">"Displaying"</string> <string name="pref_general_category_displaying">"Displaying"</string>
<string name="pref_general_category_actions">"Actions"</string> <string name="pref_general_category_actions">"Actions"</string>
<string name="pref_switch_card_view_on">"The articles will be displayed as cards"</string> <string name="pref_switch_card_view_on">"The articles will be displayed as cards"</string>
@ -116,7 +114,7 @@
<string name="no_sources_loaded">No sources loaded</string> <string name="no_sources_loaded">No sources loaded</string>
<string name="drawer_loading">Loading …</string> <string name="drawer_loading">Loading …</string>
<string name="menu_home_search">Search</string> <string name="menu_home_search">Search</string>
<string name="can_delete_source">Can\'t delete the source...</string> <string name="can_delete_source">Can\'t delete the source</string>
<string name="base_url_error">There was an issue when trying to communicate with your Selfoss Instance. If the issue persists, please get in touch with me.</string> <string name="base_url_error">There was an issue when trying to communicate with your Selfoss Instance. If the issue persists, please get in touch with me.</string>
<string name="pref_header_theme">Themes</string> <string name="pref_header_theme">Themes</string>
<string name="default_theme">Default</string> <string name="default_theme">Default</string>
@ -152,7 +150,12 @@
<string name="login_everything_title">Logging every api calls</string> <string name="login_everything_title">Logging every api calls</string>
<string name="login_everything_on">This will log every api call for debug purpose.</string> <string name="login_everything_on">This will log every api call for debug purpose.</string>
<string name="login_everything_off">No api call will be logged</string> <string name="login_everything_off">No api call will be logged</string>
<string name="pref_general_infinite_loading_title">(BETA) Load more articles on scroll</string> <string name="pref_general_infinite_loading_title">Load more articles on scroll</string>
<string name="translation">Translation</string> <string name="translation">Translation</string>
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string> <string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
<string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

View File

@ -46,9 +46,7 @@
<string name="pref_header_links">"Links"</string> <string name="pref_header_links">"Links"</string>
<string name="issue_tracker_link">"Issue Tracker"</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="issue_tracker_summary">"Melde einen Bug oder rege ein neues Feature an"</string>
<string name="warning_version">"WARNUNG"</string>
<string name="warning_wrong_url">"WARNUNG"</string> <string name="warning_wrong_url">"WARNUNG"</string>
<string name="text_version">"Du scheinst eine Version der App verwenden, die nicht aus dem Play Store kommt. Die App könnte manipuliert wurden. Ich bin nicht verantwortlich für daraus resultierende Schäden an deinem Gerät. Bitte erwäge, die ReaderForSelfoss App aus dem Play Store zu nutzen."</string>
<string name="pref_switch_card_view_title">"Kachelansicht"</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_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="cant_unmark_favortie">"Eintrag kann nicht aus Favoriten entfernt werden"</string>
@ -116,7 +114,7 @@
<string name="no_sources_loaded">Keine Quellen geladen</string> <string name="no_sources_loaded">Keine Quellen geladen</string>
<string name="drawer_loading">Lade…</string> <string name="drawer_loading">Lade…</string>
<string name="menu_home_search">Suche</string> <string name="menu_home_search">Suche</string>
<string name="can_delete_source">Quelle kann nicht gelöscht werden...</string> <string name="can_delete_source">Can\'t delete the source…</string>
<string name="base_url_error">Beim Versuch deine Selfoss-Instanz zu erreichen ist ein Fehler aufgetreten. Solltet dieser Fehler bestehen bleiben, trete bitte mit mir in Kontakt.</string> <string name="base_url_error">Beim Versuch deine Selfoss-Instanz zu erreichen ist ein Fehler aufgetreten. Solltet dieser Fehler bestehen bleiben, trete bitte mit mir in Kontakt.</string>
<string name="pref_header_theme">Designs</string> <string name="pref_header_theme">Designs</string>
<string name="default_theme">Standard</string> <string name="default_theme">Standard</string>
@ -152,7 +150,12 @@
<string name="login_everything_title">Logging every api calls</string> <string name="login_everything_title">Logging every api calls</string>
<string name="login_everything_on">This will log every api call for debug purpose.</string> <string name="login_everything_on">This will log every api call for debug purpose.</string>
<string name="login_everything_off">No api call will be logged</string> <string name="login_everything_off">No api call will be logged</string>
<string name="pref_general_infinite_loading_title">(BETA) Load more articles on scroll</string> <string name="pref_general_infinite_loading_title">Load more articles on scroll</string>
<string name="translation">Übersetzung</string> <string name="translation">Übersetzung</string>
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string> <string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
<string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

View File

@ -46,9 +46,7 @@
<string name="pref_header_links">"Links"</string> <string name="pref_header_links">"Links"</string>
<string name="issue_tracker_link">"Issue Tracker"</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="issue_tracker_summary">"Report a bug or ask for a new feature"</string>
<string name="warning_version">"WARNING"</string>
<string name="warning_wrong_url">"WARNING"</string> <string name="warning_wrong_url">"WARNING"</string>
<string name="text_version">"You seem to be using a version of the app that doesn't come from the store. The app could have been tampered with. I will not be responsible if it causes any damage to your device. Consider using the ReaderForSelfoss app from the Play Store."</string>
<string name="pref_switch_card_view_title">"Card View"</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_mark_favortie">"Can't mark article as favorite"</string>
<string name="cant_unmark_favortie">"Can't remove item from favorite"</string> <string name="cant_unmark_favortie">"Can't remove item from favorite"</string>
@ -77,7 +75,7 @@
<string name="prefer_article_viewer_title">"Use the article viewer"</string> <string name="prefer_article_viewer_title">"Use the article viewer"</string>
<string name="prefer_article_viewer_on">"Will use the article viewer instead of the internal browser"</string> <string name="prefer_article_viewer_on">"Will use the article viewer instead of the internal browser"</string>
<string name="prefer_article_viewer_off">"Will use the internal browser instead of the article viewer"</string> <string name="prefer_article_viewer_off">"Will use the internal browser instead of the article viewer"</string>
<string name="pref_general_category_links">"Link handeling"</string> <string name="pref_general_category_links">"Link handling"</string>
<string name="pref_general_category_displaying">"Displaying"</string> <string name="pref_general_category_displaying">"Displaying"</string>
<string name="pref_general_category_actions">"Actions"</string> <string name="pref_general_category_actions">"Actions"</string>
<string name="pref_switch_card_view_on">"The articles will be displayed as cards"</string> <string name="pref_switch_card_view_on">"The articles will be displayed as cards"</string>
@ -116,7 +114,7 @@
<string name="no_sources_loaded">No sources loaded</string> <string name="no_sources_loaded">No sources loaded</string>
<string name="drawer_loading">Loading …</string> <string name="drawer_loading">Loading …</string>
<string name="menu_home_search">Search</string> <string name="menu_home_search">Search</string>
<string name="can_delete_source">Can\'t delete the source...</string> <string name="can_delete_source">Can\'t delete the source</string>
<string name="base_url_error">There was an issue when trying to communicate with your Selfoss Instance. If the issue persists, please get in touch with me.</string> <string name="base_url_error">There was an issue when trying to communicate with your Selfoss Instance. If the issue persists, please get in touch with me.</string>
<string name="pref_header_theme">Themes</string> <string name="pref_header_theme">Themes</string>
<string name="default_theme">Default</string> <string name="default_theme">Default</string>
@ -152,7 +150,12 @@
<string name="login_everything_title">Logging every api calls</string> <string name="login_everything_title">Logging every api calls</string>
<string name="login_everything_on">This will log every api call for debug purpose.</string> <string name="login_everything_on">This will log every api call for debug purpose.</string>
<string name="login_everything_off">No api call will be logged</string> <string name="login_everything_off">No api call will be logged</string>
<string name="pref_general_infinite_loading_title">(BETA) Load more articles on scroll</string> <string name="pref_general_infinite_loading_title">Load more articles on scroll</string>
<string name="translation">Translation</string> <string name="translation">Translation</string>
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string> <string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
<string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

View File

@ -46,9 +46,7 @@
<string name="pref_header_links">"Links"</string> <string name="pref_header_links">"Links"</string>
<string name="issue_tracker_link">"Issue Tracker"</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="issue_tracker_summary">"Report a bug or ask for a new feature"</string>
<string name="warning_version">"WARNING"</string>
<string name="warning_wrong_url">"WARNING"</string> <string name="warning_wrong_url">"WARNING"</string>
<string name="text_version">"You seem to be using a version of the app that doesn't come from the store. The app could have been tampered with. I will not be responsible if it causes any damage to your device. Consider using the ReaderForSelfoss app from the Play Store."</string>
<string name="pref_switch_card_view_title">"Card View"</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_mark_favortie">"Can't mark article as favorite"</string>
<string name="cant_unmark_favortie">"Can't remove item from favorite"</string> <string name="cant_unmark_favortie">"Can't remove item from favorite"</string>
@ -77,7 +75,7 @@
<string name="prefer_article_viewer_title">"Use the article viewer"</string> <string name="prefer_article_viewer_title">"Use the article viewer"</string>
<string name="prefer_article_viewer_on">"Will use the article viewer instead of the internal browser"</string> <string name="prefer_article_viewer_on">"Will use the article viewer instead of the internal browser"</string>
<string name="prefer_article_viewer_off">"Will use the internal browser instead of the article viewer"</string> <string name="prefer_article_viewer_off">"Will use the internal browser instead of the article viewer"</string>
<string name="pref_general_category_links">"Link handeling"</string> <string name="pref_general_category_links">"Link handling"</string>
<string name="pref_general_category_displaying">"Displaying"</string> <string name="pref_general_category_displaying">"Displaying"</string>
<string name="pref_general_category_actions">"Actions"</string> <string name="pref_general_category_actions">"Actions"</string>
<string name="pref_switch_card_view_on">"The articles will be displayed as cards"</string> <string name="pref_switch_card_view_on">"The articles will be displayed as cards"</string>
@ -116,7 +114,7 @@
<string name="no_sources_loaded">No sources loaded</string> <string name="no_sources_loaded">No sources loaded</string>
<string name="drawer_loading">Loading …</string> <string name="drawer_loading">Loading …</string>
<string name="menu_home_search">Search</string> <string name="menu_home_search">Search</string>
<string name="can_delete_source">Can\'t delete the source...</string> <string name="can_delete_source">Can\'t delete the source</string>
<string name="base_url_error">There was an issue when trying to communicate with your Selfoss Instance. If the issue persists, please get in touch with me.</string> <string name="base_url_error">There was an issue when trying to communicate with your Selfoss Instance. If the issue persists, please get in touch with me.</string>
<string name="pref_header_theme">Themes</string> <string name="pref_header_theme">Themes</string>
<string name="default_theme">Default</string> <string name="default_theme">Default</string>
@ -152,7 +150,12 @@
<string name="login_everything_title">Logging every api calls</string> <string name="login_everything_title">Logging every api calls</string>
<string name="login_everything_on">This will log every api call for debug purpose.</string> <string name="login_everything_on">This will log every api call for debug purpose.</string>
<string name="login_everything_off">No api call will be logged</string> <string name="login_everything_off">No api call will be logged</string>
<string name="pref_general_infinite_loading_title">(BETA) Load more articles on scroll</string> <string name="pref_general_infinite_loading_title">Load more articles on scroll</string>
<string name="translation">Translation</string> <string name="translation">Translation</string>
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string> <string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
<string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

View File

@ -46,9 +46,7 @@
<string name="pref_header_links">"Links"</string> <string name="pref_header_links">"Links"</string>
<string name="issue_tracker_link">"Issue Tracker"</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="issue_tracker_summary">"Report a bug or ask for a new feature"</string>
<string name="warning_version">"WARNING"</string>
<string name="warning_wrong_url">"WARNING"</string> <string name="warning_wrong_url">"WARNING"</string>
<string name="text_version">"You seem to be using a version of the app that doesn't come from the store. The app could have been tampered with. I will not be responsible if it causes any damage to your device. Consider using the ReaderForSelfoss app from the Play Store."</string>
<string name="pref_switch_card_view_title">"Card View"</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_mark_favortie">"Can't mark article as favorite"</string>
<string name="cant_unmark_favortie">"Can't remove item from favorite"</string> <string name="cant_unmark_favortie">"Can't remove item from favorite"</string>
@ -77,7 +75,7 @@
<string name="prefer_article_viewer_title">"Use the article viewer"</string> <string name="prefer_article_viewer_title">"Use the article viewer"</string>
<string name="prefer_article_viewer_on">"Will use the article viewer instead of the internal browser"</string> <string name="prefer_article_viewer_on">"Will use the article viewer instead of the internal browser"</string>
<string name="prefer_article_viewer_off">"Will use the internal browser instead of the article viewer"</string> <string name="prefer_article_viewer_off">"Will use the internal browser instead of the article viewer"</string>
<string name="pref_general_category_links">"Link handeling"</string> <string name="pref_general_category_links">"Link handling"</string>
<string name="pref_general_category_displaying">"Displaying"</string> <string name="pref_general_category_displaying">"Displaying"</string>
<string name="pref_general_category_actions">"Actions"</string> <string name="pref_general_category_actions">"Actions"</string>
<string name="pref_switch_card_view_on">"The articles will be displayed as cards"</string> <string name="pref_switch_card_view_on">"The articles will be displayed as cards"</string>
@ -116,7 +114,7 @@
<string name="no_sources_loaded">No sources loaded</string> <string name="no_sources_loaded">No sources loaded</string>
<string name="drawer_loading">Loading …</string> <string name="drawer_loading">Loading …</string>
<string name="menu_home_search">Search</string> <string name="menu_home_search">Search</string>
<string name="can_delete_source">Can\'t delete the source...</string> <string name="can_delete_source">Can\'t delete the source</string>
<string name="base_url_error">There was an issue when trying to communicate with your Selfoss Instance. If the issue persists, please get in touch with me.</string> <string name="base_url_error">There was an issue when trying to communicate with your Selfoss Instance. If the issue persists, please get in touch with me.</string>
<string name="pref_header_theme">Themes</string> <string name="pref_header_theme">Themes</string>
<string name="default_theme">Default</string> <string name="default_theme">Default</string>
@ -152,7 +150,12 @@
<string name="login_everything_title">Logging every api calls</string> <string name="login_everything_title">Logging every api calls</string>
<string name="login_everything_on">This will log every api call for debug purpose.</string> <string name="login_everything_on">This will log every api call for debug purpose.</string>
<string name="login_everything_off">No api call will be logged</string> <string name="login_everything_off">No api call will be logged</string>
<string name="pref_general_infinite_loading_title">(BETA) Load more articles on scroll</string> <string name="pref_general_infinite_loading_title">Load more articles on scroll</string>
<string name="translation">Translation</string> <string name="translation">Translation</string>
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string> <string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
<string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

View File

@ -6,20 +6,20 @@
<string name="prompt_password">"Mot de passe"</string> <string name="prompt_password">"Mot de passe"</string>
<string name="prompt_http_password">"Mot de passe HTTP"</string> <string name="prompt_http_password">"Mot de passe HTTP"</string>
<string name="action_sign_in">"Valider"</string> <string name="action_sign_in">"Valider"</string>
<string name="error_invalid_password">"Mot de passe pas assez lent"</string> <string name="error_invalid_password">"Mot de passe trop court"</string>
<string name="error_field_required">"Champ requis"</string> <string name="error_field_required">"Champ requis"</string>
<string name="prompt_url">"Url Selfoss"</string> <string name="prompt_url">"Url Selfoss"</string>
<string name="withLoginSwitch">"Avec login ?"</string> <string name="withLoginSwitch">"Avec login ?"</string>
<string name="withHttpLoginSwitch">"Avec login HTTP ?"</string> <string name="withHttpLoginSwitch">"Avec login HTTP ?"</string>
<string name="login_url_problem">"Petit soucis. Il manque peut être un / à la fin ?"</string> <string name="login_url_problem">"Petit souci. Il manque peut être un / à la fin ?"</string>
<string name="prompt_login">"Utilisateur"</string> <string name="prompt_login">"Utilisateur"</string>
<string name="prompt_http_login">"Utilisateur HTTP"</string> <string name="prompt_http_login">"Utilisateur HTTP"</string>
<string name="label_share">"Partager"</string> <string name="label_share">"Partager"</string>
<string name="readAll">"Tout lire"</string> <string name="readAll">"Tout lire"</string>
<string name="action_disconnect">"Déconnecter"</string> <string name="action_disconnect">"Déconnecter"</string>
<string name="title_activity_settings">"Paramètres"</string> <string name="title_activity_settings">"Paramètres"</string>
<string name="pref_header_general">"General"</string> <string name="pref_header_general">"Général"</string>
<string name="pref_switch_actions_tap_title">"Action du clique sur un article"</string> <string name="pref_switch_actions_tap_title">"Action du clic sur un article"</string>
<string name="add_source_hint_tags">"Tag1, Tag2, Tag3"</string> <string name="add_source_hint_tags">"Tag1, Tag2, Tag3"</string>
<string name="add_source_hint_url">"Lien"</string> <string name="add_source_hint_url">"Lien"</string>
<string name="add_source_hint_name">"Nom"</string> <string name="add_source_hint_name">"Nom"</string>
@ -46,9 +46,7 @@
<string name="pref_header_links">"Liens utils"</string> <string name="pref_header_links">"Liens utils"</string>
<string name="issue_tracker_link">"Suivie des problèmes"</string> <string name="issue_tracker_link">"Suivie des problèmes"</string>
<string name="issue_tracker_summary">"Pour signaler un bug ou demander une nouvelle fonctionnalité"</string> <string name="issue_tracker_summary">"Pour signaler un bug ou demander une nouvelle fonctionnalité"</string>
<string name="warning_version">"ATTENTION"</string>
<string name="warning_wrong_url">"ATTENTION"</string> <string name="warning_wrong_url">"ATTENTION"</string>
<string name="text_version">"Il semblerait que vous utilisiez une version de l'application ne provenant pas du Play Store. L'application peut avoir été modifié et son utilisation peut être dangereuse. Je ne serai en aucun cas tenu responsable en cas de dommage causé sur votre appareil. Pour éviter tout problème, je vous conseille de télécharger ReaderForSelfoss directement depuis le Play Store."</string>
<string name="pref_switch_card_view_title">"Card View"</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_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="cant_unmark_favortie">"Impossible de retirer l'élément des favoris"</string>
@ -103,20 +101,20 @@
<string name="card_height_on">La taille de la carte s\'adaptera au contenu</string> <string name="card_height_on">La taille de la carte s\'adaptera au contenu</string>
<string name="card_height_off">La taille de la carte sera fixe</string> <string name="card_height_off">La taille de la carte sera fixe</string>
<string name="source_code">Code source</string> <string name="source_code">Code source</string>
<string name="cant_mark_read">Kan het artikel niet als gelezen markeren</string> <string name="cant_mark_read">Impossible de marquer l\'article comme lu</string>
<string name="drawer_error_loading_tags">Erreur lors du chargement des tags…</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_error_loading_sources">Erreur lors du chargement des sources…</string>
<string name="drawer_item_filters">Filtres</string> <string name="drawer_item_filters">Filtres</string>
<string name="drawer_action_clear">raz</string> <string name="drawer_action_clear">raz</string>
<string name="drawer_item_tags">Tags</string> <string name="drawer_item_tags">Tags</string>
<string name="drawer_item_sources">Sources</string> <string name="drawer_item_sources">Sources</string>
<string name="drawer_action_edit">editer</string> <string name="drawer_action_edit">éditer</string>
<string name="cache_drawer_error" tools:keep="@string/cache_drawer_error">Impossible de mettre en cache les filtres pour le drawer</string> <string name="cache_drawer_error" tools:keep="@string/cache_drawer_error">Impossible de mettre en cache les filtres pour le drawer</string>
<string name="no_tags_loaded">Pas de tags chargés</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="no_sources_loaded">Pas de sources chargés</string>
<string name="drawer_loading">Chargement …</string> <string name="drawer_loading">Chargement …</string>
<string name="menu_home_search">Rechercher</string> <string name="menu_home_search">Rechercher</string>
<string name="can_delete_source">Petit soucis lors de la suppression de la source.</string> <string name="can_delete_source">Impossible de supprimer la source</string>
<string name="base_url_error">Il y a eu un souci lors de la communication avec votre instance Selfoss. Si le problèmes persiste, contactez-moi pour trouver une solution.</string> <string name="base_url_error">Il y a eu un souci lors de la communication avec votre instance Selfoss. Si le problèmes persiste, contactez-moi pour trouver une solution.</string>
<string name="pref_header_theme">Thèmes</string> <string name="pref_header_theme">Thèmes</string>
<string name="default_theme">Par défaut</string> <string name="default_theme">Par défaut</string>
@ -134,7 +132,7 @@
<string name="indigo_pink_dark_theme">Indigo/Rose/Foncé</string> <string name="indigo_pink_dark_theme">Indigo/Rose/Foncé</string>
<string name="red_teal_dark_theme">Rouge/Sarcelle/Foncé</string> <string name="red_teal_dark_theme">Rouge/Sarcelle/Foncé</string>
<string name="pref_header_debug">Debug</string> <string name="pref_header_debug">Debug</string>
<string name="login_debug_title">Activez pour loguer toutes les erreurs de conexion</string> <string name="login_debug_title">Activez pour logguer toutes les erreurs de connexion</string>
<string name="login_debug_on">Toutes les erreurs de connexion vont être loguées</string> <string name="login_debug_on">Toutes les erreurs de connexion vont être loguées</string>
<string name="login_debug_off">Aucune erreur de connexion ne sera loguée</string> <string name="login_debug_off">Aucune erreur de connexion ne sera loguée</string>
<string name="login_menu_debug">Debug</string> <string name="login_menu_debug">Debug</string>
@ -144,7 +142,7 @@
<string name="pref_api_items_number_title">Nombre d\'articles chargés</string> <string name="pref_api_items_number_title">Nombre d\'articles chargés</string>
<string name="read_debug_title">Des articles lus marqués comme non lus ?</string> <string name="read_debug_title">Des articles lus marqués comme non lus ?</string>
<string name="read_debug_off">Aucun log quand un article est marqué comme lu</string> <string name="read_debug_off">Aucun log quand un article est marqué comme lu</string>
<string name="read_debug_on">Les appels API vont être logués lorsequ\'un article est marqué comme lu</string> <string name="read_debug_on">Les appels API vont être logués lorsqu\'un article est marqué comme lu</string>
<string name="summary_debug_identifier">Identifiant de debug</string> <string name="summary_debug_identifier">Identifiant de debug</string>
<string name="unique_id_to_clipboard">Texte copié</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_summary">Afficher une entête avec l\'url de votre instance de Selfoss en haut du drawer lateral.</string>
@ -152,7 +150,12 @@
<string name="login_everything_title">Log de tous les appels à l\'API</string> <string name="login_everything_title">Log de tous les appels à l\'API</string>
<string name="login_everything_on">Tous les appels à l\'API vont êtres logués</string> <string name="login_everything_on">Tous les appels à l\'API vont êtres logués</string>
<string name="login_everything_off">Aucun appel à l\'API ne sera logué</string> <string name="login_everything_off">Aucun appel à l\'API ne sera logué</string>
<string name="pref_general_infinite_loading_title">(BETA) Charger plus d\'articles au scroll</string> <string name="pref_general_infinite_loading_title">Charger plus d\'articles au scroll</string>
<string name="translation">Traduction</string> <string name="translation">Traduction</string>
<string name="cant_open_invalid_url">Lurl de lélément nest pas valide. En attendant la résolution du problème, le lien ne s\'ouvrira pas.</string> <string name="cant_open_invalid_url">Lurl de lélément nest pas valide. En attendant la résolution du problème, le lien ne s\'ouvrira pas.</string>
<string name="drawer_report_bug">Signaler un bug</string>
<string name="items_number_should_be_number">Le nombre d\'articles doit être un entier.</string>
<string name="reader_action_more">Lire plus</string>
<string name="reader_action_open">Ouvrir</string>
<string name="reader_action_share">Partager</string>
</resources> </resources>

View File

@ -46,9 +46,7 @@
<string name="pref_header_links">"Links"</string> <string name="pref_header_links">"Links"</string>
<string name="issue_tracker_link">"Issue Tracker"</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="issue_tracker_summary">"Report a bug or ask for a new feature"</string>
<string name="warning_version">"WARNING"</string>
<string name="warning_wrong_url">"WARNING"</string> <string name="warning_wrong_url">"WARNING"</string>
<string name="text_version">"You seem to be using a version of the app that doesn't come from the store. The app could have been tampered with. I will not be responsible if it causes any damage to your device. Consider using the ReaderForSelfoss app from the Play Store."</string>
<string name="pref_switch_card_view_title">"Card View"</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_mark_favortie">"Can't mark article as favorite"</string>
<string name="cant_unmark_favortie">"Can't remove item from favorite"</string> <string name="cant_unmark_favortie">"Can't remove item from favorite"</string>
@ -77,7 +75,7 @@
<string name="prefer_article_viewer_title">"Use the article viewer"</string> <string name="prefer_article_viewer_title">"Use the article viewer"</string>
<string name="prefer_article_viewer_on">"Will use the article viewer instead of the internal browser"</string> <string name="prefer_article_viewer_on">"Will use the article viewer instead of the internal browser"</string>
<string name="prefer_article_viewer_off">"Will use the internal browser instead of the article viewer"</string> <string name="prefer_article_viewer_off">"Will use the internal browser instead of the article viewer"</string>
<string name="pref_general_category_links">"Link handeling"</string> <string name="pref_general_category_links">"Link handling"</string>
<string name="pref_general_category_displaying">"Displaying"</string> <string name="pref_general_category_displaying">"Displaying"</string>
<string name="pref_general_category_actions">"Actions"</string> <string name="pref_general_category_actions">"Actions"</string>
<string name="pref_switch_card_view_on">"The articles will be displayed as cards"</string> <string name="pref_switch_card_view_on">"The articles will be displayed as cards"</string>
@ -116,7 +114,7 @@
<string name="no_sources_loaded">No sources loaded</string> <string name="no_sources_loaded">No sources loaded</string>
<string name="drawer_loading">Loading …</string> <string name="drawer_loading">Loading …</string>
<string name="menu_home_search">Search</string> <string name="menu_home_search">Search</string>
<string name="can_delete_source">Can\'t delete the source...</string> <string name="can_delete_source">Can\'t delete the source</string>
<string name="base_url_error">There was an issue when trying to communicate with your Selfoss Instance. If the issue persists, please get in touch with me.</string> <string name="base_url_error">There was an issue when trying to communicate with your Selfoss Instance. If the issue persists, please get in touch with me.</string>
<string name="pref_header_theme">Themes</string> <string name="pref_header_theme">Themes</string>
<string name="default_theme">Default</string> <string name="default_theme">Default</string>
@ -152,7 +150,12 @@
<string name="login_everything_title">Logging every api calls</string> <string name="login_everything_title">Logging every api calls</string>
<string name="login_everything_on">This will log every api call for debug purpose.</string> <string name="login_everything_on">This will log every api call for debug purpose.</string>
<string name="login_everything_off">No api call will be logged</string> <string name="login_everything_off">No api call will be logged</string>
<string name="pref_general_infinite_loading_title">(BETA) Load more articles on scroll</string> <string name="pref_general_infinite_loading_title">Load more articles on scroll</string>
<string name="translation">Translation</string> <string name="translation">Translation</string>
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string> <string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
<string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

View File

@ -46,9 +46,7 @@
<string name="pref_header_links">"Links"</string> <string name="pref_header_links">"Links"</string>
<string name="issue_tracker_link">"Issue Tracker"</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="issue_tracker_summary">"Report a bug or ask for a new feature"</string>
<string name="warning_version">"WARNING"</string>
<string name="warning_wrong_url">"WARNING"</string> <string name="warning_wrong_url">"WARNING"</string>
<string name="text_version">"You seem to be using a version of the app that doesn't come from the store. The app could have been tampered with. I will not be responsible if it causes any damage to your device. Consider using the ReaderForSelfoss app from the Play Store."</string>
<string name="pref_switch_card_view_title">"Card View"</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_mark_favortie">"Can't mark article as favorite"</string>
<string name="cant_unmark_favortie">"Can't remove item from favorite"</string> <string name="cant_unmark_favortie">"Can't remove item from favorite"</string>
@ -77,7 +75,7 @@
<string name="prefer_article_viewer_title">"Use the article viewer"</string> <string name="prefer_article_viewer_title">"Use the article viewer"</string>
<string name="prefer_article_viewer_on">"Will use the article viewer instead of the internal browser"</string> <string name="prefer_article_viewer_on">"Will use the article viewer instead of the internal browser"</string>
<string name="prefer_article_viewer_off">"Will use the internal browser instead of the article viewer"</string> <string name="prefer_article_viewer_off">"Will use the internal browser instead of the article viewer"</string>
<string name="pref_general_category_links">"Link handeling"</string> <string name="pref_general_category_links">"Link handling"</string>
<string name="pref_general_category_displaying">"Displaying"</string> <string name="pref_general_category_displaying">"Displaying"</string>
<string name="pref_general_category_actions">"Actions"</string> <string name="pref_general_category_actions">"Actions"</string>
<string name="pref_switch_card_view_on">"The articles will be displayed as cards"</string> <string name="pref_switch_card_view_on">"The articles will be displayed as cards"</string>
@ -116,7 +114,7 @@
<string name="no_sources_loaded">No sources loaded</string> <string name="no_sources_loaded">No sources loaded</string>
<string name="drawer_loading">Loading …</string> <string name="drawer_loading">Loading …</string>
<string name="menu_home_search">Search</string> <string name="menu_home_search">Search</string>
<string name="can_delete_source">Can\'t delete the source...</string> <string name="can_delete_source">Can\'t delete the source</string>
<string name="base_url_error">There was an issue when trying to communicate with your Selfoss Instance. If the issue persists, please get in touch with me.</string> <string name="base_url_error">There was an issue when trying to communicate with your Selfoss Instance. If the issue persists, please get in touch with me.</string>
<string name="pref_header_theme">Themes</string> <string name="pref_header_theme">Themes</string>
<string name="default_theme">Default</string> <string name="default_theme">Default</string>
@ -152,7 +150,12 @@
<string name="login_everything_title">Logging every api calls</string> <string name="login_everything_title">Logging every api calls</string>
<string name="login_everything_on">This will log every api call for debug purpose.</string> <string name="login_everything_on">This will log every api call for debug purpose.</string>
<string name="login_everything_off">No api call will be logged</string> <string name="login_everything_off">No api call will be logged</string>
<string name="pref_general_infinite_loading_title">(BETA) Load more articles on scroll</string> <string name="pref_general_infinite_loading_title">Load more articles on scroll</string>
<string name="translation">Translation</string> <string name="translation">Translation</string>
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string> <string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
<string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

View File

@ -46,9 +46,7 @@
<string name="pref_header_links">"Links"</string> <string name="pref_header_links">"Links"</string>
<string name="issue_tracker_link">"Issue Tracker"</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="issue_tracker_summary">"Report a bug or ask for a new feature"</string>
<string name="warning_version">"WARNING"</string>
<string name="warning_wrong_url">"WARNING"</string> <string name="warning_wrong_url">"WARNING"</string>
<string name="text_version">"You seem to be using a version of the app that doesn't come from the store. The app could have been tampered with. I will not be responsible if it causes any damage to your device. Consider using the ReaderForSelfoss app from the Play Store."</string>
<string name="pref_switch_card_view_title">"Card View"</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_mark_favortie">"Can't mark article as favorite"</string>
<string name="cant_unmark_favortie">"Can't remove item from favorite"</string> <string name="cant_unmark_favortie">"Can't remove item from favorite"</string>
@ -77,7 +75,7 @@
<string name="prefer_article_viewer_title">"Use the article viewer"</string> <string name="prefer_article_viewer_title">"Use the article viewer"</string>
<string name="prefer_article_viewer_on">"Will use the article viewer instead of the internal browser"</string> <string name="prefer_article_viewer_on">"Will use the article viewer instead of the internal browser"</string>
<string name="prefer_article_viewer_off">"Will use the internal browser instead of the article viewer"</string> <string name="prefer_article_viewer_off">"Will use the internal browser instead of the article viewer"</string>
<string name="pref_general_category_links">"Link handeling"</string> <string name="pref_general_category_links">"Link handling"</string>
<string name="pref_general_category_displaying">"Displaying"</string> <string name="pref_general_category_displaying">"Displaying"</string>
<string name="pref_general_category_actions">"Actions"</string> <string name="pref_general_category_actions">"Actions"</string>
<string name="pref_switch_card_view_on">"The articles will be displayed as cards"</string> <string name="pref_switch_card_view_on">"The articles will be displayed as cards"</string>
@ -116,7 +114,7 @@
<string name="no_sources_loaded">No sources loaded</string> <string name="no_sources_loaded">No sources loaded</string>
<string name="drawer_loading">Loading …</string> <string name="drawer_loading">Loading …</string>
<string name="menu_home_search">Search</string> <string name="menu_home_search">Search</string>
<string name="can_delete_source">Can\'t delete the source...</string> <string name="can_delete_source">Can\'t delete the source</string>
<string name="base_url_error">There was an issue when trying to communicate with your Selfoss Instance. If the issue persists, please get in touch with me.</string> <string name="base_url_error">There was an issue when trying to communicate with your Selfoss Instance. If the issue persists, please get in touch with me.</string>
<string name="pref_header_theme">Themes</string> <string name="pref_header_theme">Themes</string>
<string name="default_theme">Default</string> <string name="default_theme">Default</string>
@ -152,7 +150,12 @@
<string name="login_everything_title">Logging every api calls</string> <string name="login_everything_title">Logging every api calls</string>
<string name="login_everything_on">This will log every api call for debug purpose.</string> <string name="login_everything_on">This will log every api call for debug purpose.</string>
<string name="login_everything_off">No api call will be logged</string> <string name="login_everything_off">No api call will be logged</string>
<string name="pref_general_infinite_loading_title">(BETA) Load more articles on scroll</string> <string name="pref_general_infinite_loading_title">Load more articles on scroll</string>
<string name="translation">Translation</string> <string name="translation">Translation</string>
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string> <string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
<string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

View File

@ -46,9 +46,7 @@
<string name="pref_header_links">"Links"</string> <string name="pref_header_links">"Links"</string>
<string name="issue_tracker_link">"Issue Tracker"</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="issue_tracker_summary">"Report a bug or ask for a new feature"</string>
<string name="warning_version">"WARNING"</string>
<string name="warning_wrong_url">"WARNING"</string> <string name="warning_wrong_url">"WARNING"</string>
<string name="text_version">"You seem to be using a version of the app that doesn't come from the store. The app could have been tampered with. I will not be responsible if it causes any damage to your device. Consider using the ReaderForSelfoss app from the Play Store."</string>
<string name="pref_switch_card_view_title">"Card View"</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_mark_favortie">"Can't mark article as favorite"</string>
<string name="cant_unmark_favortie">"Can't remove item from favorite"</string> <string name="cant_unmark_favortie">"Can't remove item from favorite"</string>
@ -77,7 +75,7 @@
<string name="prefer_article_viewer_title">"Use the article viewer"</string> <string name="prefer_article_viewer_title">"Use the article viewer"</string>
<string name="prefer_article_viewer_on">"Will use the article viewer instead of the internal browser"</string> <string name="prefer_article_viewer_on">"Will use the article viewer instead of the internal browser"</string>
<string name="prefer_article_viewer_off">"Will use the internal browser instead of the article viewer"</string> <string name="prefer_article_viewer_off">"Will use the internal browser instead of the article viewer"</string>
<string name="pref_general_category_links">"Link handeling"</string> <string name="pref_general_category_links">"Link handling"</string>
<string name="pref_general_category_displaying">"Displaying"</string> <string name="pref_general_category_displaying">"Displaying"</string>
<string name="pref_general_category_actions">"Actions"</string> <string name="pref_general_category_actions">"Actions"</string>
<string name="pref_switch_card_view_on">"The articles will be displayed as cards"</string> <string name="pref_switch_card_view_on">"The articles will be displayed as cards"</string>
@ -116,7 +114,7 @@
<string name="no_sources_loaded">No sources loaded</string> <string name="no_sources_loaded">No sources loaded</string>
<string name="drawer_loading">Loading …</string> <string name="drawer_loading">Loading …</string>
<string name="menu_home_search">Search</string> <string name="menu_home_search">Search</string>
<string name="can_delete_source">Can\'t delete the source...</string> <string name="can_delete_source">Can\'t delete the source</string>
<string name="base_url_error">There was an issue when trying to communicate with your Selfoss Instance. If the issue persists, please get in touch with me.</string> <string name="base_url_error">There was an issue when trying to communicate with your Selfoss Instance. If the issue persists, please get in touch with me.</string>
<string name="pref_header_theme">Themes</string> <string name="pref_header_theme">Themes</string>
<string name="default_theme">Default</string> <string name="default_theme">Default</string>
@ -152,7 +150,12 @@
<string name="login_everything_title">Logging every api calls</string> <string name="login_everything_title">Logging every api calls</string>
<string name="login_everything_on">This will log every api call for debug purpose.</string> <string name="login_everything_on">This will log every api call for debug purpose.</string>
<string name="login_everything_off">No api call will be logged</string> <string name="login_everything_off">No api call will be logged</string>
<string name="pref_general_infinite_loading_title">(BETA) Load more articles on scroll</string> <string name="pref_general_infinite_loading_title">Load more articles on scroll</string>
<string name="translation">Translation</string> <string name="translation">Translation</string>
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string> <string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
<string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

View File

@ -46,9 +46,7 @@
<string name="pref_header_links">"Links"</string> <string name="pref_header_links">"Links"</string>
<string name="issue_tracker_link">"Issue Tracker"</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="issue_tracker_summary">"Report a bug or ask for a new feature"</string>
<string name="warning_version">"WARNING"</string>
<string name="warning_wrong_url">"WARNING"</string> <string name="warning_wrong_url">"WARNING"</string>
<string name="text_version">"You seem to be using a version of the app that doesn't come from the store. The app could have been tampered with. I will not be responsible if it causes any damage to your device. Consider using the ReaderForSelfoss app from the Play Store."</string>
<string name="pref_switch_card_view_title">"Card View"</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_mark_favortie">"Can't mark article as favorite"</string>
<string name="cant_unmark_favortie">"Can't remove item from favorite"</string> <string name="cant_unmark_favortie">"Can't remove item from favorite"</string>
@ -77,7 +75,7 @@
<string name="prefer_article_viewer_title">"Use the article viewer"</string> <string name="prefer_article_viewer_title">"Use the article viewer"</string>
<string name="prefer_article_viewer_on">"Will use the article viewer instead of the internal browser"</string> <string name="prefer_article_viewer_on">"Will use the article viewer instead of the internal browser"</string>
<string name="prefer_article_viewer_off">"Will use the internal browser instead of the article viewer"</string> <string name="prefer_article_viewer_off">"Will use the internal browser instead of the article viewer"</string>
<string name="pref_general_category_links">"Link handeling"</string> <string name="pref_general_category_links">"Link handling"</string>
<string name="pref_general_category_displaying">"Displaying"</string> <string name="pref_general_category_displaying">"Displaying"</string>
<string name="pref_general_category_actions">"Actions"</string> <string name="pref_general_category_actions">"Actions"</string>
<string name="pref_switch_card_view_on">"The articles will be displayed as cards"</string> <string name="pref_switch_card_view_on">"The articles will be displayed as cards"</string>
@ -116,7 +114,7 @@
<string name="no_sources_loaded">No sources loaded</string> <string name="no_sources_loaded">No sources loaded</string>
<string name="drawer_loading">Loading …</string> <string name="drawer_loading">Loading …</string>
<string name="menu_home_search">Search</string> <string name="menu_home_search">Search</string>
<string name="can_delete_source">Can\'t delete the source...</string> <string name="can_delete_source">Can\'t delete the source</string>
<string name="base_url_error">There was an issue when trying to communicate with your Selfoss Instance. If the issue persists, please get in touch with me.</string> <string name="base_url_error">There was an issue when trying to communicate with your Selfoss Instance. If the issue persists, please get in touch with me.</string>
<string name="pref_header_theme">Themes</string> <string name="pref_header_theme">Themes</string>
<string name="default_theme">Default</string> <string name="default_theme">Default</string>
@ -152,7 +150,12 @@
<string name="login_everything_title">Logging every api calls</string> <string name="login_everything_title">Logging every api calls</string>
<string name="login_everything_on">This will log every api call for debug purpose.</string> <string name="login_everything_on">This will log every api call for debug purpose.</string>
<string name="login_everything_off">No api call will be logged</string> <string name="login_everything_off">No api call will be logged</string>
<string name="pref_general_infinite_loading_title">(BETA) Load more articles on scroll</string> <string name="pref_general_infinite_loading_title">Load more articles on scroll</string>
<string name="translation">Translation</string> <string name="translation">Translation</string>
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string> <string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
<string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

Some files were not shown because too many files have changed in this diff Show More