Compare commits

...
385 Commits
Author SHA1 Message Date
aminecmi 193f538d29 Trying fastlane for f-droid repository. Fixes #321. 2021-01-10 21:40:17 +01:00
aminecmi 7f45db0473 Bakcground image caching issues should be fixed. 2021-01-10 21:20:33 +01:00
davidoskky d89423b9ac Fix crash when loading image that doesn't exist (#329)
* Wait until the image is downloaded

* Use timeout
2021-01-10 21:14:23 +01:00
aminecmi 25fd869c01 Closes #322. 2021-01-10 12:13:19 +01:00
davidoskky d1d956b77a Improve image caching (#327)
* Update to support rebase

* Prevent Glide from opening svg images
2021-01-10 05:08:40 +01:00
aminecmi 41c14362a8 Fixes #323. 2021-01-09 15:01:59 +01:00
davidoskky 6fa8c901fc Decode the title of sources containing special html characters (#326)
#325
2021-01-07 21:22:01 +01:00
aminecmi db124ab9de Changelog. 2020-12-24 13:49:32 +01:00
Amine Bou 953940690d New Crowdin updates (#317)
* New translations strings.xml (Sinhala)

* New translations strings.xml (Sinhala)
2020-12-23 09:34:21 +01:00
davidoskky 918661be2d Expand images on tap (#315)
* Detect click on images in WebView

* First stub of the fragment to show the image in full screen

* Scale image dimension to fit the display

* Hide toolbar from Image view

* Add back button to the Image view

* Open one image on tap

* Allow zooming on images

* Revert to using Toolbar for navigation.

* Remove vibration when opening the Image view

* Do not open links associated with images

* Send all images in the webpage to the Image fragment.

* Change image on swipe

* Store article images in cache in background.

* Use PhotoView in place of WebView to display images. Implemented a pager to swipe through images.

* Removed debugging logging.
2020-12-22 20:06:38 +01:00
aminecmi 7b8a5c9a56 Fixed migration issue. 2020-12-22 18:02:03 +01:00
davidoskky 2d5ab7bf0c Fix crash when a feed has no icon (#318) 2020-12-12 19:06:30 +01:00
davidoskky 9ba281befb Position of the elements in list view fixed in place. (#314)
Closes #287
2020-12-08 20:13:33 +01:00
davidoskky 00c8eed034 Fix back button closing settings from submenu (#313)
* Prevent back button from closing the activity.

* Remove redundant overrides

* Do not close the settings after resetting the themes.

Closes #290
2020-12-08 15:36:12 +01:00
davidoskky a1e4f89cd1 Decode title of articles from html (#312)
* Decode the title of the articles from html.

* Remove unused imports.

Closes #300
2020-12-07 22:22:54 +01:00
davidoskky 36a43b3861 Allow the value of the thumbnail to be null. (#311)
Closes #310
2020-12-07 15:48:58 +01:00
Amine Bou aa6d470f40 Update README.md 2020-11-14 14:06:09 +01:00
Amine Bou 0046a8a477 New Crowdin updates (#304)
* New translations strings.xml (French)

* New translations strings.xml (Spanish)

* New translations strings.xml (Catalan)

* New translations strings.xml (German)

* New translations strings.xml (Italian)

* New translations strings.xml (Korean)

* New translations strings.xml (Dutch)

* New translations strings.xml (Portuguese)

* New translations strings.xml (Turkish)

* New translations strings.xml (Chinese Simplified)

* New translations strings.xml (Chinese Traditional)

* New translations strings.xml (Galician)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Indonesian)

* New translations strings.xml (Persian)
2020-07-13 13:49:40 +02:00
Amine Bou 43ff9d186a Update README.md 2020-07-13 11:49:57 +02:00
aminecmi 73dae304be Added screenshots. 2020-07-13 08:59:34 +02:00
Amine Bou 66103a451b Update README.md 2020-04-29 10:38:05 +02:00
Amine Bou 600c62316d Update README.md 2020-04-28 21:49:07 +02:00
aminecmi d370ddc4d1 Fixed dark mode webview background. 2020-02-01 14:30:48 +01:00
aminecmi 4049f6a5c7 Removed acra because the issues wern't sent anyway. 2020-02-01 14:30:03 +01:00
Hector 3e96ac207e Created new LoggingInterceptor that doesn't log any errors related to… (#291)
* Created new LoggingInterceptor that doesn't log any errors related to SocketTimeoutException.

* Formatted with ktlint

* Intercept timeoutException to bypass the logging but still throwing an exception.
2019-10-12 19:36:55 +02:00
aminecmi 84f1ab12cf Finally fixed issue with crash on launch. 2019-05-17 20:28:21 +02:00
aminecmi f48f6ed788 Trying to fix crashes. 2019-05-17 19:05:11 +02:00
aminecmi e517803bd8 Fixed a bug with theme settings page. 2019-05-12 21:42:56 +02:00
aminecmi 3eaf390790 Background thing issue. 2019-05-12 21:38:10 +02:00
aminecmi 6de54d63e6 Updates. 2019-05-12 21:17:45 +02:00
aminecmi dd7a2f476b Fixed an issue with compilation not working. 2019-05-12 21:07:05 +02:00
aminecmi 1485cc05f4 Fixing dark background webview. 2019-04-06 12:50:30 +02:00
aminecmi d1dad3e61a Cleaning and update. 2019-04-06 12:42:25 +02:00
Amine Bou e5024b0420 Update README.md 2019-04-04 10:17:51 +02:00
Amine Bou 9b01692c55 Update README.md 2019-03-16 19:19:29 +01:00
Amine Bou 33aa587d36 Update index.html 2019-03-16 11:26:57 +01:00
Amine Bou 12e0766803 No more playstore. 2019-03-16 09:06:06 +01:00
aminecmi a8721ad7a4 Should intercept socket timeout errors. 2019-01-30 21:11:24 +01:00
Amine Bou bc5e882894 New translations strings.xml (Chinese Traditional) (#280) 2019-01-29 08:39:28 +01:00
aminecmi e3460322b1 Closes #279. 2019-01-27 13:59:28 +01:00
aminecmi 7e3288a076 For now not sending issue report for #278. 2019-01-27 13:47:41 +01:00
aminecmi ddc754ec25 Closes #270. 2019-01-15 19:54:46 +01:00
aminecmi 134a0766d6 Updates. 2019-01-14 20:56:12 +01:00
aminecmi 69da932ab5 Just to be sure. 2019-01-14 19:39:54 +01:00
aminecmi 592fb6328a Workaround for #275. 2019-01-14 19:37:43 +01:00
aminecmi a0aead6491 Closes #271. 2019-01-13 15:59:38 +01:00
aminecmi 722b6cc06d Fixed issue with read/unread cont when swiping. 2019-01-13 15:59:38 +01:00
aminecmi 6d7c4b40f6 Wip fixing the badges reloading when reading all the items. 2019-01-13 15:59:38 +01:00
Amine Bou f538ed39fc New translations strings.xml (Chinese Traditional) (#274) 2019-01-11 14:20:35 +01:00
Amine Bou 65821492ad New Crowdin translations (#273)
* New translations strings.xml (Catalan)

* New translations strings.xml (Chinese Simplified)

* New translations strings.xml (Chinese Traditional)

* New translations strings.xml (Dutch)

* New translations strings.xml (French)

* New translations strings.xml (Galician)

* New translations strings.xml (German)

* New translations strings.xml (Indonesian)

* New translations strings.xml (Italian)

* New translations strings.xml (Korean)

* New translations strings.xml (Portuguese)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Spanish)

* New translations strings.xml (Turkish)

* New translations strings.xml (Galician)

* New translations strings.xml (Spanish)

* New translations strings.xml (French)
2019-01-10 11:19:46 +01:00
aminecmi 6ede718a9f Closes #269. 2019-01-09 21:28:55 +01:00
Amine Bou f1757937a4 Disabled resources shrinking after #262. 2019-01-09 13:33:02 +01:00
Binnette 2bd2e0a953 Vector assets (#262) 2019-01-09 10:43:49 +01:00
Amine Bou b5aef28af0 New Crowdin translations (#268)
* New translations strings.xml (Galician)

* New translations strings.xml (Spanish)
2019-01-08 10:00:28 +01:00
Amine Bou 45747a1506 New Crowdin translations (#267)
* New translations strings.xml (Catalan)

* New translations strings.xml (Chinese Simplified)

* New translations strings.xml (Chinese Traditional)

* New translations strings.xml (Dutch)

* New translations strings.xml (French)

* New translations strings.xml (Galician)

* New translations strings.xml (German)

* New translations strings.xml (Indonesian)

* New translations strings.xml (Italian)

* New translations strings.xml (Korean)

* New translations strings.xml (Portuguese)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Spanish)

* New translations strings.xml (Turkish)

* New translations strings.xml (French)
2019-01-06 18:46:38 +01:00
Amine Bou c6e2e08bcb Merge pull request #265 from aminecmi/feature/261
WIP: Webview font
2019-01-06 18:25:26 +01:00
aminecmi 25bf18661e Adde a bigger line-height. 2019-01-06 18:17:10 +01:00
aminecmi 6b088dcd24 Font family. 2019-01-06 18:12:18 +01:00
aminecmi d2b18e1880 Removed lazy loaded fonts. 2019-01-06 16:26:40 +01:00
Amine eec7c94e98 WIP. 2019-01-06 16:16:35 +01:00
Amine d1f8fcacc0 Changelog. 2019-01-05 21:47:45 +01:00
Amine 07e4a33cbd Closes #266. 2019-01-05 21:43:09 +01:00
Amine f6317f566e Same change for hidden tags. 2019-01-02 21:30:26 +01:00
Amine 9f51e4e6a5 Closes #264 2019-01-02 21:21:32 +01:00
Amine Bou 750604a31f Languages cleaning. (#260) 2018-12-12 21:49:38 +01:00
Amine Bou 392eee0ad4 New Crowdin translations (#258)
* New translations strings.xml (Catalan)

* New translations strings.xml (Japanese)

* New translations strings.xml (Vietnamese)

* 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 (Afrikaans)

* New translations strings.xml (Indonesian)

* 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 (Chinese Simplified)

* New translations strings.xml (Arabic)

* New translations strings.xml (Galician)

* New translations strings.xml (French)

* New translations strings.xml (Spanish)

* New translations strings.xml (Galician)
2018-12-10 19:26:48 +01:00
Amine 37e7b987ee Changed color of alignment icons. 2018-12-10 19:25:18 +01:00
Amine 9eac51e729 Closes #257. 2018-12-09 16:38:35 +01:00
Amine fa9cce6783 Removed some logs. 2018-12-09 14:26:20 +01:00
Amine Bou f0d4b63a97 Merge pull request #256 from aminecmi/fdroid/build
Fixes #254 and #255.
2018-12-02 13:22:37 +01:00
Amine 83eeb11388 Fixes #254 and #255. 2018-12-02 13:13:19 +01:00
Amine Bou 01f746f33d Merge pull request #255 from aminecmi/fdroid/build
A fix for #254.
2018-12-02 03:54:36 +01:00
Amine 200851894b See #254. 2018-12-01 19:32:28 +01:00
Amine Bou 862e5cf4ab New Crowdin translations (#253)
* New translations strings.xml (Spanish)

* New translations strings.xml (Galician)

* New translations strings.xml (Spanish)
2018-11-29 06:06:32 +01:00
Amine 0b07f2a407 Closes #174. Closes #248. 2018-11-28 21:03:00 +01:00
Amine 9ba6feef0b Removed density calculation to solve #248. 2018-11-27 21:44:34 +01:00
Amine 63a0638522 Removed throw... 2018-11-27 21:36:12 +01:00
Amine Bou f9a4e6e363 New Crowdin translations (#252)
* New translations strings.xml (Catalan)

* New translations strings.xml (Japanese)

* New translations strings.xml (Vietnamese)

* 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 (Afrikaans)

* New translations strings.xml (Indonesian)

* 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 (Chinese Simplified)

* New translations strings.xml (Arabic)

* New translations strings.xml (Galician)

* New translations strings.xml (Catalan)

* New translations strings.xml (Japanese)

* New translations strings.xml (Vietnamese)

* 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 (Afrikaans)

* New translations strings.xml (Indonesian)

* 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 (Chinese Simplified)

* New translations strings.xml (Arabic)

* New translations strings.xml (Galician)

* New translations strings.xml (French)
2018-11-27 21:32:12 +01:00
Amine 6b40fd4bdc Typos. 2018-11-27 21:25:18 +01:00
Amine 04c7776466 Trying to fix an issue with webview not available with the article viewer. Fixed an issue when the browser isn't available. 2018-11-27 21:14:03 +01:00
Amine 92c335b4e1 Closes #251. 2018-11-27 20:02:53 +01:00
Amine Bou 17251e576b New Crowdin translations (#250)
* New translations strings.xml (Catalan)

* New translations strings.xml (Catalan)

* New translations strings.xml (Catalan)
2018-11-27 15:27:24 +01:00
Amine Bou 62ea782429 Update CONTRIBUTING.md 2018-11-26 16:22:34 +01:00
Amine Bou f99474e3c1 Update CONTRIBUTING.md 2018-11-26 16:21:39 +01:00
Amine Bou 57ac8f428f Update README.md 2018-11-26 16:14:48 +01:00
Amine 9cc1adbf15 Changing acra errors handling. 2018-11-24 09:47:58 +01:00
Amine 1d9a440ae7 Do not log for test labs devices. 2018-11-22 19:50:15 +01:00
Amine Bou 511553806c No idea why this was changed. 2018-11-21 09:57:44 +01:00
Amine Bou 87e7d7c4fe New Crowdin translations (#247)
* New translations strings.xml (German)

* New translations strings.xml (German)

* New translations strings.xml (German)
2018-11-21 08:51:38 +01:00
Amine ec87089310 Fixed issue with Android 9 and CLEARTEXT communication issue. 2018-11-20 21:06:05 +01:00
Amine d8478ebb01 Added loging url validation. 2018-11-20 19:44:10 +01:00
Amine Bou 600adc81b5 Merge pull request #246 from Binnette/ExtraSubject
Add a vertical scrollbar to article fragment
2018-11-17 20:51:10 +01:00
Amine ddac2870af Changed git tag sort for it to work on the jenkins server. 2018-11-17 20:48:18 +01:00
Binnette 8d9c8c1394 Add a vertical scrollbar to article fragment 2018-11-17 20:37:21 +01:00
Amine Bou b59c3bcb23 Merge pull request #245 from Binnette/ExtraSubject
Add EXTRA_SUBJECT when sharing link
2018-11-17 19:46:51 +01:00
Binnette 7f554adba5 Add EXTRA_SUBJECT when sharing link 2018-11-17 18:07:38 +01:00
Amine 21ce061282 Better handling for version code automation. 2018-11-15 21:11:15 +01:00
Amine bdb71e9b14 Note for build. 2018-11-13 22:02:44 +01:00
Amine df22e7de15 Still not working. 2018-11-13 22:01:41 +01:00
Amine 6b3550396b Jenkins not executing the rest of the script. 2018-11-13 21:59:28 +01:00
Amine c70f1e31a6 Added fetch to the build script. 2018-11-13 21:57:36 +01:00
Amine 695670e944 Still fixing the local publish issue. 2018-11-13 21:47:12 +01:00
Amine 1028826788 No more local publish. 2018-11-13 21:45:10 +01:00
Amine 82a8977c96 Closes #244. 2018-11-13 20:24:06 +01:00
Amine Bou 07d9ce1054 New Crowdin translations (#243)
* New translations strings.xml (Spanish)

* New translations strings.xml (Galician)
2018-11-13 15:51:16 +01:00
Amine Bou 7da7d49277 New Crowdin translations (#242)
* New translations strings.xml (Catalan)

* New translations strings.xml (Japanese)

* New translations strings.xml (Vietnamese)

* 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 (Afrikaans)

* New translations strings.xml (Indonesian)

* 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 (Chinese Simplified)

* New translations strings.xml (Arabic)

* New translations strings.xml (Galician)
2018-11-11 17:17:37 +01:00
Amine 9b45365441 Changelog. Previous commit should close #238. 2018-11-11 12:25:45 +01:00
Amine 91a7464bce Added experimental settings with a custom timeout setting. 2018-11-11 12:23:59 +01:00
Amine Bou 51add226eb New Crowdin translations (#241)
* New translations strings.xml (Spanish)

* New translations strings.xml (Galician)
2018-11-08 08:59:37 +01:00
Amine Bou 332e9f5108 New Crowdin translations (#240)
* New translations strings.xml (Catalan)

* New translations strings.xml (Japanese)

* New translations strings.xml (Vietnamese)

* 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 (Afrikaans)

* New translations strings.xml (Indonesian)

* 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 (Chinese Simplified)

* New translations strings.xml (Arabic)

* New translations strings.xml (Galician)

* New translations strings.xml (French)
2018-11-07 21:25:14 +01:00
Amine 0b91087c07 CHANGELOG. 2018-11-07 21:22:19 +01:00
Amine ebbb1ba0f8 Closes #220. 2018-11-07 21:22:06 +01:00
Amine e9143ae852 Initial changes for #238. 2018-11-07 21:07:29 +01:00
Amine 42e8ecee78 Offline shortcut. 2018-11-07 21:05:23 +01:00
Amine 4efd76fcbc Tab selection from app shortcut. 2018-11-07 20:45:51 +01:00
Amine fb1614070e Inital app shortcuts. 2018-11-07 20:25:48 +01:00
Amine c473dd7227 Fixes #239. 2018-11-07 19:32:10 +01:00
Amine Bou 76bddb195d New Crowdin translations (#237)
* New translations strings.xml (Catalan)

* New translations strings.xml (Japanese)

* New translations strings.xml (Vietnamese)

* 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 (Afrikaans)

* New translations strings.xml (Indonesian)

* 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 (Chinese Simplified)

* New translations strings.xml (Arabic)

* New translations strings.xml (Galician)

* New translations strings.xml (French)
2018-11-06 20:35:30 +01:00
Amine 1e02ad2041 Closes #201. 2018-11-06 20:29:00 +01:00
Amine f6ab909f8b Fixed issue. 2018-11-06 20:11:07 +01:00
Amine 7e520e9bed Still fixing selfoss version issues. 2018-11-05 21:11:25 +01:00
Amine 32e2d05014 CHANGELOG. 2018-11-05 20:30:58 +01:00
Amine 40d9c97f73 Fixes #216. 2018-11-05 20:30:37 +01:00
Amine Bou 1aa68d3449 New Crowdin translations (#234)
* New translations strings.xml (Chinese Simplified)

* New translations strings.xml (Galician)

* New translations strings.xml (Spanish)

* New translations strings.xml (Galician)
2018-11-05 13:44:22 +01:00
Amine aeeac8cccd Little fix. 2018-11-04 14:56:48 +01:00
Amine 7292edf997 #Closes #179. 2018-11-04 14:37:22 +01:00
Amine f49256c72f Manual sync for read/unread/star/unstar. 2018-11-04 14:33:50 +01:00
Amine d02b28b81f Initial changes for #179. 2018-11-04 14:25:05 +01:00
Amine 08117043dd Do not replace the background task. 2018-11-03 21:07:27 +01:00
Amine Bou 63496c993e New Crowdin translations (#233)
* New translations strings.xml (Catalan)

* New translations strings.xml (Japanese)

* New translations strings.xml (Vietnamese)

* 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 (Afrikaans)

* New translations strings.xml (Indonesian)

* 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 (Chinese Simplified)

* New translations strings.xml (Arabic)

* New translations strings.xml (Galician)

* New translations strings.xml (French)

* New translations strings.xml (Chinese Simplified)
2018-11-03 19:01:40 +01:00
Amine 00ef542e49 Closes #33. 2018-11-03 18:48:50 +01:00
Amine a78c6e6b33 Sync with settings. 2018-11-03 18:47:43 +01:00
Amine 363eaf9bf9 Preferences for the background tasks. 2018-11-03 18:14:22 +01:00
Amine fec6683701 Merge branch 'master' of github.com:aminecmi/ReaderforSelfoss 2018-11-03 11:30:13 +01:00
Amine 1549edb647 ... 2018-11-03 11:29:53 +01:00
Amine 3de48ba162 Some more background tasks. 2018-11-03 11:29:03 +01:00
Amine Bou a2a3d6f1a7 New Crowdin translations (#232)
* New translations strings.xml (Spanish)

* New translations strings.xml (Galician)

* New translations strings.xml (French)
2018-11-02 10:34:04 +01:00
Amine ccab2c7648 Initial work on background task. 2018-11-01 21:51:31 +01:00
Amine Bou 880dd1db5c New Crowdin translations (#231)
* New translations strings.xml (Catalan)

* New translations strings.xml (Japanese)

* New translations strings.xml (Vietnamese)

* 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 (Afrikaans)

* New translations strings.xml (Indonesian)

* 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 (Chinese Simplified)

* New translations strings.xml (Arabic)

* New translations strings.xml (Galician)
2018-11-01 21:27:59 +01:00
Amine ed18fea356 Closes #38. 2018-11-01 21:11:54 +01:00
Amine 9816b20bf6 Only do api calls on network available. 2018-11-01 21:10:00 +01:00
Amine 0bb2195bff Network status on articles loading. 2018-11-01 20:42:49 +01:00
Amine ab2d0c4036 Closes #230. 2018-10-31 20:14:20 +01:00
Amine 99fc417109 Fixed #230. 2018-10-29 19:53:41 +01:00
Amine dc304ef8c1 Updated gradle. 2018-10-20 09:29:09 +02:00
Amine c5511880bc Just trying to fix fragment issues. 2018-10-19 05:27:16 +02:00
Amine 5fe76d735e Remiving items from the cache on swipe. 2018-10-17 20:19:35 +02:00
Amine 3064b3b835 Closes #228 by removing the list action bar. Action buttons are exclusively on the card view from now on. 2018-10-17 19:46:30 +02:00
Amine Bou 70dc8af3ce New Crowdin translations (#227)
* New translations strings.xml (Spanish)

* New translations strings.xml (Galician)
2018-10-16 08:33:34 +02:00
Amine 53c8c241da Order By id desc for items. 2018-10-14 18:56:07 +02:00
Amine bdc4f5680b Merge branch 'crowdin_translation' 2018-10-14 16:58:15 +02:00
Amine ed290573b2 Merge branch 'master' into crowdin_translation 2018-10-14 16:57:45 +02:00
Amine Bou 1616a97a8a New translations strings.xml (French) 2018-10-14 16:32:43 +02:00
Amine Bou d090183007 New translations strings.xml (French) 2018-10-14 16:31:09 +02:00
Amine de337fd260 Moving to version 1.7 with caching. 2018-10-14 15:59:02 +02:00
Amine 12dc206323 Build with optional publish. 2018-10-14 15:57:22 +02:00
Amine Bou d47c508dee New translations strings.xml (Galician) 2018-10-14 15:42:10 +02:00
Amine Bou ed75f55437 New translations strings.xml (Arabic) 2018-10-14 15:42:09 +02:00
Amine Bou 5ad3ad4a57 New translations strings.xml (Chinese Simplified) 2018-10-14 15:42:07 +02:00
Amine Bou aeac1bd1d4 New translations strings.xml (Chinese Traditional) 2018-10-14 15:42:06 +02:00
Amine Bou 4d18085072 New translations strings.xml (Czech) 2018-10-14 15:42:04 +02:00
Amine Bou 0c9f8214ca New translations strings.xml (Danish) 2018-10-14 15:42:03 +02:00
Amine Bou a7ce7ce02e New translations strings.xml (Dutch) 2018-10-14 15:42:01 +02:00
Amine Bou 820986c7f0 New translations strings.xml (Finnish) 2018-10-14 15:42:00 +02:00
Amine Bou 8079cae745 New translations strings.xml (French) 2018-10-14 15:41:59 +02:00
Amine Bou 6f067bd258 New translations strings.xml (German) 2018-10-14 15:41:58 +02:00
Amine Bou b6ade0f212 New translations strings.xml (Greek) 2018-10-14 15:41:56 +02:00
Amine Bou 27dadc1be3 New translations strings.xml (Hebrew) 2018-10-14 15:41:55 +02:00
Amine Bou 95e4162b4c New translations strings.xml (Hungarian) 2018-10-14 15:41:54 +02:00
Amine Bou f75557585e New translations strings.xml (Indonesian) 2018-10-14 15:41:52 +02:00
Amine Bou 1b4c26919b New translations strings.xml (Afrikaans) 2018-10-14 15:41:51 +02:00
Amine Bou ad085bf129 New translations strings.xml (Italian) 2018-10-14 15:41:50 +02:00
Amine Bou 8fcd551105 New translations strings.xml (Korean) 2018-10-14 15:41:48 +02:00
Amine Bou a0954700e2 New translations strings.xml (Norwegian) 2018-10-14 15:41:47 +02:00
Amine Bou 9705560442 New translations strings.xml (Polish) 2018-10-14 15:41:45 +02:00
Amine Bou 1f47a13ce5 New translations strings.xml (Portuguese) 2018-10-14 15:41:44 +02:00
Amine Bou 6f0ff2c975 New translations strings.xml (Portuguese, Brazilian) 2018-10-14 15:41:43 +02:00
Amine Bou 76e5477986 New translations strings.xml (Romanian) 2018-10-14 15:41:41 +02:00
Amine Bou 7f308d5be3 New translations strings.xml (Russian) 2018-10-14 15:41:40 +02:00
Amine Bou 54a43c83e8 New translations strings.xml (Serbian (Cyrillic)) 2018-10-14 15:41:38 +02:00
Amine Bou 8fe7266c84 New translations strings.xml (Spanish) 2018-10-14 15:41:37 +02:00
Amine Bou d7a46b27b7 New translations strings.xml (Swedish) 2018-10-14 15:41:36 +02:00
Amine Bou 2257d09fdd New translations strings.xml (Turkish) 2018-10-14 15:41:34 +02:00
Amine Bou 047c5481c4 New translations strings.xml (Ukrainian) 2018-10-14 15:41:33 +02:00
Amine Bou 8a6719f934 New translations strings.xml (Vietnamese) 2018-10-14 15:41:32 +02:00
Amine Bou 51a692f3be New translations strings.xml (Japanese) 2018-10-14 15:41:30 +02:00
Amine Bou b333f93171 New translations strings.xml (Catalan) 2018-10-14 15:41:29 +02:00
Amine 89d34a1a71 Closes #1. May need some fine tuning. 2018-10-14 15:38:06 +02:00
Amine 8788e920ce More resources cleaning. 2018-10-14 11:25:14 +02:00
Amine d306fb53d3 Migration with new table and schemas. 2018-10-14 11:17:24 +02:00
Amine 374537b5c7 Preparing for room migrations. Some cleaning. 2018-10-14 11:07:10 +02:00
Amine 598149d4cd Publish version. 2018-10-13 22:13:56 +02:00
Amine Bou 50bcf18096 New translations strings.xml (Galician) 2018-10-13 22:11:24 +02:00
Amine Bou a089ced03f New translations strings.xml (Arabic) 2018-10-13 22:11:23 +02:00
Amine Bou 1f18dddf8b New translations strings.xml (Chinese Simplified) 2018-10-13 22:11:21 +02:00
Amine Bou f5934e240e New translations strings.xml (Chinese Traditional) 2018-10-13 22:11:20 +02:00
Amine Bou 6b8da2eacf New translations strings.xml (Czech) 2018-10-13 22:11:19 +02:00
Amine Bou f4757a67b7 New translations strings.xml (Danish) 2018-10-13 22:11:17 +02:00
Amine Bou 6edeb9d840 New translations strings.xml (Dutch) 2018-10-13 22:11:16 +02:00
Amine Bou 43ce0fd7bc New translations strings.xml (Finnish) 2018-10-13 22:11:15 +02:00
Amine Bou 5599f5a8fc New translations strings.xml (French) 2018-10-13 22:11:13 +02:00
Amine Bou 6fd45ceb4f New translations strings.xml (German) 2018-10-13 22:11:12 +02:00
Amine Bou 05ad8aac29 New translations strings.xml (Greek) 2018-10-13 22:11:11 +02:00
Amine Bou fa4f2476b7 New translations strings.xml (Hebrew) 2018-10-13 22:11:10 +02:00
Amine Bou 00818a94e9 New translations strings.xml (Hungarian) 2018-10-13 22:11:08 +02:00
Amine Bou 5d5250e44a New translations strings.xml (Indonesian) 2018-10-13 22:11:07 +02:00
Amine Bou 3052b33132 New translations strings.xml (Afrikaans) 2018-10-13 22:11:06 +02:00
Amine Bou 50de6f8b5b New translations strings.xml (Italian) 2018-10-13 22:11:04 +02:00
Amine Bou f88a2f415f New translations strings.xml (Norwegian) 2018-10-13 22:11:02 +02:00
Amine Bou 96f9813e01 New translations strings.xml (Polish) 2018-10-13 22:11:01 +02:00
Amine Bou fee739cb17 New translations strings.xml (Portuguese) 2018-10-13 22:11:00 +02:00
Amine Bou b1814c63b9 New translations strings.xml (Portuguese, Brazilian) 2018-10-13 22:10:59 +02:00
Amine Bou c1d45678f8 New translations strings.xml (Romanian) 2018-10-13 22:10:58 +02:00
Amine Bou 3d34e59a94 New translations strings.xml (Russian) 2018-10-13 22:10:56 +02:00
Amine Bou f1133bea8b New translations strings.xml (Spanish) 2018-10-13 22:10:54 +02:00
Amine Bou ec64c88ff1 New translations strings.xml (Swedish) 2018-10-13 22:10:53 +02:00
Amine Bou be66dbba6c New translations strings.xml (Turkish) 2018-10-13 22:10:52 +02:00
Amine Bou 8926cdbbf5 New translations strings.xml (Vietnamese) 2018-10-13 22:10:50 +02:00
Amine Bou a956870dec New translations strings.xml (Japanese) 2018-10-13 22:10:49 +02:00
Amine Bou 8ed7951c9b New translations strings.xml (Catalan) 2018-10-13 22:10:48 +02:00
Amine 5569a47674 Some cleaning and preparing for items storage in room. 2018-10-13 22:02:13 +02:00
Amine 0dc6981913 Removed some unused resources. 2018-10-13 21:14:08 +02:00
Amine 4984f2f7ad Removed the intro. It was causing issues. 2018-10-13 20:49:26 +02:00
Amine 3b6891c84a App was a little slow with livedata. 2018-10-13 10:24:58 +02:00
Amine 4901e7174c Still trying to fix the build issue. 2018-10-13 04:52:55 +02:00
Amine 8d70e68fe2 Trying to fix build issue. 2018-10-12 22:50:43 +02:00
Amine d3e1527b70 AS changes gradle version to one that does not exist. 2018-10-12 22:29:33 +02:00
Amine 0c201301f2 Replaced reservoir by room. 2018-10-12 22:04:47 +02:00
Amine 6090590f24 Imports cleaning. Libraries update. 2018-10-12 21:01:39 +02:00
Amine 06b88c783d Auto migration to android x. 2018-10-12 20:36:18 +02:00
Amine bb75ebf635 Merge branch 'master' of github.com:aminecmi/ReaderforSelfoss 2018-10-07 22:30:30 +02:00
Amine 7d7d0014be Fixes #83. The issue wasn't selfoss related at all... 2018-10-07 22:30:07 +02:00
Amine Bou b3f8d44794 New Crowdin translations (#224)
* New translations strings.xml (Korean)

* New translations strings.xml (Korean)

* New translations strings.xml (Korean)
2018-10-03 14:35:03 +02:00
Amine 29d1e38340 Fixes #223. Fixes internal reader issue on 4.2.2 2018-09-30 09:37:22 +02:00
Amine 2be872e61e Fixed version update. 2018-09-25 20:56:25 +02:00
Amine 377c5518f7 Minimal versions updates. 2018-09-25 20:47:38 +02:00
Amine 21be7357b5 Revert "Updated to androidx."
This reverts commit d47ba2c820.
2018-09-25 20:27:27 +02:00
Amine d47ba2c820 Updated to androidx. 2018-09-25 20:08:51 +02:00
Amine Bou a64b14614a New Crowdin translations (#222)
* New translations strings.xml (Italian)

* New translations strings.xml (Italian)

* New translations strings.xml (Italian)
2018-09-24 08:06:00 +02:00
Amine 6a88192e77 Fixes #221 2018-09-21 21:39:37 +02:00
Amine aa7c630818 erge branch 'master' of github.com:aminecmi/ReaderforSelfoss 2018-09-15 16:26:22 +02:00
Amine 7fb54f14c7 Fixed bug 2018-09-15 16:24:29 +02:00
Amine Bou 3d709c02b7 New Crowdin translations (#219)
* New translations strings.xml (French)

* New translations strings.xml (French)

* New translations strings.xml (Spanish)

* New translations strings.xml (Galician)
2018-09-12 13:16:07 +02:00
Amine 339d384561 Changelog. 2018-09-10 20:29:22 +02:00
Amine Bou 50338d51af New Crowdin translations (#218)
* New translations strings.xml (French)

* New translations strings.xml (French)
2018-09-10 15:17:16 +02:00
Amine Bou 92dbabf899 New Crowdin translations (#217)
* New translations strings.xml (Catalan)

* New translations strings.xml (Japanese)

* New translations strings.xml (Vietnamese)

* 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 (Afrikaans)

* New translations strings.xml (Indonesian)

* 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 (Chinese Simplified)

* New translations strings.xml (Arabic)

* New translations strings.xml (Galician)
2018-09-09 20:59:34 +02:00
Amine 0043021390 Merge branch 'master' of github.com:aminecmi/ReaderforSelfoss 2018-09-09 20:40:13 +02:00
Amine 70ba9b20da Items marked as read on open. Closes #208. 2018-09-09 20:39:27 +02:00
Amine 7fda0a04a1 Fixes #215. 2018-09-09 19:45:49 +02:00
Amine 3db3157dc9 Trying to fix a strange issue with the loading when hiding items.. 2018-09-09 19:44:01 +02:00
Amine Bou 2089fe60ca New Crowdin translations (#214)
* New translations strings.xml (Galician)

* New translations strings.xml (French)

* New translations strings.xml (Spanish)
2018-08-06 15:49:50 +02:00
Amine 9606d36670 Hiding hidden tags from the "normal" tags section. 2018-08-03 09:49:49 +02:00
Amine Bou 869cf64c54 New Crowdin translations (#213)
* New translations strings.xml (Catalan)

* New translations strings.xml (Japanese)

* New translations strings.xml (Vietnamese)

* 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 (Afrikaans)

* New translations strings.xml (Indonesian)

* 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 (Chinese Simplified)

* New translations strings.xml (Arabic)

* New translations strings.xml (Galician)
2018-08-02 22:33:58 +02:00
Amine Bou f57ec1f6c0 Add hidden tags option (#212)
* Add filter for hidden tags. (#207)

This commit adds the option to configure hidden tags. Articles tagged
with these hidden tags won't appear in the list of articles by default.
To see these articles the user must explicitly filter by those tags.

* Closes #211. Handling hidden tags in the lateral panel.

* Changelog.
2018-08-02 22:04:15 +02:00
Amine Bou 361eea9a06 New Crowdin translations (#209)
* New translations strings.xml (Galician)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Portuguese, Brazilian)
2018-08-01 20:34:39 +02:00
Licaon_Kter 838b4056ac Add store logos, put badges on the same line (#210)
* Add store logos, put badges on the same line

* fix link

* Changed Jenkins url.
2018-08-01 20:32:21 +02:00
Amine Bou 0c0a98510b New translations strings.xml (Galician) (#206) 2018-07-17 19:21:42 +02:00
Amine Bou be642ed06f New Crowdin translations (#205)
* New translations strings.xml (Galician)

* New translations strings.xml (Galician)

* New translations strings.xml (Galician)
2018-07-17 17:47:45 +02:00
Amine Bou fd77f38e95 New Crowdin translations (#204)
* New translations strings.xml (Spanish)

* New translations strings.xml (Spanish)

* New translations strings.xml (Galician)

* New translations strings.xml (Galician)
2018-07-17 17:12:01 +02:00
Amine Bou c9baab7267 New Crowdin translations (#203)
* New translations strings.xml (Spanish)

* New translations strings.xml (Spanish)

* New translations strings.xml (Spanish)

* New translations strings.xml (Spanish)
2018-07-17 11:01:54 +02:00
Amine Bou 86985cfd5b Update README.md 2018-07-16 11:24:56 +02:00
Amine 1327a4e069 Merge branch 'master' of github.com:aminecmi/ReaderforSelfoss 2018-07-07 13:52:53 +02:00
Amine c46acbc579 Dependencies update to solve fdroid issues. 2018-07-07 13:50:32 +02:00
Amine Bou 4c6a403fae New Crowdin translations (#202)
* New translations strings.xml (Catalan)

* New translations strings.xml (Catalan)
2018-06-15 13:45:01 +02:00
Amine Bou 78920022bd Update 2018-06-04 19:22:40 +02:00
Amine Bou 7b16c41e82 Added the alpha steps. 2018-06-04 19:22:05 +02:00
Amine Bou 3389f8bd09 New Crowdin translations (#200)
* New translations strings.xml (Catalan)

* New translations strings.xml (Catalan)

* New translations strings.xml (Catalan)

* New translations strings.xml (Catalan)
2018-06-03 17:20:36 +02:00
Amine Bou 8dc25c527d Trying to fix issues with Glide, fragment, and destroyed activity. 2018-05-31 22:41:23 +02:00
Amine Bou 46d6bd57c1 Changelog. 2018-05-31 12:46:45 +02:00
Amine Bou db014fe13d Fixed issue on pre lolipop devices. 2018-05-31 12:42:06 +02:00
Amine Bou 6c293f4cac Changing the tag handling. 2018-05-26 10:51:11 +02:00
Amine Bou 91e5d3736f Cleaning build script. 2018-05-25 22:47:36 +02:00
Amine Bou e11dee220f Adde dHTTP version check for fdroid. 2018-05-25 22:22:32 +02:00
Amine Bou fcebf916d2 New translations strings.xml (French) (#199) 2018-05-25 20:28:15 +02:00
Amine Bou 73cc1a7297 Remove any email from the reports, as there seems to be no way to secure the data. 2018-05-25 20:20:47 +02:00
Amine Bou 798f112498 Added the ability to force push and force tag creation. 2018-05-24 22:36:20 +02:00
Amine Bou 38b5e7dc65 New (new, new, new, new) way for handling versions. Will work with jenkins and fdroid. 2018-05-24 22:32:34 +02:00
Amine Bou 2799a48f2b Fixed build issue. 2018-05-24 21:43:27 +02:00
Amine Bou ad5edae6cd Fixed jenkins build issue. 2018-05-23 20:56:30 +02:00
Amine Bou 9cb02f0272 Changelog. 2018-05-23 20:44:47 +02:00
Amine Bou 6d24fd9336 Removed every config string added at build time. 2018-05-23 20:39:50 +02:00
Amine Bou a3a7b78c96 Removed direct call to mercury api. 2018-05-23 20:00:46 +02:00
Amine Bou e995286068 New Crowdin translations (#196)
* New translations strings.xml (Catalan)

* 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 (Afrikaans)

* New translations strings.xml (Indonesian)

* 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 (Chinese Simplified)

* New translations strings.xml (Arabic)

* New translations strings.xml (Vietnamese)

* New translations strings.xml (French)

* New translations strings.xml (French)
2018-05-22 21:20:27 +02:00
Amine Bou 65fb6d9b7e Fixes #59. 2018-05-22 21:14:10 +02:00
Amine Bou eb02d1efad Settings for silent debug. 2018-05-22 20:21:31 +02:00
Amine Bou f8d3e1eefb New Crowdin translations (#195)
* New translations strings.xml (Catalan)

* 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 (Afrikaans)

* New translations strings.xml (Indonesian)

* 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 (Chinese Simplified)

* New translations strings.xml (Arabic)

* New translations strings.xml (Vietnamese)
2018-05-22 13:21:03 +02:00
Amine Bou 218b8fa843 Replace with ACRA bug reporter. 2018-05-21 21:39:23 +02:00
Amine Bou 9f94af6239 Removed firebase and crashlytics 2018-05-20 10:19:46 +02:00
Amine Bou d3584ac40e New Crowdin translations (#194)
* New translations strings.xml (Catalan)

* New translations strings.xml (Catalan)

* New translations strings.xml (Catalan)

* New translations strings.xml (Catalan)

* New translations strings.xml (Catalan)

* New translations strings.xml (Catalan)

* 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 (Afrikaans)

* New translations strings.xml (Indonesian)

* 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 (Chinese Simplified)

* New translations strings.xml (Arabic)

* New translations strings.xml (Vietnamese)
2018-05-14 22:36:36 +02:00
Amine Bou 90bdb289d0 Fixed build and version issue. 2018-05-14 22:36:12 +02:00
Amine Bou 78a08750a2 CHANGELOG. 2018-05-14 22:07:50 +02:00
Amine Bou baba851e97 Strings cleaning and versions updates. 2018-05-14 22:02:57 +02:00
Amine Bou 2a03783623 Trying to fix some swipe and reload items issues. 2018-05-10 12:57:57 +02:00
Amine Bou 9f2a4438b1 Trying to debug and fix a swipe to hide issue. 2018-05-08 10:23:12 +02:00
Amine Bou 5ee5287ffa changelog. 2018-05-07 11:28:24 +02:00
Amine Bou 29547c2c94 Changed the email subject. 2018-05-07 11:27:16 +02:00
Amine Bou 4846c870fa Fixed dark theme issue. 2018-05-07 10:16:02 +02:00
Amine Bou c17980a032 Versionning changes. 2018-04-15 21:32:34 +02:00
Amine Bou a929e419d9 Version names. 2018-04-15 15:46:42 +02:00
Amine Bou 487d484bae More styling. 2018-04-15 11:33:37 +02:00
Amine Bou 0ca4c04c61 Add to sources. 2018-04-11 22:25:51 +02:00
Amine Bou c857cf2d67 No theme handling for the login page. 2018-04-11 22:25:51 +02:00
Amine Bou acb502028b Article fragment color. 2018-04-11 22:25:51 +02:00
Amine Bou 533636f3a1 Link colors in cards and list items. 2018-04-11 22:25:51 +02:00
Amine Bou eb5672901b AS update. 2018-04-11 22:25:51 +02:00
Amine Bou 53a8716b51 New translations strings.xml (Spanish) (#190) 2018-04-09 11:06:40 +02:00
Amine Bou 3aaff612af WIP. All activities dynamic themes. 2018-04-08 14:16:16 +02:00
Amine Bou fdcd8c6c6a Dynamic theme handling. Works only on the homeactivity for now. 2018-04-08 13:08:42 +02:00
Amine Bou bafd478604 Keeping the source even when fetching details from mercury. 2018-04-07 19:55:55 +02:00
Amine Bou 987513a88b Version for alpha deploy. 2018-04-07 19:31:50 +02:00
Amine Bou a450ab2a3b Handling items with multiple tags. 2018-04-07 18:51:39 +02:00
Amine Bou db89fe5aad Updating lateral panel tags without network call. 2018-04-07 18:19:24 +02:00
Amine Bou 67a30b92f6 Cleaning. 2018-04-07 17:19:41 +02:00
Amine Bou c397de8c3e New Crowdin translations (#189)
* New translations strings.xml (German)

* 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 (Afrikaans)

* New translations strings.xml (Indonesian)

* New translations strings.xml (Hungarian)

* New translations strings.xml (Hebrew)

* New translations strings.xml (Greek)

* 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 (Chinese Simplified)

* New translations strings.xml (Catalan)

* New translations strings.xml (Arabic)

* New translations strings.xml (Vietnamese)

* New translations strings.xml (French)

* New translations strings.xml (Portuguese)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Spanish)

* New translations strings.xml (Chinese Simplified)
2018-04-07 10:56:13 +02:00
Amine Bou b4db532c45 Fixes #184. Needs translations. 2018-04-07 10:40:27 +02:00
Amine Bou ebecc9c80a Fixes #188. 2018-04-02 09:08:58 +02:00
Amine Bou 4f8556fca8 Change version code generation. 2018-03-31 18:25:14 +02:00
Amine Bou 68892fb41b Fixed play store update. 2018-03-31 08:22:57 +02:00
Amine Bou 6d6f6c72ac Fixes #187. 2018-03-31 07:40:11 +02:00
Amine Bou df5556b945 Build. 2018-03-30 22:17:47 +02:00
Amine Bou d6c74049c3 Fixes #185. 2018-03-30 22:14:49 +02:00
Amine Bou 18946464a2 Do nothing if ids are empty. More logging. 2018-03-30 19:54:42 +02:00
Amine Bou edb5eabee7 Fixing NPE. And obfuscation. 2018-03-29 19:59:07 +02:00
Amine Bou 99a305f3e2 Cache url as parameter. 2018-03-28 21:11:25 +02:00
Amine Bou 68dc5a6acf Debugging read all items. WILL ONLY WORK IF THE OPTION IS ENABLED IN SETTINGS. 2018-03-28 19:26:59 +02:00
Amine Bou 6816461502 D8 enabling and gradle cache debug. 2018-03-28 19:13:47 +02:00
Amine Bou 15b93bbd9e Updated AS. Enabled build cache. 2018-03-27 20:00:02 +02:00
Amine Bou cd61e140f6 New Crowdin translations (#182)
* New translations strings.xml (German)

* New translations strings.xml (German)

* New translations strings.xml (French)

* New translations strings.xml (German)

* New translations strings.xml (French)

* New translations strings.xml (Portuguese, Brazilian)
2018-03-26 16:08:18 +02:00
Amine Bou 4d861a84e6 Fixing permissions added by firebase update
See https://www.reddit.com/r/androiddev/comments/86c02l/google_play_services_1200_released/dw4ehln/?context=0 for more details.
2018-03-26 12:00:57 +02:00
Amine Bou f24de68618 Code cleaning and versions updates. 2018-03-25 21:11:47 +02:00
Amine Bou 3bcffff444 Fixing crashlytics issues. 2018-03-25 20:54:33 +02:00
Amine Bou 75e9031fa5 Changelog. 2018-03-19 07:53:46 +01:00
Amine Bou 3b77e24399 Removed english indonesian translation. 2018-03-19 07:48:08 +01:00
Amine Bou 0a738e895f Version updates. 2018-03-03 16:18:29 +01:00
Amine Bou 242e5ba035 New Crowdin translations (#181)
* New translations strings.xml (Spanish)

* New translations strings.xml (Spanish)

* New translations strings.xml (Indonesian)

* New translations strings.xml (Ukrainian)

* New translations strings.xml (Turkish)

* New translations strings.xml (Swedish)

* 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 (Japanese)

* New translations strings.xml (Italian)

* New translations strings.xml (Hungarian)

* New translations strings.xml (Afrikaans)

* 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 (English, Indonesia)

* 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 (Chinese Simplified)

* New translations strings.xml (Catalan)

* New translations strings.xml (Arabic)

* New translations strings.xml (Vietnamese)
2018-03-03 16:10:02 +01:00
Amine Bou c94612106c Changelog. 2018-03-03 16:03:07 +01:00
Amine Bou 320924b4ed Fixes #180. 2018-03-03 16:00:56 +01:00
Amine Bou 403ecc4521 Trying to understand #83. 2018-02-07 21:30:39 +01:00
Amine Bou 6a50b37364 Added a padding to the recyclerview. 2018-02-07 21:22:08 +01:00
Amine Bou d9d341ac5d Versions updates. 2018-02-07 21:16:51 +01:00
Amine Bou e9805b731e New translations strings.xml (Portuguese, Brazilian) (#177) 2018-02-06 11:35:31 +01:00
Amine Bou c6d4337cd1 New Crowdin translations (#176)
* New translations strings.xml (English, Indonesia)

* New translations strings.xml (English, Indonesia)

* New translations strings.xml (English, Indonesia)

* New translations strings.xml (English, Indonesia)

* New translations strings.xml (English, Indonesia)
2018-02-01 17:55:54 +01:00
Amine Bou 173f4b2ff7 Build. 2018-01-27 17:23:31 +01:00
Amine Bou 3b9436264c Still fixing small fonts issues. 2018-01-27 17:17:43 +01:00
Amine Bou 35fe87d79d New Crowdin translations (#175)
* New translations strings.xml (Afrikaans)

* New translations strings.xml (Italian)

* 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 (Japanese)

* New translations strings.xml (Indonesian)

* 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 (English, Indonesia)

* 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 (Chinese Simplified)

* New translations strings.xml (Catalan)

* New translations strings.xml (Vietnamese)

* New translations strings.xml (French)
2018-01-27 12:39:55 +01:00
Amine Bou f1bb7ba9ad Should fix #174. Added the ability to set the font size of the content of the article reader. 2018-01-27 12:29:14 +01:00
Amine Bou 279f229166 Trying jekkyl. 2018-01-21 18:53:00 +01:00
Amine Bou be1794e27b Github page. 2018-01-21 18:23:47 +01:00
Amine Bou 4d4a2039c8 Reformated code according to official kotling style. 2018-01-21 18:08:39 +01:00
Amine Bou 3013ae4f35 Set theme jekyll-theme-cayman 2018-01-21 17:56:58 +01:00
Amine Bou bb3f7d3786 Page. 2018-01-21 17:54:24 +01:00
Amine Bou f7cc305e44 Changed suffix back to normal. 2018-01-16 22:13:00 +01:00
Amine Bou da17f89148 Building. 2018-01-12 06:26:39 +01:00
Amine Bou ec71ab3c6f Fix issue with list adapter. 2018-01-12 06:24:06 +01:00
Amine Bou 0d007f1492 Added logging for StringIndexOutOfBound. 2018-01-12 05:19:49 +01:00
Amine Bou 96f8663b8f Simpler (kind of) way to have multiple builds a day) 2018-01-12 05:15:28 +01:00
Amine Bou 1a4bc1b301 Refactoring to use #158. 2018-01-12 04:58:43 +01:00
Amine Bou b51ae58a97 A lot of logs to clean after solving an issue. 2018-01-11 21:21:40 +01:00
Amine Bou b126fc32da Fixing the same issue as #158. 2018-01-11 21:10:53 +01:00
Amine Bou b8d234c415 Removed sonar. 2018-01-11 20:53:17 +01:00
Amine Bou 2c8902d404 Working on #169.
List isn't reloaded each time.
When new articles arrive, the list is still updated, but the list stays at the same (old) position.
Not sure if I keep this behavior, or try to keep the old position and scroll to it.
2018-01-06 15:37:12 +01:00
Amine Bou 80ad65b196 New Crowdin translations (#171)
* New translations strings.xml (French)

* New translations strings.xml (French)
2018-01-06 03:52:23 +01:00
Amine Bou 744d9ba72b Contributing to translations. 2018-01-06 03:38:08 +01:00
Amine Bou 0c1d708588 Merge pull request #170 from aancel/fix/values-fr-rFR
Update values-fr-rFR/strings.xml
2018-01-06 03:14:21 +01:00
Alexandre Ancel 95e79e7c5d Update values-fr-rFR/strings.xml
Fix typos
2018-01-06 01:49:07 +01:00
Amine Bou 3ce3260d20 Fixes #165. 2018-01-05 10:51:19 +01:00
Amine Bou 641f4f34d3 Fixes #168. 2018-01-04 20:45:25 +01:00
Amine Bou 99620cb1c5 Update README.md 2018-01-04 13:32:21 +01:00
Amine Bou 8f5f33f5d2 Crowdin fixing Android Studio indentation issue.
* New translations strings.xml (Chinese Simplified)

* New translations strings.xml (Italian)

* 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 (Japanese)

* New translations strings.xml (Indonesian)

* New translations strings.xml (Afrikaans)

* 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 (English, Indonesia)

* 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 (Arabic)

* New translations strings.xml (Vietnamese)
2018-01-03 19:19:56 +01:00
Amine Bou 78e9230b82 Fixes #161. 2018-01-03 19:07:27 +01:00
Amine Bou 78aa44c007 Changed from gitter to slack. 2018-01-01 15:04:52 +01:00
Amine Bou 53fd944f00 Update README.md 2018-01-01 15:00:04 +01:00
Amine Bou 9e6cb4ee3d Fixes #164. Page indicator position. 2018-01-01 07:55:57 +01:00
Amine Bou 87ad6f2826 (Again) fixed auto version number. 2018-01-01 07:27:10 +01:00
Amine Bou 9050f5a56f Changelog. 2018-01-01 07:03:11 +01:00
Amine Bou 3437004082 Multiple crash fixes. 2018-01-01 07:02:19 +01:00
Amine Bou dcf620af87 New translations strings.xml (Chinese Simplified) (#163) 2017-12-27 05:44:58 +01:00
Amine Bou 128085a02e New Crowdin translations (#159)
* New translations strings.xml (Afrikaans)

* New translations strings.xml (Korean)

* New translations strings.xml (English, Indonesia)

* New translations strings.xml (Vietnamese)

* 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 (Japanese)

* New translations strings.xml (Arabic)

* New translations strings.xml (Italian)

* 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 (Chinese Simplified)

* New translations strings.xml (Catalan)

* New translations strings.xml (Indonesian)

* New translations strings.xml (French)
2017-12-20 06:39:27 +01:00
Amine Bou 302040ec25 Fixed #160. 2017-12-20 06:33:10 +01:00
Amine Bou e177c22032 Fixes #157. 2017-12-17 21:30:42 +01:00
Amine Bou a11007113a Maybe fixing IllegalStateException. 2017-12-17 20:59:16 +01:00
Amine Bou 5e7897bcf4 Fixes #152. 2017-12-17 20:40:14 +01:00
Amine Bou 9559af3637 Closes #154. 2017-12-17 19:51:20 +01:00
Sergey Babkin 4c499abcdb Issue 155 - fix StringIndexOutOfBoundException 2017-12-17 17:12:54 +01:00
Amine Bou 0055a503b3 New Crowdin translations (#156)
* New translations strings.xml (Afrikaans)

* New translations strings.xml (Korean)

* New translations strings.xml (English, Indonesia)

* New translations strings.xml (Vietnamese)

* 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 (Japanese)

* New translations strings.xml (Arabic)

* New translations strings.xml (Italian)

* 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 (Chinese Simplified)

* New translations strings.xml (Catalan)

* New translations strings.xml (Indonesian)
2017-12-13 10:48:56 +01:00
302 changed files with 8340 additions and 8355 deletions
+9 -14
View File
@@ -8,7 +8,7 @@ Please read the guidelines before contributing, and follow them (or try to) when
### What you can do to help. ### What you can do to help.
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 [translate the app](https://crowdin.com/project/readerforselfoss), report bugs, request missing features, suggest enhancements and changes to existing ones. You also can improve the README with useful tips that could help the other users.
You can fork the repository, and [help me solve some issues](https://github.com/aminecmi/ReaderforSelfoss/issues?q=is%3Aissue+is%3Aopen+label%3A%22Up+For+Grabs%22) or [develop new things](https://github.com/aminecmi/ReaderforSelfoss/issues) You can fork the repository, and [help me solve some issues](https://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)
@@ -28,6 +28,7 @@ Always check if the web version of your instance is working.
### Pull requests ### Pull requests
* Don't create a PR for translations. See [here](https://github.com/aminecmi/ReaderforSelfoss/pull/170#issuecomment-355715654) for an explanation why.
* 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.
@@ -40,21 +41,20 @@ Always check if the web version of your instance is working.
* Remember that PR review can take time. * Remember that PR review can take time.
# Install Selfoss (if you don't have an instance)
I won't provide any selfoss instance url. If you want to help, but to not have one, you'll have to install one, and use it.
All the details to need are [here](https://selfoss.aditu.de/).
# Build the project # Build the project
You can directly import this project into IntellIJ/Android Studio. You can directly import this project into IntellIJ/Android Studio.
You'll have to: You'll have to:
- 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.
- Define 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
- feedbackEmail: An email to receive users feedback.
- 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.**
- 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:
@@ -64,15 +64,10 @@ You'll have to:
appLoginUrl="URL" # It can be empty. appLoginUrl="URL" # It can be empty.
appLoginUsername="LOGIN" # It can be empty. appLoginUsername="LOGIN" # It can be empty.
appLoginPassword="PASS" # It can be empty. appLoginPassword="PASS" # It can be empty.
mercuryApiKey="LONGAPIKEY"
feedbackEmail="EMAIL"
sourceUrl="URLSOURCE" # 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" -P githubToken="GITHUBTOKEN" ./gradlew .... -P appLoginUrl="URL" -P appLoginUsername="LOGIN" -P appLoginPassword="PASS"
``` ```
+1
View File
@@ -5,6 +5,7 @@
- [ ] I have updated the documentation accordingly. - [ ] I have updated the documentation accordingly.
- [ ] I have added tests to cover my changes. - [ ] I have added tests to cover my changes.
- [ ] All new and existing tests passed. - [ ] All new and existing tests passed.
- [ ] This is **NOT** translation related. (See [here](https://github.com/aminecmi/ReaderforSelfoss/pull/170#issuecomment-355715654))
This closes issue #XXX This closes issue #XXX
+93 -1
View File
@@ -1,8 +1,98 @@
**1.7.x**
- Hiding tags with 0 articles
- Fixed issue with basic auth and images loading
- Added the ability to justify or left align the reader text
- Fixed #251
- Added experimental issue to set a default timeout. Should work for #238.
- Closing #220.
- Start of #238. "Add a quick shortcut to open the app on offline mode ?"
- Closes #216. Issue with selfoss version 2.19.
- Closes #179. Sync of read/unread/star/unstar items on background task or on app reload with network available.
- Closes #33. Background sync with settings.
- Closing #1. Initial article caching.
- Closing #228 by removing the list action bar. Action buttons are exclusively on the card view from now on.
- Closing #38. Only doing api calls on network available.
- Closing #298 and #287. Issues with Listview rendering
- Closing #290. Fixing back button issue in Settings
- Closing #300. Fixing issues when displaying some special characters.
- Closing #310. Some feeds don't have icons nor thumbnails.
- Closing #178. Expending images on tap.
- Closing #323. Old issue with textview not having the right color.
- Closing #324. Svg images loading crashes the app.
- Closing #322. App crashed because of svg images.
**1.6.x**
- Handling hidden tags.
- Fixed pre-lolipop issue with automatic theme changes.
- Removed all Build config things.
- Removed firebase and fabric.
- Added Acra for optional crash reporting and error logging.
- Dynamic themes !
- Strings cleaning.
- Versions updates.
- Fixes #215, #208.
- Fixes #328.
**1.5.7.x** **1.5.7.x**
- Added confirmation to the mark as read and update menues.
- Add to favorites from article viewer.
- Added an option to use a webview in the article viewer (see #149) - Added an option to use a webview in the article viewer (see #149)
- Fixes (#151) - Fixes (#151 #152 #155 #157 #160 #174) and more.
- New year fixes !!!
- Changed page indicator position as it was overlaping content.
- Now using slack instead of gitter.
- Moved completely to a webview to fix #161.
- Fixed typos in French ( Thanks @aancel )
- Updated the Contribution guide about translations.
- Better handling for articles update. (See #169)
- Ability to change the article viewer content font size (see #153)
- Versions updates * 2.
- Added padding to the recyclerview.
**1.5.5.x (didn't last long) AND 1.5.6.x** **1.5.5.x (didn't last long) AND 1.5.6.x**
@@ -20,6 +110,8 @@
- Changed versions handling. - Changed versions handling.
- Removed indonesian english as it was causing issues with the english version of the app.
**1.5.4.22** **1.5.4.22**
- You can now scroll through the loaded articles ! - You can now scroll through the loaded articles !
+23 -11
View File
@@ -1,21 +1,34 @@
# ReaderForSelfoss # ReaderForSelfoss **(Only available from F-Droid)**
[![Crowdin](https://d322cqt584bo4o.cloudfront.net/readerforselfoss/localized.svg)](https://crowdin.com/project/readerforselfoss) [![Gitter chat](https://badges.gitter.im/amine-bou/ReaderForSelfoss.png)](https://gitter.im/amine-bou/ReaderForSelfoss) [![Crowdin](https://d322cqt584bo4o.cloudfront.net/readerforselfoss/localized.svg)](https://crowdin.com/project/readerforselfoss)
[![Build Status](http://jenkins.amine-bou.fr/job/ReaderForSelfoss/badge/icon)](http://jenkins.amine-bou.fr/job/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).
It's an RSS Reader for Android, that **only** works with [Selfoss](https://selfoss.aditu.de/) It's an RSS Reader for Android, that **only** works with [Selfoss](https://selfoss.aditu.de/)
The last APK built from source is available [here](https://jenkins.amine-bou.fr/job/ReaderForSelfoss/lastSuccessfulBuild/artifact/SignApksBuilder-out/selfoss-key/selfoss/app-githubConfig-release-unsigned.apk/app-githubConfig-release.apk). **The project is not dead at all.**
I still want to work on it, but for the last few months, I didn't have that much time to do so.
If you are a developer, don't hesitate to help with PRs.
If you are a user, you can still create new issues. I'll fix them when I can.
<a href="https://f-droid.org/packages/apps.amine.bou.readerforselfoss"><img src="https://f-droid.org/badge/get-it-on.png" alt="Get it on F-Droid" height="100"></a>
## Screen captures
<img src="res//fr-card.png?raw=true" alt="card view" width="400"/> <img src="res//fr-list.png?raw=true" alt="list view" width="400"/>
## Like my app ?
<a href="https://www.buymeacoffee.com/aminecmi" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/lato-orange.png" alt="Buy Me A Coffee" style="height: 51px !important;width: 217px !important;" ></a>
## Want to help ? ## Want to help ?
Check the [Contribution guide](https://github.com/aminecmi/ReaderforSelfoss/blob/master/.github/CONTRIBUTING.md) 1. **You'll have to have a Selfoss instance running.** You'll find everything you need to install it [here](https://selfoss.aditu.de/).
2. Check the [Contribution guide](https://github.com/aminecmi/ReaderforSelfoss/blob/master/.github/CONTRIBUTING.md).
3. Build the project by following [these steps](https://github.com/aminecmi/ReaderforSelfoss/blob/master/.github/CONTRIBUTING.md#build-the-project) (you should have read them after the contribution guide)
## Useful links ## Useful links
@@ -23,4 +36,3 @@ Check the [Contribution guide](https://github.com/aminecmi/ReaderforSelfoss/blob
- [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) - [Help translation the app](https://crowdin.com/project/readerforselfoss)
- [Ask for help](https://gitter.im/amine-bou/ReaderForSelfoss)
+70 -146
View File
@@ -1,59 +1,48 @@
buildscript { buildscript {
repositories {
maven { url 'https://maven.fabric.io/public' }
}
dependencies {
classpath 'io.fabric.tools:gradle:1.+'
}
}
ext {
configuration = [
buildDate: new Date()
]
} }
def gitVersion() { def gitVersion() {
def process = "git describe --abbrev=0 --tags".execute() def process
return process.text.substring(1).replaceAll("\\.", "").trim() def maybeTagOfCurrentCommit = 'git describe --contains HEAD'.execute()
if (maybeTagOfCurrentCommit.text.isEmpty()) {
println "No tag on current commit. Will take the latest one."
process = "git for-each-ref refs/tags --sort=-authordate --format='%(refname:short)' --count=1".execute()
} else {
println "Tag found on current commit"
process = 'git describe --contains HEAD'.execute()
}
return process.text.replaceAll("'", "").substring(1).replaceAll("\\.", "").trim()
} }
def versionCodeFromGit() { def versionCodeFromGit() {
def versionCode = gitVersion() + (ext.configuration.buildDate.format("yyMMD")).toInteger() println "version code " + gitVersion()
println "version code " + versionCode return gitVersion().toInteger()
return versionCode.toInteger()
} }
def versionNameFromGit() { def versionNameFromGit() {
def versionName = gitVersion() + ext.configuration.buildDate.format('yyyyMMddHHmm') println "version name " + gitVersion()
println "version name " + versionName return gitVersion()
return versionName
} }
apply plugin: 'org.sonarqube'
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
apply plugin: 'io.fabric'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-android-extensions'
repositories {
maven {
url 'https://maven.fabric.io/public'
}
}
android { android {
compileSdkVersion 27 compileOptions {
buildToolsVersion '27.0.2' sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
compileSdkVersion 30
buildToolsVersion '30.0.3'
defaultConfig { defaultConfig {
applicationId "apps.amine.bou.readerforselfoss" applicationId "apps.amine.bou.readerforselfoss"
minSdkVersion 16 minSdkVersion 16
targetSdkVersion 27 targetSdkVersion 30
versionCode versionCodeFromGit() versionCode versionCodeFromGit()
versionName versionNameFromGit() versionName versionNameFromGit()
@@ -66,26 +55,23 @@ android {
vectorDrawables.useSupportLibrary = true vectorDrawables.useSupportLibrary = true
// tests // tests
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
buildConfigField "String", "MERCURY_KEY", mercuryApiKey javaCompileOptions {
buildConfigField "String", "FEEDBACK_EMAIL", feedbackEmail annotationProcessorOptions {
buildConfigField "String", "SOURCE_URL", sourceUrl arguments = ["room.schemaLocation":
buildConfigField "String", "TRACKER_URL", trackerUrl "$projectDir/schemas".toString()]
buildConfigField "String", "TRANSLATION_URL", translationUrl }
buildConfigField "String", "GITHUB_TOKEN", githubToken }
} }
buildTypes { buildTypes {
release { release {
minifyEnabled true minifyEnabled true
shrinkResources true shrinkResources false
proguardFiles getDefaultProguardFile('proguard-android.txt'), proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro' 'proguard-rules.pro'
} }
debug { debug {
buildConfigField "String", "LOGIN_URL", appLoginUrl
buildConfigField "String", "LOGIN_USERNAME", appLoginUsername
buildConfigField "String", "LOGIN_PASSWORD", appLoginPassword
} }
} }
flavorDimensions "build" flavorDimensions "build"
@@ -93,137 +79,75 @@ android {
githubConfig { githubConfig {
versionNameSuffix '-github' versionNameSuffix '-github'
dimension "build" dimension "build"
buildConfigField "boolean", "GITHUB_VERSION", "true"
}
storeConfig {
versionNameSuffix '-store'
dimension "build"
buildConfigField "boolean", "GITHUB_VERSION", "false"
} }
} }
} }
dependencies { dependencies {
// Testing // Testing
androidTestCompile 'com.android.support.test.espresso:espresso-core:3.0.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0-alpha02'
androidTestCompile 'com.android.support.test:runner:1.0.1' androidTestImplementation 'androidx.test:runner:1.3.1-alpha02'
// 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.1' androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.4.0-alpha02'
// 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.1' androidTestImplementation 'androidx.test.espresso:espresso-intents:3.4.0-alpha02'
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
compile fileTree(dir: 'libs', include: ['*.jar'])
compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
// Android Support // Android Support
compile 'com.android.support:appcompat-v7:27.0.2' implementation "androidx.appcompat:appcompat:1.3.0-alpha02"
compile 'com.android.support:design:27.0.2' implementation 'com.google.android.material:material:1.3.0-beta01'
compile 'com.android.support:recyclerview-v7:27.0.2' implementation 'androidx.recyclerview:recyclerview:1.2.0-beta01'
compile 'com.android.support:support-v4:27.0.2' implementation "androidx.legacy:legacy-support-v4:$android_version"
compile 'com.android.support:support-vector-drawable:27.0.2' implementation 'androidx.vectordrawable:vectordrawable:1.2.0-alpha02'
compile 'com.android.support:customtabs:27.0.2' implementation "androidx.browser:browser:1.3.0"
compile 'com.android.support:cardview-v7:27.0.2' implementation "androidx.cardview:cardview:$android_version"
compile 'com.android.support.constraint:constraint-layout:1.0.2' implementation 'androidx.constraintlayout:constraintlayout:2.1.0-alpha2'
implementation 'org.jsoup:jsoup:1.13.1'
// Firebase + crashlytics
compile 'com.google.firebase:firebase-core:11.6.2'
compile 'com.google.firebase:firebase-config:11.6.2'
compile 'com.google.firebase:firebase-invites:11.6.2'
compile('com.crashlytics.sdk.android:crashlytics:2.8.0@aar') {
transitive = true;
}
//multidex //multidex
compile 'com.android.support:multidex:1.0.2' implementation 'androidx.multidex:multidex:2.0.1'
// Intro
compile 'agency.tango.android:material-intro-screen:0.0.5'
// About // About
compile('com.mikepenz:aboutlibraries:6.0.0@aar') { implementation('com.mikepenz:aboutlibraries:6.2.0@aar') {
transitive = true transitive = true
} }
// Retrofit + http logging + okhttp // Retrofit + http logging + okhttp
compile 'com.squareup.retrofit2:retrofit:2.3.0' implementation 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.okhttp3:logging-interceptor:3.9.0' implementation 'com.squareup.okhttp3:logging-interceptor:3.9.0'
compile 'com.squareup.retrofit2:converter-gson:2.3.0' implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
compile 'com.burgstaller:okhttp-digest:1.12' implementation 'com.burgstaller:okhttp-digest:1.12'
// Material-ish things // Material-ish things
compile 'com.ashokvarma.android:bottom-navigation-bar:2.0.3' implementation 'com.ashokvarma.android:bottom-navigation-bar:2.1.0'
compile 'com.github.jd-alexander:LikeButton:0.2.1' implementation 'com.github.jd-alexander:LikeButton:0.2.3'
compile 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1' implementation 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1'
compile 'org.sufficientlysecure:html-textview:3.5'
// glide // glide
compile 'com.github.bumptech.glide:glide:4.1.1' implementation 'com.github.bumptech.glide:glide:4.1.1'
compile 'com.github.bumptech.glide:okhttp3-integration:4.1.1' implementation 'com.github.bumptech.glide:okhttp3-integration:4.1.1'
// Asking politely users to rate the app
compile 'com.github.stkent:amplify:2.1.0'
// Drawer // Drawer
implementation 'co.zsmb:materialdrawer-kt:1.2.1' implementation 'co.zsmb:materialdrawer-kt:2.0.2'
compile 'com.anupcowkur:reservoir:3.1.0'
// Themes // Themes
compile 'com.52inc:scoops:1.0.0' implementation 'com.52inc:scoops:1.0.0'
implementation 'com.jaredrummler:colorpicker:1.0.2'
// Github issues reporter implementation 'com.github.rubensousa:floatingtoolbar:1.5.1'
compile 'com.heinrichreimersoftware:android-issue-reporter:1.3.1'
compile 'com.github.rubensousa:floatingtoolbar:1.5.1'
// Pager // Pager
compile 'me.relex:circleindicator:1.2.2@aar' implementation 'me.relex:circleindicator:2.0.0@aar'
} //PhotoView
implementation 'com.github.chrisbanes:PhotoView:2.0.0'
apply plugin: 'com.google.gms.google-services' implementation 'androidx.core:core-ktx:1.5.0-alpha05'
implementation "androidx.lifecycle:lifecycle-livedata:2.3.0-rc01"
implementation "androidx.lifecycle:lifecycle-common-java8:2.3.0-rc01"
afterEvaluate { implementation "androidx.room:room-runtime:2.3.0-alpha04"
initFabricPropertiesIfNeeded() kapt "androidx.room:room-compiler:2.3.0-alpha04"
initAppLoginPropertiesIfNeeded()
initAppForSecretPropertiesIfNeeded()
}
def initFabricPropertiesIfNeeded() { implementation "android.arch.work:work-runtime-ktx:$work_version"
def propertiesFile = file('fabric.properties')
if (!propertiesFile.exists()) {
def commentMessage = "This is autogenerated fabric property from system environment to prevent key to be committed to source control."
ant.propertyfile(file: "fabric.properties", comment: commentMessage) {
entry(key: "apiSecret", value: crashlyticsdemoApisecret)
entry(key: "apiKey", value: crashlyticsdemoApikey)
}
}
}
def initAppLoginPropertiesIfNeeded() {
def propertiesFile = file(System.getProperty("user.home") + '/.gradle/gradle.properties')
if (!propertiesFile.exists()) {
def commentMessage = "This is autogenerated local property from system environment to prevent key to be committed to source control."
ant.propertyfile(file: System.getProperty("user.home") + "/.gradle/gradle.properties", comment: commentMessage) {
entry(key: "appLoginUrl", value: System.getProperty("appLoginUrl"))
entry(key: "appLoginUsername", value: System.getProperty("appLoginUsername"))
entry(key: "appLoginPassword", value: System.getProperty("appLoginPassword"))
}
}
}
def initAppForSecretPropertiesIfNeeded() {
def propertiesFile = file(System.getProperty("user.home") + '/.gradle/gradle.properties')
if (!propertiesFile.exists()) {
def commentMessage = "This is autogenerated local property from system environment to prevent key to be committed to source control."
ant.propertyfile(file: System.getProperty("user.home") + "/.gradle/gradle.properties", comment: commentMessage) {
entry(key: "mercuryApiKey", value: System.getProperty("mercuryApiKey"))
entry(key: "feedbackEmail", value: System.getProperty("feedbackEmail"))
entry(key: "sourceUrl", value: System.getProperty("sourceUrl"))
entry(key: "trackerUrl", value: System.getProperty("trackerUrl"))
entry(key: "translationUrl", value: System.getProperty("translationUrl"))
entry(key: "githubToken", value: System.getProperty("githubToken"))
}
}
} }
+8 -17
View File
@@ -30,25 +30,13 @@
<fields>; <fields>;
} }
##Retrofit
#-keep class com.google.gson.** { *; }
#-keep class com.google.inject.** { *; }
#-keep class org.apache.http.** { *; }
#-keep class org.apache.james.mime4j.** { *; }
#-keep class javax.inject.** { *; }
#-keep class retrofit.** { *; }
#-keepclassmembernames interface * {
# @retrofit.http.* <methods>;
#}
#-keep class retrofit.** { *; }
#-keep class apps.amine.bou.readerforselfoss.api.selfoss.model.** { *; }
#-keepclassmembernames interface * {
# @retrofit.http.* <methods>;
#}
-dontwarn okio.** -dontwarn okio.**
-dontwarn retrofit2.Platform$Java8 -dontwarn retrofit2.Platform$Java8
-keepattributes Signature -keep class retrofit.** { *; }
-keepclasseswithmembers class * {
@retrofit.http.* <methods>;
}
-keepattributes *Annotation*,Signature
-keepattributes Exceptions -keepattributes Exceptions
-dontwarn okio.** -dontwarn okio.**
-dontwarn javax.annotation.Nullable -dontwarn javax.annotation.Nullable
@@ -72,3 +60,6 @@
-dontwarn javax.annotation.** -dontwarn javax.annotation.**
-keep class android.support.v7.widget.SearchView { *; } -keep class android.support.v7.widget.SearchView { *; }
# maybe remove later ?
-keep class * extends androidx.fragment.app.Fragment
@@ -0,0 +1,96 @@
{
"formatVersion": 1,
"database": {
"version": 1,
"identityHash": "08ca537d7ac9d4dd216e8e395d70801a",
"entities": [
{
"tableName": "tags",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`tag` TEXT NOT NULL, `color` TEXT NOT NULL, `unread` INTEGER NOT NULL, PRIMARY KEY(`tag`))",
"fields": [
{
"fieldPath": "tag",
"columnName": "tag",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "color",
"columnName": "color",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "unread",
"columnName": "unread",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"tag"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "sources",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `title` TEXT NOT NULL, `tags` TEXT NOT NULL, `spout` TEXT NOT NULL, `error` TEXT NOT NULL, `icon` TEXT NOT NULL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "title",
"columnName": "title",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "tags",
"columnName": "tags",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "spout",
"columnName": "spout",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "error",
"columnName": "error",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "icon",
"columnName": "icon",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"08ca537d7ac9d4dd216e8e395d70801a\")"
]
}
}
@@ -0,0 +1,176 @@
{
"formatVersion": 1,
"database": {
"version": 2,
"identityHash": "6fa6944b04100d68eab61039876a8804",
"entities": [
{
"tableName": "tags",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`tag` TEXT NOT NULL, `color` TEXT NOT NULL, `unread` INTEGER NOT NULL, PRIMARY KEY(`tag`))",
"fields": [
{
"fieldPath": "tag",
"columnName": "tag",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "color",
"columnName": "color",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "unread",
"columnName": "unread",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"tag"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "sources",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `title` TEXT NOT NULL, `tags` TEXT NOT NULL, `spout` TEXT NOT NULL, `error` TEXT NOT NULL, `icon` TEXT NOT NULL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "title",
"columnName": "title",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "tags",
"columnName": "tags",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "spout",
"columnName": "spout",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "error",
"columnName": "error",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "icon",
"columnName": "icon",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "items",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `datetime` TEXT NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `unread` INTEGER NOT NULL, `starred` INTEGER NOT NULL, `thumbnail` TEXT NOT NULL, `icon` TEXT NOT NULL, `link` TEXT NOT NULL, `sourcetitle` TEXT NOT NULL, `tags` TEXT NOT NULL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "datetime",
"columnName": "datetime",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "title",
"columnName": "title",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "content",
"columnName": "content",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "unread",
"columnName": "unread",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "starred",
"columnName": "starred",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "thumbnail",
"columnName": "thumbnail",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "icon",
"columnName": "icon",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "link",
"columnName": "link",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "sourcetitle",
"columnName": "sourcetitle",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "tags",
"columnName": "tags",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"6fa6944b04100d68eab61039876a8804\")"
]
}
}
@@ -0,0 +1,226 @@
{
"formatVersion": 1,
"database": {
"version": 3,
"identityHash": "7ad9c4961992c13b670128485ebb3efc",
"entities": [
{
"tableName": "tags",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`tag` TEXT NOT NULL, `color` TEXT NOT NULL, `unread` INTEGER NOT NULL, PRIMARY KEY(`tag`))",
"fields": [
{
"fieldPath": "tag",
"columnName": "tag",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "color",
"columnName": "color",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "unread",
"columnName": "unread",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"tag"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "sources",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `title` TEXT NOT NULL, `tags` TEXT NOT NULL, `spout` TEXT NOT NULL, `error` TEXT NOT NULL, `icon` TEXT NOT NULL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "title",
"columnName": "title",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "tags",
"columnName": "tags",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "spout",
"columnName": "spout",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "error",
"columnName": "error",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "icon",
"columnName": "icon",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "items",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `datetime` TEXT NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `unread` INTEGER NOT NULL, `starred` INTEGER NOT NULL, `thumbnail` TEXT NOT NULL, `icon` TEXT NOT NULL, `link` TEXT NOT NULL, `sourcetitle` TEXT NOT NULL, `tags` TEXT NOT NULL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "datetime",
"columnName": "datetime",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "title",
"columnName": "title",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "content",
"columnName": "content",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "unread",
"columnName": "unread",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "starred",
"columnName": "starred",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "thumbnail",
"columnName": "thumbnail",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "icon",
"columnName": "icon",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "link",
"columnName": "link",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "sourcetitle",
"columnName": "sourcetitle",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "tags",
"columnName": "tags",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "actions",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `articleid` TEXT NOT NULL, `read` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `starred` INTEGER NOT NULL, `unstarred` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "articleId",
"columnName": "articleid",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "read",
"columnName": "read",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "unread",
"columnName": "unread",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "starred",
"columnName": "starred",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "unstarred",
"columnName": "unstarred",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"7ad9c4961992c13b670128485ebb3efc\")"
]
}
}
@@ -0,0 +1,226 @@
{
"formatVersion": 1,
"database": {
"version": 4,
"identityHash": "9cf8b03d32f80dfd58160599a1df197d",
"entities": [
{
"tableName": "tags",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`tag` TEXT NOT NULL, `color` TEXT NOT NULL, `unread` INTEGER NOT NULL, PRIMARY KEY(`tag`))",
"fields": [
{
"fieldPath": "tag",
"columnName": "tag",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "color",
"columnName": "color",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "unread",
"columnName": "unread",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"tag"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "sources",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `title` TEXT NOT NULL, `tags` TEXT NOT NULL, `spout` TEXT NOT NULL, `error` TEXT NOT NULL, `icon` TEXT NOT NULL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "title",
"columnName": "title",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "tags",
"columnName": "tags",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "spout",
"columnName": "spout",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "error",
"columnName": "error",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "icon",
"columnName": "icon",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "items",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `datetime` TEXT NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `unread` INTEGER NOT NULL, `starred` INTEGER NOT NULL, `thumbnail` TEXT, `icon` TEXT, `link` TEXT NOT NULL, `sourcetitle` TEXT NOT NULL, `tags` TEXT NOT NULL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "datetime",
"columnName": "datetime",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "title",
"columnName": "title",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "content",
"columnName": "content",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "unread",
"columnName": "unread",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "starred",
"columnName": "starred",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "thumbnail",
"columnName": "thumbnail",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "icon",
"columnName": "icon",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "link",
"columnName": "link",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "sourcetitle",
"columnName": "sourcetitle",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "tags",
"columnName": "tags",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "actions",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `articleid` TEXT NOT NULL, `read` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `starred` INTEGER NOT NULL, `unstarred` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "articleId",
"columnName": "articleid",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "read",
"columnName": "read",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "unread",
"columnName": "unread",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "starred",
"columnName": "starred",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "unstarred",
"columnName": "unstarred",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"9cf8b03d32f80dfd58160599a1df197d\")"
]
}
}
@@ -2,30 +2,29 @@ package apps.amine.bou.readerforselfoss
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.support.test.InstrumentationRegistry import androidx.test.InstrumentationRegistry
import android.support.test.espresso.Espresso.onView import androidx.test.espresso.Espresso.onView
import android.support.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu import androidx.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu
import android.support.test.espresso.action.ViewActions.click import androidx.test.espresso.action.ViewActions.click
import android.support.test.espresso.action.ViewActions.closeSoftKeyboard import androidx.test.espresso.action.ViewActions.closeSoftKeyboard
import android.support.test.espresso.action.ViewActions.pressBack import androidx.test.espresso.action.ViewActions.pressBack
import android.support.test.espresso.action.ViewActions.pressKey import androidx.test.espresso.action.ViewActions.pressKey
import android.support.test.espresso.action.ViewActions.typeText import androidx.test.espresso.action.ViewActions.typeText
import android.support.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.assertion.ViewAssertions.matches
import android.support.test.espresso.contrib.DrawerActions import androidx.test.espresso.contrib.DrawerActions
import android.support.test.espresso.intent.Intents import androidx.test.espresso.intent.Intents
import android.support.test.espresso.intent.Intents.intended import androidx.test.espresso.intent.Intents.intended
import android.support.test.espresso.intent.Intents.times import androidx.test.espresso.intent.Intents.times
import android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent import androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent
import android.support.test.espresso.matcher.ViewMatchers.isDisplayed import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import android.support.test.espresso.matcher.ViewMatchers.isRoot import androidx.test.espresso.matcher.ViewMatchers.isRoot
import android.support.test.espresso.matcher.ViewMatchers.withContentDescription import androidx.test.espresso.matcher.ViewMatchers.withContentDescription
import android.support.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.matcher.ViewMatchers.withId
import android.support.test.espresso.matcher.ViewMatchers.withText import androidx.test.espresso.matcher.ViewMatchers.withText
import android.support.test.rule.ActivityTestRule import androidx.test.rule.ActivityTestRule
import android.support.test.runner.AndroidJUnit4 import androidx.test.runner.AndroidJUnit4
import android.view.KeyEvent import android.view.KeyEvent
import apps.amine.bou.readerforselfoss.utils.Config import apps.amine.bou.readerforselfoss.utils.Config
import com.heinrichreimersoftware.androidissuereporter.IssueReporterLauncher
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Rule import org.junit.Rule
@@ -92,25 +91,6 @@ class HomeActivityEspressoTest {
intended(hasComponent(LoginActivity::class.java.name), times(1)) intended(hasComponent(LoginActivity::class.java.name), times(1))
} }
@Test
fun drawerTesting() {
rule.launchActivity(Intent())
onView(withId(R.id.material_drawer_layout)).perform(DrawerActions.open())
onView(withText(R.string.drawer_report_bug)).perform(click())
intended(hasComponent(IssueReporterLauncher.Activity::class.java.name))
onView(isRoot()).perform(pressBack())
onView(isRoot()).perform(pressBack())
intended(hasComponent(HomeActivity::class.java.name))
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())
}
// TODO: test articles opening and actions for cards and lists // TODO: test articles opening and actions for cards and lists
@After @After
@@ -1,91 +0,0 @@
package apps.amine.bou.readerforselfoss
import android.content.Context
import android.content.Intent
import android.support.test.InstrumentationRegistry.getInstrumentation
import android.support.test.espresso.Espresso.onView
import android.support.test.espresso.action.ViewActions.click
import android.support.test.espresso.assertion.ViewAssertions.matches
import android.support.test.espresso.intent.Intents
import android.support.test.espresso.intent.Intents.intended
import android.support.test.espresso.intent.Intents.times
import android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent
import android.support.test.espresso.matcher.ViewMatchers.isDisplayed
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.runner.AndroidJUnit4
import apps.amine.bou.readerforselfoss.utils.Config
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import java.util.*
@RunWith(AndroidJUnit4::class)
class IntroActivityEspressoTest {
@Rule @JvmField
val rule = ActivityTestRule(IntroActivity::class.java, true, false)
@Before
fun clearData() {
val editor =
getInstrumentation().targetContext
.getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
.edit()
editor.clear()
editor.commit()
Intents.init()
}
@Test
fun nextEachTimes() {
rule.launchActivity(Intent())
onView(withText(R.string.intro_hello_title)).check(matches(isDisplayed()))
onView(withId(R.id.button_next)).perform(click())
onView(withText(R.string.intro_needs_selfoss_message)).check(matches(isDisplayed()))
onView(withId(R.id.button_next)).perform(click())
onView(withText(R.string.intro_all_set_message)).check(matches(isDisplayed()))
onView(withId(R.id.button_next)).perform(click())
intended(hasComponent(IntroActivity::class.java.name), times(1))
intended(hasComponent(LoginActivity::class.java.name), times(1))
}
@Test
fun nextBackRandomTimes() {
val max = 5
val min = 1
val random = (Random().nextInt(max + 1 - min)) + min
rule.launchActivity(Intent())
onView(withText(R.string.intro_hello_title)).check(matches(isDisplayed()))
onView(withId(R.id.button_next)).perform(click())
repeat(random) { _ ->
onView(withText(R.string.intro_needs_selfoss_message)).check(matches(isDisplayed()))
onView(withId(R.id.button_next)).perform(click())
onView(withText(R.string.intro_all_set_message)).check(matches(isDisplayed()))
onView(withId(R.id.button_back)).perform(click())
}
onView(withId(R.id.button_next)).perform(click())
onView(withText(R.string.intro_all_set_message)).check(matches(isDisplayed()))
onView(withId(R.id.button_next)).perform(click())
intended(hasComponent(IntroActivity::class.java.name), times(1))
intended(hasComponent(LoginActivity::class.java.name), times(1))
}
@After
fun releaseIntents() {
Intents.release()
}
}
@@ -2,25 +2,25 @@ package apps.amine.bou.readerforselfoss
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.support.test.InstrumentationRegistry import androidx.test.InstrumentationRegistry
import android.support.test.espresso.Espresso.onView import androidx.test.espresso.Espresso.onView
import android.support.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu import androidx.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu
import android.support.test.espresso.action.ViewActions.click import androidx.test.espresso.action.ViewActions.click
import android.support.test.espresso.action.ViewActions.closeSoftKeyboard import androidx.test.espresso.action.ViewActions.closeSoftKeyboard
import android.support.test.espresso.action.ViewActions.pressBack import androidx.test.espresso.action.ViewActions.pressBack
import android.support.test.espresso.action.ViewActions.typeText import androidx.test.espresso.action.ViewActions.typeText
import android.support.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.assertion.ViewAssertions.matches
import android.support.test.espresso.intent.Intents import androidx.test.espresso.intent.Intents
import android.support.test.espresso.intent.Intents.intended import androidx.test.espresso.intent.Intents.intended
import android.support.test.espresso.intent.Intents.times import androidx.test.espresso.intent.Intents.times
import android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent import androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent
import android.support.test.espresso.matcher.ViewMatchers import androidx.test.espresso.matcher.ViewMatchers
import android.support.test.espresso.matcher.ViewMatchers.isRoot import androidx.test.espresso.matcher.ViewMatchers.isRoot
import android.support.test.espresso.matcher.ViewMatchers.withEffectiveVisibility import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
import android.support.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.matcher.ViewMatchers.withId
import android.support.test.espresso.matcher.ViewMatchers.withText import androidx.test.espresso.matcher.ViewMatchers.withText
import android.support.test.rule.ActivityTestRule import androidx.test.rule.ActivityTestRule
import android.support.test.runner.AndroidJUnit4 import androidx.test.runner.AndroidJUnit4
import apps.amine.bou.readerforselfoss.utils.Config 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.After
@@ -3,13 +3,13 @@ package apps.amine.bou.readerforselfoss
import android.content.Intent import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import android.preference.PreferenceManager import android.preference.PreferenceManager
import android.support.test.InstrumentationRegistry.getInstrumentation import androidx.test.InstrumentationRegistry.getInstrumentation
import android.support.test.espresso.intent.Intents import androidx.test.espresso.intent.Intents
import android.support.test.espresso.intent.Intents.intended import androidx.test.espresso.intent.Intents.intended
import android.support.test.espresso.intent.Intents.times import androidx.test.espresso.intent.Intents.times
import android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent import androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent
import android.support.test.rule.ActivityTestRule import androidx.test.rule.ActivityTestRule
import android.support.test.runner.AndroidJUnit4 import androidx.test.runner.AndroidJUnit4
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
@@ -45,7 +45,6 @@ class MainActivityEspressoTest {
rule.launchActivity(intent) rule.launchActivity(intent)
intended(hasComponent(MainActivity::class.java.name)) intended(hasComponent(MainActivity::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))
} }
@@ -58,7 +57,6 @@ 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))
} }
@After @After
@@ -1,7 +1,7 @@
package apps.amine.bou.readerforselfoss package apps.amine.bou.readerforselfoss
import android.support.design.widget.TextInputLayout import com.google.android.material.textfield.TextInputLayout
import android.support.test.espresso.matcher.ViewMatchers import androidx.test.espresso.matcher.ViewMatchers
import android.view.View import android.view.View
import org.hamcrest.Description import org.hamcrest.Description
import org.hamcrest.Matcher import org.hamcrest.Matcher
+15 -12
View File
@@ -2,11 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="apps.amine.bou.readerforselfoss"> package="apps.amine.bou.readerforselfoss">
<uses-permission android:name="android.permission.INTERNET" />
<!-- For firebase only -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.INTERNET" />
<application <application
android:name=".MyApp" android:name=".MyApp"
@@ -14,19 +11,19 @@
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
android:supportsRtl="true" android:supportsRtl="true"
android:networkSecurityConfig="@xml/network_security_config"
android:theme="@style/NoBar"> android:theme="@style/NoBar">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:theme="@style/SplashTheme"> android:theme="@style/SplashTheme">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity>
<activity <meta-data
android:name=".IntroActivity" android:name="android.app.shortcuts"
android:theme="@style/Theme.Intro"> android:resource="@xml/shortcuts" />
</activity> </activity>
<activity <activity
android:name=".LoginActivity" android:name=".LoginActivity"
@@ -40,7 +37,7 @@
android:parentActivityName=".HomeActivity"> android:parentActivityName=".HomeActivity">
<meta-data <meta-data
android:name="android.support.PARENT_ACTIVITY" android:name="android.support.PARENT_ACTIVITY"
android:value="apps.amine.bou.readerforselfoss.HomeActivity" /> android:value=".HomeActivity" />
</activity> </activity>
<activity <activity
android:name=".SourcesActivity" android:name=".SourcesActivity"
@@ -58,15 +55,16 @@
<intent-filter> <intent-filter>
<action android:name="android.intent.action.SEND" /> <action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" /> <data android:mimeType="text/plain" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity <activity
android:name=".ReaderActivity"> android:name=".ReaderActivity">
</activity> </activity>
<activity
android:name=".ImageActivity">
</activity>
<meta-data <meta-data
android:name="apps.amine.bou.readerforselfoss.utils.glide.SelfSignedGlideModule" android:name="apps.amine.bou.readerforselfoss.utils.glide.SelfSignedGlideModule"
@@ -77,6 +75,11 @@
<meta-data android:name="android.webkit.WebView.EnableSafeBrowsing" <meta-data android:name="android.webkit.WebView.EnableSafeBrowsing"
android:value="true" /> android:value="true" />
<meta-data android:name="android.max_aspect" android:value="2.1" />
<meta-data
android:name="preloaded_fonts"
android:resource="@array/preloaded_fonts" />
</application> </application>
</manifest> </manifest>
@@ -1,10 +1,12 @@
package apps.amine.bou.readerforselfoss package apps.amine.bou.readerforselfoss
import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.preference.PreferenceManager import android.preference.PreferenceManager
import android.support.constraint.ConstraintLayout import androidx.constraintlayout.widget.ConstraintLayout
import android.support.v7.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import android.view.View import android.view.View
import android.widget.AdapterView import android.widget.AdapterView
import android.widget.ArrayAdapter import android.widget.ArrayAdapter
@@ -16,6 +18,8 @@ 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.themes.AppColors
import apps.amine.bou.readerforselfoss.themes.Toppings
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
@@ -23,29 +27,72 @@ import kotlinx.android.synthetic.main.activity_add_source.*
import retrofit2.Call import retrofit2.Call
import retrofit2.Callback import retrofit2.Callback
import retrofit2.Response import retrofit2.Response
import android.graphics.PorterDuff
class AddSourceActivity : AppCompatActivity() { class AddSourceActivity : AppCompatActivity() {
private var mSpoutsValue: String? = null private var mSpoutsValue: String? = null
private lateinit var api: SelfossApi
private lateinit var appColors: AppColors
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
appColors = AppColors(this@AddSourceActivity)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
Scoop.getInstance().apply(this)
setContentView(R.layout.activity_add_source) setContentView(R.layout.activity_add_source)
val scoop = Scoop.getInstance()
scoop.bind(this, Toppings.PRIMARY.value, toolbar)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
scoop.bindStatusBar(this, Toppings.PRIMARY_DARK.value)
}
val drawable = nameInput.background
drawable.setColorFilter(appColors.colorAccent, PorterDuff.Mode.SRC_ATOP)
// TODO: clean
if(Build.VERSION.SDK_INT > 16) {
nameInput.background = drawable
} else{
nameInput.setBackgroundDrawable(drawable)
}
val drawable1 = sourceUri.background
drawable1.setColorFilter(appColors.colorAccent, PorterDuff.Mode.SRC_ATOP)
if(Build.VERSION.SDK_INT > 16) {
sourceUri.background = drawable1
} else{
sourceUri.setBackgroundDrawable(drawable1)
}
val drawable2 = tags.background
drawable2.setColorFilter(appColors.colorAccent, PorterDuff.Mode.SRC_ATOP)
if(Build.VERSION.SDK_INT > 16) {
tags.background = drawable2
} else{
tags.setBackgroundDrawable(drawable2)
}
setSupportActionBar(toolbar) setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setDisplayShowHomeEnabled(true) supportActionBar?.setDisplayShowHomeEnabled(true)
var api: SelfossApi? = null
try { try {
val prefs = PreferenceManager.getDefaultSharedPreferences(this) val prefs = PreferenceManager.getDefaultSharedPreferences(this)
val settings =
getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
api = SelfossApi( api = SelfossApi(
this, this,
this@AddSourceActivity, this@AddSourceActivity,
prefs.getBoolean("isSelfSignedCert", false), settings.getBoolean("isSelfSignedCert", false),
prefs.getBoolean("should_log_everything", false) prefs.getString("api_timeout", "-1")!!.toLong()
) )
} catch (e: IllegalArgumentException) { } catch (e: IllegalArgumentException) {
mustLoginToAddSource() mustLoginToAddSource()
@@ -53,13 +100,18 @@ class AddSourceActivity : AppCompatActivity() {
maybeGetDetailsFromIntentSharing(intent, sourceUri, nameInput) maybeGetDetailsFromIntentSharing(intent, sourceUri, nameInput)
saveBtn.setTextColor(appColors.colorAccent)
saveBtn.setOnClickListener { saveBtn.setOnClickListener {
handleSaveSource(tags, nameInput.text.toString(), sourceUri.text.toString(), api!!) handleSaveSource(tags, nameInput.text.toString(), sourceUri.text.toString(), api!!)
} }
}
override fun onResume() {
super.onResume()
val config = Config(this) val config = Config(this)
if (config.baseUrl.isEmpty() || !config.baseUrl.isBaseUrlValid()) { if (config.baseUrl.isEmpty() || !config.baseUrl.isBaseUrlValid(this@AddSourceActivity)) {
mustLoginToAddSource() mustLoginToAddSource()
} else { } else {
handleSpoutsSpinner(spoutsSpinner, api, progress, formContainer) handleSpoutsSpinner(spoutsSpinner, api, progress, formContainer)
@@ -74,10 +126,12 @@ class AddSourceActivity : AppCompatActivity() {
) { ) {
val spoutsKV = HashMap<String, String>() val spoutsKV = HashMap<String, String>()
spoutsSpinner.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) {
if (view != null) {
val spoutName = (view as TextView).text.toString() val spoutName = (view as TextView).text.toString()
mSpoutsValue = spoutsKV[spoutName] mSpoutsValue = spoutsKV[spoutName]
} }
}
override fun onNothingSelected(adapterView: AdapterView<*>) { override fun onNothingSelected(adapterView: AdapterView<*>) {
mSpoutsValue = null mSpoutsValue = null
@@ -95,7 +149,7 @@ class AddSourceActivity : AppCompatActivity() {
val itemsStrings = items.map { it.value.name } val itemsStrings = items.map { it.value.name }
for ((key, value) in items) { for ((key, value) in items) {
spoutsKV.put(value.name, key) spoutsKV[value.name] = key
} }
mProgress.visibility = View.GONE mProgress.visibility = View.GONE
@@ -149,7 +203,8 @@ class AddSourceActivity : AppCompatActivity() {
private fun handleSaveSource(tags: EditText, title: String, url: String, api: SelfossApi) { private fun handleSaveSource(tags: EditText, title: String, url: String, api: SelfossApi) {
val sourceDetailsAvailable = title.isEmpty() || url.isEmpty() || mSpoutsValue == null || mSpoutsValue!!.isEmpty() val sourceDetailsAvailable =
title.isEmpty() || url.isEmpty() || mSpoutsValue == null || mSpoutsValue!!.isEmpty()
if (sourceDetailsAvailable) { 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()
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,52 @@
package apps.amine.bou.readerforselfoss
import android.os.Bundle
import android.view.MenuItem
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentStatePagerAdapter
import apps.amine.bou.readerforselfoss.fragments.ImageFragment
import kotlinx.android.synthetic.main.activity_reader.*
class ImageActivity : AppCompatActivity() {
private lateinit var allImages : ArrayList<String>
private var position : Int = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_image)
setSupportActionBar(toolBar)
supportActionBar?.setDisplayShowTitleEnabled(false)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
allImages = intent.getStringArrayListExtra("allImages") as ArrayList<String>
position = intent.getIntExtra("position", 0)
pager.adapter = ScreenSlidePagerAdapter(supportFragmentManager)
pager.currentItem = position
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
android.R.id.home -> {
onBackPressed()
return true
}
}
return super.onOptionsItemSelected(item)
}
private inner class ScreenSlidePagerAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm, FragmentStatePagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
override fun getCount(): Int {
return allImages.size
}
override fun getItem(position: Int): ImageFragment {
return ImageFragment.newInstance(allImages[position])
}
}
}
@@ -1,70 +0,0 @@
package apps.amine.bou.readerforselfoss
import agency.tango.materialintroscreen.MaterialIntroActivity
import agency.tango.materialintroscreen.MessageButtonBehaviour
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.view.View
class IntroActivity : MaterialIntroActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
addSlide(
SlideFragmentBuilder()
.backgroundColor(R.color.colorPrimary)
.buttonsColor(R.color.colorAccent)
.image(R.drawable.web_hi_res_512)
.title(getString(R.string.intro_hello_title))
.description(getString(R.string.intro_hello_message))
.build()
)
addSlide(
SlideFragmentBuilder()
.backgroundColor(R.color.colorAccent)
.buttonsColor(R.color.colorPrimary)
.image(R.drawable.ic_info_outline_white_48px)
.title(getString(R.string.intro_needs_selfoss_title))
.description(getString(R.string.intro_needs_selfoss_message))
.build(),
MessageButtonBehaviour(
View.OnClickListener {
val browserIntent = Intent(
Intent.ACTION_VIEW,
Uri.parse("https://selfoss.aditu.de")
)
startActivity(browserIntent)
}, getString(R.string.intro_needs_selfoss_link)
)
)
addSlide(
SlideFragmentBuilder()
.backgroundColor(R.color.colorPrimaryDark)
.buttonsColor(R.color.colorAccentDark)
.image(R.drawable.ic_thumb_up_white_48px)
.title(getString(R.string.intro_all_set_title))
.description(getString(R.string.intro_all_set_message))
.build()
)
}
override fun onFinish() {
super.onFinish()
val getPrefs = PreferenceManager.getDefaultSharedPreferences(baseContext)
val e = getPrefs.edit()
e.putBoolean("firstStart", false)
e.apply()
val intent = Intent(this, LoginActivity::class.java)
startActivity(intent)
finish()
}
}
@@ -6,8 +6,8 @@ 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.v7.app.AlertDialog import androidx.appcompat.app.AlertDialog
import android.support.v7.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import android.text.TextUtils import android.text.TextUtils
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
@@ -17,11 +17,10 @@ import android.widget.TextView
import android.widget.Toast 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.themes.AppColors
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.crashlytics.android.Crashlytics import apps.amine.bou.readerforselfoss.utils.network.isNetworkAccessible
import com.ftinc.scoop.Scoop
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 kotlinx.android.synthetic.main.activity_login.*
@@ -38,32 +37,29 @@ 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 firebaseAnalytics: FirebaseAnalytics
private lateinit var userIdentifier: String private lateinit var userIdentifier: String
private var logErrors: Boolean = false private lateinit var appColors: AppColors
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
appColors = AppColors(this@LoginActivity)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
Scoop.getInstance().apply(this)
setContentView(R.layout.activity_login) setContentView(R.layout.activity_login)
setSupportActionBar(toolbar) setSupportActionBar(toolbar)
handleBaseUrlFail() handleBaseUrlFail()
settings = getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE) settings = getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
userIdentifier = settings.getString("unique_id", "") userIdentifier = settings.getString("unique_id", "")!!
logErrors = settings.getBoolean("login_debug", false)
editor = settings.edit() editor = settings.edit()
if (settings.getString("url", "").isNotEmpty()) { if (settings.getString("url", "")!!.isNotEmpty()) {
goToMain() goToMain()
} }
firebaseAnalytics = FirebaseAnalytics.getInstance(this)
handleActions() handleActions()
} }
@@ -144,7 +140,7 @@ class LoginActivity : AppCompatActivity() {
var cancel = false var cancel = false
var focusView: View? = null var focusView: View? = null
if (!url.isBaseUrlValid()) { if (!url.isBaseUrlValid(this@LoginActivity)) {
urlView.error = getString(R.string.login_url_problem) urlView.error = getString(R.string.login_url_problem)
focusView = urlView focusView = urlView
cancel = true cancel = true
@@ -163,7 +159,7 @@ class LoginActivity : AppCompatActivity() {
} }
} }
if (isWithLogin || isWithHTTPLogin) { if (isWithLogin) {
if (TextUtils.isEmpty(password)) { if (TextUtils.isEmpty(password)) {
passwordView.error = getString(R.string.error_invalid_password) passwordView.error = getString(R.string.error_invalid_password)
focusView = passwordView focusView = passwordView
@@ -177,6 +173,20 @@ class LoginActivity : AppCompatActivity() {
} }
} }
if (isWithHTTPLogin) {
if (TextUtils.isEmpty(httpPassword)) {
httpPasswordView.error = getString(R.string.error_invalid_password)
focusView = httpPasswordView
cancel = true
}
if (TextUtils.isEmpty(httpLogin)) {
httpLoginView.error = getString(R.string.error_field_required)
focusView = httpLoginView
cancel = true
}
}
if (cancel) { if (cancel) {
focusView?.requestFocus() focusView?.requestFocus()
} else { } else {
@@ -194,8 +204,10 @@ class LoginActivity : AppCompatActivity() {
this, this,
this@LoginActivity, this@LoginActivity,
isWithSelfSignedCert, isWithSelfSignedCert,
isWithSelfSignedCert -1L
) )
if (this@LoginActivity.isNetworkAccessible(this@LoginActivity.findViewById(R.id.loginForm))) {
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")
@@ -209,16 +221,6 @@ class LoginActivity : AppCompatActivity() {
passwordView.error = getString(R.string.wrong_infos) passwordView.error = getString(R.string.wrong_infos)
httpLoginView.error = getString(R.string.wrong_infos) httpLoginView.error = getString(R.string.wrong_infos)
httpPasswordView.error = getString(R.string.wrong_infos) httpPasswordView.error = getString(R.string.wrong_infos)
if (logErrors) {
Crashlytics.setUserIdentifier(userIdentifier)
Crashlytics.log(100, "LOGIN_DEBUG_ERRROR", t.message)
Crashlytics.logException(t)
Toast.makeText(
this@LoginActivity,
t.message,
Toast.LENGTH_LONG
).show()
}
showProgress(false) showProgress(false)
} }
@@ -227,7 +229,6 @@ class LoginActivity : AppCompatActivity() {
response: Response<SuccessResponse> response: Response<SuccessResponse>
) { ) {
if (response.body() != null && response.body()!!.isSuccess) { if (response.body() != null && response.body()!!.isSuccess) {
firebaseAnalytics.logEvent(FirebaseAnalytics.Event.LOGIN, Bundle())
goToMain() goToMain()
} else { } else {
preferenceError(Exception("No response body...")) preferenceError(Exception("No response body..."))
@@ -238,6 +239,9 @@ class LoginActivity : AppCompatActivity() {
preferenceError(t) preferenceError(t)
} }
}) })
} else {
showProgress(false)
}
} }
} }
@@ -273,29 +277,19 @@ class LoginActivity : AppCompatActivity() {
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.login_debug).isChecked = logErrors
return true return true
} }
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) { return when (item.itemId) {
R.id.about -> { R.id.about -> {
LibsBuilder() LibsBuilder()
.withActivityStyle(Libs.ActivityStyle.LIGHT_DARK_TOOLBAR)
.withAboutIconShown(true) .withAboutIconShown(true)
.withAboutVersionShown(true) .withAboutVersionShown(true)
.start(this) .start(this)
return true true
} }
R.id.login_debug -> { else -> super.onOptionsItemSelected(item)
val newState = !item.isChecked
item.isChecked = newState
logErrors = newState
editor.putBoolean("login_debug", newState)
editor.apply()
return true
}
else -> return super.onOptionsItemSelected(item)
} }
} }
} }
@@ -3,7 +3,7 @@ package apps.amine.bou.readerforselfoss
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.preference.PreferenceManager import android.preference.PreferenceManager
import android.support.v7.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {
@@ -11,17 +11,9 @@ class MainActivity : AppCompatActivity() {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main) setContentView(R.layout.activity_main)
if (PreferenceManager.getDefaultSharedPreferences(baseContext).getBoolean(
"firstStart",
true
)) {
val i = Intent(this@MainActivity, IntroActivity::class.java)
startActivity(i)
} else {
val intent = Intent(this, LoginActivity::class.java) val intent = Intent(this, LoginActivity::class.java)
startActivity(intent)
}
startActivity(intent)
finish() finish()
} }
} }
@@ -1,38 +1,32 @@
package apps.amine.bou.readerforselfoss package apps.amine.bou.readerforselfoss
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context import android.content.Context
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.net.Uri import android.net.Uri
import android.os.Build
import android.preference.PreferenceManager import android.preference.PreferenceManager
import android.support.multidex.MultiDexApplication
import android.widget.ImageView import android.widget.ImageView
import androidx.multidex.MultiDexApplication
import apps.amine.bou.readerforselfoss.utils.Config import apps.amine.bou.readerforselfoss.utils.Config
import com.anupcowkur.reservoir.Reservoir import apps.amine.bou.readerforselfoss.utils.glide.loadMaybeBasicAuth
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.stkent.amplify.feedback.DefaultEmailFeedbackCollector
import com.github.stkent.amplify.feedback.GooglePlayStoreFeedbackCollector
import com.github.stkent.amplify.tracking.Amplify
import com.mikepenz.materialdrawer.util.AbstractDrawerImageLoader import com.mikepenz.materialdrawer.util.AbstractDrawerImageLoader
import com.mikepenz.materialdrawer.util.DrawerImageLoader import com.mikepenz.materialdrawer.util.DrawerImageLoader
import io.fabric.sdk.android.Fabric
import java.io.IOException
import java.util.UUID.randomUUID import java.util.UUID.randomUUID
class MyApp : MultiDexApplication() { class MyApp : MultiDexApplication() {
private lateinit var config: Config
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
Fabric.with(this, Crashlytics()) config = Config(baseContext)
initAmplify()
initCache()
val prefs = getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE) val prefs = getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
if (prefs.getString("unique_id", "").isEmpty()) { if (prefs.getString("unique_id", "")!!.isEmpty()) {
val editor = prefs.edit() val editor = prefs.edit()
editor.putString("unique_id", randomUUID().toString()) editor.putString("unique_id", randomUUID().toString())
editor.apply() editor.apply()
@@ -43,20 +37,24 @@ class MyApp : MultiDexApplication() {
initTheme() initTheme()
tryToHandleBug() tryToHandleBug()
handleNotificationChannels()
} }
private fun initAmplify() { private fun handleNotificationChannels() {
Amplify.initSharedInstance(this) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
.setPositiveFeedbackCollectors(GooglePlayStoreFeedbackCollector()) val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
.setCriticalFeedbackCollectors(DefaultEmailFeedbackCollector(BuildConfig.FEEDBACK_EMAIL))
.applyAllDefaultRules()
}
private fun initCache() { val name = getString(R.string.notification_channel_sync)
try { val importance = NotificationManager.IMPORTANCE_LOW
Reservoir.init(this, 8192) //in bytes val mChannel = NotificationChannel(Config.syncChannelId, name, importance)
} catch (e: IOException) {
//failure val newItemsChannelname = getString(R.string.new_items_channel_sync)
val newItemsChannelimportance = NotificationManager.IMPORTANCE_DEFAULT
val newItemsChannelmChannel = NotificationChannel(Config.newItemsChannelId, newItemsChannelname, newItemsChannelimportance)
notificationManager.createNotificationChannel(mChannel)
notificationManager.createNotificationChannel(newItemsChannelmChannel)
} }
} }
@@ -69,7 +67,7 @@ class MyApp : MultiDexApplication() {
tag: String? tag: String?
) { ) {
Glide.with(imageView?.context) Glide.with(imageView?.context)
.load(uri) .loadMaybeBasicAuth(config, uri.toString())
.apply(RequestOptions.fitCenterTransform().placeholder(placeholder)) .apply(RequestOptions.fitCenterTransform().placeholder(placeholder))
.into(imageView) .into(imageView)
} }
@@ -87,19 +85,7 @@ class MyApp : MultiDexApplication() {
private fun initTheme() { private fun initTheme() {
Scoop.waffleCone() Scoop.waffleCone()
.addFlavor(getString(R.string.default_theme), R.style.NoBar, true) .addFlavor(getString(R.string.default_theme), R.style.NoBar, true)
.addFlavor(getString(R.string.default_dark_theme), R.style.NoBarDark) .addFlavor(getString(R.string.default_dark_theme), R.style.NoBarDark, false)
.addFlavor(getString(R.string.teal_orange_theme), R.style.NoBarTealOrange)
.addFlavor(getString(R.string.teal_orange_dark_theme), R.style.NoBarTealOrangeDark)
.addFlavor(getString(R.string.cyan_pink_theme), R.style.NoBarCyanPink)
.addFlavor(getString(R.string.cyan_pink_dark_theme), R.style.NoBarCyanPinkDark)
.addFlavor(getString(R.string.grey_orange_theme), R.style.NoBarGreyOrange)
.addFlavor(getString(R.string.grey_orange_dark_theme), R.style.NoBarGreyOrangeDark)
.addFlavor(getString(R.string.blue_amber_theme), R.style.NoBarBlueAmber)
.addFlavor(getString(R.string.blue_amber_dark_theme), R.style.NoBarBlueAmberDark)
.addFlavor(getString(R.string.indigo_pink_theme), R.style.NoBarIndigoPink)
.addFlavor(getString(R.string.indigo_pink_dark_theme), R.style.NoBarIndigoPinkDark)
.addFlavor(getString(R.string.red_teal_theme), R.style.NoBarRedTeal)
.addFlavor(getString(R.string.red_teal_dark_theme), R.style.NoBarRedTealDark)
.setSharedPreferences(PreferenceManager.getDefaultSharedPreferences(this)) .setSharedPreferences(PreferenceManager.getDefaultSharedPreferences(this))
.initialize() .initialize()
} }
@@ -1,137 +1,187 @@
package apps.amine.bou.readerforselfoss package apps.amine.bou.readerforselfoss
import android.content.Context import android.content.Context
import android.content.SharedPreferences
import android.graphics.drawable.ColorDrawable
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.preference.PreferenceManager import android.preference.PreferenceManager
import android.support.v4.app.FragmentManager import androidx.fragment.app.FragmentManager
import android.support.v4.app.FragmentStatePagerAdapter import androidx.fragment.app.FragmentStatePagerAdapter
import android.support.v4.view.ViewPager import androidx.core.content.ContextCompat
import android.support.v7.app.AppCompatActivity import androidx.viewpager.widget.ViewPager
import androidx.appcompat.app.AppCompatActivity
import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.room.Room
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.fragments.ArticleFragment import apps.amine.bou.readerforselfoss.fragments.ArticleFragment
import apps.amine.bou.readerforselfoss.persistence.database.AppDatabase
import apps.amine.bou.readerforselfoss.persistence.entities.ActionEntity
import apps.amine.bou.readerforselfoss.persistence.migrations.MIGRATION_1_2
import apps.amine.bou.readerforselfoss.persistence.migrations.MIGRATION_2_3
import apps.amine.bou.readerforselfoss.persistence.migrations.MIGRATION_3_4
import apps.amine.bou.readerforselfoss.themes.AppColors
import apps.amine.bou.readerforselfoss.themes.Toppings
import apps.amine.bou.readerforselfoss.transformers.DepthPageTransformer import apps.amine.bou.readerforselfoss.transformers.DepthPageTransformer
import apps.amine.bou.readerforselfoss.utils.Config import apps.amine.bou.readerforselfoss.utils.Config
import apps.amine.bou.readerforselfoss.utils.network.isNetworkAccessible
import apps.amine.bou.readerforselfoss.utils.persistence.toEntity
import apps.amine.bou.readerforselfoss.utils.succeeded import apps.amine.bou.readerforselfoss.utils.succeeded
import com.crashlytics.android.Crashlytics import apps.amine.bou.readerforselfoss.utils.toggleStar
import com.ftinc.scoop.Scoop import com.ftinc.scoop.Scoop
import kotlinx.android.synthetic.main.activity_reader.* import kotlinx.android.synthetic.main.activity_reader.*
import me.relex.circleindicator.CircleIndicator import me.relex.circleindicator.CircleIndicator
import retrofit2.Call import retrofit2.Call
import retrofit2.Callback import retrofit2.Callback
import retrofit2.Response import retrofit2.Response
import kotlin.concurrent.thread
class ReaderActivity : AppCompatActivity() { class ReaderActivity : AppCompatActivity() {
private var markOnScroll: Boolean = false private var markOnScroll: Boolean = false
private var currentItem: Int = 0
private lateinit var userIdentifier: String
private var useWebview: Boolean = false private lateinit var api: SelfossApi
private lateinit var toolbarMenu: Menu
private lateinit var db: AppDatabase
private lateinit var prefs: SharedPreferences
private var activeAlignment: Int = 1
val JUSTIFY = 1
val ALIGN_LEFT = 2
private fun showMenuItem(willAddToFavorite: Boolean) {
toolbarMenu.findItem(R.id.save).isVisible = willAddToFavorite
toolbarMenu.findItem(R.id.unsave).isVisible = !willAddToFavorite
}
private fun canFavorite() {
showMenuItem(true)
}
private fun canRemoveFromFavorite() {
showMenuItem(false)
}
private lateinit var editor: SharedPreferences.Editor
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
Scoop.getInstance().apply(this)
setContentView(R.layout.activity_reader) setContentView(R.layout.activity_reader)
db = Room.databaseBuilder(
applicationContext,
AppDatabase::class.java, "selfoss-database"
).addMigrations(MIGRATION_1_2).addMigrations(MIGRATION_2_3).addMigrations(MIGRATION_3_4).build()
val scoop = Scoop.getInstance()
scoop.bind(this, Toppings.PRIMARY.value, toolBar)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
scoop.bindStatusBar(this, Toppings.PRIMARY_DARK.value)
}
setSupportActionBar(toolBar) setSupportActionBar(toolBar)
supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setDisplayShowHomeEnabled(true) supportActionBar?.setDisplayShowHomeEnabled(true)
val settings = getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE) val settings =
val sharedPref = PreferenceManager.getDefaultSharedPreferences(this) getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
val debugReadingItems = sharedPref.getBoolean("read_debug", false) prefs = PreferenceManager.getDefaultSharedPreferences(this)
val userIdentifier = sharedPref.getString("unique_id", "") editor = prefs.edit()
markOnScroll = sharedPref.getBoolean("mark_on_scroll", false)
useWebview = sharedPref.getBoolean("prefer_webview_in_article_viewer", false)
userIdentifier = prefs.getString("unique_id", "")!!
markOnScroll = prefs.getBoolean("mark_on_scroll", false)
activeAlignment = prefs.getInt("text_align", JUSTIFY)
if (allItems.isEmpty()) { api = SelfossApi(
Crashlytics.setUserIdentifier(userIdentifier)
Crashlytics.log(
100,
"READER_ITEMS_EMPTY",
"Items empty when trying to open the Article Reader. Was (static) companion object field set ?"
)
Crashlytics.logException(Exception("Empty items on Reader Activity."))
finish()
}
val api = SelfossApi(
this, this,
this@ReaderActivity, this@ReaderActivity,
settings.getBoolean("isSelfSignedCert", false), settings.getBoolean("isSelfSignedCert", false),
sharedPref.getBoolean("should_log_everything", false) prefs.getString("api_timeout", "-1")!!.toLong()
) )
val currentItem = intent.getIntExtra("currentItem", 0) if (allItems.isEmpty()) {
finish()
}
var adapter = ScreenSlidePagerAdapter(supportFragmentManager) currentItem = intent.getIntExtra("currentItem", 0)
pager.adapter = adapter
readItem(allItems[currentItem])
pager.adapter =
ScreenSlidePagerAdapter(supportFragmentManager, AppColors(this@ReaderActivity))
pager.currentItem = currentItem pager.currentItem = currentItem
}
override fun onResume() {
super.onResume()
notifyAdapter()
pager.setPageTransformer(true, DepthPageTransformer()) pager.setPageTransformer(true, DepthPageTransformer())
(indicator as CircleIndicator).setViewPager(pager) (indicator as CircleIndicator).setViewPager(pager)
if (markOnScroll) {
pager.addOnPageChangeListener( pager.addOnPageChangeListener(
object : ViewPager.SimpleOnPageChangeListener() { object : ViewPager.SimpleOnPageChangeListener() {
var isLastItem = false
override fun onPageSelected(position: Int) { override fun onPageSelected(position: Int) {
isLastItem = (position === (allItems.size - 1))
if (allItems[position].starred) {
canRemoveFromFavorite()
} else {
canFavorite()
}
readItem(allItems[pager.currentItem])
}
}
)
} }
override fun onPageScrollStateChanged(state: Int) { fun readItem(item: Item) {
if (state === ViewPager.SCROLL_STATE_DRAGGING || (state === ViewPager.SCROLL_STATE_IDLE && isLastItem)) { if (markOnScroll) {
api.markItem(allItems[pager.currentItem].id).enqueue( thread {
db.itemsDao().delete(item.toEntity())
}
if (this@ReaderActivity.isNetworkAccessible(this@ReaderActivity.findViewById(R.id.reader_activity_view))) {
api.markItem(item.id).enqueue(
object : Callback<SuccessResponse> { object : Callback<SuccessResponse> {
override fun onResponse( override fun onResponse(
call: Call<SuccessResponse>, call: Call<SuccessResponse>,
response: Response<SuccessResponse> response: Response<SuccessResponse>
) { ) {
if (!response.succeeded() && debugReadingItems) {
val message =
"message: ${response.message()} " +
"response isSuccess: ${response.isSuccessful} " +
"response code: ${response.code()} " +
"response message: ${response.message()} " +
"response errorBody: ${response.errorBody()?.string()} " +
"body success: ${response.body()?.success} " +
"body isSuccess: ${response.body()?.isSuccess}"
Crashlytics.setUserIdentifier(userIdentifier)
Crashlytics.log(
100,
"READ_DEBUG_SUCCESS",
message
)
Crashlytics.logException(Exception("Was success, but did it work ?"))
}
} }
override fun onFailure( override fun onFailure(
call: Call<SuccessResponse>, call: Call<SuccessResponse>,
t: Throwable t: Throwable
) { ) {
if (debugReadingItems) { thread {
Crashlytics.setUserIdentifier(userIdentifier) db.itemsDao().insertAllItems(item.toEntity())
Crashlytics.log(
100,
"READ_DEBUG_ERROR",
t.message
)
Crashlytics.logException(t)
} }
} }
} }
) )
} else {
thread {
db.actionsDao().insertAllActions(ActionEntity(item.id, true, false, false, false))
} }
} }
} }
)
} }
private fun notifyAdapter() {
(pager.adapter as ScreenSlidePagerAdapter).notifyDataSetChanged()
} }
override fun onPause() { override fun onPause() {
@@ -141,31 +191,158 @@ class ReaderActivity : AppCompatActivity() {
} }
} }
override fun onSaveInstanceState(oldInstanceState: Bundle?) { override fun onSaveInstanceState(oldInstanceState: Bundle) {
super.onSaveInstanceState(oldInstanceState) super.onSaveInstanceState(oldInstanceState)
oldInstanceState!!.clear() oldInstanceState!!.clear()
} }
private inner class ScreenSlidePagerAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm) { private inner class ScreenSlidePagerAdapter(fm: FragmentManager, val appColors: AppColors) :
FragmentStatePagerAdapter(fm) {
override fun getCount(): Int { override fun getCount(): Int {
return allItems.size return allItems.size
} }
override fun getItem(position: Int): ArticleFragment { override fun getItem(position: Int): ArticleFragment {
return ArticleFragment.newInstance(position, allItems, useWebview) return ArticleFragment.newInstance(position, allItems)
}
override fun startUpdate(container: ViewGroup) {
super.startUpdate(container)
container.background = ColorDrawable(
ContextCompat.getColor(
this@ReaderActivity,
appColors.colorBackground
)
)
} }
} }
fun alignmentMenu(showJustify: Boolean) {
toolbarMenu.findItem(R.id.align_left).isVisible = !showJustify
toolbarMenu.findItem(R.id.align_justify).isVisible = showJustify
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
val inflater = menuInflater
inflater.inflate(R.menu.reader_menu, menu)
toolbarMenu = menu
if (!allItems.isEmpty() && allItems[currentItem].starred) {
canRemoveFromFavorite()
} else {
canFavorite()
}
if (activeAlignment == JUSTIFY) {
alignmentMenu(false)
} else {
alignmentMenu(true)
}
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
fun afterSave() {
allItems[pager.currentItem] =
allItems[pager.currentItem].toggleStar()
notifyAdapter()
canRemoveFromFavorite()
}
fun afterUnsave() {
allItems[pager.currentItem] = allItems[pager.currentItem].toggleStar()
notifyAdapter()
canFavorite()
}
when (item.itemId) { when (item.itemId) {
android.R.id.home -> { android.R.id.home -> {
onBackPressed() onBackPressed()
return true return true
} }
R.id.save -> {
if (this@ReaderActivity.isNetworkAccessible(null)) {
api.starrItem(allItems[pager.currentItem].id)
.enqueue(object : Callback<SuccessResponse> {
override fun onResponse(
call: Call<SuccessResponse>,
response: Response<SuccessResponse>
) {
afterSave()
}
override fun onFailure(
call: Call<SuccessResponse>,
t: Throwable
) {
Toast.makeText(
baseContext,
R.string.cant_mark_favortie,
Toast.LENGTH_SHORT
).show()
}
})
} else {
thread {
db.actionsDao().insertAllActions(ActionEntity(allItems[pager.currentItem].id, false, false, true, false))
afterSave()
}
}
}
R.id.unsave -> {
if (this@ReaderActivity.isNetworkAccessible(null)) {
api.unstarrItem(allItems[pager.currentItem].id)
.enqueue(object : Callback<SuccessResponse> {
override fun onResponse(
call: Call<SuccessResponse>,
response: Response<SuccessResponse>
) {
afterUnsave()
}
override fun onFailure(
call: Call<SuccessResponse>,
t: Throwable
) {
Toast.makeText(
baseContext,
R.string.cant_unmark_favortie,
Toast.LENGTH_SHORT
).show()
}
})
} else {
thread {
db.actionsDao().insertAllActions(ActionEntity(allItems[pager.currentItem].id, false, false, false, true))
afterUnsave()
}
}
}
R.id.align_left -> {
editor.putInt("text_align", ALIGN_LEFT)
editor.apply()
alignmentMenu(true)
refreshFragment()
}
R.id.align_justify -> {
editor.putInt("text_align", JUSTIFY)
editor.apply()
alignmentMenu(false)
refreshFragment()
}
} }
return super.onOptionsItemSelected(item) return super.onOptionsItemSelected(item)
} }
private fun refreshFragment() {
finish()
overridePendingTransition(0, 0)
startActivity(intent)
overridePendingTransition(0, 0)
}
companion object { companion object {
var allItems: ArrayList<Item> = ArrayList() var allItems: ArrayList<Item> = ArrayList()
} }
@@ -1,14 +1,21 @@
package apps.amine.bou.readerforselfoss package apps.amine.bou.readerforselfoss
import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.res.ColorStateList
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.preference.PreferenceManager import android.preference.PreferenceManager
import android.support.v7.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import android.support.v7.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import android.widget.Toast import android.widget.Toast
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.Source
import apps.amine.bou.readerforselfoss.themes.AppColors
import apps.amine.bou.readerforselfoss.themes.Toppings
import apps.amine.bou.readerforselfoss.utils.Config
import apps.amine.bou.readerforselfoss.utils.network.isNetworkAccessible
import com.ftinc.scoop.Scoop import com.ftinc.scoop.Scoop
import kotlinx.android.synthetic.main.activity_sources.* import kotlinx.android.synthetic.main.activity_sources.*
import retrofit2.Call import retrofit2.Call
@@ -17,14 +24,27 @@ import retrofit2.Response
class SourcesActivity : AppCompatActivity() { class SourcesActivity : AppCompatActivity() {
private lateinit var appColors: AppColors
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
appColors = AppColors(this@SourcesActivity)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
Scoop.getInstance().apply(this)
setContentView(R.layout.activity_sources) setContentView(R.layout.activity_sources)
val scoop = Scoop.getInstance()
scoop.bind(this, Toppings.PRIMARY.value, toolbar)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
scoop.bindStatusBar(this, Toppings.PRIMARY_DARK.value)
}
setSupportActionBar(toolbar) setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setDisplayShowHomeEnabled(true) supportActionBar?.setDisplayShowHomeEnabled(true)
fab.rippleColor = appColors.colorAccentDark
fab.backgroundTintList = ColorStateList.valueOf(appColors.colorAccent)
} }
override fun onStop() { override fun onStop() {
@@ -36,26 +56,29 @@ class SourcesActivity : AppCompatActivity() {
super.onResume() super.onResume()
val mLayoutManager = LinearLayoutManager(this) val mLayoutManager = LinearLayoutManager(this)
val settings =
getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
val prefs = PreferenceManager.getDefaultSharedPreferences(this) val prefs = PreferenceManager.getDefaultSharedPreferences(this)
val api = SelfossApi( val api = SelfossApi(
this, this,
this@SourcesActivity, this@SourcesActivity,
prefs.getBoolean("isSelfSignedCert", false), settings.getBoolean("isSelfSignedCert", false),
prefs.getBoolean("should_log_everything", false) prefs.getString("api_timeout", "-1")!!.toLong()
) )
var items: ArrayList<Sources> = ArrayList() var items: ArrayList<Source> = ArrayList()
recyclerView.setHasFixedSize(true) recyclerView.setHasFixedSize(true)
recyclerView.layoutManager = mLayoutManager recyclerView.layoutManager = mLayoutManager
api.sources.enqueue(object : Callback<List<Sources>> { if (this@SourcesActivity.isNetworkAccessible(this@SourcesActivity.findViewById(R.id.recyclerView))) {
api.sources.enqueue(object : Callback<List<Source>> {
override fun onResponse( override fun onResponse(
call: Call<List<Sources>>, call: Call<List<Source>>,
response: Response<List<Sources>> response: Response<List<Source>>
) { ) {
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<Source>
} }
val mAdapter = SourcesListAdapter(this@SourcesActivity, items, api) val mAdapter = SourcesListAdapter(this@SourcesActivity, items, api)
recyclerView.adapter = mAdapter recyclerView.adapter = mAdapter
@@ -69,7 +92,7 @@ class SourcesActivity : AppCompatActivity() {
} }
} }
override fun onFailure(call: Call<List<Sources>>, t: Throwable) { override fun onFailure(call: Call<List<Source>>, t: Throwable) {
Toast.makeText( Toast.makeText(
this@SourcesActivity, this@SourcesActivity,
R.string.cant_get_sources, R.string.cant_get_sources,
@@ -77,6 +100,7 @@ class SourcesActivity : AppCompatActivity() {
).show() ).show()
} }
}) })
}
fab.setOnClickListener { fab.setOnClickListener {
startActivity(Intent(this@SourcesActivity, AddSourceActivity::class.java)) startActivity(Intent(this@SourcesActivity, AddSourceActivity::class.java))
@@ -2,58 +2,66 @@ 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 androidx.cardview.widget.CardView
import android.support.design.widget.Snackbar import androidx.recyclerview.widget.RecyclerView
import android.support.v7.widget.CardView
import android.support.v7.widget.RecyclerView
import android.text.Html
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.ImageView.ScaleType import android.widget.ImageView.ScaleType
import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import androidx.core.content.ContextCompat
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.persistence.database.AppDatabase
import apps.amine.bou.readerforselfoss.persistence.entities.ActionEntity
import apps.amine.bou.readerforselfoss.themes.AppColors import apps.amine.bou.readerforselfoss.themes.AppColors
import apps.amine.bou.readerforselfoss.utils.Config
import apps.amine.bou.readerforselfoss.utils.LinkOnTouchListener
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.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.network.isNetworkAccessible
import apps.amine.bou.readerforselfoss.utils.openInBrowserAsNewTask import apps.amine.bou.readerforselfoss.utils.openInBrowserAsNewTask
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 apps.amine.bou.readerforselfoss.utils.sourceAndDateText import apps.amine.bou.readerforselfoss.utils.sourceAndDateText
import apps.amine.bou.readerforselfoss.utils.succeeded
import apps.amine.bou.readerforselfoss.utils.toTextDrawableString import apps.amine.bou.readerforselfoss.utils.toTextDrawableString
import com.amulyakhare.textdrawable.TextDrawable import com.amulyakhare.textdrawable.TextDrawable
import com.amulyakhare.textdrawable.util.ColorGenerator import com.amulyakhare.textdrawable.util.ColorGenerator
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.crashlytics.android.Crashlytics
import com.like.LikeButton import com.like.LikeButton
import com.like.OnLikeListener import com.like.OnLikeListener
import kotlinx.android.synthetic.main.card_item.view.* import kotlinx.android.synthetic.main.card_item.view.*
import kotlinx.android.synthetic.main.card_item.view.itemImage
import kotlinx.android.synthetic.main.card_item.view.sourceTitleAndDate
import kotlinx.android.synthetic.main.card_item.view.title
import kotlinx.android.synthetic.main.list_item.view.*
import retrofit2.Call import retrofit2.Call
import retrofit2.Callback import retrofit2.Callback
import retrofit2.Response import retrofit2.Response
import kotlin.concurrent.thread
class ItemCardAdapter( class ItemCardAdapter(
private val app: Activity, override val app: Activity,
private val items: ArrayList<Item>, override var items: ArrayList<Item>,
private val api: SelfossApi, override val api: SelfossApi,
override val db: AppDatabase,
private val helper: CustomTabActivityHelper, private val helper: CustomTabActivityHelper,
private val internalBrowser: Boolean, private val internalBrowser: Boolean,
private val articleViewer: Boolean, private val articleViewer: Boolean,
private val fullHeightCards: Boolean, private val fullHeightCards: Boolean,
private val appColors: AppColors, override val appColors: AppColors,
val debugReadingItems: Boolean, override val userIdentifier: String,
val userIdentifier: String override val config: Config,
) : RecyclerView.Adapter<ItemCardAdapter.ViewHolder>() { override val updateItems: (ArrayList<Item>) -> Unit
) : ItemsAdapter<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
private val imageMaxHeight: Int = c.resources.getDimension(R.dimen.card_image_max_height).toInt() private val imageMaxHeight: Int =
c.resources.getDimension(R.dimen.card_image_max_height).toInt()
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 CardView val v = LayoutInflater.from(c).inflate(R.layout.card_item, parent, false) as CardView
@@ -65,10 +73,22 @@ class ItemCardAdapter(
holder.mView.favButton.isLiked = itm.starred holder.mView.favButton.isLiked = itm.starred
holder.mView.title.text = Html.fromHtml(itm.title) holder.mView.title.text = itm.getTitleDecoded()
holder.mView.title.setTextColor(ContextCompat.getColor(
c,
appColors.textColor
))
holder.mView.title.setOnTouchListener(LinkOnTouchListener())
holder.mView.title.setLinkTextColor(appColors.colorAccent)
holder.mView.sourceTitleAndDate.text = itm.sourceAndDateText() holder.mView.sourceTitleAndDate.text = itm.sourceAndDateText()
holder.mView.sourceTitleAndDate.setTextColor(ContextCompat.getColor(
c,
appColors.textColor
))
if (!fullHeightCards) { if (!fullHeightCards) {
holder.mView.itemImage.maxHeight = imageMaxHeight holder.mView.itemImage.maxHeight = imageMaxHeight
holder.mView.itemImage.scaleType = ScaleType.CENTER_CROP holder.mView.itemImage.scaleType = ScaleType.CENTER_CROP
@@ -80,20 +100,20 @@ class ItemCardAdapter(
holder.mView.itemImage.setImageDrawable(null) holder.mView.itemImage.setImageDrawable(null)
} else { } else {
holder.mView.itemImage.visibility = View.VISIBLE holder.mView.itemImage.visibility = View.VISIBLE
c.bitmapCenterCrop(itm.getThumbnail(c), holder.mView.itemImage) c.bitmapCenterCrop(config, itm.getThumbnail(c), holder.mView.itemImage)
} }
if (itm.getIcon(c).isEmpty()) { if (itm.getIcon(c).isEmpty()) {
val color = generator.getColor(itm.sourcetitle) val color = generator.getColor(itm.getSourceTitle())
val drawable = val drawable =
TextDrawable TextDrawable
.builder() .builder()
.round() .round()
.build(itm.sourcetitle.toTextDrawableString(), color) .build(itm.getSourceTitle().toTextDrawableString(c), color)
holder.mView.sourceImage.setImageDrawable(drawable) holder.mView.sourceImage.setImageDrawable(drawable)
} else { } else {
c.circularBitmapDrawable(itm.getIcon(c), holder.mView.sourceImage) c.circularBitmapDrawable(config, itm.getIcon(c), holder.mView.sourceImage)
} }
holder.mView.favButton.isLiked = itm.starred holder.mView.favButton.isLiked = itm.starred
@@ -103,89 +123,9 @@ class ItemCardAdapter(
return items.size return items.size
} }
private fun doUnmark(i: Item, position: Int) {
val s = Snackbar
.make(
app.findViewById(R.id.coordLayout),
R.string.marked_as_read,
Snackbar.LENGTH_LONG
)
.setAction(R.string.undo_string) {
items.add(position, i)
notifyItemInserted(position)
api.unmarkItem(i.id).enqueue(object : Callback<SuccessResponse> {
override fun onResponse(
call: Call<SuccessResponse>,
response: Response<SuccessResponse>
) {
}
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
items.remove(i)
notifyItemRemoved(position)
doUnmark(i, position)
}
})
}
val view = s.view
val tv: TextView = view.findViewById(android.support.design.R.id.snackbar_text)
tv.setTextColor(Color.WHITE)
s.show()
}
fun removeItemAtIndex(position: Int) {
val i = items[position]
items.remove(i)
notifyItemRemoved(position)
api.markItem(i.id).enqueue(object : Callback<SuccessResponse> {
override fun onResponse(
call: Call<SuccessResponse>,
response: Response<SuccessResponse>
) {
if (!response.succeeded() && debugReadingItems) {
val message =
"message: ${response.message()} " +
"response isSuccess: ${response.isSuccessful} " +
"response code: ${response.code()} " +
"response message: ${response.message()} " +
"response errorBody: ${response.errorBody()?.string()} " +
"body success: ${response.body()?.success} " +
"body isSuccess: ${response.body()?.isSuccess}"
Crashlytics.setUserIdentifier(userIdentifier)
Crashlytics.log(100, "READ_DEBUG_SUCCESS", message)
Crashlytics.logException(Exception("Was success, but did it work ?"))
Toast.makeText(c, message, Toast.LENGTH_LONG).show()
}
doUnmark(i, position)
}
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
if (debugReadingItems) {
Crashlytics.setUserIdentifier(userIdentifier)
Crashlytics.log(100, "READ_DEBUG_ERROR", t.message)
Crashlytics.logException(t)
Toast.makeText(c, t.message, Toast.LENGTH_LONG).show()
}
Toast.makeText(
app,
app.getString(R.string.cant_mark_read),
Toast.LENGTH_SHORT
).show()
items.add(i)
notifyItemInserted(position)
}
})
}
inner class ViewHolder(val mView: CardView) : RecyclerView.ViewHolder(mView) { inner class ViewHolder(val mView: CardView) : RecyclerView.ViewHolder(mView) {
init { init {
mView.setCardBackgroundColor(appColors.cardBackground) mView.setCardBackgroundColor(appColors.cardBackgroundColor)
handleClickListeners() handleClickListeners()
handleCustomTabActions() handleCustomTabActions()
} }
@@ -195,6 +135,7 @@ class ItemCardAdapter(
mView.favButton.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]
if (c.isNetworkAccessible(null)) {
api.starrItem(id).enqueue(object : Callback<SuccessResponse> { api.starrItem(id).enqueue(object : Callback<SuccessResponse> {
override fun onResponse( override fun onResponse(
call: Call<SuccessResponse>, call: Call<SuccessResponse>,
@@ -214,10 +155,16 @@ class ItemCardAdapter(
).show() ).show()
} }
}) })
} else {
thread {
db.actionsDao().insertAllActions(ActionEntity(id, false, false, true, false))
}
}
} }
override fun unLiked(likeButton: LikeButton) { override fun unLiked(likeButton: LikeButton) {
val (id) = items[adapterPosition] val (id) = items[adapterPosition]
if (c.isNetworkAccessible(null)) {
api.unstarrItem(id).enqueue(object : Callback<SuccessResponse> { api.unstarrItem(id).enqueue(object : Callback<SuccessResponse> {
override fun onResponse( override fun onResponse(
call: Call<SuccessResponse>, call: Call<SuccessResponse>,
@@ -237,11 +184,17 @@ class ItemCardAdapter(
).show() ).show()
} }
}) })
} else {
thread {
db.actionsDao().insertAllActions(ActionEntity(id, false, false, false, true))
}
}
} }
}) })
mView.shareBtn.setOnClickListener { mView.shareBtn.setOnClickListener {
c.shareLink(items[adapterPosition].getLinkDecoded()) val item = items[adapterPosition]
c.shareLink(item.getLinkDecoded(), item.getTitleDecoded())
} }
mView.browserBtn.setOnClickListener { mView.browserBtn.setOnClickListener {
@@ -2,21 +2,26 @@ 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 androidx.constraintlayout.widget.ConstraintLayout
import android.support.constraint.ConstraintLayout import androidx.recyclerview.widget.RecyclerView
import android.support.design.widget.Snackbar import android.text.Spannable
import android.support.v7.widget.RecyclerView import android.text.style.ClickableSpan
import android.text.Html
import android.util.TypedValue import android.util.TypedValue
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.TextView import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import androidx.core.content.ContextCompat
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.persistence.database.AppDatabase
import apps.amine.bou.readerforselfoss.themes.AppColors
import apps.amine.bou.readerforselfoss.utils.Config
import apps.amine.bou.readerforselfoss.utils.LinkOnTouchListener
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.glide.bitmapCenterCrop import apps.amine.bou.readerforselfoss.utils.glide.bitmapCenterCrop
@@ -25,10 +30,9 @@ import apps.amine.bou.readerforselfoss.utils.openInBrowserAsNewTask
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 apps.amine.bou.readerforselfoss.utils.sourceAndDateText 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.TextDrawable
import com.amulyakhare.textdrawable.util.ColorGenerator import com.amulyakhare.textdrawable.util.ColorGenerator
import com.crashlytics.android.Crashlytics
import com.like.LikeButton import com.like.LikeButton
import com.like.OnLikeListener import com.like.OnLikeListener
import kotlinx.android.synthetic.main.list_item.view.* import kotlinx.android.synthetic.main.list_item.view.*
@@ -39,19 +43,20 @@ import java.util.*
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
class ItemListAdapter( class ItemListAdapter(
private val app: Activity, override val app: Activity,
private val items: ArrayList<Item>, override var items: ArrayList<Item>,
private val api: SelfossApi, override val api: SelfossApi,
override val db: AppDatabase,
private val helper: CustomTabActivityHelper, private val helper: CustomTabActivityHelper,
private val clickBehavior: Boolean,
private val internalBrowser: Boolean, private val internalBrowser: Boolean,
private val articleViewer: Boolean, private val articleViewer: Boolean,
val debugReadingItems: Boolean, override val userIdentifier: String,
val userIdentifier: String override val appColors: AppColors,
) : RecyclerView.Adapter<ItemListAdapter.ViewHolder>() { override val config: Config,
override val updateItems: (ArrayList<Item>) -> Unit
) : ItemsAdapter<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))
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val v = LayoutInflater.from(c).inflate( val v = LayoutInflater.from(c).inflate(
@@ -66,211 +71,56 @@ class ItemListAdapter(
val itm = items[position] val itm = items[position]
holder.mView.favButton.isLiked = itm.starred holder.mView.title.text = itm.getTitleDecoded()
holder.mView.title.text = Html.fromHtml(itm.title)
holder.mView.title.setTextColor(ContextCompat.getColor(
c,
appColors.textColor
))
holder.mView.title.setOnTouchListener(LinkOnTouchListener())
holder.mView.title.setLinkTextColor(appColors.colorAccent)
holder.mView.sourceTitleAndDate.text = itm.sourceAndDateText() holder.mView.sourceTitleAndDate.text = itm.sourceAndDateText()
holder.mView.sourceTitleAndDate.setTextColor(ContextCompat.getColor(
c,
appColors.textColor
))
if (itm.getThumbnail(c).isEmpty()) { if (itm.getThumbnail(c).isEmpty()) {
val sizeInInt = 46
val sizeInDp = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, sizeInInt.toFloat(), c.resources
.displayMetrics
).toInt()
val marginInInt = 16
val marginInDp = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, marginInInt.toFloat(), c.resources
.displayMetrics
).toInt()
val params = holder.mView.itemImage.layoutParams as ViewGroup.MarginLayoutParams
params.height = sizeInDp
params.width = sizeInDp
params.setMargins(marginInDp, 0, 0, 0)
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.getSourceTitle())
val textDrawable = StringBuilder()
for (s in itm.sourcetitle.split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()) {
textDrawable.append(s[0])
}
val builder = TextDrawable.builder().round() val drawable =
TextDrawable
.builder()
.round()
.build(itm.getSourceTitle().toTextDrawableString(c), color)
val drawable = builder.build(textDrawable.toString(), color)
holder.mView.itemImage.setImageDrawable(drawable) holder.mView.itemImage.setImageDrawable(drawable)
} else { } else {
c.circularBitmapDrawable(itm.getIcon(c), holder.mView.itemImage) c.circularBitmapDrawable(config, itm.getIcon(c), holder.mView.itemImage)
} }
} else { } else {
c.bitmapCenterCrop(itm.getThumbnail(c), holder.mView.itemImage) c.bitmapCenterCrop(config, itm.getThumbnail(c), holder.mView.itemImage)
} }
if (bars[position]) {
holder.mView.actionBar.visibility = View.VISIBLE
} else {
holder.mView.actionBar.visibility = View.GONE
}
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) {
val s = Snackbar
.make(
app.findViewById(R.id.coordLayout),
R.string.marked_as_read,
Snackbar.LENGTH_LONG
)
.setAction(R.string.undo_string) {
items.add(position, i)
notifyItemInserted(position)
api.unmarkItem(i.id).enqueue(object : Callback<SuccessResponse> {
override fun onResponse(
call: Call<SuccessResponse>,
response: Response<SuccessResponse>
) {
}
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
items.remove(i)
notifyItemRemoved(position)
doUnmark(i, position)
}
})
}
val view = s.view
val tv: TextView = view.findViewById(android.support.design.R.id.snackbar_text)
tv.setTextColor(Color.WHITE)
s.show()
}
fun removeItemAtIndex(position: Int) {
val i = items[position]
items.remove(i)
notifyItemRemoved(position)
api.markItem(i.id).enqueue(object : Callback<SuccessResponse> {
override fun onResponse(
call: Call<SuccessResponse>,
response: Response<SuccessResponse>
) {
if (!response.succeeded() && debugReadingItems) {
val message =
"message: ${response.message()} " +
"response isSuccess: ${response.isSuccessful} " +
"response code: ${response.code()} " +
"response message: ${response.message()} " +
"response errorBody: ${response.errorBody()?.string()} " +
"body success: ${response.body()?.success} " +
"body isSuccess: ${response.body()?.isSuccess}"
Crashlytics.setUserIdentifier(userIdentifier)
Crashlytics.log(100, "READ_DEBUG_SUCCESS", message)
Crashlytics.logException(Exception("Was success, but did it work ?"))
Toast.makeText(c, message, Toast.LENGTH_LONG).show()
}
doUnmark(i, position)
}
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
if (debugReadingItems) {
Crashlytics.setUserIdentifier(userIdentifier)
Crashlytics.log(100, "READ_DEBUG_ERROR", t.message)
Crashlytics.logException(t)
Toast.makeText(c, t.message, Toast.LENGTH_LONG).show()
}
Toast.makeText(
app,
app.getString(R.string.cant_mark_read),
Toast.LENGTH_SHORT
).show()
items.add(i)
notifyItemInserted(position)
}
})
}
inner class ViewHolder(val mView: ConstraintLayout) : RecyclerView.ViewHolder(mView) { inner class ViewHolder(val mView: ConstraintLayout) : RecyclerView.ViewHolder(mView) {
init { init {
handleClickListeners()
handleCustomTabActions() handleCustomTabActions()
} }
private fun handleClickListeners() {
mView.favButton.setOnLikeListener(object : OnLikeListener {
override fun liked(likeButton: LikeButton) {
val (id) = items[adapterPosition]
api.starrItem(id).enqueue(object : Callback<SuccessResponse> {
override fun onResponse(
call: Call<SuccessResponse>,
response: Response<SuccessResponse>
) {
}
override fun onFailure(
call: Call<SuccessResponse>,
t: Throwable
) {
mView.favButton.isLiked = false
Toast.makeText(
c,
R.string.cant_mark_favortie,
Toast.LENGTH_SHORT
).show()
}
})
}
override fun unLiked(likeButton: LikeButton) {
val (id) = items[adapterPosition]
api.unstarrItem(id).enqueue(object : Callback<SuccessResponse> {
override fun onResponse(
call: Call<SuccessResponse>,
response: Response<SuccessResponse>
) {
}
override fun onFailure(
call: Call<SuccessResponse>,
t: Throwable
) {
mView.favButton.isLiked = true
Toast.makeText(
c,
R.string.cant_unmark_favortie,
Toast.LENGTH_SHORT
).show()
}
})
}
})
mView.shareBtn.setOnClickListener {
c.shareLink(items[adapterPosition].getLinkDecoded())
}
mView.browserBtn.setOnClickListener {
c.openInBrowserAsNewTask(items[adapterPosition])
}
}
private fun handleCustomTabActions() { private fun handleCustomTabActions() {
val customTabsIntent = c.buildCustomTabsIntent() val customTabsIntent = c.buildCustomTabsIntent()
helper.bindCustomTabsService(app) helper.bindCustomTabsService(app)
if (!clickBehavior) {
mView.setOnClickListener { mView.setOnClickListener {
c.openItemUrl( c.openItemUrl(
items, items,
@@ -282,34 +132,6 @@ class ItemListAdapter(
app app
) )
} }
mView.setOnLongClickListener {
actionBarShowHide()
true
}
} else {
mView.setOnClickListener { actionBarShowHide() }
mView.setOnLongClickListener {
c.openItemUrl(
items,
adapterPosition,
items[adapterPosition].getLinkDecoded(),
customTabsIntent,
internalBrowser,
articleViewer,
app
)
true
}
}
}
private fun actionBarShowHide() {
bars[adapterPosition] = true
if (mView.actionBar.visibility == View.GONE) {
mView.actionBar.visibility = View.VISIBLE
} else {
mView.actionBar.visibility = View.GONE
}
} }
} }
} }
@@ -0,0 +1,241 @@
package apps.amine.bou.readerforselfoss.adapters
import android.app.Activity
import android.graphics.Color
import com.google.android.material.snackbar.Snackbar
import androidx.recyclerview.widget.RecyclerView
import android.widget.TextView
import android.widget.Toast
import apps.amine.bou.readerforselfoss.R
import apps.amine.bou.readerforselfoss.api.selfoss.Item
import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse
import apps.amine.bou.readerforselfoss.persistence.database.AppDatabase
import apps.amine.bou.readerforselfoss.persistence.entities.ActionEntity
import apps.amine.bou.readerforselfoss.themes.AppColors
import apps.amine.bou.readerforselfoss.utils.Config
import apps.amine.bou.readerforselfoss.utils.network.isNetworkAccessible
import apps.amine.bou.readerforselfoss.utils.persistence.toEntity
import apps.amine.bou.readerforselfoss.utils.succeeded
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import kotlin.concurrent.thread
abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapter<VH>() {
abstract var items: ArrayList<Item>
abstract val api: SelfossApi
abstract val db: AppDatabase
abstract val userIdentifier: String
abstract val app: Activity
abstract val appColors: AppColors
abstract val config: Config
abstract val updateItems: (ArrayList<Item>) -> Unit
fun updateAllItems(newItems: ArrayList<Item>) {
items = newItems
notifyDataSetChanged()
updateItems(items)
}
private fun unmarkSnackbar(i: Item, position: Int) {
val s = Snackbar
.make(
app.findViewById(R.id.coordLayout),
R.string.marked_as_read,
Snackbar.LENGTH_LONG
)
.setAction(R.string.undo_string) {
items.add(position, i)
thread {
db.itemsDao().insertAllItems(i.toEntity())
}
notifyItemInserted(position)
updateItems(items)
if (app.isNetworkAccessible(null)) {
api.unmarkItem(i.id).enqueue(object : Callback<SuccessResponse> {
override fun onResponse(
call: Call<SuccessResponse>,
response: Response<SuccessResponse>
) {
}
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
items.remove(i)
thread {
db.itemsDao().delete(i.toEntity())
}
notifyItemRemoved(position)
updateItems(items)
}
})
} else {
thread {
db.actionsDao().insertAllActions(ActionEntity(i.id, false, true, false, false))
}
}
}
val view = s.view
val tv: TextView = view.findViewById(com.google.android.material.R.id.snackbar_text)
tv.setTextColor(Color.WHITE)
s.show()
}
private fun markSnackbar(i: Item, position: Int) {
val s = Snackbar
.make(
app.findViewById(R.id.coordLayout),
R.string.marked_as_unread,
Snackbar.LENGTH_LONG
)
.setAction(R.string.undo_string) {
items.add(position, i)
thread {
db.itemsDao().delete(i.toEntity())
}
notifyItemInserted(position)
updateItems(items)
if (app.isNetworkAccessible(null)) {
api.markItem(i.id).enqueue(object : Callback<SuccessResponse> {
override fun onResponse(
call: Call<SuccessResponse>,
response: Response<SuccessResponse>
) {
}
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
items.remove(i)
thread {
db.itemsDao().insertAllItems(i.toEntity())
}
notifyItemRemoved(position)
updateItems(items)
}
})
} else {
thread {
db.actionsDao().insertAllActions(ActionEntity(i.id, true, false, false, false))
}
}
}
val view = s.view
val tv: TextView = view.findViewById(com.google.android.material.R.id.snackbar_text)
tv.setTextColor(Color.WHITE)
s.show()
}
fun handleItemAtIndex(position: Int) {
if (unreadItemStatusAtIndex(position)) {
readItemAtIndex(position)
} else {
unreadItemAtIndex(position)
}
}
fun unreadItemStatusAtIndex(position: Int): Boolean {
return items[position].unread
}
private fun readItemAtIndex(position: Int) {
val i = items[position]
items.remove(i)
notifyItemRemoved(position)
updateItems(items)
thread {
db.itemsDao().delete(i.toEntity())
}
if (app.isNetworkAccessible(null)) {
api.markItem(i.id).enqueue(object : Callback<SuccessResponse> {
override fun onResponse(
call: Call<SuccessResponse>,
response: Response<SuccessResponse>
) {
unmarkSnackbar(i, position)
}
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
Toast.makeText(
app,
app.getString(R.string.cant_mark_read),
Toast.LENGTH_SHORT
).show()
items.add(position, i)
notifyItemInserted(position)
updateItems(items)
thread {
db.itemsDao().insertAllItems(i.toEntity())
}
}
})
} else {
thread {
db.actionsDao().insertAllActions(ActionEntity(i.id, true, false, false, false))
}
}
}
private fun unreadItemAtIndex(position: Int) {
val i = items[position]
items.remove(i)
notifyItemRemoved(position)
updateItems(items)
thread {
db.itemsDao().insertAllItems(i.toEntity())
}
if (app.isNetworkAccessible(null)) {
api.unmarkItem(i.id).enqueue(object : Callback<SuccessResponse> {
override fun onResponse(
call: Call<SuccessResponse>,
response: Response<SuccessResponse>
) {
markSnackbar(i, position)
}
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
Toast.makeText(
app,
app.getString(R.string.cant_mark_unread),
Toast.LENGTH_SHORT
).show()
items.add(i)
notifyItemInserted(position)
updateItems(items)
thread {
db.itemsDao().delete(i.toEntity())
}
}
})
} else {
thread {
db.actionsDao().insertAllActions(ActionEntity(i.id, false, true, false, false))
}
}
}
fun addItemAtIndex(item: Item, position: Int) {
items.add(position, item)
notifyItemInserted(position)
updateItems(items)
}
fun addItemsAtEnd(newItems: List<Item>) {
val oldSize = items.size
items.addAll(newItems)
notifyItemRangeInserted(oldSize, newItems.size)
updateItems(items)
}
}
@@ -2,17 +2,19 @@ package apps.amine.bou.readerforselfoss.adapters
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
import android.support.constraint.ConstraintLayout import androidx.constraintlayout.widget.ConstraintLayout
import android.support.v7.widget.RecyclerView import androidx.recyclerview.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.Toast import android.widget.Toast
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.Source
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.glide.circularBitmapDrawable import apps.amine.bou.readerforselfoss.utils.glide.circularBitmapDrawable
import apps.amine.bou.readerforselfoss.utils.network.isNetworkAccessible
import apps.amine.bou.readerforselfoss.utils.toTextDrawableString import apps.amine.bou.readerforselfoss.utils.toTextDrawableString
import com.amulyakhare.textdrawable.TextDrawable import com.amulyakhare.textdrawable.TextDrawable
import com.amulyakhare.textdrawable.util.ColorGenerator import com.amulyakhare.textdrawable.util.ColorGenerator
@@ -23,11 +25,12 @@ import retrofit2.Response
class SourcesListAdapter( class SourcesListAdapter(
private val app: Activity, private val app: Activity,
private val items: ArrayList<Sources>, private val items: ArrayList<Source>,
private val api: SelfossApi private val api: SelfossApi
) : RecyclerView.Adapter<SourcesListAdapter.ViewHolder>() { ) : 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
private lateinit var config: Config
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val v = LayoutInflater.from(c).inflate( val v = LayoutInflater.from(c).inflate(
@@ -40,21 +43,22 @@ class SourcesListAdapter(
override fun onBindViewHolder(holder: ViewHolder, position: Int) { override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val itm = items[position] val itm = items[position]
config = Config(c)
if (itm.getIcon(c).isEmpty()) { if (itm.getIcon(c).isEmpty()) {
val color = generator.getColor(itm.title) val color = generator.getColor(itm.getTitleDecoded())
val drawable = val drawable =
TextDrawable TextDrawable
.builder() .builder()
.round() .round()
.build(itm.title.toTextDrawableString(), color) .build(itm.getTitleDecoded().toTextDrawableString(c), color)
holder.mView.itemImage.setImageDrawable(drawable) holder.mView.itemImage.setImageDrawable(drawable)
} else { } else {
c.circularBitmapDrawable(itm.getIcon(c), holder.mView.itemImage) c.circularBitmapDrawable(config, itm.getIcon(c), holder.mView.itemImage)
} }
holder.mView.sourceTitle.text = itm.title holder.mView.sourceTitle.text = itm.getTitleDecoded()
} }
override fun getItemCount(): Int = items.size override fun getItemCount(): Int = items.size
@@ -70,6 +74,7 @@ class SourcesListAdapter(
val deleteBtn: Button = mView.findViewById(R.id.deleteBtn) val deleteBtn: Button = mView.findViewById(R.id.deleteBtn)
deleteBtn.setOnClickListener { deleteBtn.setOnClickListener {
if (c.isNetworkAccessible(null)) {
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( override fun onResponse(
@@ -101,3 +106,4 @@ class SourcesListAdapter(
} }
} }
} }
}
@@ -7,17 +7,13 @@ 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 service: MercuryService private val service: MercuryService
init { init {
val interceptor = HttpLoggingInterceptor() val interceptor = HttpLoggingInterceptor()
interceptor.level = if (shouldLog) { interceptor.level = HttpLoggingInterceptor.Level.NONE
HttpLoggingInterceptor.Level.BODY
} else {
HttpLoggingInterceptor.Level.NONE
}
val client = OkHttpClient.Builder().addInterceptor(interceptor).build() val client = OkHttpClient.Builder().addInterceptor(interceptor).build()
val gson = GsonBuilder() val gson = GsonBuilder()
@@ -26,7 +22,7 @@ class MercuryApi(private val key: String, shouldLog: Boolean) {
val retrofit = val retrofit =
Retrofit Retrofit
.Builder() .Builder()
.baseUrl("https://mercury.postlight.com") .baseUrl("https://www.amine-bou.fr")
.client(client) .client(client)
.addConverterFactory(GsonConverterFactory.create(gson)) .addConverterFactory(GsonConverterFactory.create(gson))
.build() .build()
@@ -34,6 +30,6 @@ class MercuryApi(private val key: String, shouldLog: Boolean) {
} }
fun parseUrl(url: String): Call<ParsedContent> { fun parseUrl(url: String): Call<ParsedContent> {
return service.parseUrl(url, this.key) return service.parseUrl(url)
} }
} }
@@ -6,9 +6,9 @@ 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?,
@SerializedName("dek") val dek: String, @SerializedName("dek") val dek: String,
@SerializedName("url") val url: String, @SerializedName("url") val url: String,
@SerializedName("domain") val domain: String, @SerializedName("domain") val domain: String,
@@ -20,24 +20,25 @@ class ParsedContent(
companion object { companion object {
@JvmField @JvmField
val CREATOR: Parcelable.Creator<ParsedContent> = object : Parcelable.Creator<ParsedContent> { 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)
} }
} }
constructor(source: Parcel) : this( constructor(source: Parcel) : this(
title = source.readString(), title = source.readString().orEmpty(),
content = source.readString(), content = source.readString(),
date_published = source.readString(), date_published = source.readString().orEmpty(),
lead_image_url = source.readString(), lead_image_url = source.readString(),
dek = source.readString(), dek = source.readString().orEmpty(),
url = source.readString(), url = source.readString().orEmpty(),
domain = source.readString(), domain = source.readString().orEmpty(),
excerpt = source.readString(), excerpt = source.readString().orEmpty(),
total_pages = source.readInt(), total_pages = source.readInt(),
rendered_pages = source.readInt(), rendered_pages = source.readInt(),
next_page_url = source.readString() next_page_url = source.readString().orEmpty()
) )
override fun describeContents() = 0 override fun describeContents() = 0
@@ -6,6 +6,6 @@ import retrofit2.http.Header
import retrofit2.http.Query import retrofit2.http.Query
interface MercuryService { interface MercuryService {
@GET("parser") @GET("parser.php")
fun parseUrl(@Query("url") url: String, @Header("x-api-key") key: String): Call<ParsedContent> fun parseUrl(@Query("link") link: String): Call<ParsedContent>
} }
@@ -12,18 +12,20 @@ import com.burgstaller.okhttp.digest.CachingAuthenticator
import com.burgstaller.okhttp.digest.Credentials 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.*
import okhttp3.logging.HttpLoggingInterceptor 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.net.SocketTimeoutException
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.TimeUnit